Merge
authorprr
Tue, 03 May 2016 12:25:20 -0700
changeset 38398 74cd426ebb3d
parent 38397 8ff4232c93c2 (current diff)
parent 37783 c6aca850d162 (diff)
child 38399 bd91ce346b5b
Merge
jdk/src/java.base/share/classes/jdk/internal/module/Hasher.java
jdk/test/javax/transaction/testng/TEST.properties
jdk/test/tools/jlink/hashes/HashesTest.java
jdk/test/tools/jlink/hashes/newsrc/m2/module-info.java
jdk/test/tools/jlink/hashes/newsrc/m2/org/m2/Util.java
jdk/test/tools/jlink/hashes/newsrc/not_matched/module-info.java
jdk/test/tools/jlink/hashes/newsrc/not_matched/org/not_matched/Name.java
jdk/test/tools/jlink/hashes/src/m1/module-info.java
jdk/test/tools/jlink/hashes/src/m1/org/m1/Main.java
jdk/test/tools/jlink/hashes/src/m2/module-info.java
jdk/test/tools/jlink/hashes/src/m2/org/m2/Util.java
jdk/test/tools/jlink/hashes/src/not_matched/module-info.java
jdk/test/tools/jlink/hashes/src/not_matched/org/not_matched/Name.java
jdk/test/tools/launcher/modules/addmods/src/app/Main.java
jdk/test/tools/launcher/modules/addmods/src/lib/jdk/lib/Util.java
jdk/test/tools/launcher/modules/addmods/src/lib/module-info.java
nashorn/test/script/basic/yield.js
--- a/.hgtags	Tue May 03 09:48:02 2016 -0700
+++ b/.hgtags	Tue May 03 12:25:20 2016 -0700
@@ -358,3 +358,4 @@
 6072af7a98be3922f26bdce71b53bb3646cb2ac9 jdk-9+113
 c84d0cce090e161d736de69e941830adf8c2f87a jdk-9+114
 8d78fb40648dd221ce4ef19f9d5aa41ee1a3a884 jdk-9+115
+84aba7335005a3a47751dcf1f37935f97df9f99a jdk-9+116
--- a/.hgtags-top-repo	Tue May 03 09:48:02 2016 -0700
+++ b/.hgtags-top-repo	Tue May 03 12:25:20 2016 -0700
@@ -358,3 +358,4 @@
 55b6d550828d1223b364e6ead4a56e56411c56df jdk-9+113
 1d992540870ff33fe6cc550443388588df9b9e4f jdk-9+114
 09617ce980b99d49abfd54dacfed353c47e2a115 jdk-9+115
+6743a8e0cab7b5f6f4a0575f6664892f0ab740af jdk-9+116
--- a/common/autoconf/boot-jdk.m4	Tue May 03 09:48:02 2016 -0700
+++ b/common/autoconf/boot-jdk.m4	Tue May 03 12:25:20 2016 -0700
@@ -397,6 +397,7 @@
   ADD_JVM_ARG_IF_OK([-XX:+UseSerialGC],boot_jdk_jvmargs_small,[$JAVA])
   ADD_JVM_ARG_IF_OK([-Xms32M],boot_jdk_jvmargs_small,[$JAVA])
   ADD_JVM_ARG_IF_OK([-Xmx512M],boot_jdk_jvmargs_small,[$JAVA])
+  ADD_JVM_ARG_IF_OK([-XX:TieredStopAtLevel=1],boot_jdk_jvmargs_small,[$JAVA])
 
   AC_MSG_RESULT([$boot_jdk_jvmargs_small])
 
--- a/common/autoconf/compare.sh.in	Tue May 03 09:48:02 2016 -0700
+++ b/common/autoconf/compare.sh.in	Tue May 03 12:25:20 2016 -0700
@@ -31,7 +31,7 @@
 
 export LEGACY_BUILD_DIR=@OPENJDK_TARGET_OS@-@OPENJDK_TARGET_CPU_LEGACY@
 
-sexport OPENJDK_TARGET_OS="@OPENJDK_TARGET_OS@"
+export OPENJDK_TARGET_OS="@OPENJDK_TARGET_OS@"
 export OPENJDK_TARGET_CPU="@OPENJDK_TARGET_CPU@"
 export OPENJDK_TARGET_CPU_LIBDIR="@OPENJDK_TARGET_CPU_LIBDIR@"
 export DEBUG_LEVEL="@DEBUG_LEVEL@"
--- a/common/autoconf/generated-configure.sh	Tue May 03 09:48:02 2016 -0700
+++ b/common/autoconf/generated-configure.sh	Tue May 03 12:25:20 2016 -0700
@@ -1224,9 +1224,9 @@
 with_dxsdk
 with_dxsdk_lib
 with_dxsdk_include
-enable_jtreg_failure_handler
 enable_new_hotspot_build
 enable_hotspot_test_in_build
+enable_jtreg_failure_handler
 with_num_cores
 with_memory_size
 with_jobs
@@ -5070,7 +5070,7 @@
 #CUSTOM_AUTOCONF_INCLUDE
 
 # Do not change or remove the following line, it is needed for consistency checks:
-DATE_WHEN_GENERATED=1460963400
+DATE_WHEN_GENERATED=1462204427
 
 ###############################################################################
 #
@@ -15492,7 +15492,7 @@
     HOTSPOT_TARGET_CPU_DEFINE=PPC32
   elif test "x$OPENJDK_TARGET_CPU" = xs390; then
     HOTSPOT_TARGET_CPU_DEFINE=S390
-  elif test "x$OPENJDK_TARGET_CPU" = ss390x; then
+  elif test "x$OPENJDK_TARGET_CPU" = xs390x; then
     HOTSPOT_TARGET_CPU_DEFINE=S390
   fi
 
@@ -15648,7 +15648,7 @@
     HOTSPOT_BUILD_CPU_DEFINE=PPC32
   elif test "x$OPENJDK_BUILD_CPU" = xs390; then
     HOTSPOT_BUILD_CPU_DEFINE=S390
-  elif test "x$OPENJDK_BUILD_CPU" = ss390x; then
+  elif test "x$OPENJDK_BUILD_CPU" = xs390x; then
     HOTSPOT_BUILD_CPU_DEFINE=S390
   fi
 
@@ -64282,6 +64282,21 @@
   fi
 
 
+  $ECHO "Check if jvm arg is ok: -XX:TieredStopAtLevel=1" >&5
+  $ECHO "Command: $JAVA -XX:TieredStopAtLevel=1 -version" >&5
+  OUTPUT=`$JAVA -XX:TieredStopAtLevel=1 -version 2>&1`
+  FOUND_WARN=`$ECHO "$OUTPUT" | grep -i warn`
+  FOUND_VERSION=`$ECHO $OUTPUT | grep " version \""`
+  if test "x$FOUND_VERSION" != x && test "x$FOUND_WARN" = x; then
+    boot_jdk_jvmargs_small="$boot_jdk_jvmargs_small -XX:TieredStopAtLevel=1"
+    JVM_ARG_OK=true
+  else
+    $ECHO "Arg failed:" >&5
+    $ECHO "$OUTPUT" >&5
+    JVM_ARG_OK=false
+  fi
+
+
   { $as_echo "$as_me:${as_lineno-$LINENO}: result: $boot_jdk_jvmargs_small" >&5
 $as_echo "$boot_jdk_jvmargs_small" >&6; }
 
--- a/common/autoconf/platform.m4	Tue May 03 09:48:02 2016 -0700
+++ b/common/autoconf/platform.m4	Tue May 03 12:25:20 2016 -0700
@@ -435,7 +435,7 @@
     HOTSPOT_$1_CPU_DEFINE=PPC32
   elif test "x$OPENJDK_$1_CPU" = xs390; then
     HOTSPOT_$1_CPU_DEFINE=S390
-  elif test "x$OPENJDK_$1_CPU" = ss390x; then
+  elif test "x$OPENJDK_$1_CPU" = xs390x; then
     HOTSPOT_$1_CPU_DEFINE=S390
   fi
   AC_SUBST(HOTSPOT_$1_CPU_DEFINE)
--- a/common/conf/jib-profiles.js	Tue May 03 09:48:02 2016 -0700
+++ b/common/conf/jib-profiles.js	Tue May 03 12:25:20 2016 -0700
@@ -212,14 +212,17 @@
  * @returns Common values
  */
 var getJibProfilesCommon = function (input) {
-    var common = {
-        dependencies: ["boot_jdk", "gnumake", "jtreg"],
-        configure_args: ["--with-default-make-target=all", "--enable-jtreg-failure-handler"],
-        configure_args_32bit: ["--with-target-bits=32", "--with-jvm-variants=client,server"],
-        configure_args_debug: ["--enable-debug"],
-        configure_args_slowdebug: ["--with-debug-level=slowdebug"],
-        organization: "jpg.infra.builddeps"
-    };
+    var common = {};
+
+    common.dependencies = ["boot_jdk", "gnumake", "jtreg"],
+    common.default_make_targets = ["product-images", "test-image"],
+    common.default_make_targets_debug = common.default_make_targets;
+    common.default_make_targets_slowdebug = common.default_make_targets;
+    common.configure_args = ["--enable-jtreg-failure-handler"],
+    common.configure_args_32bit = ["--with-target-bits=32", "--with-jvm-variants=client,server"],
+    common.configure_args_debug = ["--enable-debug"],
+    common.configure_args_slowdebug = ["--with-debug-level=slowdebug"],
+    common.organization = "jpg.infra.builddeps"
 
     return common;
 };
@@ -241,8 +244,8 @@
             target_os: "linux",
             target_cpu: "x64",
             dependencies: concat(common.dependencies, "devkit"),
-	    configure_args: concat(common.configure_args, "--with-zlib=system"),
-            make_args: common.make_args
+            configure_args: concat(common.configure_args, "--with-zlib=system"),
+            default_make_targets: concat(common.default_make_targets, "docs-image")
         },
 
         "linux-x86": {
@@ -252,39 +255,39 @@
             dependencies: concat(common.dependencies, "devkit"),
             configure_args: concat(common.configure_args, common.configure_args_32bit,
                 "--with-zlib=system"),
-            make_args: common.make_args
+            default_make_targets: common.default_make_targets
         },
 
         "macosx-x64": {
             target_os: "macosx",
             target_cpu: "x64",
             dependencies: concat(common.dependencies, "devkit"),
-	    configure_args: concat(common.configure_args, "--with-zlib=system"),
-            make_args: common.make_args
+            configure_args: concat(common.configure_args, "--with-zlib=system"),
+            default_make_targets: common.default_make_targets
         },
 
         "solaris-x64": {
             target_os: "solaris",
             target_cpu: "x64",
             dependencies: concat(common.dependencies, "devkit", "cups"),
-	    configure_args: concat(common.configure_args, "--with-zlib=system"),
-            make_args: common.make_args
+            configure_args: concat(common.configure_args, "--with-zlib=system"),
+            default_make_targets: common.default_make_targets
         },
 
         "solaris-sparcv9": {
             target_os: "solaris",
             target_cpu: "sparcv9",
             dependencies: concat(common.dependencies, "devkit", "cups"),
-	    configure_args: concat(common.configure_args, "--with-zlib=system"),
-            make_args: common.make_args
+            configure_args: concat(common.configure_args, "--with-zlib=system"),
+            default_make_targets: common.default_make_targets
         },
 
         "windows-x64": {
             target_os: "windows",
             target_cpu: "x64",
             dependencies: concat(common.dependencies, "devkit", "freetype"),
-            configure_args: common.configure_args,
-            make_args: common.make_args
+            configure_args: concat(common.configure_args),
+            default_make_targets: common.default_make_targets
         },
 
         "windows-x86": {
@@ -293,7 +296,7 @@
             build_cpu: "x64",
             dependencies: concat(common.dependencies, "devkit", "freetype"),
             configure_args: concat(common.configure_args, common.configure_args_32bit),
-            make_args: common.make_args
+            default_make_targets: common.default_make_targets
         }
     };
     profiles = concatObjects(profiles, mainProfiles);
@@ -306,14 +309,15 @@
     // implementation builds.
     var openOnlyProfiles = generateOpenOnlyProfiles(common, mainProfiles);
     // The open only profiles on linux are used for reference builds and should
-    // produce the compact profile images by default.
+    // produce the compact profile images by default. This adds "profiles" as an
+    // extra default target.
     var openOnlyProfilesExtra = {
         "linux-x64-open": {
-            configure_args: ["--with-default-make-target=all profiles"],
+            default_make_targets: "profiles"
         },
 
         "linux-x86-open": {
-            configure_args: ["--with-default-make-target=all profiles"],
+            default_make_targets: "profiles"
         }
     };
     var openOnlyProfiles = concatObjects(openOnlyProfiles, openOnlyProfilesExtra);
@@ -336,6 +340,7 @@
 
     // Generate the missing platform attributes
     profiles = generatePlatformAttributes(profiles);
+    profiles = generateDefaultMakeTargetsConfigureArg(common, profiles);
     return profiles;
 };
 
@@ -469,6 +474,8 @@
         var debugProfile = profile + "-debug";
         newProfiles[debugProfile] = clone(profiles[profile]);
         newProfiles[debugProfile].debug_level = "fastdebug";
+        newProfiles[debugProfile].default_make_targets
+            = common.default_make_targets_debug;
         newProfiles[debugProfile].labels
             = concat(newProfiles[debugProfile].labels || [], "debug"),
             newProfiles[debugProfile].configure_args
@@ -492,6 +499,8 @@
         var debugProfile = profile + "-slowdebug";
         newProfiles[debugProfile] = clone(profiles[profile]);
         newProfiles[debugProfile].debug_level = "slowdebug";
+        newProfiles[debugProfile].default_make_targets
+            = common.default_make_targets_slowdebug;
         newProfiles[debugProfile].labels
             = concat(newProfiles[debugProfile].labels || [], "slowdebug"),
             newProfiles[debugProfile].configure_args
@@ -524,6 +533,39 @@
 };
 
 /**
+ * The default_make_targets attribute on a profile is not a real Jib attribute.
+ * This function rewrites that attribute into the corresponding configure arg.
+ * Calling this function multiple times on the same profiles object is safe.
+ *
+ * @param common Common values
+ * @param profiles Profiles map to rewrite profiles for
+ * @returns {{}} New map of profiles with the make targets converted
+ */
+var generateDefaultMakeTargetsConfigureArg = function (common, profiles) {
+    var ret = concatObjects(profiles, {});
+    for (var profile in ret) {
+        if (ret[profile]["default_make_targets"] != null) {
+            var targetsString = concat(ret[profile].default_make_targets).join(" ");
+            // Iterate over all configure args and see if --with-default-make-target
+            // is already there and change it, otherwise add it.
+            var found = false;
+            for (var arg in ret[profile].configure_args) {
+                if (arg.startsWith("--with-default-make-target")) {
+                    found = true;
+                    arg.replace(/=.*/, "=" + targetsString);
+                }
+            }
+            if (!found) {
+                ret[profile].configure_args = concat(
+                    ret[profile].configure_args,
+                    "--with-default-make-target=" + targetsString);
+            }
+        }
+    }
+    return ret;
+}
+
+/**
  * Deep clones an object tree.
  *
  * @param o Object to clone
--- a/corba/.hgtags	Tue May 03 09:48:02 2016 -0700
+++ b/corba/.hgtags	Tue May 03 12:25:20 2016 -0700
@@ -358,3 +358,4 @@
 cc30faa2da498c478e89ab062ff160653ca1b170 jdk-9+113
 10d175b0368c30f54350fc648adc41b94ce357ee jdk-9+114
 7bab1b1b36824924b1c657a8419369ba93d198d3 jdk-9+115
+7dfa7377a5e601b8f740741a9a80e04c72dd04d6 jdk-9+116
--- a/hotspot/.hgtags	Tue May 03 09:48:02 2016 -0700
+++ b/hotspot/.hgtags	Tue May 03 12:25:20 2016 -0700
@@ -518,3 +518,4 @@
 c569f8d89269fb6205b90f727581eb8cc04132f9 jdk-9+113
 b64432bae5271735fd53300b2005b713e98ef411 jdk-9+114
 88dd08d7be0fe7fb9f1914b1628f0aae9bf56e25 jdk-9+115
+61a214186dae6811dd989e9165e42f7dbf02acde jdk-9+116
--- a/jaxp/.hgtags	Tue May 03 09:48:02 2016 -0700
+++ b/jaxp/.hgtags	Tue May 03 12:25:20 2016 -0700
@@ -358,3 +358,4 @@
 28626780e245fccbfb9bad8e3b05f62357958038 jdk-9+113
 147114dd0641cd7c9fe6e81642eb993a7b9c6f0b jdk-9+114
 1902a5bda18e794b31fc5f520f5e7d827714b50d jdk-9+115
+9d71d20e614777cd23c1a43b38b5c08a9094d27a jdk-9+116
--- a/jaxp/src/java.xml/share/classes/javax/xml/catalog/CatalogFeatures.java	Tue May 03 09:48:02 2016 -0700
+++ b/jaxp/src/java.xml/share/classes/javax/xml/catalog/CatalogFeatures.java	Tue May 03 12:25:20 2016 -0700
@@ -444,13 +444,15 @@
                 }
             } else if (index == Feature.FILES.ordinal()) {
                 try {
-                    if (Util.verifyAndGetURI(value, null) == null) {
-                        CatalogMessages.reportIAE(new Object[]{value, Feature.FILES.name()}, null);
+                    String[] catalogFile = value.split(";[ ]*");
+                    for (String temp : catalogFile) {
+                        if (Util.verifyAndGetURI(temp, null) == null) {
+                            CatalogMessages.reportIAE(new Object[]{value, Feature.FILES.name()}, null);
+                        }
                     }
                 }catch (MalformedURLException | URISyntaxException | IllegalArgumentException ex) {
                     CatalogMessages.reportIAE(new Object[]{value, Feature.FILES.name()}, ex);
                 }
-
             }
             if (states[index] == null || state.compareTo(states[index]) >= 0) {
                 values[index] = value;
--- a/jaxp/test/javax/xml/jaxp/libs/jaxp/library/TestPolicy.java	Tue May 03 09:48:02 2016 -0700
+++ b/jaxp/test/javax/xml/jaxp/libs/jaxp/library/TestPolicy.java	Tue May 03 12:25:20 2016 -0700
@@ -91,6 +91,7 @@
         permissions.add(new PropertyPermission("line.separator", "read"));
         permissions.add(new PropertyPermission("fileStringBuffer", "read"));
         permissions.add(new PropertyPermission("dataproviderthreadcount", "read"));
+        permissions.add(new RuntimePermission("charsetProvider"));
     }
 
     /*
--- a/jaxp/test/javax/xml/jaxp/unittest/catalog/CatalogTest.java	Tue May 03 09:48:02 2016 -0700
+++ b/jaxp/test/javax/xml/jaxp/unittest/catalog/CatalogTest.java	Tue May 03 12:25:20 2016 -0700
@@ -23,6 +23,7 @@
 package catalog;
 
 import java.io.IOException;
+import java.nio.file.Paths;
 import javax.xml.catalog.Catalog;
 import javax.xml.catalog.CatalogException;
 import javax.xml.catalog.CatalogFeatures;
@@ -34,6 +35,7 @@
 import javax.xml.parsers.SAXParser;
 import javax.xml.parsers.SAXParserFactory;
 import org.testng.Assert;
+import org.testng.annotations.BeforeClass;
 import org.testng.annotations.DataProvider;
 import org.testng.annotations.Test;
 import org.xml.sax.Attributes;
@@ -44,10 +46,49 @@
 import org.xml.sax.ext.DefaultHandler2;
 
 /*
- * @bug 8081248, 8144966, 8146606, 8146237, 8151154, 8150969, 8151162, 8152527
+ * @bug 8081248, 8144966, 8146606, 8146237, 8151154, 8150969, 8151162, 8152527, 8154220
  * @summary Tests basic Catalog functions.
  */
 public class CatalogTest {
+    static final String KEY_FILES = "javax.xml.catalog.files";
+
+    public String filepath;
+
+    /*
+     * Initializing fields
+     */
+    @BeforeClass
+    public void setUpClass() throws Exception {
+        String file1 = getClass().getResource("first_cat.xml").getFile();
+        if (System.getProperty("os.name").contains("Windows")) {
+            filepath = file1.substring(1, file1.lastIndexOf("/") + 1);
+        } else {
+            filepath = file1.substring(0, file1.lastIndexOf("/") + 1);
+        }
+    }
+
+    /*
+     * @bug 8154220
+     * Verifies that the file input is validated properly. Valid input includes
+     * multiple file paths separated by semicolon.
+     */
+    @Test(dataProvider = "hierarchyOfCatFilesData")
+    public void hierarchyOfCatFiles2(String systemId, String expectedUri) {
+        String file1 = getClass().getResource("first_cat.xml").getFile();
+        String file2 = getClass().getResource("second_cat.xml").getFile();
+        String files = file1 + ";" + file2;
+
+        try {
+            System.setProperty(KEY_FILES, files);
+            CatalogResolver catalogResolver = CatalogManager.catalogResolver(CatalogFeatures.defaults());
+            String sysId = catalogResolver.resolveEntity(null, systemId).getSystemId();
+            Assert.assertEquals(sysId, Paths.get(filepath + expectedUri).toUri().toString().replace("///", "/"), "System ID match not right");
+        } finally {
+            System.clearProperty(KEY_FILES);
+        }
+
+    }
+
     /*
      * @bug 8152527
      * This test is the same as the JDK test ResolveEntityTests:testMatch1.
@@ -289,6 +330,19 @@
     }
 
     /*
+        DataProvider: used to verify hierarchical catalogs. Refer to JCK test
+    hierarchyOfCatFiles2.
+     */
+    @DataProvider(name = "hierarchyOfCatFilesData")
+    Object[][] getHierarchyOfCatFilesData() {
+        return new Object[][]{
+            {"http://www.oracle.com/sequence.dtd", "first.dtd"},
+            {"http://www.oracle.com/sequence_next.dtd", "next.dtd"},
+            {"http://www.oracle.com/sequence_second.dtd", "second.dtd"}
+        };
+    }
+
+    /*
         DataProvider: used to verify CatalogResolver's resolveEntity function.
         Data columns:
         catalog, prefer, systemId, publicId, expectedUri, expectedFile, msg
@@ -300,6 +354,7 @@
             {"rewriteSystem_id.xml", "system", "http://www.sys00test.com/rewrite.dtd", "PUB-404", expected, expected, "Relative rewriteSystem with xml:base at group level failed"},
         };
     }
+
     static String id = "http://openjdk.java.net/xml/catalog/dtd/system.dtd";
     /*
        DataProvider: used to verify how prefer settings affect the result of the
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/unittest/catalog/first_cat.xml	Tue May 03 12:25:20 2016 -0700
@@ -0,0 +1,6 @@
+<catalog prefer="system" xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog">
+
+    <system systemId="http://www.oracle.com/sequence.dtd" uri="first.dtd"/>
+    <nextCatalog catalog="next_cat.xml"/>
+
+</catalog>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/unittest/catalog/next_cat.xml	Tue May 03 12:25:20 2016 -0700
@@ -0,0 +1,6 @@
+<catalog prefer="public" xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog">
+
+    <system systemId="http://www.oracle.com/sequence.dtd" uri="next.dtd"/>
+    <system systemId="http://www.oracle.com/sequence_next.dtd" uri="next.dtd"/>
+
+</catalog>
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/test/javax/xml/jaxp/unittest/catalog/second_cat.xml	Tue May 03 12:25:20 2016 -0700
@@ -0,0 +1,7 @@
+<catalog prefer="public" xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog">
+
+    <system systemId="http://www.oracle.com/sequence.dtd" uri="second.dtd"/>
+    <system systemId="http://www.oracle.com/sequence_next.dtd" uri="second.dtd"/>
+    <system systemId="http://www.oracle.com/sequence_second.dtd" uri="second.dtd"/>
+
+</catalog>
\ No newline at end of file
--- a/jaxws/.hgtags	Tue May 03 09:48:02 2016 -0700
+++ b/jaxws/.hgtags	Tue May 03 12:25:20 2016 -0700
@@ -361,3 +361,4 @@
 e980062475c10d21137051045bf95ee229db9b27 jdk-9+113
 b314bb02182b9ca94708a91f312c377f5435f740 jdk-9+114
 4ff86e5489e4c0513dadfa69def8601c110ca5cd jdk-9+115
+529f0bf896e58525614d863e283ad155531941cb jdk-9+116
--- a/jdk/make/Tools.gmk	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/make/Tools.gmk	Tue May 03 12:25:20 2016 -0700
@@ -96,7 +96,13 @@
 TOOL_SPP = $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes build.tools.spp.Spp
 
 # Nimbus is used somewhere in the swing build.
+
+ifeq ($(BOOT_JDK_MODULAR), true)
+  COMPILENIMBUS_ADD_MODS := -addmods java.xml.bind
+endif
+
 TOOL_GENERATENIMBUS = $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes \
+    $(COMPILENIMBUS_ADD_MODS) \
     build.tools.generatenimbus.Generator
 
 TOOL_WRAPPERGENERATOR = $(JAVA_SMALL) -cp $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes \
--- a/jdk/make/gendata/Gendata-java.base.gmk	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/make/gendata/Gendata-java.base.gmk	Tue May 03 12:25:20 2016 -0700
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 #
 # This code is free software; you can redistribute it and/or modify it
@@ -41,7 +41,7 @@
 GENDATA_UNINAME := $(JDK_OUTPUTDIR)/modules/java.base/java/lang/uniName.dat
 
 $(GENDATA_UNINAME): $(JDK_TOPDIR)/make/data/unicodedata/UnicodeData.txt $(BUILD_TOOLS_JDK)
-	$(MKDIR) -p $(@D)
+	$(call MakeDir, $(@D))
 	$(TOOL_CHARACTERNAME) $< $@
 
 TARGETS += $(GENDATA_UNINAME)
@@ -51,7 +51,7 @@
 GENDATA_CURDATA := $(JDK_OUTPUTDIR)/modules/java.base/java/util/currency.data
 
 $(GENDATA_CURDATA): $(JDK_TOPDIR)/make/data/currency/CurrencyData.properties $(BUILD_TOOLS_JDK)
-	$(MKDIR) -p $(@D)
+	$(call MakeDir, $(@D))
 	$(RM) $@
 	$(TOOL_GENERATECURRENCYDATA) -o $@.tmp < $<
 	$(MV) $@.tmp $@
@@ -67,10 +67,10 @@
 # RESTRICTED_PKGS_SRC is optionally set in custom extension for this makefile
 
 $(GENDATA_JAVA_SECURITY): $(BUILD_TOOLS) $(GENDATA_JAVA_SECURITY_SRC) $(RESTRICTED_PKGS_SRC)
-	$(ECHO) "Generating java.security"
-	$(MKDIR) -p $(@D)
+	$(call LogInfo, Generating java.security)
+	$(call MakeDir, $(@D))
 	$(TOOL_MAKEJAVASECURITY) $(GENDATA_JAVA_SECURITY_SRC) $@ $(OPENJDK_TARGET_OS) \
-		$(OPENJDK_TARGET_CPU_ARCH) $(RESTRICTED_PKGS_SRC) || exit 1
+	    $(OPENJDK_TARGET_CPU_ARCH) $(RESTRICTED_PKGS_SRC)
 
 TARGETS += $(GENDATA_JAVA_SECURITY)
 
@@ -78,7 +78,7 @@
 
 $(SUPPORT_OUTPUTDIR)/modules_libs/java.base/classlist: \
     $(JDK_TOPDIR)/make/data/classlist/classlist.$(OPENJDK_TARGET_OS)
-	$(MKDIR) -p $(@D)
+	$(call MakeDir, $(@D))
 	$(RM) $@ $@.tmp
 	$(TOOL_ADDJSUM) $< $@.tmp
 	$(MV) $@.tmp $@
--- a/jdk/make/gendata/GendataBreakIterator.gmk	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/make/gendata/GendataBreakIterator.gmk	Tue May 03 12:25:20 2016 -0700
@@ -62,10 +62,13 @@
     BIN := $(BREAK_ITERATOR_CLASSES)/jdk.localedata))
 
 ifeq ($(BOOT_JDK_MODULAR), true)
-  BREAK_ITERATOR_BOOTCLASSPATH := -Xpatch:$(BREAK_ITERATOR_CLASSES) \
-        -XaddExports:java.base/sun.text=ALL-UNNAMED \
-        -XaddExports:java.base/sun.text.resources=ALL-UNNAMED \
-        -XaddExports:jdk.localedata/sun.text.resources.ext=ALL-UNNAMED
+  BREAK_ITERATOR_BOOTCLASSPATH := \
+      -Xpatch:java.base=$(BREAK_ITERATOR_CLASSES)/java.base \
+      -Xpatch:jdk.localedata=$(BREAK_ITERATOR_CLASSES)/jdk.localedata \
+      -XaddExports:java.base/sun.text=ALL-UNNAMED \
+      -XaddExports:java.base/sun.text.resources=ALL-UNNAMED \
+      -XaddExports:jdk.localedata/sun.text.resources.ext=ALL-UNNAMED \
+      #
 else
   BREAK_ITERATOR_BOOTCLASSPATH := -Xbootclasspath/p:$(call PathList, \
       $(BREAK_ITERATOR_CLASSES)/java.base \
--- a/jdk/make/launcher/Launcher-java.desktop.gmk	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/make/launcher/Launcher-java.desktop.gmk	Tue May 03 12:25:20 2016 -0700
@@ -31,7 +31,7 @@
 ifndef BUILD_HEADLESS_ONLY
   $(eval $(call SetupBuildLauncher, appletviewer, \
       MAIN_CLASS := sun.applet.Main, \
-      JAVA_ARGS := -addmods ALL-SYSTEM, \
+      JAVA_ARGS := -addmods ALL-DEFAULT, \
       LIBS_unix := $(X_LIBS), \
   ))
 endif
--- a/jdk/make/launcher/Launcher-java.scripting.gmk	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/make/launcher/Launcher-java.scripting.gmk	Tue May 03 12:25:20 2016 -0700
@@ -27,4 +27,5 @@
 
 $(eval $(call SetupBuildLauncher, jrunscript, \
     MAIN_CLASS := com.sun.tools.script.shell.Main, \
+    JAVA_ARGS := -addmods ALL-DEFAULT, \
 ))
--- a/jdk/make/launcher/Launcher-jdk.compiler.gmk	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/make/launcher/Launcher-jdk.compiler.gmk	Tue May 03 12:25:20 2016 -0700
@@ -27,7 +27,8 @@
 
 $(eval $(call SetupBuildLauncher, javac, \
    MAIN_CLASS := com.sun.tools.javac.Main, \
-    CFLAGS := -DEXPAND_CLASSPATH_WILDCARDS \
+   JAVA_ARGS := -addmods ALL-DEFAULT, \
+   CFLAGS := -DEXPAND_CLASSPATH_WILDCARDS \
         -DNEVER_ACT_AS_SERVER_CLASS_MACHINE, \
 ))
 
--- a/jdk/make/launcher/Launcher-jdk.javadoc.gmk	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/make/launcher/Launcher-jdk.javadoc.gmk	Tue May 03 12:25:20 2016 -0700
@@ -27,6 +27,7 @@
 
 $(eval $(call SetupBuildLauncher, javadoc, \
     MAIN_CLASS := jdk.javadoc.internal.tool.Main, \
+    JAVA_ARGS := -addmods ALL-DEFAULT, \
     CFLAGS := -DEXPAND_CLASSPATH_WILDCARDS \
         -DNEVER_ACT_AS_SERVER_CLASS_MACHINE, \
 ))
--- a/jdk/make/launcher/Launcher-jdk.jlink.gmk	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/make/launcher/Launcher-jdk.jlink.gmk	Tue May 03 12:25:20 2016 -0700
@@ -32,6 +32,7 @@
 
 $(eval $(call SetupBuildLauncher, jlink,\
     MAIN_CLASS := jdk.tools.jlink.internal.Main, \
+    JAVA_ARGS := -addmods ALL-DEFAULT, \
     CFLAGS := -DENABLE_ARG_FILES \
         -DEXPAND_CLASSPATH_WILDCARDS \
         -DNEVER_ACT_AS_SERVER_CLASS_MACHINE, \
--- a/jdk/make/launcher/Launcher-jdk.scripting.nashorn.shell.gmk	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/make/launcher/Launcher-jdk.scripting.nashorn.shell.gmk	Tue May 03 12:25:20 2016 -0700
@@ -27,6 +27,6 @@
 
 $(eval $(call SetupBuildLauncher, jjs, \
     MAIN_CLASS := jdk.nashorn.tools.jjs.Main, \
-    JAVA_ARGS := -addmods ALL-SYSTEM, \
+    JAVA_ARGS := -addmods ALL-DEFAULT, \
     CFLAGS := -DENABLE_ARG_FILES, \
 ))
--- a/jdk/src/java.base/linux/classes/sun/nio/fs/LinuxFileSystemProvider.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/linux/classes/sun/nio/fs/LinuxFileSystemProvider.java	Tue May 03 12:25:20 2016 -0700
@@ -102,7 +102,7 @@
 
     @Override
     FileTypeDetector getFileTypeDetector() {
-        String userHome = GetPropertyAction.getProperty("user.home");
+        String userHome = GetPropertyAction.privilegedGetProperty("user.home");
         Path userMimeTypes = Paths.get(userHome, ".mime.types");
         Path etcMimeTypes = Paths.get("/etc/mime.types");
 
--- a/jdk/src/java.base/macosx/classes/sun/nio/ch/KQueueArrayWrapper.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/macosx/classes/sun/nio/ch/KQueueArrayWrapper.java	Tue May 03 12:25:20 2016 -0700
@@ -84,7 +84,8 @@
     static {
         IOUtil.load();
         initStructSizes();
-        String datamodel = GetPropertyAction.getProperty("sun.arch.data.model");
+        String datamodel =
+                GetPropertyAction.privilegedGetProperty("sun.arch.data.model");
         is64bit = "64".equals(datamodel);
     }
 
--- a/jdk/src/java.base/macosx/classes/sun/nio/fs/MacOSXFileSystem.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/macosx/classes/sun/nio/fs/MacOSXFileSystem.java	Tue May 03 12:25:20 2016 -0700
@@ -29,8 +29,6 @@
 import java.io.IOException;
 import java.util.*;
 import java.util.regex.Pattern;
-import java.security.AccessController;
-import sun.security.action.GetPropertyAction;
 
 import static sun.nio.fs.MacOSXNativeDispatcher.*;
 
--- a/jdk/src/java.base/macosx/classes/sun/nio/fs/MacOSXFileSystemProvider.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/macosx/classes/sun/nio/fs/MacOSXFileSystemProvider.java	Tue May 03 12:25:20 2016 -0700
@@ -46,8 +46,8 @@
 
     @Override
     FileTypeDetector getFileTypeDetector() {
-        Path userMimeTypes = Paths.get(
-            GetPropertyAction.getProperty("user.home"), ".mime.types");
+        Path userMimeTypes = Paths.get(GetPropertyAction
+                .privilegedGetProperty("user.home"), ".mime.types");
 
         return chain(new MimeTypesFileTypeDetector(userMimeTypes),
                      new UTIFileTypeDetector());
--- a/jdk/src/java.base/share/classes/java/io/File.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/io/File.java	Tue May 03 12:25:20 2016 -0700
@@ -1896,7 +1896,7 @@
 
         // temporary directory location
         private static final File tmpdir = new File(
-                GetPropertyAction.getProperty("java.io.tmpdir"));
+                GetPropertyAction.privilegedGetProperty("java.io.tmpdir"));
         static File location() {
             return tmpdir;
         }
--- a/jdk/src/java.base/share/classes/java/lang/Class.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/lang/Class.java	Tue May 03 12:25:20 2016 -0700
@@ -470,7 +470,7 @@
      * expression with an empty argument list.  The class is initialized if it
      * has not already been initialized.
      *
-     * <p>Note that this method propagates any exception thrown by the
+     * @deprecated This method propagates any exception thrown by the
      * nullary constructor, including a checked exception.  Use of
      * this method effectively bypasses the compile-time exception
      * checking that would otherwise be performed by the compiler.
@@ -500,6 +500,7 @@
      *          of this class.
      */
     @CallerSensitive
+    @Deprecated(since="9")
     public T newInstance()
         throws InstantiationException, IllegalAccessException
     {
--- a/jdk/src/java.base/share/classes/java/lang/ClassLoader.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/lang/ClassLoader.java	Tue May 03 12:25:20 2016 -0700
@@ -2615,7 +2615,7 @@
     ServicesCatalog createOrGetServicesCatalog() {
         ServicesCatalog catalog = servicesCatalog;
         if (catalog == null) {
-            catalog = new ServicesCatalog();
+            catalog = ServicesCatalog.create();
             boolean set = trySetObjectField("servicesCatalog", catalog);
             if (!set) {
                 // beaten by someone else
--- a/jdk/src/java.base/share/classes/java/lang/ProcessBuilder.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/lang/ProcessBuilder.java	Tue May 03 12:25:20 2016 -0700
@@ -468,7 +468,7 @@
      */
     public abstract static class Redirect {
         private static final File NULL_FILE = new File(
-                (GetPropertyAction.getProperty("os.name")
+                (GetPropertyAction.privilegedGetProperty("os.name")
                         .startsWith("Windows") ? "NUL" : "/dev/null")
         );
 
--- a/jdk/src/java.base/share/classes/java/lang/StackStreamFactory.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/lang/StackStreamFactory.java	Tue May 03 12:25:20 2016 -0700
@@ -78,7 +78,8 @@
      * Performance work and extensive testing is needed to replace the
      * VM built-in backtrace filled in Throwable with the StackWalker.
      */
-    final static boolean isDebug = getProperty("stackwalk.debug", false);
+    final static boolean isDebug =
+            "true".equals(GetPropertyAction.privilegedGetProperty("stackwalk.debug"));
 
     static <T> StackFrameTraverser<T>
         makeStackTraverser(StackWalker walker, Function<? super Stream<StackFrame>, ? extends T> function)
@@ -988,11 +989,4 @@
                 c.getName().startsWith("java.lang.invoke.LambdaForm");
     }
 
-    private static boolean getProperty(String key, boolean value) {
-        String s = GetPropertyAction.getProperty(key);
-        if (s != null) {
-            return Boolean.parseBoolean(s);
-        }
-        return value;
-    }
 }
--- a/jdk/src/java.base/share/classes/java/lang/String.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/lang/String.java	Tue May 03 12:25:20 2016 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1994, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1994, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -78,14 +78,8 @@
  * <p>
  * The Java language provides special support for the string
  * concatenation operator (&nbsp;+&nbsp;), and for conversion of
- * other objects to strings. String concatenation is implemented
- * through the {@code StringBuilder}(or {@code StringBuffer})
- * class and its {@code append} method.
- * String conversions are implemented through the method
- * {@code toString}, defined by {@code Object} and
- * inherited by all classes in Java. For additional information on
- * string concatenation and conversion, see Gosling, Joy, and Steele,
- * <i>The Java Language Specification</i>.
+ * other objects to strings. For additional information on string
+ * concatenation and conversion, see <i>The Java&trade; Language Specification</i>.
  *
  * <p> Unless otherwise noted, passing a {@code null} argument to a constructor
  * or method in this class will cause a {@link NullPointerException} to be
@@ -106,6 +100,14 @@
  * into account.  The {@link java.text.Collator} class provides methods for
  * finer-grain, locale-sensitive String comparison.
  *
+ * @implNote The implementation of the string concatenation operator is left to
+ * the discretion of a Java compiler, as long as the compiler ultimately conforms
+ * to <i>The Java&trade; Language Specification</i>. For example, the {@code javac} compiler
+ * may implement the operator with {@code StringBuffer}, {@code StringBuilder},
+ * or {@code java.lang.invoke.StringConcatFactory} depending on the JDK version. The
+ * implementation of string conversion is typically through the method {@code toString},
+ * defined by {@code Object} and inherited by all classes in Java.
+ *
  * @author  Lee Boynton
  * @author  Arthur van Hoff
  * @author  Martin Buchholz
@@ -115,6 +117,7 @@
  * @see     java.lang.StringBuilder
  * @see     java.nio.charset.Charset
  * @since   1.0
+ * @jls     15.18.1 String Concatenation Operator +
  */
 
 public final class String
@@ -2977,6 +2980,7 @@
      *
      * @return  a string that has the same contents as this string, but is
      *          guaranteed to be from a pool of unique strings.
+     * @jls 3.10.5 String Literals
      */
     public native String intern();
 
--- a/jdk/src/java.base/share/classes/java/lang/System.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/lang/System.java	Tue May 03 12:25:20 2016 -0700
@@ -69,7 +69,6 @@
 import jdk.internal.logger.LocalizedLoggerWrapper;
 
 import jdk.internal.module.ModuleBootstrap;
-import jdk.internal.module.Modules;
 import jdk.internal.module.ServicesCatalog;
 
 /**
@@ -1924,10 +1923,6 @@
         // initialize the module system
         System.bootLayer = ModuleBootstrap.boot();
 
-        // base module needs to be loose (CODETOOLS-7901619)
-        Module base = Object.class.getModule();
-        Modules.addReads(base, null);
-
         // module system initialized
         VM.initLevel(2);
     }
--- a/jdk/src/java.base/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java	Tue May 03 12:25:20 2016 -0700
@@ -88,7 +88,7 @@
 
     static {
         final String key = "jdk.internal.lambda.dumpProxyClasses";
-        String path = GetPropertyAction.getProperty(key);
+        String path = GetPropertyAction.privilegedGetProperty(key);
         dumper = (null == path) ? null : ProxyClassesDumper.getInstance(path);
     }
 
--- a/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleStatics.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/MethodHandleStatics.java	Tue May 03 12:25:20 2016 -0700
@@ -53,7 +53,7 @@
     static final boolean VAR_HANDLE_GUARDS;
 
     static {
-        Properties props = GetPropertyAction.getProperties();
+        Properties props = GetPropertyAction.privilegedGetProperties();
         DEBUG_METHOD_HANDLE_NAMES = Boolean.parseBoolean(
                 props.getProperty("java.lang.invoke.MethodHandle.DEBUG_NAMES"));
         DUMP_CLASS_FILES = Boolean.parseBoolean(
--- a/jdk/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java	Tue May 03 12:25:20 2016 -0700
@@ -197,7 +197,7 @@
         // DEBUG = false;        // implied
         // DUMPER = null;        // implied
 
-        Properties props = GetPropertyAction.getProperties();
+        Properties props = GetPropertyAction.privilegedGetProperties();
         final String strategy =
                 props.getProperty("java.lang.invoke.stringConcat");
         CACHE_ENABLE = Boolean.parseBoolean(
--- a/jdk/src/java.base/share/classes/java/lang/invoke/VarHandle.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/VarHandle.java	Tue May 03 12:25:20 2016 -0700
@@ -136,6 +136,7 @@
  * consists of the methods
  * {@link #compareAndSet compareAndSet},
  * {@link #weakCompareAndSet weakCompareAndSet},
+ * {@link #weakCompareAndSetVolatile weakCompareAndSetVolatile},
  * {@link #weakCompareAndSetAcquire weakCompareAndSetAcquire},
  * {@link #weakCompareAndSetRelease weakCompareAndSetRelease},
  * {@link #compareAndExchangeAcquire compareAndExchangeAcquire},
@@ -458,7 +459,7 @@
      *
      * <p>The symbolic type descriptor at the call site of {@code get}
      * must match the access mode type that is the result of calling
-     * {@code accessModeType(VarHandle.AccessMode.get)} on this VarHandle.
+     * {@code accessModeType(VarHandle.AccessMode.GET)} on this VarHandle.
      *
      * <p>This access mode is supported by all VarHandle instances and never
      * throws {@code UnsupportedOperationException}.
@@ -488,7 +489,7 @@
      *
      * <p>The symbolic type descriptor at the call site of {@code set}
      * must match the access mode type that is the result of calling
-     * {@code accessModeType(VarHandle.AccessMode.set)} on this VarHandle.
+     * {@code accessModeType(VarHandle.AccessMode.SET)} on this VarHandle.
      *
      * @param args the signature-polymorphic parameter list of the form
      * {@code (CT, T newValue)}
@@ -516,7 +517,8 @@
      *
      * <p>The symbolic type descriptor at the call site of {@code getVolatile}
      * must match the access mode type that is the result of calling
-     * {@code accessModeType(VarHandle.AccessMode.getVolatile)} on this VarHandle.
+     * {@code accessModeType(VarHandle.AccessMode.GET_VOLATILE)} on this
+     * VarHandle.
      *
      * @param args the signature-polymorphic parameter list of the form
      * {@code (CT)}
@@ -544,7 +546,8 @@
      *
      * <p>The symbolic type descriptor at the call site of {@code setVolatile}
      * must match the access mode type that is the result of calling
-     * {@code accessModeType(VarHandle.AccessMode.setVolatile)} on this VarHandle.
+     * {@code accessModeType(VarHandle.AccessMode.SET_VOLATILE)} on this
+     * VarHandle.
      *
      * @apiNote
      * Ignoring the many semantic differences from C and C++, this method has
@@ -574,7 +577,8 @@
      *
      * <p>The symbolic type descriptor at the call site of {@code getOpaque}
      * must match the access mode type that is the result of calling
-     * {@code accessModeType(VarHandle.AccessMode.getOpaque)} on this VarHandle.
+     * {@code accessModeType(VarHandle.AccessMode.GET_OPAQUE)} on this
+     * VarHandle.
      *
      * @param args the signature-polymorphic parameter list of the form
      * {@code (CT)}
@@ -603,7 +607,8 @@
      *
      * <p>The symbolic type descriptor at the call site of {@code setOpaque}
      * must match the access mode type that is the result of calling
-     * {@code accessModeType(VarHandle.AccessMode.setOpaque)} on this VarHandle.
+     * {@code accessModeType(VarHandle.AccessMode.SET_OPAQUE)} on this
+     * VarHandle.
      *
      * @param args the signature-polymorphic parameter list of the form
      * {@code (CT, T newValue)}
@@ -631,7 +636,8 @@
      *
      * <p>The symbolic type descriptor at the call site of {@code getAcquire}
      * must match the access mode type that is the result of calling
-     * {@code accessModeType(VarHandle.AccessMode.getAcquire)} on this VarHandle.
+     * {@code accessModeType(VarHandle.AccessMode.GET_ACQUIRE)} on this
+     * VarHandle.
      *
      * @apiNote
      * Ignoring the many semantic differences from C and C++, this method has
@@ -664,7 +670,8 @@
      *
      * <p>The symbolic type descriptor at the call site of {@code setRelease}
      * must match the access mode type that is the result of calling
-     * {@code accessModeType(VarHandle.AccessMode.setRelease)} on this VarHandle.
+     * {@code accessModeType(VarHandle.AccessMode.SET_RELEASE)} on this
+     * VarHandle.
      *
      * @apiNote
      * Ignoring the many semantic differences from C and C++, this method has
@@ -700,7 +707,7 @@
      *
      * <p>The symbolic type descriptor at the call site of {@code
      * compareAndSet} must match the access mode type that is the result of
-     * calling {@code accessModeType(VarHandle.AccessMode.compareAndSet)} on
+     * calling {@code accessModeType(VarHandle.AccessMode.COMPARE_AND_SET)} on
      * this VarHandle.
      *
      * @param args the signature-polymorphic parameter list of the form
@@ -734,7 +741,7 @@
      * <p>The symbolic type descriptor at the call site of {@code
      * compareAndExchangeVolatile}
      * must match the access mode type that is the result of calling
-     * {@code accessModeType(VarHandle.AccessMode.compareAndExchangeVolatile)}
+     * {@code accessModeType(VarHandle.AccessMode.COMPARE_AND_EXCHANGE_VOLATILE)}
      * on this VarHandle.
      *
      * @param args the signature-polymorphic parameter list of the form
@@ -769,7 +776,7 @@
      * <p>The symbolic type descriptor at the call site of {@code
      * compareAndExchangeAcquire}
      * must match the access mode type that is the result of calling
-     * {@code accessModeType(VarHandle.AccessMode.compareAndExchangeAcquire)} on
+     * {@code accessModeType(VarHandle.AccessMode.COMPARE_AND_EXCHANGE_ACQUIRE)} on
      * this VarHandle.
      *
      * @param args the signature-polymorphic parameter list of the form
@@ -804,7 +811,8 @@
      * <p>The symbolic type descriptor at the call site of {@code
      * compareAndExchangeRelease}
      * must match the access mode type that is the result of calling
-     * {@code accessModeType(VarHandle.AccessMode.compareAndExchangeRelease)} on this VarHandle.
+     * {@code accessModeType(VarHandle.AccessMode.COMPARE_AND_EXCHANGE_RELEASE)}
+     * on this VarHandle.
      *
      * @param args the signature-polymorphic parameter list of the form
      * {@code (CT, T expectedValue, T newValue)}
@@ -836,14 +844,14 @@
      * {@link #get}.
      *
      * <p>This operation may fail spuriously (typically, due to memory
-     * contention) even if the current value does match the expected value.
+     * contention) even if the witness value does match the expected value.
      *
      * <p>The method signature is of the form {@code (CT, T expectedValue, T newValue)boolean}.
      *
      * <p>The symbolic type descriptor at the call site of {@code
      * weakCompareAndSet} must match the access mode type that is the result of
-     * calling {@code accessModeType(VarHandle.AccessMode.weakCompareAndSet)} on
-     * this VarHandle.
+     * calling {@code accessModeType(VarHandle.AccessMode.WEAK_COMPARE_AND_SET)}
+     * on this VarHandle.
      *
      * @param args the signature-polymorphic parameter list of the form
      * {@code (CT, T expectedValue, T newValue)}
@@ -867,20 +875,58 @@
 
     /**
      * Possibly atomically sets the value of a variable to the {@code newValue}
+     * with the memory semantics of {@link #setVolatile} if the variable's
+     * current value, referred to as the <em>witness value</em>, {@code ==} the
+     * {@code expectedValue}, as accessed with the memory semantics of
+     * {@link #getVolatile}.
+     *
+     * <p>This operation may fail spuriously (typically, due to memory
+     * contention) even if the witness value does match the expected value.
+     *
+     * <p>The method signature is of the form {@code (CT, T expectedValue, T newValue)boolean}.
+     *
+     * <p>The symbolic type descriptor at the call site of {@code
+     * weakCompareAndSetVolatile} must match the access mode type that is the
+     * result of calling {@code accessModeType(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_VOLATILE)}
+     * on this VarHandle.
+     *
+     * @param args the signature-polymorphic parameter list of the form
+     * {@code (CT, T expectedValue, T newValue)}
+     * , statically represented using varargs.
+     * @return {@code true} if successful, otherwise {@code false} if the
+     * witness value was not the same as the {@code expectedValue} or if this
+     * operation spuriously failed.
+     * @throws UnsupportedOperationException if the access mode is unsupported
+     * for this VarHandle.
+     * @throws WrongMethodTypeException if the access mode type is not
+     * compatible with the caller's symbolic type descriptor.
+     * @throws ClassCastException if the access mode type is compatible with the
+     * caller's symbolic type descriptor, but a reference cast fails.
+     * @see #setVolatile(Object...)
+     * @see #getVolatile(Object...)
+     */
+    public final native
+    @MethodHandle.PolymorphicSignature
+    @HotSpotIntrinsicCandidate
+    boolean weakCompareAndSetVolatile(Object... args);
+
+    /**
+     * Possibly atomically sets the value of a variable to the {@code newValue}
      * with the semantics of {@link #set} if the variable's current value,
      * referred to as the <em>witness value</em>, {@code ==} the
      * {@code expectedValue}, as accessed with the memory semantics of
      * {@link #getAcquire}.
      *
      * <p>This operation may fail spuriously (typically, due to memory
-     * contention) even if the current value does match the expected value.
+     * contention) even if the witness value does match the expected value.
      *
      * <p>The method signature is of the form {@code (CT, T expectedValue, T newValue)boolean}.
      *
      * <p>The symbolic type descriptor at the call site of {@code
      * weakCompareAndSetAcquire}
      * must match the access mode type that is the result of calling
-     * {@code accessModeType(VarHandle.AccessMode.weakCompareAndSetAcquire)} on this VarHandle.
+     * {@code accessModeType(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE)}
+     * on this VarHandle.
      *
      * @param args the signature-polymorphic parameter list of the form
      * {@code (CT, T expectedValue, T newValue)}
@@ -910,14 +956,15 @@
      * {@link #get}.
      *
      * <p>This operation may fail spuriously (typically, due to memory
-     * contention) even if the current value does match the expected value.
+     * contention) even if the witness value does match the expected value.
      *
      * <p>The method signature is of the form {@code (CT, T expectedValue, T newValue)boolean}.
      *
      * <p>The symbolic type descriptor at the call site of {@code
      * weakCompareAndSetRelease}
      * must match the access mode type that is the result of calling
-     * {@code accessModeType(VarHandle.AccessMode.weakCompareAndSetRelease)} on this VarHandle.
+     * {@code accessModeType(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE)}
+     * on this VarHandle.
      *
      * @param args the signature-polymorphic parameter list of the form
      * {@code (CT, T expectedValue, T newValue)}
@@ -949,7 +996,8 @@
      *
      * <p>The symbolic type descriptor at the call site of {@code getAndSet}
      * must match the access mode type that is the result of calling
-     * {@code accessModeType(VarHandle.AccessMode.getAndSet)} on this VarHandle.
+     * {@code accessModeType(VarHandle.AccessMode.GET_AND_SET)} on this
+     * VarHandle.
      *
      * @param args the signature-polymorphic parameter list of the form
      * {@code (CT, T newValue)}
@@ -985,7 +1033,8 @@
      *
      * <p>The symbolic type descriptor at the call site of {@code getAndAdd}
      * must match the access mode type that is the result of calling
-     * {@code accessModeType(VarHandle.AccessMode.getAndAdd)} on this VarHandle.
+     * {@code accessModeType(VarHandle.AccessMode.GET_AND_ADD)} on this
+     * VarHandle.
      *
      * @param args the signature-polymorphic parameter list of the form
      * {@code (CT, T value)}
@@ -1017,7 +1066,8 @@
      *
      * <p>The symbolic type descriptor at the call site of {@code addAndGet}
      * must match the access mode type that is the result of calling
-     * {@code accessModeType(VarHandle.AccessMode.addAndGet)} on this VarHandle.
+     * {@code accessModeType(VarHandle.AccessMode.ADD_AND_GET)} on this
+     * VarHandle.
      *
      * @param args the signature-polymorphic parameter list of the form
      * {@code (CT, T value)}
@@ -1083,109 +1133,115 @@
          * method
          * {@link VarHandle#get VarHandle.get}
          */
-        GET("get", AccessType.GET, Object.class),   // 0
+        GET("get", AccessType.GET, Object.class),
         /**
          * The access mode whose access is specified by the corresponding
          * method
          * {@link VarHandle#set VarHandle.set}
          */
-        SET("set", AccessType.SET, void.class),     // 1
+        SET("set", AccessType.SET, void.class),
         /**
          * The access mode whose access is specified by the corresponding
          * method
          * {@link VarHandle#getVolatile VarHandle.getVolatile}
          */
-        GET_VOLATILE("getVolatile", AccessType.GET, Object.class),  // 2
+        GET_VOLATILE("getVolatile", AccessType.GET, Object.class),
         /**
          * The access mode whose access is specified by the corresponding
          * method
          * {@link VarHandle#setVolatile VarHandle.setVolatile}
          */
-        SET_VOLATILE("setVolatile", AccessType.SET, void.class),    // 3
+        SET_VOLATILE("setVolatile", AccessType.SET, void.class),
         /**
          * The access mode whose access is specified by the corresponding
          * method
          * {@link VarHandle#getAcquire VarHandle.getAcquire}
          */
-        GET_ACQUIRE("getAcquire", AccessType.GET, Object.class),   // 4
+        GET_ACQUIRE("getAcquire", AccessType.GET, Object.class),
         /**
          * The access mode whose access is specified by the corresponding
          * method
          * {@link VarHandle#setRelease VarHandle.setRelease}
          */
-        SET_RELEASE("setRelease", AccessType.SET, void.class),     // 5
+        SET_RELEASE("setRelease", AccessType.SET, void.class),
         /**
          * The access mode whose access is specified by the corresponding
          * method
          * {@link VarHandle#getOpaque VarHandle.getOpaque}
          */
-        GET_OPAQUE("getOpaque", AccessType.GET, Object.class),    // 6
+        GET_OPAQUE("getOpaque", AccessType.GET, Object.class),
         /**
          * The access mode whose access is specified by the corresponding
          * method
          * {@link VarHandle#setOpaque VarHandle.setOpaque}
          */
-        SET_OPAQUE("setOpaque", AccessType.SET, void.class),      // 7
+        SET_OPAQUE("setOpaque", AccessType.SET, void.class),
         /**
          * The access mode whose access is specified by the corresponding
          * method
          * {@link VarHandle#compareAndSet VarHandle.compareAndSet}
          */
-        COMPARE_AND_SET("compareAndSet", AccessType.COMPARE_AND_SWAP, boolean.class),    // 8
+        COMPARE_AND_SET("compareAndSet", AccessType.COMPARE_AND_SWAP, boolean.class),
         /**
          * The access mode whose access is specified by the corresponding
          * method
          * {@link VarHandle#compareAndExchangeVolatile VarHandle.compareAndExchangeVolatile}
          */
-        COMPARE_AND_EXCHANGE_VOLATILE("compareAndExchangeVolatile", AccessType.COMPARE_AND_EXCHANGE, Object.class), // 9
+        COMPARE_AND_EXCHANGE_VOLATILE("compareAndExchangeVolatile", AccessType.COMPARE_AND_EXCHANGE, Object.class),
         /**
          * The access mode whose access is specified by the corresponding
          * method
          * {@link VarHandle#compareAndExchangeAcquire VarHandle.compareAndExchangeAcquire}
          */
-        COMPARE_AND_EXCHANGE_ACQUIRE("compareAndExchangeAcquire", AccessType.COMPARE_AND_EXCHANGE, Object.class),  // 10
+        COMPARE_AND_EXCHANGE_ACQUIRE("compareAndExchangeAcquire", AccessType.COMPARE_AND_EXCHANGE, Object.class),
         /**
          * The access mode whose access is specified by the corresponding
          * method
          * {@link VarHandle#compareAndExchangeRelease VarHandle.compareAndExchangeRelease}
          */
-        COMPARE_AND_EXCHANGE_RELEASE("compareAndExchangeRelease", AccessType.COMPARE_AND_EXCHANGE, Object.class),  // 11
+        COMPARE_AND_EXCHANGE_RELEASE("compareAndExchangeRelease", AccessType.COMPARE_AND_EXCHANGE, Object.class),
         /**
          * The access mode whose access is specified by the corresponding
          * method
          * {@link VarHandle#weakCompareAndSet VarHandle.weakCompareAndSet}
          */
-        WEAK_COMPARE_AND_SET("weakCompareAndSet", AccessType.COMPARE_AND_SWAP, boolean.class),        // 12
+        WEAK_COMPARE_AND_SET("weakCompareAndSet", AccessType.COMPARE_AND_SWAP, boolean.class),
+        /**
+         * The access mode whose access is specified by the corresponding
+         * method
+         * {@link VarHandle#weakCompareAndSetVolatile VarHandle.weakCompareAndSetVolatile}
+         */
+        WEAK_COMPARE_AND_SET_VOLATILE("weakCompareAndSetVolatile", AccessType.COMPARE_AND_SWAP, boolean.class),
         /**
          * The access mode whose access is specified by the corresponding
          * method
          * {@link VarHandle#weakCompareAndSetAcquire VarHandle.weakCompareAndSetAcquire}
          */
-        WEAK_COMPARE_AND_SET_ACQUIRE("weakCompareAndSetAcquire", AccessType.COMPARE_AND_SWAP, boolean.class), // 13
+        WEAK_COMPARE_AND_SET_ACQUIRE("weakCompareAndSetAcquire", AccessType.COMPARE_AND_SWAP, boolean.class),
         /**
          * The access mode whose access is specified by the corresponding
          * method
          * {@link VarHandle#weakCompareAndSetRelease VarHandle.weakCompareAndSetRelease}
          */
-        WEAK_COMPARE_AND_SET_RELEASE("weakCompareAndSetRelease", AccessType.COMPARE_AND_SWAP, boolean.class), // 14
+        WEAK_COMPARE_AND_SET_RELEASE("weakCompareAndSetRelease", AccessType.COMPARE_AND_SWAP, boolean.class),
         /**
          * The access mode whose access is specified by the corresponding
          * method
          * {@link VarHandle#getAndSet VarHandle.getAndSet}
          */
-        GET_AND_SET("getAndSet", AccessType.GET_AND_UPDATE, Object.class),   // 15
+        GET_AND_SET("getAndSet", AccessType.GET_AND_UPDATE, Object.class),
         /**
          * The access mode whose access is specified by the corresponding
          * method
          * {@link VarHandle#getAndAdd VarHandle.getAndAdd}
          */
-        GET_AND_ADD("getAndAdd", AccessType.GET_AND_UPDATE, Object.class),   // 16
+        GET_AND_ADD("getAndAdd", AccessType.GET_AND_UPDATE, Object.class),
         /**
          * The access mode whose access is specified by the corresponding
          * method
          * {@link VarHandle#addAndGet VarHandle.addAndGet}
          */
-        ADD_AND_GET("addAndGet", AccessType.GET_AND_UPDATE, Object.class),   // 17
+        ADD_AND_GET("addAndGet", AccessType.GET_AND_UPDATE, Object.class),
         ;
 
         static final Map<String, AccessMode> methodNameToAccessMode;
--- a/jdk/src/java.base/share/classes/java/lang/invoke/X-VarHandle.java.template	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/X-VarHandle.java.template	Tue May 03 12:25:20 2016 -0700
@@ -155,6 +155,15 @@
         }
 
         @ForceInline
+        static boolean weakCompareAndSetVolatile(FieldInstanceReadWrite handle, Object holder, $type$ expected, $type$ value) {
+            // TODO defer to strong form until new Unsafe method is added
+            return UNSAFE.compareAndSwap$Type$(Objects.requireNonNull(handle.receiverType.cast(holder)),
+                                               handle.fieldOffset,
+                                               {#if[Object]?handle.fieldType.cast(expected):expected},
+                                               {#if[Object]?handle.fieldType.cast(value):value});
+        }
+
+        @ForceInline
         static boolean weakCompareAndSetAcquire(FieldInstanceReadWrite handle, Object holder, $type$ expected, $type$ value) {
             return UNSAFE.weakCompareAndSwap$Type$Acquire(Objects.requireNonNull(handle.receiverType.cast(holder)),
                                                handle.fieldOffset,
@@ -319,6 +328,15 @@
         }
 
         @ForceInline
+        static boolean weakCompareAndSetVolatile(FieldStaticReadWrite handle, $type$ expected, $type$ value) {
+            // TODO defer to strong form until new Unsafe method is added
+            return UNSAFE.compareAndSwap$Type$(handle.base,
+                                               handle.fieldOffset,
+                                               {#if[Object]?handle.fieldType.cast(expected):expected},
+                                               {#if[Object]?handle.fieldType.cast(value):value});
+        }
+
+        @ForceInline
         static boolean weakCompareAndSetAcquire(FieldStaticReadWrite handle, $type$ expected, $type$ value) {
             return UNSAFE.weakCompareAndSwap$Type$Acquire(handle.base,
                                                handle.fieldOffset,
@@ -535,6 +553,20 @@
         }
 
         @ForceInline
+        static boolean weakCompareAndSetVolatile(Array handle, Object oarray, int index, $type$ expected, $type$ value) {
+#if[Object]
+            Object[] array = (Object[]) handle.arrayType.cast(oarray);
+#else[Object]
+            $type$[] array = ($type$[]) oarray;
+#end[Object]
+            // TODO defer to strong form until new Unsafe method is added
+            return UNSAFE.compareAndSwap$Type$(array,
+                    (((long) Objects.checkIndex(index, array.length, AIOOBE_SUPPLIER)) << handle.ashift) + handle.abase,
+                    {#if[Object]?handle.componentType.cast(expected):expected},
+                    {#if[Object]?handle.componentType.cast(value):value});
+        }
+
+        @ForceInline
         static boolean weakCompareAndSetAcquire(Array handle, Object oarray, int index, $type$ expected, $type$ value) {
 #if[Object]
             Object[] array = (Object[]) handle.arrayType.cast(oarray);
--- a/jdk/src/java.base/share/classes/java/lang/invoke/X-VarHandleByteArrayView.java.template	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/lang/invoke/X-VarHandleByteArrayView.java.template	Tue May 03 12:25:20 2016 -0700
@@ -228,6 +228,16 @@
         }
 
         @ForceInline
+        static boolean weakCompareAndSetVolatile(ArrayHandle handle, Object oba, int index, $type$ expected, $type$ value) {
+            byte[] ba = (byte[]) oba;
+            // TODO defer to strong form until new Unsafe method is added
+            return UNSAFE.compareAndSwap$RawType$(
+                    ba,
+                    address(ba, index(ba, index)),
+                    convEndian(handle.be, expected), convEndian(handle.be, value));
+        }
+
+        @ForceInline
         static boolean weakCompareAndSetAcquire(ArrayHandle handle, Object oba, int index, $type$ expected, $type$ value) {
             byte[] ba = (byte[]) oba;
             return UNSAFE.weakCompareAndSwap$RawType$Acquire(
@@ -444,6 +454,16 @@
         }
 
         @ForceInline
+        static boolean weakCompareAndSetVolatile(ByteBufferHandle handle, Object obb, int index, $type$ expected, $type$ value) {
+            ByteBuffer bb = (ByteBuffer) obb;
+            // TODO defer to strong form until new Unsafe method is added
+            return UNSAFE.compareAndSwap$RawType$(
+                    UNSAFE.getObject(bb, BYTE_BUFFER_HB),
+                    address(bb, indexRO(bb, index)),
+                    convEndian(handle.be, expected), convEndian(handle.be, value));
+        }
+
+        @ForceInline
         static boolean weakCompareAndSetAcquire(ByteBufferHandle handle, Object obb, int index, $type$ expected, $type$ value) {
             ByteBuffer bb = (ByteBuffer) obb;
             return UNSAFE.weakCompareAndSwap$RawType$Acquire(
--- a/jdk/src/java.base/share/classes/java/lang/module/Configuration.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/lang/module/Configuration.java	Tue May 03 12:25:20 2016 -0700
@@ -25,6 +25,7 @@
 
 package java.lang.module;
 
+import java.io.PrintStream;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
@@ -183,17 +184,20 @@
         this.nameToModule = Collections.emptyMap();
     }
 
-    private Configuration(Configuration parent, Resolver resolver) {
-        Map<ResolvedModule, Set<ResolvedModule>> graph = resolver.finish(this);
+    private Configuration(Configuration parent,
+                          Resolver resolver,
+                          boolean check)
+    {
+        Map<ResolvedModule, Set<ResolvedModule>> g = resolver.finish(this, check);
 
         Map<String, ResolvedModule> nameToModule = new HashMap<>();
-        for (ResolvedModule resolvedModule : graph.keySet()) {
+        for (ResolvedModule resolvedModule : g.keySet()) {
             nameToModule.put(resolvedModule.name(), resolvedModule);
         }
 
         this.parent = parent;
-        this.graph = graph;
-        this.modules = Collections.unmodifiableSet(graph.keySet());
+        this.graph = g;
+        this.modules = Collections.unmodifiableSet(g.keySet());
         this.nameToModule = Collections.unmodifiableMap(nameToModule);
     }
 
@@ -283,10 +287,10 @@
         Objects.requireNonNull(after);
         Objects.requireNonNull(roots);
 
-        Resolver resolver = new Resolver(before, this, after);
+        Resolver resolver = new Resolver(before, this, after, null);
         resolver.resolveRequires(roots);
 
-        return new Configuration(this, resolver);
+        return new Configuration(this, resolver, true);
     }
 
 
@@ -340,10 +344,32 @@
         Objects.requireNonNull(after);
         Objects.requireNonNull(roots);
 
-        Resolver resolver = new Resolver(before, this, after);
+        Resolver resolver = new Resolver(before, this, after, null);
         resolver.resolveRequires(roots).resolveUses();
 
-        return new Configuration(this, resolver);
+        return new Configuration(this, resolver, true);
+    }
+
+
+    /**
+     * Resolves a collection of root modules, with service binding, and with
+     * the empty configuration as its parent. The post resolution checks
+     * are optionally run.
+     *
+     * This method is used to create the configuration for the boot layer.
+     */
+    static Configuration resolveRequiresAndUses(ModuleFinder finder,
+                                                Collection<String> roots,
+                                                boolean check,
+                                                PrintStream traceOutput)
+    {
+        Configuration parent = empty();
+
+        Resolver resolver
+            = new Resolver(finder, parent, ModuleFinder.empty(), traceOutput);
+        resolver.resolveRequires(roots).resolveUses();
+
+        return new Configuration(parent, resolver, check);
     }
 
 
--- a/jdk/src/java.base/share/classes/java/lang/module/ModuleDescriptor.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/lang/module/ModuleDescriptor.java	Tue May 03 12:25:20 2016 -0700
@@ -27,13 +27,17 @@
 
 import java.io.InputStream;
 import java.io.IOException;
+import java.io.PrintStream;
 import java.io.UncheckedIOException;
+import java.net.URI;
 import java.nio.ByteBuffer;
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.EnumSet;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
@@ -45,7 +49,7 @@
 import static java.util.Objects.*;
 
 import jdk.internal.module.Checks;
-import jdk.internal.module.Hasher.DependencyHashes;
+import jdk.internal.module.ModuleHashes;
 
 
 /**
@@ -372,8 +376,9 @@
 
         private Provides(String service, Set<String> providers, boolean check) {
             this.service = check ? requireServiceTypeName(service) : service;
-            providers = check ? Collections.unmodifiableSet(new HashSet<>(providers))
-                              : Collections.unmodifiableSet(providers);
+            providers = check
+                ? Collections.unmodifiableSet(new LinkedHashSet<>(providers))
+                : Collections.unmodifiableSet(providers);
             if (providers.isEmpty())
                 throw new IllegalArgumentException("Empty providers set");
             if (check)
@@ -787,7 +792,7 @@
     private final String osVersion;
     private final Set<String> conceals;
     private final Set<String> packages;
-    private final DependencyHashes hashes;
+    private final ModuleHashes hashes;
 
     private ModuleDescriptor(String name,
                              boolean automatic,
@@ -802,7 +807,7 @@
                              String osArch,
                              String osVersion,
                              Set<String> conceals,
-                             DependencyHashes hashes)
+                             ModuleHashes hashes)
     {
 
         this.name = name;
@@ -878,7 +883,8 @@
                      String osArch,
                      String osVersion,
                      Set<String> conceals,
-                     Set<String> packages) {
+                     Set<String> packages,
+                     ModuleHashes hashes) {
         this.name = name;
         this.automatic = automatic;
         this.synthetic = synthetic;
@@ -894,7 +900,7 @@
         this.osName = osName;
         this.osArch = osArch;
         this.osVersion = osVersion;
-        this.hashes = null;
+        this.hashes = hashes;
     }
 
     /**
@@ -1063,9 +1069,9 @@
     }
 
     /**
-     * Returns the object with the hashes of the dependences.
+     * Returns the object with the hashes of other modules
      */
-    Optional<DependencyHashes> hashes() {
+    Optional<ModuleHashes> hashes() {
         return Optional.ofNullable(hashes);
     }
 
@@ -1103,7 +1109,7 @@
         String osArch;
         String osVersion;
         String mainClass;
-        DependencyHashes hashes;
+        ModuleHashes hashes;
 
         /**
          * Initializes a new builder with the given module name.
@@ -1580,7 +1586,7 @@
             return this;
         }
 
-        /* package */ Builder hashes(DependencyHashes hashes) {
+        /* package */ Builder hashes(ModuleHashes hashes) {
             this.hashes = hashes;
             return this;
         }
@@ -1719,7 +1725,9 @@
             hc = hc * 43 + Objects.hashCode(osVersion);
             hc = hc * 43 + Objects.hashCode(conceals);
             hc = hc * 43 + Objects.hashCode(hashes);
-            if (hc != 0) hash = hc;
+            if (hc == 0)
+                hc = -1;
+            hash = hc;
         }
         return hc;
     }
@@ -1925,11 +1933,12 @@
 
     static {
         /**
-         * Setup the shared secret to allow code in other packages create
-         * ModuleDescriptor and associated objects directly.
+         * Setup the shared secret to allow code in other packages access
+         * private package methods in java.lang.module.
          */
         jdk.internal.misc.SharedSecrets
             .setJavaLangModuleAccess(new jdk.internal.misc.JavaLangModuleAccess() {
+
                 @Override
                 public Requires newRequires(Set<Requires.Modifier> ms, String mn) {
                     return new Requires(ms, mn, false);
@@ -1974,7 +1983,8 @@
                                                             String osArch,
                                                             String osVersion,
                                                             Set<String> conceals,
-                                                            Set<String> packages) {
+                                                            Set<String> packages,
+                                                            ModuleHashes hashes) {
                     return new ModuleDescriptor(name,
                                                 automatic,
                                                 synthetic,
@@ -1988,7 +1998,29 @@
                                                 osArch,
                                                 osVersion,
                                                 conceals,
-                                                packages);
+                                                packages,
+                                                hashes);
+                }
+
+                @Override
+                public Configuration resolveRequiresAndUses(ModuleFinder finder,
+                                                            Collection<String> roots,
+                                                            boolean check,
+                                                            PrintStream traceOutput)
+                {
+                    return Configuration.resolveRequiresAndUses(finder, roots, check, traceOutput);
+                }
+
+                @Override
+                public ModuleReference newPatchedModule(ModuleDescriptor descriptor,
+                                                        URI location,
+                                                        Supplier<ModuleReader> s) {
+                    return new ModuleReference(descriptor, location, s, true, null);
+                }
+
+                @Override
+                public Optional<ModuleHashes> hashes(ModuleDescriptor descriptor) {
+                    return descriptor.hashes();
                 }
             });
     }
--- a/jdk/src/java.base/share/classes/java/lang/module/ModuleInfo.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/lang/module/ModuleInfo.java	Tue May 03 12:25:20 2016 -0700
@@ -37,11 +37,12 @@
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.LinkedHashSet;
 import java.util.Map;
 import java.util.Set;
 import java.util.function.Supplier;
 
-import jdk.internal.module.Hasher.DependencyHashes;
+import jdk.internal.module.ModuleHashes;
 
 import static jdk.internal.module.ClassFileConstants.*;
 
@@ -337,7 +338,7 @@
                 // computeIfAbsent
                 Set<String> providers = pm.get(sn);
                 if (providers == null) {
-                    providers = new HashSet<>();
+                    providers = new LinkedHashSet<>(); // preserve order
                     pm.put(sn, providers);
                 }
                 providers.add(cn);
@@ -425,7 +426,7 @@
             map.put(dn, hash);
         }
 
-        builder.hashes(new DependencyHashes(algorithm, map));
+        builder.hashes(new ModuleHashes(algorithm, map));
     }
 
 
--- a/jdk/src/java.base/share/classes/java/lang/module/ModulePath.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/lang/module/ModulePath.java	Tue May 03 12:25:20 2016 -0700
@@ -40,7 +40,7 @@
 import java.nio.file.attribute.BasicFileAttributes;
 import java.util.Collections;
 import java.util.HashMap;
-import java.util.HashSet;
+import java.util.LinkedHashSet;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Optional;
@@ -52,7 +52,6 @@
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 import java.util.stream.Collectors;
-import java.util.stream.Stream;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipFile;
 
@@ -190,18 +189,16 @@
                 }
             }
 
-            if (attrs.isRegularFile() || attrs.isDirectory()) {
-                // packaged or exploded module
-                ModuleReference mref = readModule(entry, attrs);
-                if (mref != null) {
-                    String name = mref.descriptor().name();
-                    return Collections.singletonMap(name, mref);
-                }
+            // packaged or exploded module
+            ModuleReference mref = readModule(entry, attrs);
+            if (mref != null) {
+                String name = mref.descriptor().name();
+                return Collections.singletonMap(name, mref);
+            } else {
+                // skipped
+                return Collections.emptyMap();
             }
 
-            // not recognized
-            throw new FindException("Unrecognized module: " + entry);
-
         } catch (IOException ioe) {
             throw new FindException(ioe);
         }
@@ -238,16 +235,13 @@
 
                 // module found
                 if (mref != null) {
-
                     // can have at most one version of a module in the directory
                     String name = mref.descriptor().name();
                     if (nameToReference.put(name, mref) != null) {
                         throw new FindException("Two versions of module "
-                                + name + " found in " + dir);
+                                                  + name + " found in " + dir);
                     }
-
                 }
-
             }
         }
 
@@ -257,28 +251,40 @@
 
     /**
      * Locates a packaged or exploded module, returning a {@code ModuleReference}
-     * to the module. Returns {@code null} if the module is not recognized
-     * as a packaged or exploded module.
+     * to the module. Returns {@code null} if the entry is skipped because it is
+     * to a directory that does not contain a module-info.class or it's a hidden
+     * file.
      *
      * @throws IOException if an I/O error occurs
-     * @throws FindException if an error occurs parsing the module descriptor
+     * @throws FindException if the file is not recognized as a module or an
+     *         error occurs parsing its module descriptor
      */
     private ModuleReference readModule(Path entry, BasicFileAttributes attrs)
         throws IOException
     {
         try {
 
-            ModuleReference mref = null;
             if (attrs.isDirectory()) {
-                mref = readExplodedModule(entry);
-            } if (attrs.isRegularFile()) {
-                if (entry.toString().endsWith(".jar")) {
-                    mref = readJar(entry);
-                } else if (isLinkPhase && entry.toString().endsWith(".jmod")) {
-                    mref = readJMod(entry);
+                return readExplodedModule(entry); // may return null
+            }
+
+            String fn = entry.getFileName().toString();
+            if (attrs.isRegularFile()) {
+                if (fn.endsWith(".jar")) {
+                    return readJar(entry);
+                } else if (fn.endsWith(".jmod")) {
+                    if (isLinkPhase)
+                        return readJMod(entry);
+                    throw new FindException("JMOD files not supported: " + entry);
                 }
             }
-            return mref;
+
+            // skip hidden files
+            if (fn.startsWith(".") || Files.isHidden(entry)) {
+                return null;
+            } else {
+                throw new FindException("Unrecognized module: " + entry);
+            }
 
         } catch (InvalidModuleDescriptorException e) {
             throw new FindException("Error reading module: " + entry, e);
@@ -292,15 +298,17 @@
         return zf.stream()
             .filter(e -> e.getName().startsWith("classes/") &&
                     e.getName().endsWith(".class"))
-            .map(e -> toPackageName(e))
+            .map(e -> toPackageName(e.getName().substring(8)))
             .filter(pkg -> pkg.length() > 0) // module-info
-            .distinct()
             .collect(Collectors.toSet());
     }
 
     /**
      * Returns a {@code ModuleReference} to a module in jmod file on the
      * file system.
+     *
+     * @throws IOException
+     * @throws InvalidModuleDescriptorException
      */
     private ModuleReference readJMod(Path file) throws IOException {
         try (ZipFile zf = new ZipFile(file.toString())) {
@@ -419,13 +427,12 @@
 
         // scan the entries in the JAR file to locate the .class and service
         // configuration file
-        Stream<String> stream = jf.stream()
-            .map(e -> e.getName())
-            .filter(e -> (e.endsWith(".class") || e.startsWith(SERVICES_PREFIX)))
-            .distinct();
-        Map<Boolean, Set<String>> map
-            = stream.collect(Collectors.partitioningBy(s -> s.endsWith(".class"),
-                             Collectors.toSet()));
+        Map<Boolean, Set<String>> map =
+            jf.stream()
+              .map(JarEntry::getName)
+              .filter(s -> (s.endsWith(".class") ^ s.startsWith(SERVICES_PREFIX)))
+              .collect(Collectors.partitioningBy(s -> s.endsWith(".class"),
+                                                 Collectors.toSet()));
         Set<String> classFiles = map.get(Boolean.TRUE);
         Set<String> configFiles = map.get(Boolean.FALSE);
 
@@ -433,19 +440,18 @@
         classFiles.stream()
             .map(c -> toPackageName(c))
             .distinct()
-            .forEach(p -> builder.exports(p));
+            .forEach(builder::exports);
 
         // map names of service configuration files to service names
         Set<String> serviceNames = configFiles.stream()
             .map(this::toServiceName)
-            .filter(Optional::isPresent)
-            .map(Optional::get)
+            .flatMap(Optional::stream)
             .collect(Collectors.toSet());
 
         // parse each service configuration file
         for (String sn : serviceNames) {
             JarEntry entry = jf.getJarEntry(SERVICES_PREFIX + sn);
-            Set<String> providerClasses = new HashSet<>();
+            Set<String> providerClasses = new LinkedHashSet<>();
             try (InputStream in = jf.getInputStream(entry)) {
                 BufferedReader reader
                     = new BufferedReader(new InputStreamReader(in, "UTF-8"));
@@ -475,19 +481,25 @@
     private Set<String> jarPackages(JarFile jf) {
         return jf.stream()
             .filter(e -> e.getName().endsWith(".class"))
-            .map(e -> toPackageName(e))
+            .map(e -> toPackageName(e.getName()))
             .filter(pkg -> pkg.length() > 0)   // module-info
-            .distinct()
             .collect(Collectors.toSet());
     }
 
     /**
      * Returns a {@code ModuleReference} to a module in modular JAR file on
      * the file system.
+     *
+     * @throws IOException
+     * @throws FindException
+     * @throws InvalidModuleDescriptorException
      */
     private ModuleReference readJar(Path file) throws IOException {
-        try (JarFile jf = new JarFile(file.toString())) {
-
+        try (JarFile jf = new JarFile(file.toFile(),
+                                      true,               // verify
+                                      ZipFile.OPEN_READ,
+                                      JarFile.Release.RUNTIME))
+        {
             ModuleDescriptor md;
             JarEntry entry = jf.getJarEntry(MODULE_INFO);
             if (entry == null) {
@@ -520,7 +532,6 @@
                                path.toString().endsWith(".class")))
                 .map(path -> toPackageName(dir.relativize(path)))
                 .filter(pkg -> pkg.length() > 0)   // module-info
-                .distinct()
                 .collect(Collectors.toSet());
         } catch (IOException x) {
             throw new UncheckedIOException(x);
@@ -530,6 +541,9 @@
     /**
      * Returns a {@code ModuleReference} to an exploded module on the file
      * system or {@code null} if {@code module-info.class} not found.
+     *
+     * @throws IOException
+     * @throws InvalidModuleDescriptorException
      */
     private ModuleReference readExplodedModule(Path dir) throws IOException {
         Path mi = dir.resolve(MODULE_INFO);
@@ -559,19 +573,6 @@
         }
     }
 
-    private String toPackageName(ZipEntry entry) {
-        String name = entry.getName();
-        assert name.endsWith(".class");
-        // jmod classes in classes/, jar in /
-        int start = name.startsWith("classes/") ? 8 : 0;
-        int index = name.lastIndexOf("/");
-        if (index > start) {
-            return name.substring(start, index).replace('/', '.');
-        } else {
-            return "";
-        }
-    }
-
     private String toPackageName(Path path) {
         String name = path.toString();
         assert name.endsWith(".class");
--- a/jdk/src/java.base/share/classes/java/lang/module/ModuleReader.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/lang/module/ModuleReader.java	Tue May 03 12:25:20 2016 -0700
@@ -142,10 +142,11 @@
      * @see ClassLoader#defineClass(String, ByteBuffer, java.security.ProtectionDomain)
      */
     default Optional<ByteBuffer> read(String name) throws IOException {
-        Optional<InputStream> in = open(name);
-        if (in.isPresent()) {
-            byte[] bytes = in.get().readAllBytes();
-            return Optional.of(ByteBuffer.wrap(bytes));
+        Optional<InputStream> oin = open(name);
+        if (oin.isPresent()) {
+            try (InputStream in = oin.get()) {
+                return Optional.of(ByteBuffer.wrap(in.readAllBytes()));
+            }
         } else {
             return Optional.empty();
         }
--- a/jdk/src/java.base/share/classes/java/lang/module/ModuleReference.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/lang/module/ModuleReference.java	Tue May 03 12:25:20 2016 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -32,7 +32,7 @@
 import java.util.Optional;
 import java.util.function.Supplier;
 
-import jdk.internal.module.Hasher.HashSupplier;
+import jdk.internal.module.ModuleHashes.HashSupplier;
 
 
 /**
@@ -54,12 +54,33 @@
     private final URI location;
     private final Supplier<ModuleReader> readerSupplier;
 
+    // true if this is a reference to a patched module
+    private boolean patched;
+
     // the function that computes the hash of this module reference
     private final HashSupplier hasher;
 
     // cached hash string to avoid needing to compute it many times
     private String cachedHash;
 
+
+    /**
+     * Constructs a new instance of this class.
+     */
+    ModuleReference(ModuleDescriptor descriptor,
+                    URI location,
+                    Supplier<ModuleReader> readerSupplier,
+                    boolean patched,
+                    HashSupplier hasher)
+
+    {
+        this.descriptor = Objects.requireNonNull(descriptor);
+        this.location = location;
+        this.readerSupplier = Objects.requireNonNull(readerSupplier);
+        this.patched = patched;
+        this.hasher = hasher;
+    }
+
     /**
      * Constructs a new instance of this class.
      */
@@ -67,11 +88,9 @@
                     URI location,
                     Supplier<ModuleReader> readerSupplier,
                     HashSupplier hasher)
+
     {
-        this.descriptor = Objects.requireNonNull(descriptor);
-        this.location = location;
-        this.readerSupplier = Objects.requireNonNull(readerSupplier);
-        this.hasher = hasher;
+        this(descriptor, location, readerSupplier, false, hasher);
     }
 
 
@@ -96,10 +115,9 @@
                            URI location,
                            Supplier<ModuleReader> readerSupplier)
     {
-        this(descriptor, location, readerSupplier, null);
+        this(descriptor, location, readerSupplier, false, null);
     }
 
-
     /**
      * Returns the module descriptor.
      *
@@ -151,6 +169,20 @@
 
 
     /**
+     * Returns {@code true} if this module has been patched via -Xpatch.
+     */
+    boolean isPatched() {
+        return patched;
+    }
+
+    /**
+     * Returns the hash supplier for this module.
+     */
+    HashSupplier hasher() {
+        return hasher;
+    }
+
+    /**
      * Computes the hash of this module, returning it as a hex string.
      * Returns {@code null} if the hash cannot be computed.
      *
@@ -166,8 +198,6 @@
         return result;
     }
 
-    private int hash;
-
     /**
      * Computes a hash code for this module reference.
      *
@@ -181,12 +211,17 @@
     public int hashCode() {
         int hc = hash;
         if (hc == 0) {
-            hc = Objects.hash(descriptor, location, readerSupplier, hasher);
-            if (hc != 0) hash = hc;
+            hc = Objects.hash(descriptor, location, readerSupplier, hasher,
+                    Boolean.valueOf(patched));
+            if (hc == 0)
+                hc = -1;
+            hash = hc;
         }
         return hc;
     }
 
+    private int hash;
+
     /**
      * Tests this module reference for equality with the given object.
      *
@@ -214,7 +249,8 @@
         return Objects.equals(this.descriptor, that.descriptor)
                 && Objects.equals(this.location, that.location)
                 && Objects.equals(this.readerSupplier, that.readerSupplier)
-                && Objects.equals(this.hasher, that.hasher);
+                && Objects.equals(this.hasher, that.hasher)
+                && this.patched == that.patched;
     }
 
     /**
--- a/jdk/src/java.base/share/classes/java/lang/module/ModuleReferences.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/lang/module/ModuleReferences.java	Tue May 03 12:25:20 2016 -0700
@@ -48,8 +48,8 @@
 
 import jdk.internal.misc.JavaLangAccess;
 import jdk.internal.misc.SharedSecrets;
-import jdk.internal.module.Hasher;
-import jdk.internal.module.Hasher.HashSupplier;
+import jdk.internal.module.ModuleHashes;
+import jdk.internal.module.ModuleHashes.HashSupplier;
 import jdk.internal.module.ModulePatcher;
 import sun.net.www.ParseUtil;
 
@@ -89,7 +89,7 @@
     static ModuleReference newJarModule(ModuleDescriptor md, Path file) {
         URI uri = file.toUri();
         Supplier<ModuleReader> supplier = () -> new JarModuleReader(file, uri);
-        HashSupplier hasher = (algorithm) -> Hasher.generate(file, algorithm);
+        HashSupplier hasher = (a) -> ModuleHashes.computeHashAsString(file, a);
         return newModule(md, uri, supplier, hasher);
     }
 
@@ -99,7 +99,7 @@
     static ModuleReference newJModModule(ModuleDescriptor md, Path file) {
         URI uri = file.toUri();
         Supplier<ModuleReader> supplier = () -> new JModModuleReader(file, uri);
-        HashSupplier hasher = (algorithm) -> Hasher.generate(file, algorithm);
+        HashSupplier hasher = (a) -> ModuleHashes.computeHashAsString(file, a);
         return newModule(md, file.toUri(), supplier, hasher);
     }
 
@@ -122,7 +122,7 @@
         private final ReadWriteLock lock = new ReentrantReadWriteLock();
         private final Lock readLock = lock.readLock();
         private final Lock writeLock = lock.writeLock();
-        private volatile boolean closed;
+        private boolean closed;
 
         SafeCloseModuleReader() { }
 
@@ -198,7 +198,10 @@
 
         static JarFile newJarFile(Path path) {
             try {
-                return new JarFile(path.toFile());
+                return new JarFile(path.toFile(),
+                                   true,               // verify
+                                   ZipFile.OPEN_READ,
+                                   JarFile.Release.RUNTIME);
             } catch (IOException ioe) {
                 throw new UncheckedIOException(ioe);
             }
@@ -219,6 +222,8 @@
             if (je != null) {
                 String encodedPath = ParseUtil.encodePath(name, false);
                 String uris = "jar:" + uri + "!/" + encodedPath;
+                if (jf.isMultiRelease())
+                    uris += "#runtime";
                 return Optional.of(URI.create(uris));
             } else {
                 return Optional.empty();
--- a/jdk/src/java.base/share/classes/java/lang/module/Resolver.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/lang/module/Resolver.java	Tue May 03 12:25:20 2016 -0700
@@ -25,8 +25,8 @@
 
 package java.lang.module;
 
+import java.io.PrintStream;
 import java.lang.module.ModuleDescriptor.Requires.Modifier;
-import java.lang.reflect.Layer;
 import java.util.ArrayDeque;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -43,7 +43,7 @@
 import java.util.StringJoiner;
 import java.util.stream.Collectors;
 
-import jdk.internal.module.Hasher;
+import jdk.internal.module.ModuleHashes;
 
 /**
  * The resolver used by {@link Configuration#resolveRequires} and
@@ -55,6 +55,7 @@
     private final ModuleFinder beforeFinder;
     private final Configuration parent;
     private final ModuleFinder afterFinder;
+    private final PrintStream traceOutput;
 
     // maps module name to module reference
     private final Map<String, ModuleReference> nameToReference = new HashMap<>();
@@ -62,10 +63,12 @@
 
     Resolver(ModuleFinder beforeFinder,
              Configuration parent,
-             ModuleFinder afterFinder) {
+             ModuleFinder afterFinder,
+             PrintStream traceOutput) {
         this.beforeFinder = beforeFinder;
         this.parent = parent;
         this.afterFinder = afterFinder;
+        this.traceOutput = traceOutput;
     }
 
 
@@ -76,8 +79,6 @@
      */
     Resolver resolveRequires(Collection<String> roots) {
 
-        long start = trace_start("Resolve");
-
         // create the visit stack to get us started
         Deque<ModuleDescriptor> q = new ArrayDeque<>();
         for (String root : roots) {
@@ -95,10 +96,9 @@
                 }
             }
 
-            if (TRACE) {
+            if (isTracing()) {
                 trace("Root module %s located", root);
-                if (mref.location().isPresent())
-                    trace("  (%s)", mref.location().get());
+                mref.location().ifPresent(uri -> trace("  (%s)", uri));
             }
 
             assert mref.descriptor().name().equals(root);
@@ -108,13 +108,6 @@
 
         resolve(q);
 
-        if (TRACE) {
-            long duration = System.currentTimeMillis() - start;
-            Set<String> names = nameToReference.keySet();
-            trace("Resolver completed in %s ms", duration);
-            names.stream().sorted().forEach(name -> trace("  %s", name));
-        }
-
         return this;
     }
 
@@ -153,11 +146,10 @@
                     q.offer(mref.descriptor());
                     resolved.add(mref.descriptor());
 
-                    if (TRACE) {
+                    if (isTracing()) {
                         trace("Module %s located, required by %s",
                                 dn, descriptor.name());
-                        if (mref.location().isPresent())
-                            trace("  (%s)", mref.location().get());
+                        mref.location().ifPresent(uri -> trace("  (%s)", uri));
                     }
                 }
 
@@ -175,8 +167,6 @@
      */
     Resolver resolveUses() {
 
-        long start = trace_start("Bind");
-
         // Scan the finders for all available service provider modules. As
         // java.base uses services then then module finders will be scanned
         // anyway.
@@ -230,10 +220,10 @@
 
                                     String pn = provider.name();
                                     if (!nameToReference.containsKey(pn)) {
-
-                                        if (TRACE && mref.location().isPresent())
-                                            trace("  (%s)", mref.location().get());
-
+                                        if (isTracing()) {
+                                            mref.location()
+                                                .ifPresent(uri -> trace("  (%s)", uri));
+                                        }
                                         nameToReference.put(pn, mref);
                                         q.push(provider);
                                     }
@@ -248,14 +238,6 @@
 
         } while (!candidateConsumers.isEmpty());
 
-
-        if (TRACE) {
-            long duration = System.currentTimeMillis() - start;
-            Set<String> names = nameToReference.keySet();
-            trace("Bind completed in %s ms", duration);
-            names.stream().sorted().forEach(name -> trace("  %s", name));
-        }
-
         return this;
     }
 
@@ -264,23 +246,33 @@
      * Execute post-resolution checks and returns the module graph of resolved
      * modules as {@code Map}. The resolved modules will be in the given
      * configuration.
+     *
+     * @param check {@true} to execute the post resolution checks
      */
-    Map<ResolvedModule, Set<ResolvedModule>> finish(Configuration cf) {
+    Map<ResolvedModule, Set<ResolvedModule>> finish(Configuration cf,
+                                                    boolean check)
+    {
+        if (isTracing()) {
+            trace("Result:");
+            Set<String> names = nameToReference.keySet();
+            names.stream().sorted().forEach(name -> trace("  %s", name));
+        }
 
-        detectCycles();
-
-        checkPlatformConstraints();
-
-        checkHashes();
+        if (check) {
+            detectCycles();
+            checkPlatformConstraints();
+            checkHashes();
+        }
 
         Map<ResolvedModule, Set<ResolvedModule>> graph = makeGraph(cf);
 
-        checkExportSuppliers(graph);
+        if (check) {
+            checkExportSuppliers(graph);
+        }
 
         return graph;
     }
 
-
     /**
      * Checks the given module graph for cycles.
      *
@@ -420,52 +412,44 @@
 
     }
 
-
     /**
      * Checks the hashes in the module descriptor to ensure that they match
-     * the hash of the dependency's module reference.
+     * any recorded hashes.
      */
     private void checkHashes() {
-
         for (ModuleReference mref : nameToReference.values()) {
             ModuleDescriptor descriptor = mref.descriptor();
 
-            // get map of module names to hash
-            Optional<Hasher.DependencyHashes> ohashes = descriptor.hashes();
+            // get map of module hashes
+            Optional<ModuleHashes> ohashes = descriptor.hashes();
             if (!ohashes.isPresent())
                 continue;
-            Hasher.DependencyHashes hashes = ohashes.get();
-
-            // check dependences
-            for (ModuleDescriptor.Requires d : descriptor.requires()) {
-                String dn = d.name();
-                String recordedHash = hashes.hashFor(dn);
-
-                if (recordedHash != null) {
+            ModuleHashes hashes = ohashes.get();
 
-                    ModuleReference other = nameToReference.get(dn);
-                    if (other == null) {
-                        other = parent.findModule(dn)
-                                .map(ResolvedModule::reference)
-                                .orElse(null);
-                    }
-                    if (other == null)
-                        throw new InternalError(dn + " not found");
+            String algorithm = hashes.algorithm();
+            for (String dn : hashes.names()) {
+                ModuleReference other = nameToReference.get(dn);
+                if (other == null) {
+                    other = parent.findModule(dn)
+                            .map(ResolvedModule::reference)
+                            .orElse(null);
+                }
 
-                    String actualHash = other.computeHash(hashes.algorithm());
+                // skip checking the hash if the module has been patched
+                if (other != null && !other.isPatched()) {
+                    String recordedHash = hashes.hashFor(dn);
+                    String actualHash = other.computeHash(algorithm);
                     if (actualHash == null)
                         fail("Unable to compute the hash of module %s", dn);
-
                     if (!recordedHash.equals(actualHash)) {
-                        fail("Hash of %s (%s) differs to expected hash (%s)",
-                                dn, actualHash, recordedHash);
+                        fail("Hash of %s (%s) differs to expected hash (%s)" +
+                             " recorded in %s", dn, actualHash, recordedHash,
+                             descriptor.name());
                     }
+                }
+            }
 
-                }
-
-            }
         }
-
     }
 
 
@@ -666,7 +650,7 @@
                     // source is exported to descriptor2
                     String source = export.source();
                     ModuleDescriptor other
-                            = packageToExporter.put(source, descriptor2);
+                        = packageToExporter.put(source, descriptor2);
 
                     if (other != null && other != descriptor2) {
                         // package might be local to descriptor1
@@ -690,33 +674,38 @@
                 }
             }
 
-            // uses S
-            for (String service : descriptor1.uses()) {
-                String pn = packageName(service);
-                if (!packageToExporter.containsKey(pn)) {
-                    fail("Module %s does not read a module that exports %s",
-                            descriptor1.name(), pn);
-                }
-            }
+            // uses/provides checks not applicable to automatic modules
+            if (!descriptor1.isAutomatic()) {
 
-            // provides S
-            for (Map.Entry<String, ModuleDescriptor.Provides> entry :
-                    descriptor1.provides().entrySet()) {
-                String service = entry.getKey();
-                ModuleDescriptor.Provides provides = entry.getValue();
-
-                String pn = packageName(service);
-                if (!packageToExporter.containsKey(pn)) {
-                    fail("Module %s does not read a module that exports %s",
-                            descriptor1.name(), pn);
+                // uses S
+                for (String service : descriptor1.uses()) {
+                    String pn = packageName(service);
+                    if (!packageToExporter.containsKey(pn)) {
+                        fail("Module %s does not read a module that exports %s",
+                             descriptor1.name(), pn);
+                    }
                 }
 
-                for (String provider : provides.providers()) {
-                    if (!packages.contains(packageName(provider))) {
-                        fail("Provider %s not in module %s",
-                                provider, descriptor1.name());
+                // provides S
+                for (Map.Entry<String, ModuleDescriptor.Provides> entry :
+                        descriptor1.provides().entrySet()) {
+                    String service = entry.getKey();
+                    ModuleDescriptor.Provides provides = entry.getValue();
+
+                    String pn = packageName(service);
+                    if (!packageToExporter.containsKey(pn)) {
+                        fail("Module %s does not read a module that exports %s",
+                             descriptor1.name(), pn);
+                    }
+
+                    for (String provider : provides.providers()) {
+                        if (!packages.contains(packageName(provider))) {
+                            fail("Provider %s not in module %s",
+                                 provider, descriptor1.name());
+                        }
                     }
                 }
+
             }
 
         }
@@ -796,27 +785,18 @@
         throw new ResolutionException(msg);
     }
 
-
     /**
-     * Tracing support, limited to boot layer for now.
+     * Tracing support
      */
 
-    private final static boolean TRACE
-        = Boolean.getBoolean("jdk.launcher.traceResolver")
-            && (Layer.boot() == null);
-
-    private String op;
-
-    private long trace_start(String op) {
-        this.op = op;
-        return System.currentTimeMillis();
+    private boolean isTracing() {
+        return traceOutput != null;
     }
 
     private void trace(String fmt, Object ... args) {
-        if (TRACE) {
-            System.out.print("[" + op + "] ");
-            System.out.format(fmt, args);
-            System.out.println();
+        if (traceOutput != null) {
+            traceOutput.format("[Resolver] " + fmt, args);
+            traceOutput.println();
         }
     }
 
--- a/jdk/src/java.base/share/classes/java/lang/module/SystemModuleFinder.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/lang/module/SystemModuleFinder.java	Tue May 03 12:25:20 2016 -0700
@@ -44,6 +44,7 @@
 import jdk.internal.jimage.ImageLocation;
 import jdk.internal.jimage.ImageReader;
 import jdk.internal.jimage.ImageReaderFactory;
+import jdk.internal.module.ModuleHashes;
 import jdk.internal.module.SystemModules;
 import jdk.internal.module.ModulePatcher;
 import jdk.internal.perf.PerfCounter;
@@ -101,13 +102,16 @@
         for (int i = 0; i < n; i++) {
             String mn = moduleNames[i];
             ModuleDescriptor md;
+            String hash;
             if (fastLoad) {
                 md = descriptors[i];
+                hash = SystemModules.MODULES_TO_HASH[i];
             } else {
                 // fallback to read module-info.class
                 // if fast loading of ModuleDescriptors is disabled
                 ImageLocation location = imageReader.findLocation(mn, "module-info.class");
                 md = ModuleDescriptor.read(imageReader.getResourceBuffer(location));
+                hash = null;
             }
             if (!md.name().equals(mn))
                 throw new InternalError();
@@ -123,7 +127,8 @@
                 }
             };
 
-            ModuleReference mref = new ModuleReference(md, uri, readerSupplier);
+            ModuleReference mref =
+                new ModuleReference(md, uri, readerSupplier, hashSupplier(hash));
 
             // may need a reference to a patched module if -Xpatch specified
             mref = ModulePatcher.interposeIfNeeded(mref);
@@ -142,6 +147,18 @@
         initTime.addElapsedTimeFrom(t0);
     }
 
+    private static ModuleHashes.HashSupplier hashSupplier(String hash) {
+        if (hash == null)
+            return null;
+
+        return new ModuleHashes.HashSupplier() {
+            @Override
+            public String generate(String algorithm) {
+                return hash;
+            }
+        };
+    }
+
     SystemModuleFinder() { }
 
     @Override
--- a/jdk/src/java.base/share/classes/java/lang/reflect/Layer.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/lang/reflect/Layer.java	Tue May 03 12:25:20 2016 -0700
@@ -27,6 +27,7 @@
 
 import java.lang.module.Configuration;
 import java.lang.module.ModuleDescriptor;
+import java.lang.module.ModuleDescriptor.Provides;
 import java.lang.module.ResolvedModule;
 import java.util.Collections;
 import java.util.HashMap;
@@ -41,6 +42,8 @@
 import jdk.internal.loader.Loader;
 import jdk.internal.loader.LoaderPool;
 import jdk.internal.misc.SharedSecrets;
+import jdk.internal.module.ServicesCatalog;
+import jdk.internal.module.ServicesCatalog.ServiceProvider;
 import sun.security.util.SecurityConstants;
 
 
@@ -549,4 +552,55 @@
     public static Layer boot() {
         return SharedSecrets.getJavaLangAccess().getBootLayer();
     }
+
+
+    /**
+     * Returns the ServicesCatalog for this Layer, creating it if not
+     * already created.
+     */
+    ServicesCatalog getServicesCatalog() {
+        ServicesCatalog servicesCatalog = this.servicesCatalog;
+        if (servicesCatalog != null)
+            return servicesCatalog;
+
+        Map<String, Set<ServiceProvider>> map = new HashMap<>();
+        for (Module m : nameToModule.values()) {
+            ModuleDescriptor descriptor = m.getDescriptor();
+            for (Provides provides : descriptor.provides().values()) {
+                String service = provides.service();
+                Set<ServiceProvider> providers
+                    = map.computeIfAbsent(service, k -> new HashSet<>());
+                for (String pn : provides.providers()) {
+                    providers.add(new ServiceProvider(m, pn));
+                }
+            }
+        }
+
+        ServicesCatalog catalog = new ServicesCatalog() {
+            @Override
+            public void register(Module module) {
+                throw new UnsupportedOperationException();
+            }
+            @Override
+            public Set<ServiceProvider> findServices(String service) {
+                Set<ServiceProvider> providers = map.get(service);
+                if (providers == null) {
+                    return Collections.emptySet();
+                } else {
+                    return Collections.unmodifiableSet(providers);
+                }
+            }
+        };
+
+        synchronized (this) {
+            servicesCatalog = this.servicesCatalog;
+            if (servicesCatalog == null) {
+                this.servicesCatalog = servicesCatalog = catalog;
+            }
+        }
+
+        return servicesCatalog;
+    }
+
+    private volatile ServicesCatalog servicesCatalog;
 }
--- a/jdk/src/java.base/share/classes/java/lang/reflect/Module.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/lang/reflect/Module.java	Tue May 03 12:25:20 2016 -0700
@@ -43,11 +43,7 @@
 import java.util.Objects;
 import java.util.Optional;
 import java.util.Set;
-import java.util.WeakHashMap;
 import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReadWriteLock;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
 import java.util.function.Function;
 import java.util.stream.Stream;
 
@@ -142,9 +138,6 @@
         this.name = null;
         this.loader = loader;
         this.descriptor = null;
-
-        // unnamed modules are loose
-        this.loose = true;
     }
 
 
@@ -245,17 +238,27 @@
     }
 
 
-    // -- readability --
+    // --
+
+    // the special Module to mean reads or exported to "all unnamed modules"
+    private static final Module ALL_UNNAMED_MODULE = new Module(null);
 
-    // true if this module reads all unnamed modules (a.k.a. loose module)
-    private volatile boolean loose;
+    // special Module to mean exported to "everyone"
+    private static final Module EVERYONE_MODULE = new Module(null);
+
+    // exported to all modules
+    private static final Set<Module> EVERYONE = Collections.singleton(EVERYONE_MODULE);
+
+
+    // -- readability --
 
     // the modules that this module permanently reads
     // (will be final when the modules are defined in reverse topology order)
     private volatile Set<Module> reads;
 
-    // created lazily, additional modules that this module reflectively reads
-    private volatile WeakSet<Module> transientReads;
+    // additional module (2nd key) that some module (1st key) reflectively reads
+    private static final WeakPairMap<Module, Module, Boolean> transientReads
+        = new WeakPairMap<>();
 
 
     /**
@@ -284,22 +287,19 @@
 
         // check if this module reads other
         if (other.isNamed()) {
-
             Set<Module> reads = this.reads; // volatile read
             if (reads != null && reads.contains(other))
                 return true;
-
-        } else {
-
-            // loose modules read all unnamed modules
-            if (this.loose)
-                return true;
-
         }
 
         // check if this module reads the other module reflectively
-        WeakSet<Module> tr = this.transientReads; // volatile read
-        if (tr != null && tr.contains(other))
+        if (transientReads.containsKeyPair(this, other))
+            return true;
+
+        // if other is an unnamed module then check if this module reads
+        // all unnamed modules
+        if (!other.isNamed()
+            && transientReads.containsKeyPair(this, ALL_UNNAMED_MODULE))
             return true;
 
         return false;
@@ -346,8 +346,7 @@
     }
 
     /**
-     * Makes the given {@code Module} readable to this module without
-     * notifying the VM.
+     * Updates this module to read another module without notifying the VM.
      *
      * @apiNote This method is for VM white-box testing.
      */
@@ -361,40 +360,28 @@
      * If {@code syncVM} is {@code true} then the VM is notified.
      */
     private void implAddReads(Module other, boolean syncVM) {
+        Objects.requireNonNull(other);
 
         // nothing to do
         if (other == this || !this.isNamed())
             return;
 
-        // if the other is null then change this module to be loose.
-        if (other == null) {
-            if (syncVM)
-                addReads0(this, null);
-            this.loose = true;
-            return;
-        }
-
         // check if we already read this module
         Set<Module> reads = this.reads;
         if (reads != null && reads.contains(other))
             return;
 
         // update VM first, just in case it fails
-        if (syncVM)
-            addReads0(this, other);
+        if (syncVM) {
+            if (other == ALL_UNNAMED_MODULE) {
+                addReads0(this, null);
+            } else {
+                addReads0(this, other);
+            }
+        }
 
         // add reflective read
-        WeakSet<Module> tr = this.transientReads;
-        if (tr == null) {
-            synchronized (this) {
-                tr = this.transientReads;
-                if (tr == null) {
-                    tr = new WeakSet<>();
-                    this.transientReads = tr;
-                }
-            }
-        }
-        tr.add(other);
+        transientReads.putIfAbsent(this, other, Boolean.TRUE);
     }
 
 
@@ -404,15 +391,10 @@
     // (will be final when the modules are defined in reverse topology order)
     private volatile Map<String, Set<Module>> exports;
 
-    // created lazily, additional exports added at run-time
-    private volatile Map<String, WeakSet<Module>> transientExports;
-
-    // the special Module to mean exported to all modules
-    private static final Module EVERYONE_MODULE = new Module(null);
-    private static final Set<Module> EVERYONE = Collections.singleton(EVERYONE_MODULE);
-
-    // the special Module to mean exported to all unnamed modules
-    private static final Module ALL_UNNAMED_MODULE = new Module(null);
+    // additional exports added at run-time
+    // this module (1st key), other module (2nd key), exported packages (value)
+    private static final WeakPairMap<Module, Module, Map<String, Boolean>>
+        transientExports = new WeakPairMap<>();
 
 
     /**
@@ -489,23 +471,9 @@
         if (exports != null) {
             Set<Module> targets = exports.get(pn);
 
-            if (targets != null) {
-
-                // exported to all modules
-                if (targets.contains(EVERYONE_MODULE))
-                    return true;
-
-                if (other != EVERYONE_MODULE) {
-                    // exported to other
-                    if (targets.contains(other))
-                        return true;
-
-                    // other is an unnamed module && exported to all unnamed
-                    if (!other.isNamed() && targets.contains(ALL_UNNAMED_MODULE))
-                        return true;
-                }
-
-            }
+            if ((targets != null)
+                && (targets.contains(other) || targets.contains(EVERYONE_MODULE)))
+                return true;
         }
         return false;
     }
@@ -515,29 +483,27 @@
      * package package to the given module.
      */
     private boolean isExportedReflectively(String pn, Module other) {
-        Map<String, WeakSet<Module>> te = this.transientExports;
-        if (te != null) {
-            WeakSet<Module> targets = te.get(pn);
+        // exported to all modules
+        Map<String, ?> exports = transientExports.get(this, EVERYONE_MODULE);
+        if (exports != null && exports.containsKey(pn))
+            return true;
 
-            if (targets != null) {
-
-                // exported to all modules
-                if (targets.contains(EVERYONE_MODULE))
-                    return true;
+        if (other != EVERYONE_MODULE) {
 
-                if (other != EVERYONE_MODULE) {
+            // exported to other
+            exports = transientExports.get(this, other);
+            if (exports != null && exports.containsKey(pn))
+                return true;
 
-                    // exported to other
-                    if (targets.contains(other))
-                        return true;
-
-                    // other is an unnamed module && exported to all unnamed
-                    if (!other.isNamed() && targets.contains(ALL_UNNAMED_MODULE))
-                        return true;
-                }
+            // other is an unnamed module && exported to all unnamed
+            if (!other.isNamed()) {
+                exports = transientExports.get(this, ALL_UNNAMED_MODULE);
+                if (exports != null && exports.containsKey(pn))
+                    return true;
             }
 
         }
+
         return false;
     }
 
@@ -638,34 +604,19 @@
             }
         }
 
-        // create transientExports if needed
-        Map<String, WeakSet<Module>> te = this.transientExports; // read
-        if (te == null) {
-            synchronized (this) {
-                te = this.transientExports;
-                if (te == null) {
-                    te = new ConcurrentHashMap<>();
-                    this.transientExports = te;  // volatile write
-                }
-            }
-        }
-
         // add package name to transientExports if absent
-        WeakSet<Module> s = te.get(pn);
-        if (s == null) {
-            s = new WeakSet<>();
-            WeakSet<Module> prev = te.putIfAbsent(pn, s);
-            if (prev != null)
-                s = prev;
-        }
-        s.add(other);
+        transientExports
+            .computeIfAbsent(this, other,
+                             (_this, _other) -> new ConcurrentHashMap<>())
+            .putIfAbsent(pn, Boolean.TRUE);
     }
 
 
     // -- services --
 
-    // created lazily, additional service types that this module uses
-    private volatile WeakSet<Class<?>> transientUses;
+    // additional service type (2nd key) that some module (1st key) uses
+    private static final WeakPairMap<Module, Class<?>, Boolean> transientUses
+        = new WeakPairMap<>();
 
     /**
      * If the caller's module is this module then update this module to add a
@@ -702,17 +653,7 @@
             }
 
             if (!canUse(st)) {
-                WeakSet<Class<?>> uses = this.transientUses;
-                if (uses == null) {
-                    synchronized (this) {
-                        uses = this.transientUses;
-                        if (uses == null) {
-                            uses = new WeakSet<>();
-                            this.transientUses = uses;
-                        }
-                    }
-                }
-                uses.add(st);
+                transientUses.putIfAbsent(this, st, Boolean.TRUE);
             }
 
         }
@@ -746,11 +687,7 @@
             return true;
 
         // uses added via addUses
-        WeakSet<Class<?>> uses = this.transientUses;
-        if (uses != null && uses.contains(st))
-            return true;
-
-        return false;
+        return transientUses.containsKeyPair(this, st);
     }
 
 
@@ -885,7 +822,7 @@
     // -- creating Module objects --
 
     /**
-     * Find the runtime Module corresponding to the given ReadDependence
+     * Find the runtime Module corresponding to the given ResolvedModule
      * in the given parent Layer (or its parents).
      */
     private static Module find(ResolvedModule resolvedModule, Layer layer) {
@@ -969,7 +906,7 @@
 
             // automatic modules reads all unnamed modules
             if (descriptor.isAutomatic()) {
-                m.implAddReads(null, true);
+                m.implAddReads(ALL_UNNAMED_MODULE, true);
             }
 
             // exports
@@ -1097,7 +1034,7 @@
      * the representation is the string {@code "module"}, followed by a space,
      * and then the module name. For an unnamed module, the representation is
      * the string {@code "unnamed module"}, followed by a space, and then an
-     * implementation specific identifier for the unnamed module.
+     * implementation specific string that identifies the unnamed module.
      *
      * @return The string representation of this module
      */
@@ -1112,46 +1049,6 @@
     }
 
 
-    // -- supporting classes --
-
-
-    /**
-     * A "not-a-Set" set of weakly referenced objects that supports concurrent
-     * access.
-     */
-    private static class WeakSet<E> {
-        private final ReadWriteLock lock = new ReentrantReadWriteLock();
-        private final Lock readLock = lock.readLock();
-        private final Lock writeLock = lock.writeLock();
-
-        private final WeakHashMap<E, Boolean> map = new WeakHashMap<>();
-
-        /**
-         * Adds the specified element to the set.
-         */
-        void add(E e) {
-            writeLock.lock();
-            try {
-                map.put(e, Boolean.TRUE);
-            } finally {
-                writeLock.unlock();
-            }
-        }
-
-        /**
-         * Returns {@code true} if this set contains the specified element.
-         */
-        boolean contains(E e) {
-            readLock.lock();
-            try {
-                return map.containsKey(e);
-            } finally {
-                readLock.unlock();
-            }
-        }
-    }
-
-
     // -- native methods --
 
     // JVM_DefineModule
@@ -1196,8 +1093,12 @@
                     m1.implAddReads(m2, true);
                 }
                 @Override
+                public void addReadsAllUnnamed(Module m) {
+                    m.implAddReads(Module.ALL_UNNAMED_MODULE);
+                }
+                @Override
                 public void addExports(Module m, String pn, Module other) {
-                    m.implAddExports(pn, Objects.requireNonNull(other), true);
+                    m.implAddExports(pn, other, true);
                 }
                 @Override
                 public void addExportsToAll(Module m, String pn) {
@@ -1211,6 +1112,10 @@
                 public void addPackage(Module m, String pn) {
                     m.implAddPackage(pn, true);
                 }
+                @Override
+                public ServicesCatalog getServicesCatalog(Layer layer) {
+                    return layer.getServicesCatalog();
+                }
             });
     }
 }
--- a/jdk/src/java.base/share/classes/java/lang/reflect/Proxy.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/lang/reflect/Proxy.java	Tue May 03 12:25:20 2016 -0700
@@ -582,7 +582,7 @@
         }
 
         private static final String DEBUG =
-                GetPropertyAction.getProperty("jdk.proxy.debug", "");
+                GetPropertyAction.privilegedGetProperty("jdk.proxy.debug", "");
 
         private static boolean isDebug() {
             return !DEBUG.isEmpty();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/classes/java/lang/reflect/WeakPairMap.java	Tue May 03 12:25:20 2016 -0700
@@ -0,0 +1,354 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.lang.reflect;
+
+import java.lang.ref.Reference;
+import java.lang.ref.ReferenceQueue;
+import java.lang.ref.WeakReference;
+import java.util.Collection;
+import java.util.Objects;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.BiFunction;
+
+/**
+ * A WeakHashMap-like data structure that uses a pair of weakly-referenced keys
+ * with identity equality semantics to associate a strongly-referenced value.
+ * Unlike WeakHashMap, this data structure is thread-safe.
+ *
+ * @param <K1> the type of 1st key in key pair
+ * @param <K2> the type of 2nd key in key pair
+ * @param <V>  the type of value
+ * @author Peter Levart
+ */
+final class WeakPairMap<K1, K2, V> {
+
+    private final ConcurrentHashMap<Pair<K1, K2>, V> map = new ConcurrentHashMap<>();
+    private final ReferenceQueue<Object> queue = new ReferenceQueue<>();
+
+    /**
+     * Tests if the specified pair of keys are associated with a value
+     * in the WeakPairMap.
+     *
+     * @param k1 the 1st of the pair of keys
+     * @param k2 the 2nd of the pair of keys
+     * @return true if and only if the specified key pair is in this WeakPairMap,
+     * as determined by the identity comparison; false otherwise
+     * @throws NullPointerException if any of the specified keys is null
+     */
+    public boolean containsKeyPair(K1 k1, K2 k2) {
+        expungeStaleAssociations();
+        return map.containsKey(Pair.lookup(k1, k2));
+    }
+
+    /**
+     * Returns the value to which the specified pair of keys is mapped, or null
+     * if this WeakPairMap contains no mapping for the key pair.
+     * <p>More formally, if this WeakPairMap contains a mapping from a key pair
+     * {@code (_k1, _k2)} to a value {@code v} such that
+     * {@code k1 == _k1 && k2 == _k2}, then this method returns {@code v};
+     * otherwise it returns {@code null}.
+     * (There can be at most one such mapping.)
+     *
+     * @param k1 the 1st of the pair of keys for which the mapped value is to
+     *           be returned
+     * @param k2 the 2nd of the pair of keys for which the mapped value is to
+     *           be returned
+     * @return the value to which the specified key pair is mapped, or null if
+     * this map contains no mapping for the key pair
+     * @throws NullPointerException if any of the specified keys is null
+     */
+    public V get(K1 k1, K2 k2) {
+        expungeStaleAssociations();
+        return map.get(Pair.lookup(k1, k2));
+    }
+
+    /**
+     * Maps the specified key pair to the specified value in this WeakPairMap.
+     * Neither the keys nor the value can be null.
+     * <p>The value can be retrieved by calling the {@link #get} method
+     * with the the same keys (compared by identity).
+     *
+     * @param k1 the 1st of the pair of keys with which the specified value is to
+     *           be associated
+     * @param k2 the 2nd of the pair of keys with which the specified value is to
+     *           be associated
+     * @param v  value to be associated with the specified key pair
+     * @return the previous value associated with key pair, or {@code null} if
+     * there was no mapping for key pair
+     * @throws NullPointerException if any of the specified keys or value is null
+     */
+    public V put(K1 k1, K2 k2, V v) {
+        expungeStaleAssociations();
+        return map.put(Pair.weak(k1, k2, queue), v);
+    }
+
+    /**
+     * If the specified key pair is not already associated with a value,
+     * associates it with the given value and returns {@code null}, else does
+     * nothing and returns the currently associated value.
+     *
+     * @param k1 the 1st of the pair of keys with which the specified value is to
+     *           be associated
+     * @param k2 the 2nd of the pair of keys with which the specified value is to
+     *           be associated
+     * @param v  value to be associated with the specified key pair
+     * @return the previous value associated with key pair, or {@code null} if
+     * there was no mapping for key pair
+     * @throws NullPointerException if any of the specified keys or value is null
+     */
+    public V putIfAbsent(K1 k1, K2 k2, V v) {
+        expungeStaleAssociations();
+        return map.putIfAbsent(Pair.weak(k1, k2, queue), v);
+    }
+
+    /**
+     * If the specified key pair is not already associated with a value,
+     * attempts to compute its value using the given mapping function
+     * and enters it into this WeakPairMap unless {@code null}. The entire
+     * method invocation is performed atomically, so the function is
+     * applied at most once per key pair. Some attempted update operations
+     * on this WeakPairMap by other threads may be blocked while computation
+     * is in progress, so the computation should be short and simple,
+     * and must not attempt to update any other mappings of this WeakPairMap.
+     *
+     * @param k1              the 1st of the pair of keys with which the
+     *                        computed value is to be associated
+     * @param k2              the 2nd of the pair of keys with which the
+     *                        computed value is to be associated
+     * @param mappingFunction the function to compute a value
+     * @return the current (existing or computed) value associated with
+     * the specified key pair, or null if the computed value is null
+     * @throws NullPointerException  if any of the specified keys or
+     *                               mappingFunction is null
+     * @throws IllegalStateException if the computation detectably
+     *                               attempts a recursive update to this map
+     *                               that would otherwise never complete
+     * @throws RuntimeException      or Error if the mappingFunction does so, in
+     *                               which case the mapping is left unestablished
+     */
+    public V computeIfAbsent(K1 k1, K2 k2,
+                             BiFunction<? super K1, ? super K2, ? extends V>
+                                 mappingFunction) {
+        expungeStaleAssociations();
+        try {
+            return map.computeIfAbsent(
+                Pair.weak(k1, k2, queue),
+                pair -> mappingFunction.apply(pair.first(), pair.second()));
+        } finally {
+            Reference.reachabilityFence(k1);
+            Reference.reachabilityFence(k2);
+        }
+    }
+
+    /**
+     * Returns a {@link Collection} view of the values contained in this
+     * WeakPairMap. The collection is backed by the WeakPairMap, so changes to
+     * the map are reflected in the collection, and vice-versa.  The collection
+     * supports element removal, which removes the corresponding
+     * mapping from this map, via the {@code Iterator.remove},
+     * {@code Collection.remove}, {@code removeAll},
+     * {@code retainAll}, and {@code clear} operations.  It does not
+     * support the {@code add} or {@code addAll} operations.
+     *
+     * @return the collection view
+     */
+    public Collection<V> values() {
+        expungeStaleAssociations();
+        return map.values();
+    }
+
+    /**
+     * Removes associations from this WeakPairMap for which at least one of the
+     * keys in key pair has been found weakly-reachable and corresponding
+     * WeakRefPeer(s) enqueued. Called as part of each public operation.
+     */
+    private void expungeStaleAssociations() {
+        WeakRefPeer<?> peer;
+        while ((peer = (WeakRefPeer<?>) queue.poll()) != null) {
+            map.remove(peer.weakPair());
+        }
+    }
+
+    /**
+     * Common interface of both {@link Weak} and {@link Lookup} key pairs.
+     */
+    private interface Pair<K1, K2> {
+
+        static <K1, K2> Pair<K1, K2> weak(K1 k1, K2 k2,
+                                          ReferenceQueue<Object> queue) {
+            return new Weak<>(k1, k2, queue);
+        }
+
+        static <K1, K2> Pair<K1, K2> lookup(K1 k1, K2 k2) {
+            return new Lookup<>(k1, k2);
+        }
+
+        /**
+         * @return The 1st of the pair of keys (may be null for {@link Weak}
+         * when it gets cleared)
+         */
+        K1 first();
+
+        /**
+         * @return The 2nd of the pair of keys (may be null for {@link Weak}
+         * when it gets cleared)
+         */
+        K2 second();
+
+        static int hashCode(Object first, Object second) {
+            // assert first != null && second != null;
+            return System.identityHashCode(first) ^
+                   System.identityHashCode(second);
+        }
+
+        static boolean equals(Object first, Object second, Pair<?, ?> p) {
+            return first != null && second != null &&
+                   first == p.first() && second == p.second();
+        }
+
+        /**
+         * A Pair where both keys are weakly-referenced.
+         * It is composed of two instances of {@link WeakRefPeer}s:
+         * <pre>{@code
+         *
+         *     +-referent-> [K1]                +-referent-> [K2]
+         *     |                                |
+         *   +----------------+               +----------------+
+         *   | Pair.Weak <:   |-----peer----->| (anonymous) <: |
+         *   | WeakRefPeer,   |               | WeakRefPeer    |
+         *   | Pair           |<--weakPair()--|                |
+         *   +----------------+               +----------------+
+         *     |            ^
+         *     |            |
+         *     +-weakPair()-+
+         *
+         * }</pre>
+         * <p>
+         * Pair.Weak is used for CHM keys. Both peers are associated with the
+         * same {@link ReferenceQueue} so when either of their referents
+         * becomes weakly-reachable, the corresponding entries can be
+         * {@link #expungeStaleAssociations() expunged} from the map.
+         */
+        final class Weak<K1, K2> extends WeakRefPeer<K1> implements Pair<K1, K2> {
+
+            // saved hash so it can be retrieved after the reference is cleared
+            private final int hash;
+            // link to <K2> peer
+            private final WeakRefPeer<K2> peer;
+
+            Weak(K1 k1, K2 k2, ReferenceQueue<Object> queue) {
+                super(k1, queue);
+                hash = Pair.hashCode(k1, k2);
+                peer = new WeakRefPeer<>(k2, queue) {
+                    // link back to <K1> peer
+                    @Override
+                    Weak<?, ?> weakPair() { return Weak.this; }
+                };
+            }
+
+            @Override
+            Weak<?, ?> weakPair() {
+                return this;
+            }
+
+            @Override
+            public K1 first() {
+                return get();
+            }
+
+            @Override
+            public K2 second() {
+                return peer.get();
+            }
+
+            @Override
+            public int hashCode() {
+                return hash;
+            }
+
+            @Override
+            public boolean equals(Object obj) {
+                return this == obj ||
+                       (obj instanceof Pair &&
+                        Pair.equals(first(), second(), (Pair<?, ?>) obj));
+            }
+        }
+
+        /**
+         * Optimized lookup Pair, used as lookup key in methods like
+         * {@link java.util.Map#get(Object)} or
+         * {@link java.util.Map#containsKey(Object)}) where
+         * there is a great chance its allocation is eliminated
+         * by escape analysis when such lookups are inlined by JIT.
+         * All its methods are purposely designed so that 'this' is never
+         * passed to any other method or used as identity.
+         */
+        final class Lookup<K1, K2> implements Pair<K1, K2> {
+            private final K1 k1;
+            private final K2 k2;
+
+            Lookup(K1 k1, K2 k2) {
+                this.k1 = Objects.requireNonNull(k1);
+                this.k2 = Objects.requireNonNull(k2);
+            }
+
+            @Override
+            public K1 first() {
+                return k1;
+            }
+
+            @Override
+            public K2 second() {
+                return k2;
+            }
+
+            @Override
+            public int hashCode() {
+                return Pair.hashCode(k1, k2);
+            }
+
+            @Override
+            public boolean equals(Object obj) {
+                return obj instanceof Pair &&
+                       Pair.equals(k1, k2, (Pair<?, ?>) obj);
+            }
+        }
+    }
+
+    /**
+     * Common abstract supertype of a pair of WeakReference peers.
+     */
+    private static abstract class WeakRefPeer<K> extends WeakReference<K> {
+
+        WeakRefPeer(K k, ReferenceQueue<Object> queue) {
+            super(Objects.requireNonNull(k), queue);
+        }
+
+        /**
+         * @return the {@link Pair.Weak} side of the pair of peers.
+         */
+        abstract Pair.Weak<?, ?> weakPair();
+    }
+}
--- a/jdk/src/java.base/share/classes/java/net/AbstractPlainDatagramSocketImpl.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/net/AbstractPlainDatagramSocketImpl.java	Tue May 03 12:25:20 2016 -0700
@@ -52,7 +52,8 @@
     protected InetAddress connectedAddress = null;
     private int connectedPort = -1;
 
-    private static final String os = GetPropertyAction.getProperty("os.name");
+    private static final String os =
+            GetPropertyAction.privilegedGetProperty("os.name");
 
     /**
      * flag set if the native connect() call not to be used
--- a/jdk/src/java.base/share/classes/java/net/InetAddress.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/net/InetAddress.java	Tue May 03 12:25:20 2016 -0700
@@ -1124,7 +1124,7 @@
     private static NameService createNameService() {
 
         String hostsFileName =
-                GetPropertyAction.getProperty("jdk.net.hosts.file");
+                GetPropertyAction.privilegedGetProperty("jdk.net.hosts.file");
         NameService theNameService;
         if (hostsFileName != null) {
             theNameService = new HostsFileNameService(hostsFileName);
@@ -1643,9 +1643,11 @@
          * property can vary across implementations of the java.
          * classes.  The default is an empty String "".
          */
-        String prefix = GetPropertyAction.getProperty("impl.prefix", "");
+        String prefix = GetPropertyAction.privilegedGetProperty("impl.prefix", "");
         try {
-            impl = Class.forName("java.net." + prefix + implName).newInstance();
+            @SuppressWarnings("deprecation")
+            Object tmp = Class.forName("java.net." + prefix + implName).newInstance();
+            impl = tmp;
         } catch (ClassNotFoundException e) {
             System.err.println("Class not found: java.net." + prefix +
                                implName + ":\ncheck impl.prefix property " +
@@ -1662,7 +1664,9 @@
 
         if (impl == null) {
             try {
-                impl = Class.forName(implName).newInstance();
+                @SuppressWarnings("deprecation")
+                Object tmp = Class.forName(implName).newInstance();
+                impl = tmp;
             } catch (Exception e) {
                 throw new Error("System property impl.prefix incorrect");
             }
--- a/jdk/src/java.base/share/classes/java/net/ProxySelector.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/net/ProxySelector.java	Tue May 03 12:25:20 2016 -0700
@@ -71,7 +71,9 @@
         try {
             Class<?> c = Class.forName("sun.net.spi.DefaultProxySelector");
             if (c != null && ProxySelector.class.isAssignableFrom(c)) {
-                theProxySelector = (ProxySelector) c.newInstance();
+                @SuppressWarnings("deprecation")
+                ProxySelector tmp = (ProxySelector) c.newInstance();
+                theProxySelector = tmp;
             }
         } catch (Exception e) {
             theProxySelector = null;
--- a/jdk/src/java.base/share/classes/java/net/SocksSocketImpl.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/net/SocksSocketImpl.java	Tue May 03 12:25:20 2016 -0700
@@ -178,7 +178,7 @@
                 userName = pw.getUserName();
                 password = new String(pw.getPassword());
             } else {
-                userName = GetPropertyAction.getProperty("user.name");
+                userName = GetPropertyAction.privilegedGetProperty("user.name");
             }
             if (userName == null)
                 return false;
@@ -1088,7 +1088,7 @@
                 userName = System.getProperty("user.name");
             } catch (SecurityException se) { /* swallow Exception */ }
         } else {
-            userName = GetPropertyAction.getProperty("user.name");
+            userName = GetPropertyAction.privilegedGetProperty("user.name");
         }
         return userName;
     }
--- a/jdk/src/java.base/share/classes/java/net/URL.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/net/URL.java	Tue May 03 12:25:20 2016 -0700
@@ -1198,8 +1198,9 @@
         public URLStreamHandler createURLStreamHandler(String protocol) {
             String name = PREFIX + "." + protocol + ".Handler";
             try {
-                Class<?> c = Class.forName(name);
-                return (URLStreamHandler)c.newInstance();
+                @SuppressWarnings("deprecation")
+                Object o = Class.forName(name).newInstance();
+                return (URLStreamHandler)o;
             } catch (ClassNotFoundException x) {
                 // ignore
             } catch (Exception e) {
@@ -1212,7 +1213,7 @@
 
     private static URLStreamHandler lookupViaProperty(String protocol) {
         String packagePrefixList =
-                GetPropertyAction.getProperty(protocolPathProp);
+                GetPropertyAction.privilegedGetProperty(protocolPathProp);
         if (packagePrefixList == null) {
             // not set
             return null;
@@ -1234,7 +1235,9 @@
                     }
                 }
                 if (cls != null) {
-                    handler = (URLStreamHandler)cls.newInstance();
+                    @SuppressWarnings("deprecation")
+                    Object tmp = cls.newInstance();
+                    handler = (URLStreamHandler)tmp;
                 }
             } catch (Exception e) {
                 // any number of exceptions can get thrown here
--- a/jdk/src/java.base/share/classes/java/net/URLConnection.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/net/URLConnection.java	Tue May 03 12:25:20 2016 -0700
@@ -1323,7 +1323,9 @@
                     }
                 }
                 if (cls != null) {
-                    return (ContentHandler) cls.newInstance();
+                    @SuppressWarnings("deprecation")
+                    Object tmp = cls.newInstance();
+                    return (ContentHandler) tmp;
                 }
             } catch(Exception ignored) { }
         }
@@ -1397,7 +1399,7 @@
      */
     private String getContentHandlerPkgPrefixes() {
         String packagePrefixList =
-                GetPropertyAction.getProperty(contentPathProp, "");
+                GetPropertyAction.privilegedGetProperty(contentPathProp, "");
 
         if (packagePrefixList != "") {
             packagePrefixList += "|";
--- a/jdk/src/java.base/share/classes/java/net/URLEncoder.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/net/URLEncoder.java	Tue May 03 12:25:20 2016 -0700
@@ -133,7 +133,7 @@
         dontNeedEncoding.set('.');
         dontNeedEncoding.set('*');
 
-        dfltEncName = GetPropertyAction.getProperty("file.encoding");
+        dfltEncName = GetPropertyAction.privilegedGetProperty("file.encoding");
     }
 
     /**
--- a/jdk/src/java.base/share/classes/java/nio/channels/spi/AsynchronousChannelProvider.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/nio/channels/spi/AsynchronousChannelProvider.java	Tue May 03 12:25:20 2016 -0700
@@ -94,9 +94,10 @@
             if (cn == null)
                 return null;
             try {
-                Class<?> c = Class.forName(cn, true,
-                                           ClassLoader.getSystemClassLoader());
-                return (AsynchronousChannelProvider)c.newInstance();
+                @SuppressWarnings("deprecation")
+                Object tmp = Class.forName(cn, true,
+                                           ClassLoader.getSystemClassLoader()).newInstance();
+                return (AsynchronousChannelProvider)tmp;
             } catch (ClassNotFoundException x) {
                 throw new ServiceConfigurationError(null, x);
             } catch (IllegalAccessException x) {
--- a/jdk/src/java.base/share/classes/java/nio/channels/spi/SelectorProvider.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/nio/channels/spi/SelectorProvider.java	Tue May 03 12:25:20 2016 -0700
@@ -95,9 +95,10 @@
         if (cn == null)
             return false;
         try {
-            Class<?> c = Class.forName(cn, true,
-                                       ClassLoader.getSystemClassLoader());
-            provider = (SelectorProvider)c.newInstance();
+            @SuppressWarnings("deprecation")
+            Object tmp = Class.forName(cn, true,
+                                       ClassLoader.getSystemClassLoader()).newInstance();
+            provider = (SelectorProvider)tmp;
             return true;
         } catch (ClassNotFoundException x) {
             throw new ServiceConfigurationError(null, x);
--- a/jdk/src/java.base/share/classes/java/nio/charset/Charset.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/nio/charset/Charset.java	Tue May 03 12:25:20 2016 -0700
@@ -283,8 +283,8 @@
         if (level == null) {
             if (!VM.isBooted())
                 return false;
-            bugLevel = level =
-                    GetPropertyAction.getProperty("sun.nio.cs.bugLevel", "");
+            bugLevel = level = GetPropertyAction
+                    .privilegedGetProperty("sun.nio.cs.bugLevel", "");
         }
         return level.equals(bl);
     }
@@ -609,7 +609,8 @@
     public static Charset defaultCharset() {
         if (defaultCharset == null) {
             synchronized (Charset.class) {
-                String csn = GetPropertyAction.getProperty("file.encoding");
+                String csn = GetPropertyAction
+                        .privilegedGetProperty("file.encoding");
                 Charset cs = lookup(csn);
                 if (cs != null)
                     defaultCharset = cs;
--- a/jdk/src/java.base/share/classes/java/nio/file/TempFileHelper.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/nio/file/TempFileHelper.java	Tue May 03 12:25:20 2016 -0700
@@ -46,7 +46,7 @@
 
     // temporary directory location
     private static final Path tmpdir =
-        Paths.get(GetPropertyAction.getProperty("java.io.tmpdir"));
+        Paths.get(GetPropertyAction.privilegedGetProperty("java.io.tmpdir"));
 
     private static final boolean isPosix =
         FileSystems.getDefault().supportedFileAttributeViews().contains("posix");
--- a/jdk/src/java.base/share/classes/java/security/Policy.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/security/Policy.java	Tue May 03 12:25:20 2016 -0700
@@ -222,8 +222,9 @@
             public Policy run() {
                 try {
                     ClassLoader scl = ClassLoader.getSystemClassLoader();
-                    Class<?> c = Class.forName(policyProvider, true, scl);
-                    return (Policy)c.newInstance();
+                    @SuppressWarnings("deprecation")
+                    Object o = Class.forName(policyProvider, true, scl).newInstance();
+                    return (Policy)o;
                 } catch (Exception e) {
                     if (debug != null) {
                         debug.println("policy provider " + policyProvider +
--- a/jdk/src/java.base/share/classes/java/time/zone/ZoneRulesProvider.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/time/zone/ZoneRulesProvider.java	Tue May 03 12:25:20 2016 -0700
@@ -147,6 +147,7 @@
                 if (prop != null) {
                     try {
                         Class<?> c = Class.forName(prop, true, ClassLoader.getSystemClassLoader());
+                        @SuppressWarnings("deprecation")
                         ZoneRulesProvider provider = ZoneRulesProvider.class.cast(c.newInstance());
                         registerProvider(provider);
                         loaded.add(provider);
--- a/jdk/src/java.base/share/classes/java/util/Locale.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/util/Locale.java	Tue May 03 12:25:20 2016 -0700
@@ -858,7 +858,7 @@
 
     private static Locale initDefault() {
         String language, region, script, country, variant;
-        Properties props = GetPropertyAction.getProperties();
+        Properties props = GetPropertyAction.privilegedGetProperties();
         language = props.getProperty("user.language", "en");
         // for compatibility, check for old user.region property
         region = props.getProperty("user.region");
@@ -883,7 +883,7 @@
     }
 
     private static Locale initDefault(Locale.Category category) {
-        Properties props = GetPropertyAction.getProperties();
+        Properties props = GetPropertyAction.privilegedGetProperties();
         return getInstance(
             props.getProperty(category.languageKey,
                     defaultLocale.getLanguage()),
--- a/jdk/src/java.base/share/classes/java/util/PropertyResourceBundle.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/util/PropertyResourceBundle.java	Tue May 03 12:25:20 2016 -0700
@@ -140,9 +140,8 @@
 
     // Check whether the strict encoding is specified.
     // The possible encoding is either "ISO-8859-1" or "UTF-8".
-    private static final String encoding =
-        GetPropertyAction
-                .getProperty("java.util.PropertyResourceBundle.encoding", "")
+    private static final String encoding = GetPropertyAction
+        .privilegedGetProperty("java.util.PropertyResourceBundle.encoding", "")
         .toUpperCase(Locale.ROOT);
 
     /**
--- a/jdk/src/java.base/share/classes/java/util/ServiceLoader.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/util/ServiceLoader.java	Tue May 03 12:25:20 2016 -0700
@@ -29,8 +29,6 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
-import java.lang.module.ModuleDescriptor;
-import java.lang.module.ModuleDescriptor.Provides;
 import java.lang.reflect.Constructor;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Layer;
@@ -85,7 +83,7 @@
  * and deployed as a named module must have an appropriate <i>uses</i> clause
  * in its <i>module descriptor</i> to declare that the module uses
  * implementations of the service. A corresponding requirement is that a
- * provider deployed as a named modules must have an appropriate
+ * provider deployed as a named module must have an appropriate
  * <i>provides</i> clause in its module descriptor to declare that the module
  * provides an implementation of the service. The <i>uses</i> and
  * <i>provides</i> allow consumers of a service to be <i>linked</i> to
@@ -550,35 +548,29 @@
     /**
      * Implements lazy service provider lookup of service providers that
      * are provided by modules in a module Layer.
-     *
-     * For now, this iterator examines all modules in each Layer. This will
-     * be replaced once we decide on how the service-use graph is exposed
-     * in the module API.
      */
     private class LayerLookupIterator
         extends RestrictedIterator<S>
     {
         final String serviceName;
         Layer currentLayer;
-        Iterator<ModuleDescriptor> descriptorIterator;
-        Iterator<String> providersIterator;
-
-        Module nextModule;
-        String nextProvider;
+        Iterator<ServiceProvider> iterator;
+        ServiceProvider nextProvider;
 
         LayerLookupIterator() {
             serviceName = service.getName();
             currentLayer = layer;
 
             // need to get us started
-            descriptorIterator = descriptors(layer, serviceName);
+            iterator = providers(currentLayer, serviceName);
         }
 
-        Iterator<ModuleDescriptor> descriptors(Layer layer, String service) {
-            return layer.modules().stream()
-                    .map(Module::getDescriptor)
-                    .filter(d -> d.provides().get(service) != null)
-                    .iterator();
+        Iterator<ServiceProvider> providers(Layer layer, String service) {
+            ServicesCatalog catalog = SharedSecrets
+                    .getJavaLangReflectModuleAccess()
+                    .getServicesCatalog(layer);
+
+            return catalog.findServices(serviceName).iterator();
         }
 
         @Override
@@ -591,30 +583,18 @@
             while (true) {
 
                 // next provider
-                if (providersIterator != null && providersIterator.hasNext()) {
-                    nextProvider = providersIterator.next();
+                if (iterator != null && iterator.hasNext()) {
+                    nextProvider = iterator.next();
                     return true;
                 }
 
-                // next descriptor
-                if (descriptorIterator.hasNext()) {
-                    ModuleDescriptor descriptor = descriptorIterator.next();
-
-                    nextModule = currentLayer.findModule(descriptor.name()).get();
-
-                    Provides provides = descriptor.provides().get(serviceName);
-                    providersIterator = provides.providers().iterator();
-
-                    continue;
-                }
-
                 // next layer
                 Layer parent = currentLayer.parent().orElse(null);
                 if (parent == null)
                     return false;
 
                 currentLayer = parent;
-                descriptorIterator = descriptors(currentLayer, serviceName);
+                iterator = providers(currentLayer, serviceName);
             }
         }
 
@@ -623,13 +603,14 @@
             if (!hasNextService())
                 throw new NoSuchElementException();
 
-            assert nextModule != null && nextProvider != null;
-
-            String cn = nextProvider;
+            ServiceProvider provider = nextProvider;
             nextProvider = null;
 
+            Module module = provider.module();
+            String cn = provider.providerName();
+
             // attempt to load the provider
-            Class<?> c = loadClassInModule(nextModule, cn);
+            Class<?> c = loadClassInModule(module, cn);
             if (c == null)
                 fail(service, "Provider " + cn  + " not found");
             if (!service.isAssignableFrom(c))
@@ -830,7 +811,9 @@
             }
             S p = null;
             try {
-                p = service.cast(c.newInstance());
+                @SuppressWarnings("deprecation")
+                Object tmp = c.newInstance();
+                p = service.cast(tmp);
             } catch (Throwable x) {
                 fail(service,
                      "Provider " + cn + " could not be instantiated",
--- a/jdk/src/java.base/share/classes/java/util/TimeZone.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/util/TimeZone.java	Tue May 03 12:25:20 2016 -0700
@@ -42,6 +42,7 @@
 import java.security.AccessController;
 import java.security.PrivilegedAction;
 import java.time.ZoneId;
+import java.util.Properties;
 import sun.security.action.GetPropertyAction;
 import sun.util.calendar.ZoneInfo;
 import sun.util.calendar.ZoneInfoFile;
@@ -660,12 +661,13 @@
     private static synchronized TimeZone setDefaultZone() {
         TimeZone tz;
         // get the time zone ID from the system properties
-        String zoneID = GetPropertyAction.getProperty("user.timezone");
+        Properties props = GetPropertyAction.privilegedGetProperties();
+        String zoneID = props.getProperty("user.timezone");
 
         // if the time zone ID is not set (yet), perform the
         // platform to Java time zone ID mapping.
         if (zoneID == null || zoneID.isEmpty()) {
-            String javaHome = GetPropertyAction.getProperty("java.home");
+            String javaHome = props.getProperty("java.home");
             try {
                 zoneID = getSystemTimeZoneID(javaHome);
                 if (zoneID == null) {
@@ -693,13 +695,7 @@
         assert tz != null;
 
         final String id = zoneID;
-        AccessController.doPrivileged(new PrivilegedAction<>() {
-            @Override
-                public Void run() {
-                    System.setProperty("user.timezone", id);
-                    return null;
-                }
-            });
+        props.setProperty("user.timezone", id);
 
         defaultTimeZone = tz;
         return tz;
--- a/jdk/src/java.base/share/classes/java/util/concurrent/ForkJoinPool.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/util/concurrent/ForkJoinPool.java	Tue May 03 12:25:20 2016 -0700
@@ -3507,6 +3507,7 @@
      * Creates and returns the common pool, respecting user settings
      * specified via system properties.
      */
+    @SuppressWarnings("deprecation") // Class.newInstance
     static ForkJoinPool makeCommonPool() {
         int parallelism = -1;
         ForkJoinWorkerThreadFactory factory = null;
--- a/jdk/src/java.base/share/classes/java/util/jar/JarFile.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/util/jar/JarFile.java	Tue May 03 12:25:20 2016 -0700
@@ -155,7 +155,7 @@
         BASE_VERSION = 8;  // one less than lowest version for versioned entries
         int runtimeVersion = jdk.Version.current().major();
         String jarVersion =
-                GetPropertyAction.getProperty("jdk.util.jar.version");
+                GetPropertyAction.privilegedGetProperty("jdk.util.jar.version");
         if (jarVersion != null) {
             int jarVer = Integer.parseInt(jarVersion);
             runtimeVersion = (jarVer > runtimeVersion)
@@ -163,7 +163,7 @@
         }
         RUNTIME_VERSION = runtimeVersion;
         String enableMultiRelease = GetPropertyAction
-                .getProperty("jdk.util.jar.enableMultiRelease", "true");
+                .privilegedGetProperty("jdk.util.jar.enableMultiRelease", "true");
         switch (enableMultiRelease) {
             case "true":
             default:
--- a/jdk/src/java.base/share/classes/java/util/jar/Pack200.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/util/jar/Pack200.java	Tue May 03 12:25:20 2016 -0700
@@ -695,7 +695,7 @@
             Class<?> impl = (PACK_PROVIDER.equals(prop))? packerImpl: unpackerImpl;
             if (impl == null) {
                 // The first time, we must decide which class to use.
-                implName = GetPropertyAction.getProperty(prop,"");
+                implName = GetPropertyAction.privilegedGetProperty(prop,"");
                 if (implName != null && !implName.equals(""))
                     impl = Class.forName(implName);
                 else if (PACK_PROVIDER.equals(prop))
@@ -704,7 +704,9 @@
                     impl = com.sun.java.util.jar.pack.UnpackerImpl.class;
             }
             // We have a class.  Now instantiate it.
-            return impl.newInstance();
+            @SuppressWarnings("deprecation")
+            Object result = impl.newInstance();
+            return result;
         } catch (ClassNotFoundException e) {
             throw new Error("Class not found: " + implName +
                                 ":\ncheck property " + prop +
--- a/jdk/src/java.base/share/classes/java/util/regex/PatternSyntaxException.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/util/regex/PatternSyntaxException.java	Tue May 03 12:25:20 2016 -0700
@@ -94,7 +94,7 @@
     }
 
     private static final String nl =
-            GetPropertyAction.getProperty("line.separator");
+            GetPropertyAction.privilegedGetProperty("line.separator");
 
     /**
      * Returns a multi-line string containing the description of the syntax
--- a/jdk/src/java.base/share/classes/java/util/stream/DoublePipeline.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/util/stream/DoublePipeline.java	Tue May 03 12:25:20 2016 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -167,6 +167,19 @@
         return Nodes.doubleBuilder(exactSizeIfKnown);
     }
 
+    private <U> Stream<U> mapToObj(DoubleFunction<? extends U> mapper, int opFlags) {
+        return new ReferencePipeline.StatelessOp<Double, U>(this, StreamShape.DOUBLE_VALUE, opFlags) {
+            @Override
+            Sink<Double> opWrapSink(int flags, Sink<U> sink) {
+                return new Sink.ChainedDouble<U>(sink) {
+                    @Override
+                    public void accept(double t) {
+                        downstream.accept(mapper.apply(t));
+                    }
+                };
+            }
+        };
+    }
 
     // DoubleStream
 
@@ -184,7 +197,7 @@
 
     @Override
     public final Stream<Double> boxed() {
-        return mapToObj(Double::valueOf);
+        return mapToObj(Double::valueOf, 0);
     }
 
     @Override
@@ -207,18 +220,7 @@
     @Override
     public final <U> Stream<U> mapToObj(DoubleFunction<? extends U> mapper) {
         Objects.requireNonNull(mapper);
-        return new ReferencePipeline.StatelessOp<Double, U>(this, StreamShape.DOUBLE_VALUE,
-                                                            StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
-            @Override
-            Sink<Double> opWrapSink(int flags, Sink<U> sink) {
-                return new Sink.ChainedDouble<U>(sink) {
-                    @Override
-                    public void accept(double t) {
-                        downstream.accept(mapper.apply(t));
-                    }
-                };
-            }
-        };
+        return mapToObj(mapper, StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT);
     }
 
     @Override
--- a/jdk/src/java.base/share/classes/java/util/stream/IntPipeline.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/util/stream/IntPipeline.java	Tue May 03 12:25:20 2016 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -170,6 +170,19 @@
         return Nodes.intBuilder(exactSizeIfKnown);
     }
 
+    private <U> Stream<U> mapToObj(IntFunction<? extends U> mapper, int opFlags) {
+        return new ReferencePipeline.StatelessOp<Integer, U>(this, StreamShape.INT_VALUE, opFlags) {
+            @Override
+            Sink<Integer> opWrapSink(int flags, Sink<U> sink) {
+                return new Sink.ChainedInt<U>(sink) {
+                    @Override
+                    public void accept(int t) {
+                        downstream.accept(mapper.apply(t));
+                    }
+                };
+            }
+        };
+    }
 
     // IntStream
 
@@ -187,8 +200,7 @@
 
     @Override
     public final LongStream asLongStream() {
-        return new LongPipeline.StatelessOp<Integer>(this, StreamShape.INT_VALUE,
-                                                     StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
+        return new LongPipeline.StatelessOp<Integer>(this, StreamShape.INT_VALUE, 0) {
             @Override
             Sink<Integer> opWrapSink(int flags, Sink<Long> sink) {
                 return new Sink.ChainedInt<Long>(sink) {
@@ -203,8 +215,7 @@
 
     @Override
     public final DoubleStream asDoubleStream() {
-        return new DoublePipeline.StatelessOp<Integer>(this, StreamShape.INT_VALUE,
-                                                       StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
+        return new DoublePipeline.StatelessOp<Integer>(this, StreamShape.INT_VALUE, 0) {
             @Override
             Sink<Integer> opWrapSink(int flags, Sink<Double> sink) {
                 return new Sink.ChainedInt<Double>(sink) {
@@ -219,7 +230,7 @@
 
     @Override
     public final Stream<Integer> boxed() {
-        return mapToObj(Integer::valueOf);
+        return mapToObj(Integer::valueOf, 0);
     }
 
     @Override
@@ -242,18 +253,7 @@
     @Override
     public final <U> Stream<U> mapToObj(IntFunction<? extends U> mapper) {
         Objects.requireNonNull(mapper);
-        return new ReferencePipeline.StatelessOp<Integer, U>(this, StreamShape.INT_VALUE,
-                                                             StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
-            @Override
-            Sink<Integer> opWrapSink(int flags, Sink<U> sink) {
-                return new Sink.ChainedInt<U>(sink) {
-                    @Override
-                    public void accept(int t) {
-                        downstream.accept(mapper.apply(t));
-                    }
-                };
-            }
-        };
+        return mapToObj(mapper, StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT);
     }
 
     @Override
--- a/jdk/src/java.base/share/classes/java/util/stream/LongPipeline.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/util/stream/LongPipeline.java	Tue May 03 12:25:20 2016 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -167,6 +167,19 @@
         return Nodes.longBuilder(exactSizeIfKnown);
     }
 
+    private <U> Stream<U> mapToObj(LongFunction<? extends U> mapper, int opFlags) {
+        return new ReferencePipeline.StatelessOp<Long, U>(this, StreamShape.LONG_VALUE, opFlags) {
+            @Override
+            Sink<Long> opWrapSink(int flags, Sink<U> sink) {
+                return new Sink.ChainedLong<U>(sink) {
+                    @Override
+                    public void accept(long t) {
+                        downstream.accept(mapper.apply(t));
+                    }
+                };
+            }
+        };
+    }
 
     // LongStream
 
@@ -184,8 +197,7 @@
 
     @Override
     public final DoubleStream asDoubleStream() {
-        return new DoublePipeline.StatelessOp<Long>(this, StreamShape.LONG_VALUE,
-                                                    StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
+        return new DoublePipeline.StatelessOp<Long>(this, StreamShape.LONG_VALUE, StreamOpFlag.NOT_DISTINCT) {
             @Override
             Sink<Long> opWrapSink(int flags, Sink<Double> sink) {
                 return new Sink.ChainedLong<Double>(sink) {
@@ -200,7 +212,7 @@
 
     @Override
     public final Stream<Long> boxed() {
-        return mapToObj(Long::valueOf);
+        return mapToObj(Long::valueOf, 0);
     }
 
     @Override
@@ -223,18 +235,7 @@
     @Override
     public final <U> Stream<U> mapToObj(LongFunction<? extends U> mapper) {
         Objects.requireNonNull(mapper);
-        return new ReferencePipeline.StatelessOp<Long, U>(this, StreamShape.LONG_VALUE,
-                                                          StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT) {
-            @Override
-            Sink<Long> opWrapSink(int flags, Sink<U> sink) {
-                return new Sink.ChainedLong<U>(sink) {
-                    @Override
-                    public void accept(long t) {
-                        downstream.accept(mapper.apply(t));
-                    }
-                };
-            }
-        };
+        return mapToObj(mapper, StreamOpFlag.NOT_SORTED | StreamOpFlag.NOT_DISTINCT);
     }
 
     @Override
--- a/jdk/src/java.base/share/classes/java/util/stream/StreamSpliterators.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/util/stream/StreamSpliterators.java	Tue May 03 12:25:20 2016 -0700
@@ -28,6 +28,7 @@
 import java.util.Objects;
 import java.util.Spliterator;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ForkJoinPool;
 import java.util.concurrent.atomic.AtomicLong;
 import java.util.function.BooleanSupplier;
 import java.util.function.Consumer;
@@ -905,6 +906,7 @@
         // The spliterator to slice
         protected final T_SPLITR s;
         protected final boolean unlimited;
+        protected final int chunkSize;
         private final long skipThreshold;
         private final AtomicLong permits;
 
@@ -912,6 +914,8 @@
             this.s = s;
             this.unlimited = limit < 0;
             this.skipThreshold = limit >= 0 ? limit : 0;
+            this.chunkSize = limit >= 0 ? (int)Math.min(CHUNK_SIZE,
+                ((skip + limit) / AbstractTask.LEAF_TARGET) + 1) : CHUNK_SIZE;
             this.permits = new AtomicLong(limit >= 0 ? skip + limit : skip);
         }
 
@@ -921,6 +925,7 @@
             this.unlimited = parent.unlimited;
             this.permits = parent.permits;
             this.skipThreshold = parent.skipThreshold;
+            this.chunkSize = parent.chunkSize;
         }
 
         /**
@@ -1029,13 +1034,13 @@
                 PermitStatus permitStatus;
                 while ((permitStatus = permitStatus()) != PermitStatus.NO_MORE) {
                     if (permitStatus == PermitStatus.MAYBE_MORE) {
-                        // Optimistically traverse elements up to a threshold of CHUNK_SIZE
+                        // Optimistically traverse elements up to a threshold of chunkSize
                         if (sb == null)
-                            sb = new ArrayBuffer.OfRef<>(CHUNK_SIZE);
+                            sb = new ArrayBuffer.OfRef<>(chunkSize);
                         else
                             sb.reset();
                         long permitsRequested = 0;
-                        do { } while (s.tryAdvance(sb) && ++permitsRequested < CHUNK_SIZE);
+                        do { } while (s.tryAdvance(sb) && ++permitsRequested < chunkSize);
                         if (permitsRequested == 0)
                             return;
                         sb.forEach(action, acquirePermits(permitsRequested));
@@ -1102,15 +1107,15 @@
                 PermitStatus permitStatus;
                 while ((permitStatus = permitStatus()) != PermitStatus.NO_MORE) {
                     if (permitStatus == PermitStatus.MAYBE_MORE) {
-                        // Optimistically traverse elements up to a threshold of CHUNK_SIZE
+                        // Optimistically traverse elements up to a threshold of chunkSize
                         if (sb == null)
-                            sb = bufferCreate(CHUNK_SIZE);
+                            sb = bufferCreate(chunkSize);
                         else
                             sb.reset();
                         @SuppressWarnings("unchecked")
                         T_CONS sbc = (T_CONS) sb;
                         long permitsRequested = 0;
-                        do { } while (s.tryAdvance(sbc) && ++permitsRequested < CHUNK_SIZE);
+                        do { } while (s.tryAdvance(sbc) && ++permitsRequested < chunkSize);
                         if (permitsRequested == 0)
                             return;
                         sb.forEach(action, acquirePermits(permitsRequested));
--- a/jdk/src/java.base/share/classes/java/util/zip/ZipOutputStream.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/java/util/zip/ZipOutputStream.java	Tue May 03 12:25:20 2016 -0700
@@ -55,7 +55,7 @@
      */
     private static final boolean inhibitZip64 =
         Boolean.parseBoolean(
-            GetPropertyAction.getProperty("jdk.util.zip.inhibitZip64"));
+            GetPropertyAction.privilegedGetProperty("jdk.util.zip.inhibitZip64"));
 
     private static class XEntry {
         final ZipEntry entry;
--- a/jdk/src/java.base/share/classes/javax/net/ssl/SSLServerSocketFactory.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/javax/net/ssl/SSLServerSocketFactory.java	Tue May 03 12:25:20 2016 -0700
@@ -97,6 +97,7 @@
                         }
                     }
                     log("class " + clsName + " is loaded");
+                    @SuppressWarnings("deprecation")
                     SSLServerSocketFactory fac = (SSLServerSocketFactory)cls.newInstance();
                     log("instantiated an instance of class " + clsName);
                     theFactory = fac;
--- a/jdk/src/java.base/share/classes/javax/net/ssl/SSLSocketFactory.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/javax/net/ssl/SSLSocketFactory.java	Tue May 03 12:25:20 2016 -0700
@@ -51,7 +51,7 @@
     static final boolean DEBUG;
 
     static {
-        String s = GetPropertyAction.getProperty("javax.net.debug", "")
+        String s = GetPropertyAction.privilegedGetProperty("javax.net.debug", "")
                 .toLowerCase(Locale.ENGLISH);
 
         DEBUG = s.contains("all") || s.contains("ssl");
@@ -106,6 +106,7 @@
                         }
                     }
                     log("class " + clsName + " is loaded");
+                    @SuppressWarnings("deprecation")
                     SSLSocketFactory fac = (SSLSocketFactory)cls.newInstance();
                     log("instantiated an instance of class " + clsName);
                     theFactory = fac;
--- a/jdk/src/java.base/share/classes/javax/security/auth/login/Configuration.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/javax/security/auth/login/Configuration.java	Tue May 03 12:25:20 2016 -0700
@@ -250,7 +250,9 @@
                                             finalClass, false,
                                             Thread.currentThread().getContextClassLoader()
                                     ).asSubclass(Configuration.class);
-                                    return implClass.newInstance();
+                                    @SuppressWarnings("deprecation")
+                                    Configuration result = implClass.newInstance();
+                                    return result;
                                 }
                             });
                     AccessController.doPrivileged(
--- a/jdk/src/java.base/share/classes/javax/security/auth/login/LoginContext.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/javax/security/auth/login/LoginContext.java	Tue May 03 12:25:20 2016 -0700
@@ -304,7 +304,9 @@
                     Class<? extends CallbackHandler> c = Class.forName(
                             defaultHandler, true,
                             finalLoader).asSubclass(CallbackHandler.class);
-                    return c.newInstance();
+                    @SuppressWarnings("deprecation")
+                    CallbackHandler result = c.newInstance();
+                    return result;
                 }
             });
         } catch (java.security.PrivilegedActionException pae) {
@@ -697,8 +699,9 @@
 
                     if (moduleStack[i].module == null) {
                         try {
-                            moduleStack[i].module = (LoginModule) Class.forName(
-                                    name, false, contextClassLoader).newInstance();
+                            @SuppressWarnings("deprecation")
+                            Object tmp = Class.forName(name, false, contextClassLoader).newInstance();
+                            moduleStack[i].module = (LoginModule) tmp;
                             if (debug != null) {
                                 debug.println(name + " loaded via reflection");
                             }
--- a/jdk/src/java.base/share/classes/jdk/Version.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/jdk/Version.java	Tue May 03 12:25:20 2016 -0700
@@ -273,7 +273,8 @@
      */
     public static Version current() {
         if (current == null) {
-            current = parse(GetPropertyAction.getProperty("java.version"));
+            current = parse(
+                    GetPropertyAction.privilegedGetProperty("java.version"));
         }
         return current;
     }
--- a/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileSystemProvider.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/jdk/internal/jrtfs/JrtFileSystemProvider.java	Tue May 03 12:25:20 2016 -0700
@@ -124,7 +124,9 @@
         ClassLoader cl = newJrtFsLoader(jrtfs);
         try {
             Class<?> c = Class.forName(JrtFileSystemProvider.class.getName(), false, cl);
-            return ((FileSystemProvider)c.newInstance()).newFileSystem(uri, newEnv);
+            @SuppressWarnings("deprecation")
+            Object tmp = c.newInstance();
+            return ((FileSystemProvider)tmp).newFileSystem(uri, newEnv);
         } catch (ClassNotFoundException |
                  IllegalAccessException |
                  InstantiationException e) {
--- a/jdk/src/java.base/share/classes/jdk/internal/loader/BootLoader.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/jdk/internal/loader/BootLoader.java	Tue May 03 12:25:20 2016 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -68,7 +68,7 @@
     }
 
     // ServiceCatalog for the boot class loader
-    private static final ServicesCatalog SERVICES_CATALOG = new ServicesCatalog();
+    private static final ServicesCatalog SERVICES_CATALOG = ServicesCatalog.create();
 
     // ClassLoaderValue map for boot class loader
     private static final ConcurrentHashMap<?, ?> CLASS_LOADER_VALUE_MAP =
--- a/jdk/src/java.base/share/classes/jdk/internal/loader/BuiltinClassLoader.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/jdk/internal/loader/BuiltinClassLoader.java	Tue May 03 12:25:20 2016 -0700
@@ -104,7 +104,7 @@
      * A module defined/loaded by a built-in class loader.
      *
      * A LoadedModule encapsulates a ModuleReference along with its CodeSource
-     * URL to avoid needing to create this URL when define classes.
+     * URL to avoid needing to create this URL when defining classes.
      */
     private static class LoadedModule {
         private final BuiltinClassLoader loader;
--- a/jdk/src/java.base/share/classes/jdk/internal/loader/URLClassPath.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/jdk/internal/loader/URLClassPath.java	Tue May 03 12:25:20 2016 -0700
@@ -85,7 +85,7 @@
     private static final boolean DISABLE_JAR_CHECKING;
 
     static {
-        Properties props = GetPropertyAction.getProperties();
+        Properties props = GetPropertyAction.privilegedGetProperties();
         JAVA_VERSION = props.getProperty("java.version");
         DEBUG = (props.getProperty("sun.misc.URLClassPath.debug") != null);
         String p = props.getProperty("sun.misc.URLClassPath.disableJarChecking");
--- a/jdk/src/java.base/share/classes/jdk/internal/logger/LoggerFinderLoader.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/jdk/internal/logger/LoggerFinderLoader.java	Tue May 03 12:25:20 2016 -0700
@@ -81,7 +81,7 @@
     // Get configuration error policy
     private static ErrorPolicy configurationErrorPolicy() {
         String errorPolicy =
-                GetPropertyAction.getProperty("jdk.logger.finder.error");
+                GetPropertyAction.privilegedGetProperty("jdk.logger.finder.error");
         if (errorPolicy == null || errorPolicy.isEmpty()) {
             return ErrorPolicy.WARNING;
         }
@@ -96,7 +96,7 @@
     // This is further submitted to the configuration error policy.
     private static boolean ensureSingletonProvider() {
         return Boolean.parseBoolean(
-                GetPropertyAction.getProperty("jdk.logger.finder.singleton"));
+                GetPropertyAction.privilegedGetProperty("jdk.logger.finder.singleton"));
     }
 
     private static Iterator<System.LoggerFinder> findLoggerFinderProviders() {
--- a/jdk/src/java.base/share/classes/jdk/internal/logger/SimpleConsoleLogger.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/jdk/internal/logger/SimpleConsoleLogger.java	Tue May 03 12:25:20 2016 -0700
@@ -56,7 +56,7 @@
 
     static Level getDefaultLevel() {
         String levelName = GetPropertyAction
-                .getProperty("jdk.system.logger.level", "INFO");
+                .privilegedGetProperty("jdk.system.logger.level", "INFO");
         try {
             return Level.valueOf(levelName);
         } catch (IllegalArgumentException iae) {
@@ -426,7 +426,7 @@
         static private final String[] skips;
         static {
             String additionalPkgs =
-                    GetPropertyAction.getProperty("jdk.logger.packages");
+                    GetPropertyAction.privilegedGetProperty("jdk.logger.packages");
             skips = additionalPkgs == null ? new String[0] : additionalPkgs.split(",");
         }
 
@@ -485,7 +485,7 @@
             //    jdk/test/java/lang/invoke/lambda/LogGeneratedClassesTest.java
             // to fail - because that test has a testcase which somehow references
             // PlatformLogger and counts the number of generated lambda classes.
-            String format = GetPropertyAction.getProperty(key);
+            String format = GetPropertyAction.privilegedGetProperty(key);
 
             if (format == null && defaultPropertyGetter != null) {
                 format = defaultPropertyGetter.apply(key);
--- a/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangModuleAccess.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangModuleAccess.java	Tue May 03 12:25:20 2016 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,13 +25,24 @@
 
 package jdk.internal.misc;
 
+import java.io.PrintStream;
+import java.lang.module.Configuration;
+import jdk.internal.module.ModuleHashes;
+
 import java.lang.module.ModuleDescriptor;
 import java.lang.module.ModuleDescriptor.Exports;
 import java.lang.module.ModuleDescriptor.Requires;
 import java.lang.module.ModuleDescriptor.Provides;
 import java.lang.module.ModuleDescriptor.Version;
+import java.lang.module.ModuleFinder;
+import java.util.Collection;
+import java.lang.module.ModuleReader;
+import java.lang.module.ModuleReference;
+import java.net.URI;
 import java.util.Map;
+import java.util.Optional;
 import java.util.Set;
+import java.util.function.Supplier;
 
 /**
  * Provides access to non-public methods in java.lang.module.
@@ -89,5 +100,29 @@
                                          String osArch,
                                          String osVersion,
                                          Set<String> conceals,
-                                         Set<String> packages);
+                                         Set<String> packages,
+                                         ModuleHashes hashes);
+
+    /**
+     * Resolves a collection of root modules, with service binding
+     * and the empty configuration as the parent. The post resolution
+     * checks are optionally run.
+     */
+    Configuration resolveRequiresAndUses(ModuleFinder finder,
+                                         Collection<String> roots,
+                                         boolean check,
+                                         PrintStream traceOutput);
+
+    /**
+     * Creates a ModuleReference to a "patched" module.
+     */
+    ModuleReference newPatchedModule(ModuleDescriptor descriptor,
+                                     URI location,
+                                     Supplier<ModuleReader> readerSupplier);
+
+    /**
+     * Returns the object with the hashes of other modules
+     */
+    Optional<ModuleHashes> hashes(ModuleDescriptor descriptor);
+
 }
--- a/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangReflectModuleAccess.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/jdk/internal/misc/JavaLangReflectModuleAccess.java	Tue May 03 12:25:20 2016 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -26,9 +26,12 @@
 package jdk.internal.misc;
 
 import java.lang.module.ModuleDescriptor;
+import java.lang.reflect.Layer;
 import java.lang.reflect.Module;
 import java.net.URI;
 
+import jdk.internal.module.ServicesCatalog;
+
 /**
  * Provides access to non-public methods in java.lang.reflect.Module
  */
@@ -57,6 +60,11 @@
     void addReads(Module m1, Module m2);
 
     /**
+     * Updates module m to read all unnamed modules.
+     */
+    void addReadsAllUnnamed(Module m);
+
+    /**
      * Updates module m1 to export a package to module m2. The export does
      * not result in a strong reference to m2 (m2 can be GC'ed).
      */
@@ -76,4 +84,10 @@
      * Add a package to the given module.
      */
     void addPackage(Module m, String pkg);
-}
+
+    /**
+     * Returns the ServicesCatalog for the given Layer.
+     */
+    ServicesCatalog getServicesCatalog(Layer layer);
+
+}
\ No newline at end of file
--- a/jdk/src/java.base/share/classes/jdk/internal/module/Builder.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/Builder.java	Tue May 03 12:25:20 2016 -0700
@@ -74,6 +74,8 @@
     String osName;
     String osArch;
     String osVersion;
+    String algorithm;
+    Map<String, String> hashes;
 
     Builder(String name, int reqs, int exports,
             int provides, int conceals, int packages) {
@@ -252,6 +254,25 @@
     }
 
     /**
+     * Sets the algorithm of the module hashes
+     */
+    public Builder algorithm(String algorithm) {
+        this.algorithm = algorithm;
+        return this;
+    }
+
+    /**
+     * Sets the module hash for the given module name
+     */
+    public Builder moduleHash(String mn, String hash) {
+        if (hashes == null)
+            hashes = new HashMap<>();
+
+        hashes.put(mn, hash);
+        return this;
+    }
+
+    /**
      * Returns the set of packages that is the union of the exported and
      * concealed packages.
      */
@@ -273,6 +294,9 @@
     public ModuleDescriptor build() {
         assert name != null;
 
+        ModuleHashes moduleHashes =
+            hashes != null ? new ModuleHashes(algorithm, hashes) : null;
+
         return jlma.newModuleDescriptor(name,
                                         false,    // automatic
                                         false,    // assume not synthetic for now
@@ -286,6 +310,7 @@
                                         osArch,
                                         osVersion,
                                         conceals,
-                                        computePackages(exports, conceals));
+                                        computePackages(exports, conceals),
+                                        moduleHashes);
     }
 }
--- a/jdk/src/java.base/share/classes/jdk/internal/module/ClassFileAttributes.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ClassFileAttributes.java	Tue May 03 12:25:20 2016 -0700
@@ -34,6 +34,7 @@
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.LinkedHashSet;
 import java.util.Map;
 import java.util.Set;
 
@@ -42,7 +43,6 @@
 import jdk.internal.org.objectweb.asm.ClassReader;
 import jdk.internal.org.objectweb.asm.ClassWriter;
 import jdk.internal.org.objectweb.asm.Label;
-import jdk.internal.module.Hasher.DependencyHashes;
 import static jdk.internal.module.ClassFileConstants.*;
 
 
@@ -148,7 +148,7 @@
                 for (int i=0; i<provides_count; i++) {
                     String sn = cr.readClass(off, buf).replace('/', '.');
                     String cn = cr.readClass(off + 2, buf).replace('/', '.');
-                    provides.computeIfAbsent(sn, k -> new HashSet<>()).add(cn);
+                    provides.computeIfAbsent(sn, k -> new LinkedHashSet<>()).add(cn);
                     off += 4;
                 }
                 provides.entrySet().forEach(e -> builder.provides(e.getKey(),
@@ -281,10 +281,10 @@
      *   u4 attribute_length;
      *
      *   // the number of entries in the packages table
-     *   u2 package_count;
+     *   u2 packages_count;
      *   { // index to CONSTANT_CONSTANT_utf8_info structure with the package name
      *     u2 package_index
-     *   } package[package_count];
+     *   } packages[package_count];
      *
      * }</pre>
      */
@@ -579,9 +579,9 @@
      * alternative is to store it as an array of u1.
      */
     static class HashesAttribute extends Attribute {
-        private final DependencyHashes hashes;
+        private final ModuleHashes hashes;
 
-        HashesAttribute(DependencyHashes hashes) {
+        HashesAttribute(ModuleHashes hashes) {
             super(HASHES);
             this.hashes = hashes;
         }
@@ -613,7 +613,7 @@
                 map.put(dn, hash);
             }
 
-            DependencyHashes hashes = new DependencyHashes(algorithm, map);
+            ModuleHashes hashes = new ModuleHashes(algorithm, map);
 
             return new HashesAttribute(hashes);
         }
--- a/jdk/src/java.base/share/classes/jdk/internal/module/Hasher.java	Tue May 03 09:48:02 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,142 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package jdk.internal.module;
-
-import java.io.IOException;
-import java.io.UncheckedIOException;
-import java.nio.ByteBuffer;
-import java.nio.channels.FileChannel;
-import java.nio.file.Path;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-import java.util.Base64;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Supporting class for computing, encoding and decoding hashes (message
- * digests).
- */
-
-public class Hasher {
-    private Hasher() { }
-
-    /**
-     * A supplier of an encoded message digest.
-     */
-    public static interface HashSupplier {
-        String generate(String algorithm);
-    }
-
-    /**
-     * Encapsulates the result of hashing the contents of a number of module
-     * artifacts.
-     */
-    public static class DependencyHashes {
-        private final String algorithm;
-        private final Map<String, String> nameToHash;
-
-        public DependencyHashes(String algorithm, Map<String, String> nameToHash) {
-            this.algorithm = algorithm;
-            this.nameToHash = nameToHash;
-        }
-
-        /**
-         * Returns the algorithm used to hash the dependences ("SHA-256" or
-         * "MD5" for example).
-         */
-        public String algorithm() {
-            return algorithm;
-        }
-
-        /**
-         * Returns the set of module names for which hashes are recorded.
-         */
-        public Set<String> names() {
-            return nameToHash.keySet();
-        }
-
-        /**
-         * Retruns the hash string for the given module name, {@code null}
-         * if there is no hash recorded for the module.
-         */
-        public String hashFor(String dn) {
-            return nameToHash.get(dn);
-        }
-    }
-
-
-    /**
-     * Computes the hash for the given file with the given message digest
-     * algorithm. Returns the results a base64-encoded String.
-     *
-     * @throws UncheckedIOException if an I/O error occurs
-     * @throws RuntimeException if the algorithm is not available
-     */
-    public static String generate(Path file, String algorithm) {
-        try {
-            MessageDigest md = MessageDigest.getInstance(algorithm);
-
-            // Ideally we would just mmap the file but this consumes too much
-            // memory when jlink is running concurrently on very large jmods
-            try (FileChannel fc = FileChannel.open(file)) {
-                ByteBuffer bb = ByteBuffer.allocate(32*1024);
-                int nread;
-                while ((nread = fc.read(bb)) > 0) {
-                    bb.flip();
-                    md.update(bb);
-                    assert bb.remaining() == 0;
-                    bb.clear();
-                }
-            }
-
-            byte[] bytes = md.digest();
-            return Base64.getEncoder().encodeToString(bytes);
-        } catch (NoSuchAlgorithmException e) {
-            throw new RuntimeException(e);
-        } catch (IOException ioe) {
-            throw new UncheckedIOException(ioe);
-        }
-    }
-
-    /**
-     * Computes the hash for every entry in the given map, returning a
-     * {@code DependencyHashes} to encapsulate the result. The map key is
-     * the entry name, typically the module name. The map value is the file
-     * path to the entry (module artifact).
-     *
-     * @return DependencyHashes encapsulate the hashes
-     */
-    public static DependencyHashes generate(Map<String, Path> map, String algorithm) {
-        Map<String, String> nameToHash = new HashMap<>();
-        for (Map.Entry<String, Path> entry: map.entrySet()) {
-            String name = entry.getKey();
-            Path path = entry.getValue();
-            nameToHash.put(name, generate(path, algorithm));
-        }
-        return new DependencyHashes(algorithm, nameToHash);
-    }
-}
--- a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java	Tue May 03 12:25:20 2016 -0700
@@ -26,12 +26,15 @@
 package jdk.internal.module;
 
 import java.io.File;
+import java.io.PrintStream;
 import java.lang.module.Configuration;
+import java.lang.module.ModuleDescriptor;
+import java.lang.module.ModuleFinder;
 import java.lang.module.ModuleReference;
-import java.lang.module.ModuleFinder;
 import java.lang.module.ResolvedModule;
 import java.lang.reflect.Layer;
 import java.lang.reflect.Module;
+import java.net.URI;
 import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.util.Collections;
@@ -41,10 +44,10 @@
 import java.util.Optional;
 import java.util.Set;
 import java.util.function.Function;
-import java.util.stream.Collectors;
 
 import jdk.internal.loader.BootLoader;
 import jdk.internal.loader.BuiltinClassLoader;
+import jdk.internal.misc.SharedSecrets;
 import jdk.internal.perf.PerfCounter;
 
 /**
@@ -54,10 +57,9 @@
  * the module system. In summary, the boot method creates a Configuration by
  * resolving a set of module names specified via the launcher (or equivalent)
  * -m and -addmods options. The modules are located on a module path that is
- * constructed from the upgrade, system and application module paths. The
- * Configuration is reified by creating the boot Layer with each module in the
- * the configuration defined to one of the built-in class loaders. The mapping
- * of modules to class loaders is statically mapped in a helper class.
+ * constructed from the upgrade module path, system modules, and application
+ * module path. The Configuration is instantiated as the boot Layer with each
+ * module in the the configuration defined to one of the built-in class loaders.
  */
 
 public final class ModuleBootstrap {
@@ -65,6 +67,11 @@
 
     private static final String JAVA_BASE = "java.base";
 
+    private static final String JAVA_SE = "java.se";
+
+    // the token for "all default modules"
+    private static final String ALL_DEFAULT = "ALL-DEFAULT";
+
     // the token for "all unnamed modules"
     private static final String ALL_UNNAMED = "ALL-UNNAMED";
 
@@ -94,47 +101,65 @@
 
         long t0 = System.nanoTime();
 
-        // system module path
-        ModuleFinder systemModulePath = ModuleFinder.ofSystem();
+        // system modules
+        ModuleFinder systemModules = ModuleFinder.ofSystem();
+
+        PerfCounters.systemModulesTime.addElapsedTimeFrom(t0);
 
-        // Once we have the system module path then we define the base module.
-        // We do this here so that java.base is defined to the VM as early as
+
+        long t1 = System.nanoTime();
+
+        // Once we have the system modules then we define the base module to
+        // the VM. We do this here so that java.base is defined as early as
         // possible and also that resources in the base module can be located
         // for error messages that may happen from here on.
-        Optional<ModuleReference> obase = systemModulePath.find(JAVA_BASE);
-        if (!obase.isPresent())
+        ModuleReference base = systemModules.find(JAVA_BASE).orElse(null);
+        if (base == null)
             throw new InternalError(JAVA_BASE + " not found");
-        ModuleReference base = obase.get();
+        URI baseUri = base.location().orElse(null);
+        if (baseUri == null)
+            throw new InternalError(JAVA_BASE + " does not have a location");
         BootLoader.loadModule(base);
-        Modules.defineModule(null, base.descriptor(), base.location().orElse(null));
+        Modules.defineModule(null, base.descriptor(), baseUri);
 
+        PerfCounters.defineBaseTime.addElapsedTimeFrom(t1);
+
+
+        long t2 = System.nanoTime();
 
         // -upgrademodulepath option specified to launcher
         ModuleFinder upgradeModulePath
             = createModulePathFinder("jdk.upgrade.module.path");
+        if (upgradeModulePath != null)
+            systemModules = ModuleFinder.compose(upgradeModulePath, systemModules);
 
         // -modulepath option specified to the launcher
         ModuleFinder appModulePath = createModulePathFinder("jdk.module.path");
 
-        // The module finder: [-upgrademodulepath] system-module-path [-modulepath]
-        ModuleFinder finder = systemModulePath;
-        if (upgradeModulePath != null)
-            finder = ModuleFinder.compose(upgradeModulePath, finder);
+        // The module finder: [-upgrademodulepath] system [-modulepath]
+        ModuleFinder finder = systemModules;
         if (appModulePath != null)
             finder = ModuleFinder.compose(finder, appModulePath);
 
-        // launcher -m option to specify the initial module
+        // The root modules to resolve
+        Set<String> roots = new HashSet<>();
+
+        // launcher -m option to specify the main/initial module
         String mainModule = System.getProperty("jdk.module.main");
+        if (mainModule != null)
+            roots.add(mainModule);
 
         // additional module(s) specified by -addmods
+        boolean addAllDefaultModules = false;
         boolean addAllSystemModules = false;
         boolean addAllApplicationModules = false;
-        Set<String> addModules = null;
         String propValue = System.getProperty("jdk.launcher.addmods");
         if (propValue != null) {
-            addModules = new HashSet<>();
             for (String mod: propValue.split(",")) {
                 switch (mod) {
+                    case ALL_DEFAULT:
+                        addAllDefaultModules = true;
+                        break;
                     case ALL_SYSTEM:
                         addAllSystemModules = true;
                         break;
@@ -142,28 +167,12 @@
                         addAllApplicationModules = true;
                         break;
                     default :
-                        addModules.add(mod);
+                        roots.add(mod);
                 }
             }
         }
 
-        // The root modules to resolve
-        Set<String> roots = new HashSet<>();
-
-        // main/initial module
-        if (mainModule != null) {
-            roots.add(mainModule);
-            if (addAllApplicationModules)
-                fail(ALL_MODULE_PATH + " not allowed with initial module");
-        }
-
-        // If -addmods is specified then those modules need to be resolved
-        if (addModules != null)
-            roots.addAll(addModules);
-
-
         // -limitmods
-        boolean limitmods = false;
         propValue = System.getProperty("jdk.launcher.limitmods");
         if (propValue != null) {
             Set<String> mods = new HashSet<>();
@@ -171,62 +180,101 @@
                 mods.add(mod);
             }
             finder = limitFinder(finder, mods, roots);
-            limitmods = true;
         }
 
-
-        // If there is no initial module specified then assume that the
-        // initial module is the unnamed module of the application class
-        // loader. By convention, and for compatibility, this is
-        // implemented by putting the names of all modules on the system
-        // module path into the set of modules to resolve.
-        //
-        // If `-addmods ALL-SYSTEM` is used then all modules on the system
-        // module path will be resolved, irrespective of whether an initial
-        // module is specified.
-        //
-        // If `-addmods ALL-MODULE-PATH` is used, and no initial module is
-        // specified, then all modules on the application module path will
-        // be resolved.
-        //
-        if (mainModule == null || addAllSystemModules) {
-            Set<ModuleReference> mrefs;
-            if (addAllApplicationModules) {
-                assert mainModule == null;
-                mrefs = finder.findAll();
-            } else {
-                mrefs = systemModulePath.findAll();
-                if (limitmods) {
-                    ModuleFinder f = finder;
-                    mrefs = mrefs.stream()
-                        .filter(m -> f.find(m.descriptor().name()).isPresent())
-                        .collect(Collectors.toSet());
+        // If there is no initial module specified then assume that the initial
+        // module is the unnamed module of the application class loader. This
+        // is implemented by resolving "java.se" and all (non-java.*) modules
+        // that export an API. If "java.se" is not observable then all java.*
+        // modules are resolved.
+        if (mainModule == null || addAllDefaultModules) {
+            boolean hasJava = false;
+            if (systemModules.find(JAVA_SE).isPresent()) {
+                // java.se is a system module
+                if (finder == systemModules || finder.find(JAVA_SE).isPresent()) {
+                    // java.se is observable
+                    hasJava = true;
+                    roots.add(JAVA_SE);
                 }
             }
-            // map to module names
-            for (ModuleReference mref : mrefs) {
-                roots.add(mref.descriptor().name());
+
+            for (ModuleReference mref : systemModules.findAll()) {
+                String mn = mref.descriptor().name();
+                if (hasJava && mn.startsWith("java."))
+                    continue;
+
+                // add as root if observable and exports at least one package
+                if ((finder == systemModules || finder.find(mn).isPresent())) {
+                    ModuleDescriptor descriptor = mref.descriptor();
+                    for (ModuleDescriptor.Exports e : descriptor.exports()) {
+                        if (!e.isQualified()) {
+                            roots.add(mn);
+                            break;
+                        }
+                    }
+                }
             }
         }
 
-        long t1 = System.nanoTime();
+        // If `-addmods ALL-SYSTEM` is specified then all observable system
+        // modules will be resolved.
+        if (addAllSystemModules) {
+            ModuleFinder f = finder;  // observable modules
+            systemModules.findAll()
+                .stream()
+                .map(ModuleReference::descriptor)
+                .map(ModuleDescriptor::name)
+                .filter(mn -> f.find(mn).isPresent())  // observable
+                .forEach(mn -> roots.add(mn));
+        }
+
+        // If `-addmods ALL-MODULE-PATH` is specified then all observable
+        // modules on the application module path will be resolved.
+        if  (appModulePath != null && addAllApplicationModules) {
+            ModuleFinder f = finder;  // observable modules
+            appModulePath.findAll()
+                .stream()
+                .map(ModuleReference::descriptor)
+                .map(ModuleDescriptor::name)
+                .filter(mn -> f.find(mn).isPresent())  // observable
+                .forEach(mn -> roots.add(mn));
+        }
+
+        PerfCounters.optionsAndRootsTime.addElapsedTimeFrom(t2);
+
+
+        long t3 = System.nanoTime();
+
+        // determine if post resolution checks are needed
+        boolean needPostResolutionChecks = true;
+        if (baseUri.getScheme().equals("jrt")   // toLowerCase not needed here
+                && (upgradeModulePath == null)
+                && (appModulePath == null)
+                && (System.getProperty("jdk.launcher.patch.0") == null)) {
+            needPostResolutionChecks = false;
+        }
+
+        PrintStream traceOutput = null;
+        if (Boolean.getBoolean("jdk.launcher.traceResolver"))
+            traceOutput = System.out;
 
         // run the resolver to create the configuration
-
-        Configuration cf = Configuration.empty()
+        Configuration cf = SharedSecrets.getJavaLangModuleAccess()
                 .resolveRequiresAndUses(finder,
-                                        ModuleFinder.empty(),
-                                        roots);
+                                        roots,
+                                        needPostResolutionChecks,
+                                        traceOutput);
 
         // time to create configuration
-        PerfCounters.resolveTime.addElapsedTimeFrom(t1);
+        PerfCounters.resolveTime.addElapsedTimeFrom(t3);
+
 
         // mapping of modules to class loaders
         Function<String, ClassLoader> clf = ModuleLoaderMap.mappingFunction(cf);
 
         // check that all modules to be mapped to the boot loader will be
-        // loaded from the system module path
-        if (finder != systemModulePath) {
+        // loaded from the runtime image
+        if (needPostResolutionChecks) {
             for (ResolvedModule resolvedModule : cf.modules()) {
                 ModuleReference mref = resolvedModule.reference();
                 String name = mref.descriptor().name();
@@ -237,20 +285,22 @@
                             && upgradeModulePath.find(name).isPresent())
                         fail(name + ": cannot be loaded from upgrade module path");
 
-                    if (!systemModulePath.find(name).isPresent())
+                    if (!systemModules.find(name).isPresent())
                         fail(name + ": cannot be loaded from application module path");
                 }
             }
         }
 
-        long t2 = System.nanoTime();
+
+        long t4 = System.nanoTime();
 
         // define modules to VM/runtime
         Layer bootLayer = Layer.empty().defineModules(cf, clf);
 
-        PerfCounters.layerCreateTime.addElapsedTimeFrom(t2);
+        PerfCounters.layerCreateTime.addElapsedTimeFrom(t4);
 
-        long t3 = System.nanoTime();
+
+        long t5 = System.nanoTime();
 
         // define the module to its class loader, except java.base
         for (ResolvedModule resolvedModule : cf.modules()) {
@@ -264,7 +314,8 @@
             }
         }
 
-        PerfCounters.loadModulesTime.addElapsedTimeFrom(t3);
+        PerfCounters.loadModulesTime.addElapsedTimeFrom(t5);
+
 
         // -XaddReads and -XaddExports
         addExtraReads(bootLayer);
@@ -295,25 +346,21 @@
 
         // module name -> reference
         Map<String, ModuleReference> map = new HashMap<>();
+
+        // root modules and their transitive dependences
         cf.modules().stream()
             .map(ResolvedModule::reference)
             .forEach(mref -> map.put(mref.descriptor().name(), mref));
 
+        // additional modules
+        otherMods.stream()
+            .map(finder::find)
+            .flatMap(Optional::stream)
+            .forEach(mref -> map.putIfAbsent(mref.descriptor().name(), mref));
+
         // set of modules that are observable
         Set<ModuleReference> mrefs = new HashSet<>(map.values());
 
-        // add the other modules
-        for (String mod : otherMods) {
-            Optional<ModuleReference> omref = finder.find(mod);
-            if (omref.isPresent()) {
-                ModuleReference mref = omref.get();
-                map.putIfAbsent(mod, mref);
-                mrefs.add(mref);
-            } else {
-                // no need to fail
-            }
-        }
-
         return new ModuleFinder() {
             @Override
             public Optional<ModuleReference> find(String name) {
@@ -369,15 +416,15 @@
 
                 Module other;
                 if (ALL_UNNAMED.equals(name)) {
-                    other = null;  // loose
+                    Modules.addReadsAllUnnamed(m);
                 } else {
                     om = bootLayer.findModule(name);
                     if (!om.isPresent())
                         fail("Unknown module: " + name);
                     other = om.get();
+                    Modules.addReads(m, other);
                 }
 
-                Modules.addReads(m, other);
             }
         }
     }
@@ -439,10 +486,6 @@
      * Decodes the values of -XaddReads or -XaddExports options
      *
      * The format of the options is: $KEY=$MODULE(,$MODULE)*
-     *
-     * For transition purposes, this method allows the first usage to be
-     *     $KEY=$MODULE(,$KEY=$MODULE)
-     * This format will eventually be removed.
      */
     private static Map<String, Set<String>> decode(String prefix) {
         int index = 0;
@@ -467,42 +510,15 @@
             if (rhs.isEmpty())
                 fail("Unable to parse: " + value);
 
-            // new format $MODULE(,$MODULE)* or old format $(MODULE)=...
-            pos = rhs.indexOf('=');
 
-            // old format only allowed in first -X option
-            if (pos >= 0 && index > 0)
-                fail("Unable to parse: " + value);
-
-            if (pos == -1) {
-
-                // new format: $KEY=$MODULE(,$MODULE)*
-
-                Set<String> values = map.get(key);
-                if (values != null)
-                    fail(key + " specified more than once");
+            // value is <module>(,<module>)*
+            if (map.containsKey(key))
+                fail(key + " specified more than once");
 
-                values = new HashSet<>();
-                map.put(key, values);
-                for (String s : rhs.split(",")) {
-                    if (s.length() > 0) values.add(s);
-                }
-
-            } else {
-
-                // old format: $KEY=$MODULE(,$KEY=$MODULE)*
-
-                assert index == 0;  // old format only allowed in first usage
-
-                for (String expr : value.split(",")) {
-                    if (expr.length() > 0) {
-                        String[] s = expr.split("=");
-                        if (s.length != 2)
-                            fail("Unable to parse: " + expr);
-
-                        map.computeIfAbsent(s[0], k -> new HashSet<>()).add(s[1]);
-                    }
-                }
+            Set<String> values = new HashSet<>();
+            map.put(key, values);
+            for (String s : rhs.split(",")) {
+                if (s.length() > 0) values.add(s);
             }
 
             index++;
@@ -521,6 +537,13 @@
     }
 
     static class PerfCounters {
+
+        static PerfCounter systemModulesTime
+            = PerfCounter.newPerfCounter("jdk.module.bootstrap.systemModulesTime");
+        static PerfCounter defineBaseTime
+            = PerfCounter.newPerfCounter("jdk.module.bootstrap.defineBaseTime");
+        static PerfCounter optionsAndRootsTime
+            = PerfCounter.newPerfCounter("jdk.module.bootstrap.optionsAndRootsTime");
         static PerfCounter resolveTime
             = PerfCounter.newPerfCounter("jdk.module.bootstrap.resolveTime");
         static PerfCounter layerCreateTime
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleHashes.java	Tue May 03 12:25:20 2016 -0700
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.internal.module;
+
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+import java.nio.file.Path;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Base64;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * The result of hashing the contents of a number of module artifacts.
+ */
+
+public final class ModuleHashes {
+
+    /**
+     * A supplier of an encoded message digest.
+     */
+    public static interface HashSupplier {
+        String generate(String algorithm);
+    }
+
+
+    private final String algorithm;
+    private final Map<String, String> nameToHash;
+
+    /**
+     * Creates a {@code ModuleHashes}.
+     *
+     * @param algorithm   the algorithm used to create the hashes
+     * @param nameToHash  the map of module name to hash value (in string form)
+     */
+    public ModuleHashes(String algorithm, Map<String, String> nameToHash) {
+        this.algorithm = algorithm;
+        this.nameToHash = Collections.unmodifiableMap(nameToHash);
+    }
+
+    /**
+     * Returns the algorithm used to hash the modules ("SHA-256" for example).
+     */
+    public String algorithm() {
+        return algorithm;
+    }
+
+    /**
+     * Returns the set of module names for which hashes are recorded.
+     */
+    public Set<String> names() {
+        return nameToHash.keySet();
+    }
+
+    /**
+     * Returns the hash string for the given module name, {@code null}
+     * if there is no hash recorded for the module.
+     */
+    public String hashFor(String mn) {
+        return nameToHash.get(mn);
+    }
+
+    /**
+     * Returns unmodifiable map of module name to hash string.
+     */
+    public Map<String, String> hashes() {
+        return nameToHash;
+    }
+
+    /**
+     * Computes the hash for the given file with the given message digest
+     * algorithm. Returns the results a base64-encoded String.
+     *
+     * @throws UncheckedIOException if an I/O error occurs
+     * @throws RuntimeException if the algorithm is not available
+     */
+    public static String computeHashAsString(Path file, String algorithm) {
+        try {
+            MessageDigest md = MessageDigest.getInstance(algorithm);
+
+            // Ideally we would just mmap the file but this consumes too much
+            // memory when jlink is running concurrently on very large jmods
+            try (FileChannel fc = FileChannel.open(file)) {
+                ByteBuffer bb = ByteBuffer.allocate(32*1024);
+                while (fc.read(bb) > 0) {
+                    bb.flip();
+                    md.update(bb);
+                    assert bb.remaining() == 0;
+                    bb.clear();
+                }
+            }
+
+            byte[] bytes = md.digest();
+            return Base64.getEncoder().encodeToString(bytes);
+        } catch (NoSuchAlgorithmException e) {
+            throw new RuntimeException(e);
+        } catch (IOException ioe) {
+            throw new UncheckedIOException(ioe);
+        }
+    }
+
+    /**
+     * Computes the hash for every entry in the given map, returning a
+     * {@code ModuleHashes} to encapsulate the result. The map key is
+     * the entry name, typically the module name. The map value is the file
+     * path to the entry (module artifact).
+     *
+     * @return ModuleHashes encapsulate the hashes
+     */
+    public static ModuleHashes generate(Map<String, Path> map, String algorithm) {
+        Map<String, String> nameToHash = new HashMap<>();
+        for (Map.Entry<String, Path> entry: map.entrySet()) {
+            String name = entry.getKey();
+            Path path = entry.getValue();
+            nameToHash.put(name, computeHashAsString(path, algorithm));
+        }
+        return new ModuleHashes(algorithm, nameToHash);
+    }
+}
--- a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfoExtender.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfoExtender.java	Tue May 03 12:25:20 2016 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -41,7 +41,6 @@
 import jdk.internal.org.objectweb.asm.ClassVisitor;
 import jdk.internal.org.objectweb.asm.ClassWriter;
 import jdk.internal.org.objectweb.asm.Opcodes;
-import jdk.internal.module.Hasher.DependencyHashes;
 
 import static jdk.internal.module.ClassFileAttributes.*;
 
@@ -69,7 +68,7 @@
     private String osVersion;
 
     // the hashes for the Hashes attribute
-    private DependencyHashes hashes;
+    private ModuleHashes hashes;
 
     private ModuleInfoExtender(InputStream in) {
         this.in = in;
@@ -113,10 +112,10 @@
 
     /**
      * The Hashes attribute will be emitted to the module-info with
-     * the hashes encapsulated in the given {@code DependencyHashes}
+     * the hashes encapsulated in the given {@code ModuleHashes}
      * object.
      */
-    public ModuleInfoExtender hashes(DependencyHashes hashes) {
+    public ModuleInfoExtender hashes(ModuleHashes hashes) {
         this.hashes = hashes;
         return this;
     }
--- a/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfoWriter.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModuleInfoWriter.java	Tue May 03 12:25:20 2016 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -49,28 +49,22 @@
      * Writes the given module descriptor to a module-info.class file,
      * returning it in a byte array.
      */
-    private static byte[] toModuleInfo(ModuleDescriptor descriptor) {
+    private static byte[] toModuleInfo(ModuleDescriptor md) {
 
         ClassWriter cw = new ClassWriter(0);
 
-        String name = descriptor.name().replace('.', '/') + "/module-info";
+        String name = md.name().replace('.', '/') + "/module-info";
         cw.visit(Opcodes.V1_8, ACC_MODULE, name, null, null, null);
 
-        cw.visitAttribute(new ModuleAttribute(descriptor));
-        cw.visitAttribute(new ConcealedPackagesAttribute(descriptor.conceals()));
-
-        Optional<Version> oversion = descriptor.version();
-        if (oversion.isPresent())
-            cw.visitAttribute(new VersionAttribute(oversion.get()));
-
-        Optional<String> omain = descriptor.mainClass();
-        if (omain.isPresent())
-            cw.visitAttribute(new MainClassAttribute(omain.get()));
+        cw.visitAttribute(new ModuleAttribute(md));
+        cw.visitAttribute(new ConcealedPackagesAttribute(md.conceals()));
+        md.version().ifPresent(v -> cw.visitAttribute(new VersionAttribute(v)));
+        md.mainClass().ifPresent(mc -> cw.visitAttribute(new MainClassAttribute(mc)));
 
         // write the TargetPlatform attribute if have any of OS name/arch/version
-        String osName = descriptor.osName().orElse(null);
-        String osArch = descriptor.osArch().orElse(null);
-        String osVersion = descriptor.osVersion().orElse(null);
+        String osName = md.osName().orElse(null);
+        String osArch = md.osArch().orElse(null);
+        String osVersion = md.osVersion().orElse(null);
         if (osName != null || osArch != null || osVersion != null) {
             cw.visitAttribute(new TargetPlatformAttribute(osName,
                                                           osArch,
--- a/jdk/src/java.base/share/classes/jdk/internal/module/ModulePatcher.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ModulePatcher.java	Tue May 03 12:25:20 2016 -0700
@@ -91,56 +91,29 @@
 
         Map<String, List<Path>> map = new HashMap<>();
         while (value != null) {
-            int pos = value.indexOf('=');
+
+            // <module>=<file>(:<file>)*
 
-            if (pos == -1 && index > 0)
+            int pos = value.indexOf('=');
+            if (pos == -1)
                 throwIAE("Unable to parse: " + value);
-
             if (pos == 0)
                 throwIAE("Missing module name: " + value);
 
-            if (pos > 0) {
-
-                // new format: <module>=<file>(:<file>)*
-
-                String mn = value.substring(0, pos);
-                List<Path> list = map.get(mn);
-                if (list != null)
-                    throwIAE("Module " + mn + " specified more than once");
-                list = new ArrayList<>();
-                map.put(mn, list);
-
-                String paths = value.substring(pos+1);
-                for (String path : paths.split(File.pathSeparator)) {
-                    if (!path.isEmpty()) {
-                        list.add(Paths.get(path));
-                    }
-                }
-
-            } else {
+            String mn = value.substring(0, pos);
+            List<Path> list = map.get(mn);
+            if (list != null)
+                throwIAE("Module " + mn + " specified more than once");
+            list = new ArrayList<>();
+            map.put(mn, list);
 
-                // old format: <dir>(:<dir>)*
-
-                assert index == 0; // old format only allowed in first -Xpatch
-
-                String[] dirs = value.split(File.pathSeparator);
-                for (String d : dirs) {
-                    if (d.length() > 0) {
-                        Path top = Paths.get(d);
-                        try {
-                            Files.list(top).forEach(e -> {
-                                String mn = e.getFileName().toString();
-                                Path dir = top.resolve(mn);
-                                map.computeIfAbsent(mn, k -> new ArrayList<>())
-                                    .add(dir);
-                            });
-                        } catch (IOException ignore) { }
-                    }
+            String paths = value.substring(pos+1);
+            for (String path : paths.split(File.pathSeparator)) {
+                if (!path.isEmpty()) {
+                    list.add(Paths.get(path));
                 }
-
             }
 
-
             index++;
             value = System.getProperty(PATCH_PROPERTY_PREFIX + index);
         }
@@ -175,7 +148,8 @@
             for (Path file : paths) {
                 if (Files.isRegularFile(file)) {
 
-                    // JAR file
+                    // JAR file - do not open as a multi-release JAR as this
+                    // is not supported by the boot class loader
                     try (JarFile jf = new JarFile(file.toFile())) {
                         jf.stream()
                           .filter(e -> e.getName().endsWith(".class"))
@@ -209,10 +183,11 @@
             descriptor = JLMA.newModuleDescriptor(descriptor, packages);
         }
 
-        // return a new module reference
+        // return a module reference to the patched module
         URI location = mref.location().orElse(null);
-        return new ModuleReference(descriptor, location,
-                                   () -> new PatchedModuleReader(paths, mref));
+        return JLMA.newPatchedModule(descriptor,
+                                     location,
+                                     () -> new PatchedModuleReader(paths, mref));
 
     }
 
--- a/jdk/src/java.base/share/classes/jdk/internal/module/Modules.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/Modules.java	Tue May 03 12:25:20 2016 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -58,7 +58,7 @@
      * Creates a new Module. The module has the given ModuleDescriptor and
      * is defined to the given class loader.
      *
-     * The resulting Module is in a larva state in that it does not not read
+     * The resulting Module is in a larval state in that it does not not read
      * any other module and does not have any exports.
      *
      * The URI is for information purposes only.
@@ -74,7 +74,7 @@
      * Define a new module to the VM. The module has the given set of
      * concealed packages and is defined to the given class loader.
      *
-     * The resulting Module is in a larva state in that it does not not read
+     * The resulting Module is in a larval state in that it does not not read
      * any other module and does not have any exports.
      */
     public static Module defineModule(ClassLoader loader,
@@ -96,6 +96,13 @@
     }
 
     /**
+     * Update module {@code m} to read all unnamed modules.
+     */
+    public static void addReadsAllUnnamed(Module m) {
+        JLRMA.addReadsAllUnnamed(m);
+    }
+
+    /**
      * Updates module m1 to export a package to module m2.
      * Same as m1.addExports(pkg, m2) but without a caller check.
      */
--- a/jdk/src/java.base/share/classes/jdk/internal/module/ServicesCatalog.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/ServicesCatalog.java	Tue May 03 12:25:20 2016 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -29,94 +29,105 @@
 import java.lang.module.ModuleDescriptor;
 import java.lang.module.ModuleDescriptor.Provides;
 import java.util.Collections;
-import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Set;
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReadWriteLock;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
+import java.util.concurrent.ConcurrentHashMap;
 
 /**
- * A services catalog. Each {@code ClassLoader} has an optional {@code
- * ServicesCatalog} for modules that provide services. This is to support
- * ClassLoader centric ServiceLoader.load methods.
+ * A <em>services catalog</em>. Each {@code ClassLoader} and {@code Layer} has
+ * an optional {@code ServicesCatalog} for modules that provide services.
+ *
+ * @see java.util.ServiceLoader
  */
-public class ServicesCatalog {
-
-    // use RW locks as register is rare
-    private final ReadWriteLock lock = new ReentrantReadWriteLock();
-    private final Lock readLock = lock.readLock();
-    private final Lock writeLock = lock.writeLock();
+public interface ServicesCatalog {
 
     /**
      * Represents a service provider in the services catalog.
      */
-    public class ServiceProvider {
+    public final class ServiceProvider {
         private final Module module;
         private final String providerName;
-        ServiceProvider(Module module, String providerName) {
+
+        public ServiceProvider(Module module, String providerName) {
             this.module = module;
             this.providerName = providerName;
         }
+
         public Module module() {
             return module;
         }
+
         public String providerName() {
             return providerName;
         }
-    }
 
-    // service providers
-    private final Map<String, Set<ServiceProvider>> loaderServices = new HashMap<>();
-
-    /**
-     * Creates a new module catalog.
-     */
-    public ServicesCatalog() { }
-
-    /**
-     * Registers the module in this module catalog.
-     */
-    public void register(Module m) {
-        ModuleDescriptor descriptor = m.getDescriptor();
+        @Override
+        public int hashCode() {
+            return Objects.hash(module, providerName);
+        }
 
-        writeLock.lock();
-        try {
-            // extend the services map
-            for (Provides ps : descriptor.provides().values()) {
-                String service = ps.service();
-                Set<String> providerNames = ps.providers();
-
-                // create a new set to replace the existing
-                Set<ServiceProvider> result = new HashSet<>();
-                Set<ServiceProvider> providers = loaderServices.get(service);
-                if (providers != null) {
-                    result.addAll(providers);
-                }
-                for (String pn : providerNames) {
-                    result.add(new ServiceProvider(m, pn));
-                }
-                loaderServices.put(service, Collections.unmodifiableSet(result));
-            }
-
-        } finally {
-            writeLock.unlock();
+        @Override
+        public boolean equals(Object ob) {
+            if (!(ob instanceof ServiceProvider))
+                return false;
+            ServiceProvider that = (ServiceProvider)ob;
+            return Objects.equals(this.module, that.module)
+                    && Objects.equals(this.providerName, that.providerName);
         }
     }
 
     /**
+     * Registers the providers in the given module in this services catalog.
+     *
+     * @throws UnsupportedOperationException
+     *         If this services catalog is immutable
+     */
+    void register(Module module);
+
+    /**
      * Returns the (possibly empty) set of service providers that implement the
      * given service type.
-     *
-     * @see java.util.ServiceLoader
+     */
+    Set<ServiceProvider> findServices(String service);
+
+    /**
+     * Creates a ServicesCatalog that supports concurrent registration and
+     * and lookup.
      */
-    public Set<ServiceProvider> findServices(String service) {
-        readLock.lock();
-        try {
-            return loaderServices.getOrDefault(service, Collections.emptySet());
-        } finally {
-            readLock.unlock();
-        }
+    static ServicesCatalog create() {
+        return new ServicesCatalog() {
+
+            private Map<String, Set<ServiceProvider>> map = new ConcurrentHashMap<>();
+
+            @Override
+            public void register(Module m) {
+                ModuleDescriptor descriptor = m.getDescriptor();
+
+                for (Provides provides : descriptor.provides().values()) {
+                    String service = provides.service();
+                    Set<String> providerNames = provides.providers();
+
+                    // create a new set to replace the existing
+                    Set<ServiceProvider> result = new HashSet<>();
+                    Set<ServiceProvider> providers = map.get(service);
+                    if (providers != null) {
+                        result.addAll(providers);
+                    }
+                    for (String pn : providerNames) {
+                        result.add(new ServiceProvider(m, pn));
+                    }
+                    map.put(service, Collections.unmodifiableSet(result));
+                }
+
+            }
+
+            @Override
+            public Set<ServiceProvider> findServices(String service) {
+                return map.getOrDefault(service, Collections.emptySet());
+            }
+
+        };
     }
-}
+}
\ No newline at end of file
--- a/jdk/src/java.base/share/classes/jdk/internal/module/SystemModules.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/jdk/internal/module/SystemModules.java	Tue May 03 12:25:20 2016 -0700
@@ -40,21 +40,26 @@
  */
 public final class SystemModules {
     /**
-     * Name of the installed modules.
+     * Name of the system modules.
      *
-     * This array provides a way for InstalledModuleFinder to fallback
+     * This array provides a way for SystemModuleFinder to fallback
      * and read module-info.class from the run-time image instead of
      * the fastpath.
      */
     public static final String[] MODULE_NAMES = new String[1];
 
     /**
+     * Hash of system modules.
+     */
+    public static String[] MODULES_TO_HASH = new String[1];
+
+    /**
      * Number of packages in the boot layer from the installed modules.
      *
      * Don't make it final to avoid inlining during compile time as
      * the value will be changed at jlink time.
      */
-    public static final int PACKAGES_IN_BOOT_LAYER = 1024;
+    public static int PACKAGES_IN_BOOT_LAYER = 1024;
 
     /**
      * Returns a non-empty array of ModuleDescriptors in the run-time image.
@@ -64,4 +69,5 @@
     public static ModuleDescriptor[] modules() {
         return new ModuleDescriptor[0];
     }
-}
\ No newline at end of file
+
+}
--- a/jdk/src/java.base/share/classes/jdk/internal/reflect/MethodAccessorGenerator.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/jdk/internal/reflect/MethodAccessorGenerator.java	Tue May 03 12:25:20 2016 -0700
@@ -392,6 +392,7 @@
         // matter.
         return AccessController.doPrivileged(
             new PrivilegedAction<MagicAccessorImpl>() {
+                @SuppressWarnings("deprecation") // Class.newInstance
                 public MagicAccessorImpl run() {
                         try {
                         return (MagicAccessorImpl)
--- a/jdk/src/java.base/share/classes/jdk/internal/reflect/Reflection.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/jdk/internal/reflect/Reflection.java	Tue May 03 12:25:20 2016 -0700
@@ -343,8 +343,8 @@
 
     private static void printStackTraceIfNeeded(Throwable e) {
         if (!printStackWhenAccessFailsSet && VM.initLevel() >= 1) {
-            String s = GetPropertyAction
-                    .getProperty("sun.reflect.debugModuleAccessChecks");
+            String s = GetPropertyAction.privilegedGetProperty(
+                    "sun.reflect.debugModuleAccessChecks");
             printStackWhenAccessFails =
                     (s != null && !s.equalsIgnoreCase("false"));
             printStackWhenAccessFailsSet = true;
--- a/jdk/src/java.base/share/classes/jdk/internal/reflect/ReflectionFactory.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/jdk/internal/reflect/ReflectionFactory.java	Tue May 03 12:25:20 2016 -0700
@@ -398,7 +398,7 @@
             return;
         }
 
-        Properties props = GetPropertyAction.getProperties();
+        Properties props = GetPropertyAction.privilegedGetProperties();
         String val = props.getProperty("sun.reflect.noInflation");
         if (val != null && val.equals("true")) {
             noInflation = true;
--- a/jdk/src/java.base/share/classes/module-info.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/module-info.java	Tue May 03 12:25:20 2016 -0700
@@ -166,6 +166,8 @@
         java.sql,
         java.xml,
         jdk.charsets,
+        jdk.jartool,
+        jdk.jlink,
         jdk.net,
         jdk.scripting.nashorn,
         jdk.unsupported,
--- a/jdk/src/java.base/share/classes/sun/launcher/resources/launcher.properties	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/sun/launcher/resources/launcher.properties	Tue May 03 12:25:20 2016 -0700
@@ -27,7 +27,7 @@
 java.launcher.opt.header  =   Usage: {0} [options] class [args...]\n\
 \           (to execute a class)\n   or  {0} [options] -jar jarfile [args...]\n\
 \           (to execute a jar file)\n\
-\   or  {0} [-options] -mp <modulepath> -m <modulename> | <modulename>/<mainclass>\n\
+\   or  {0} [options] -mp <modulepath> -m <modulename>[/<mainclass>] [args...]\n\
 \           (to execute the main class in a module)\n\
 where options include:\n
 
@@ -51,8 +51,9 @@
 \                  A {0} separated list of directories, each directory\n\
 \                  is a directory of modules that replace upgradeable\n\
 \                  modules in the runtime image\n\
-\    -m <modulename> | <modulename>/<mainclass>\n\
-\                  the initial or main module to resolve\n\
+\    -m <modulename>[/<mainclass>]\n\
+\                  the initial module to resolve, and the name of the main class\n\
+\                  to execute if not specified by the module\n\
 \    -addmods <modulename>[,<modulename>...]\n\
 \                  root modules to resolve in addition to the initial module\n\
 \    -limitmods <modulename>[,<modulename>...]\n\
--- a/jdk/src/java.base/share/classes/sun/net/ResourceManager.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/sun/net/ResourceManager.java	Tue May 03 12:25:20 2016 -0700
@@ -53,8 +53,8 @@
     private static final AtomicInteger numSockets;
 
     static {
-        String prop =
-                GetPropertyAction.getProperty("sun.net.maxDatagramSockets");
+        String prop = GetPropertyAction
+                .privilegedGetProperty("sun.net.maxDatagramSockets");
         int defmax = DEFAULT_MAX_SOCKETS;
         try {
             if (prop != null) {
--- a/jdk/src/java.base/share/classes/sun/net/ftp/FtpClientProvider.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/sun/net/ftp/FtpClientProvider.java	Tue May 03 12:25:20 2016 -0700
@@ -67,8 +67,9 @@
             return false;
         }
         try {
-            Class<?> c = Class.forName(cm, true, null);
-            provider = (FtpClientProvider) c.newInstance();
+            @SuppressWarnings("deprecation")
+            Object o = Class.forName(cm, true, null).newInstance();
+            provider = (FtpClientProvider)o;
             return true;
         } catch (ClassNotFoundException |
                  IllegalAccessException |
--- a/jdk/src/java.base/share/classes/sun/net/sdp/SdpSupport.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/sun/net/sdp/SdpSupport.java	Tue May 03 12:25:20 2016 -0700
@@ -40,7 +40,7 @@
  */
 
 public final class SdpSupport {
-    private static final String os = GetPropertyAction.getProperty("os.name");
+    private static final String os = GetPropertyAction.privilegedGetProperty("os.name");
     private static final boolean isSupported = (os.equals("SunOS") || (os.equals("Linux")));
     private static final JavaIOFileDescriptorAccess fdAccess =
         SharedSecrets.getJavaIOFileDescriptorAccess();
--- a/jdk/src/java.base/share/classes/sun/net/smtp/SmtpClient.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/sun/net/smtp/SmtpClient.java	Tue May 03 12:25:20 2016 -0700
@@ -157,7 +157,7 @@
         }
         try {
             String s;
-            mailhost = GetPropertyAction.getProperty("mail.host");
+            mailhost = GetPropertyAction.privilegedGetProperty("mail.host");
             if (mailhost != null) {
                 openServer(mailhost);
                 return;
@@ -183,7 +183,7 @@
         setConnectTimeout(to);
         try {
             String s;
-            mailhost = GetPropertyAction.getProperty("mail.host");
+            mailhost = GetPropertyAction.privilegedGetProperty("mail.host");
             if (mailhost != null) {
                 openServer(mailhost);
                 return;
--- a/jdk/src/java.base/share/classes/sun/net/www/MimeLauncher.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/sun/net/www/MimeLauncher.java	Tue May 03 12:25:20 2016 -0700
@@ -183,7 +183,7 @@
         }
 
         String execPathList;
-        execPathList = GetPropertyAction.getProperty("exec.path");
+        execPathList = GetPropertyAction.privilegedGetProperty("exec.path");
         if (execPathList == null) {
             // exec.path property not set
             return false;
--- a/jdk/src/java.base/share/classes/sun/net/www/http/HttpClient.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/sun/net/www/http/HttpClient.java	Tue May 03 12:25:20 2016 -0700
@@ -145,7 +145,7 @@
     }
 
     static {
-        Properties props = GetPropertyAction.getProperties();
+        Properties props = GetPropertyAction.privilegedGetProperties();
         String keepAlive = props.getProperty("http.keepAlive");
         String retryPost = props.getProperty("sun.net.http.retryPost");
 
--- a/jdk/src/java.base/share/classes/sun/net/www/protocol/ftp/FtpURLConnection.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/sun/net/www/protocol/ftp/FtpURLConnection.java	Tue May 03 12:25:20 2016 -0700
@@ -278,7 +278,7 @@
 
         if (user == null) {
             user = "anonymous";
-            Properties props = GetPropertyAction.getProperties();
+            Properties props = GetPropertyAction.privilegedGetProperties();
             String vers = props.getProperty("java.version");
             password = props.getProperty("ftp.protocol.user",
                     "Java" + vers + "@");
--- a/jdk/src/java.base/share/classes/sun/net/www/protocol/http/AuthenticationHeader.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/sun/net/www/protocol/http/AuthenticationHeader.java	Tue May 03 12:25:20 2016 -0700
@@ -94,7 +94,7 @@
     }
 
     static {
-        authPref = GetPropertyAction.getProperty("http.auth.preference");
+        authPref = GetPropertyAction.privilegedGetProperty("http.auth.preference");
 
         // http.auth.preference can be set to SPNEGO or Kerberos.
         // In fact they means "Negotiate with SPNEGO" and "Negotiate with
--- a/jdk/src/java.base/share/classes/sun/net/www/protocol/http/HttpURLConnection.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/sun/net/www/protocol/http/HttpURLConnection.java	Tue May 03 12:25:20 2016 -0700
@@ -207,9 +207,9 @@
     };
 
     static {
-        Properties props = GetPropertyAction.getProperties();
-        maxRedirects = GetIntegerAction.getProperty("http.maxRedirects",
-                        defaultmaxRedirects);
+        Properties props = GetPropertyAction.privilegedGetProperties();
+        maxRedirects = GetIntegerAction.privilegedGetProperty(
+                "http.maxRedirects", defaultmaxRedirects);
         version = props.getProperty("java.version");
         String agent = props.getProperty("http.agent");
         if (agent == null) {
@@ -225,14 +225,14 @@
 
         enableESBuffer = Boolean.parseBoolean(
                 props.getProperty("sun.net.http.errorstream.enableBuffering"));
-        timeout4ESBuffer = GetIntegerAction
-                .getProperty("sun.net.http.errorstream.timeout", 300);
+        timeout4ESBuffer = GetIntegerAction.privilegedGetProperty(
+                "sun.net.http.errorstream.timeout", 300);
         if (timeout4ESBuffer <= 0) {
             timeout4ESBuffer = 300; // use the default
         }
 
-        bufSize4ES = GetIntegerAction
-                .getProperty("sun.net.http.errorstream.bufferSize", 4096);
+        bufSize4ES = GetIntegerAction.privilegedGetProperty(
+                "sun.net.http.errorstream.bufferSize", 4096);
         if (bufSize4ES <= 0) {
             bufSize4ES = 4096; // use the default
         }
--- a/jdk/src/java.base/share/classes/sun/net/www/protocol/https/HttpsClient.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/sun/net/www/protocol/https/HttpsClient.java	Tue May 03 12:25:20 2016 -0700
@@ -139,7 +139,7 @@
         //
         String ciphers [];
         String cipherString =
-                GetPropertyAction.getProperty("https.cipherSuites");
+                GetPropertyAction.privilegedGetProperty("https.cipherSuites");
 
         if (cipherString == null || "".equals(cipherString)) {
             ciphers = null;
@@ -163,7 +163,7 @@
         //
         String protocols [];
         String protocolString =
-                GetPropertyAction.getProperty("https.protocols");
+                GetPropertyAction.privilegedGetProperty("https.protocols");
 
         if (protocolString == null || "".equals(protocolString)) {
             protocols = null;
@@ -183,7 +183,8 @@
     }
 
     private String getUserAgent() {
-        String userAgent = GetPropertyAction.getProperty("https.agent");
+        String userAgent =
+                GetPropertyAction.privilegedGetProperty("https.agent");
         if (userAgent == null || userAgent.length() == 0) {
             userAgent = "JSSE";
         }
--- a/jdk/src/java.base/share/classes/sun/net/www/protocol/jrt/JavaRuntimeURLConnection.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/sun/net/www/protocol/jrt/JavaRuntimeURLConnection.java	Tue May 03 12:25:20 2016 -0700
@@ -161,7 +161,7 @@
     public Permission getPermission() throws IOException {
         Permission p = permission;
         if (p == null) {
-            String home = GetPropertyAction.getProperty("java.home");
+            String home = GetPropertyAction.privilegedGetProperty("java.home");
             p = new FilePermission(home + File.separator + "-", "read");
             permission = p;
         }
--- a/jdk/src/java.base/share/classes/sun/net/www/protocol/netdoc/Handler.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/sun/net/www/protocol/netdoc/Handler.java	Tue May 03 12:25:20 2016 -0700
@@ -56,9 +56,9 @@
         URL ru;
 
         boolean localonly = Boolean.parseBoolean(
-                GetPropertyAction.getProperty("newdoc.localonly"));
+                GetPropertyAction.privilegedGetProperty("newdoc.localonly"));
 
-        String docurl = GetPropertyAction.getProperty("doc.url");
+        String docurl = GetPropertyAction.privilegedGetProperty("doc.url");
 
         String file = u.getFile();
         if (!localonly) {
--- a/jdk/src/java.base/share/classes/sun/nio/ch/FileChannelImpl.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/sun/nio/ch/FileChannelImpl.java	Tue May 03 12:25:20 2016 -0700
@@ -1019,7 +1019,7 @@
         if (!propertyChecked) {
             synchronized (FileChannelImpl.class) {
                 if (!propertyChecked) {
-                    String value = GetPropertyAction.getProperty(
+                    String value = GetPropertyAction.privilegedGetProperty(
                             "sun.nio.ch.disableSystemWideOverlappingFileLockCheck");
                     isSharedFileLockTable = ((value == null) || value.equals("false"));
                     propertyChecked = true;
--- a/jdk/src/java.base/share/classes/sun/nio/ch/Net.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/sun/nio/ch/Net.java	Tue May 03 12:25:20 2016 -0700
@@ -374,8 +374,8 @@
     }
 
     public static boolean isFastTcpLoopbackRequested() {
-        String loopbackProp =
-                GetPropertyAction.getProperty("jdk.net.useFastTcpLoopback");
+        String loopbackProp = GetPropertyAction
+                .privilegedGetProperty("jdk.net.useFastTcpLoopback");
         boolean enable;
         if ("".equals(loopbackProp)) {
             enable = true;
@@ -633,8 +633,8 @@
     static {
         int availLevel = isExclusiveBindAvailable();
         if (availLevel >= 0) {
-            String exclBindProp =
-                    GetPropertyAction.getProperty("sun.net.useExclusiveBind");
+            String exclBindProp = GetPropertyAction
+                    .privilegedGetProperty("sun.net.useExclusiveBind");
             if (exclBindProp != null) {
                 exclusiveBind = exclBindProp.isEmpty() ?
                         true : Boolean.parseBoolean(exclBindProp);
--- a/jdk/src/java.base/share/classes/sun/nio/ch/ThreadPool.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/sun/nio/ch/ThreadPool.java	Tue May 03 12:25:20 2016 -0700
@@ -165,14 +165,11 @@
             GetPropertyAction(DEFAULT_THREAD_POOL_THREAD_FACTORY));
         if (propValue != null) {
             try {
-                Class<?> c = Class
-                    .forName(propValue, true, ClassLoader.getSystemClassLoader());
-                return ((ThreadFactory)c.newInstance());
-            } catch (ClassNotFoundException x) {
-                throw new Error(x);
-            } catch (InstantiationException x) {
-                throw new Error(x);
-            } catch (IllegalAccessException x) {
+                @SuppressWarnings("deprecation")
+                Object tmp = Class
+                    .forName(propValue, true, ClassLoader.getSystemClassLoader()).newInstance();
+                return (ThreadFactory)tmp;
+            } catch (ClassNotFoundException | InstantiationException | IllegalAccessException x) {
                 throw new Error(x);
             }
         }
--- a/jdk/src/java.base/share/classes/sun/nio/ch/Util.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/sun/nio/ch/Util.java	Tue May 03 12:25:20 2016 -0700
@@ -64,7 +64,8 @@
      * for potential future-proofing.
      */
     private static long getMaxCachedBufferSize() {
-        String s = GetPropertyAction.getProperty("jdk.nio.maxCachedBufferSize");
+        String s = GetPropertyAction
+                .privilegedGetProperty("jdk.nio.maxCachedBufferSize");
         if (s != null) {
             try {
                 long m = Long.parseLong(s);
@@ -465,7 +466,8 @@
         if (bugLevel == null) {
             if (!jdk.internal.misc.VM.isBooted())
                 return false;
-            String value = GetPropertyAction.getProperty("sun.nio.ch.bugLevel");
+            String value = GetPropertyAction
+                    .privilegedGetProperty("sun.nio.ch.bugLevel");
             bugLevel = (value != null) ? value : "";
         }
         return bugLevel.equals(bl);
--- a/jdk/src/java.base/share/classes/sun/nio/cs/FastCharsetProvider.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/sun/nio/cs/FastCharsetProvider.java	Tue May 03 12:25:20 2016 -0700
@@ -115,10 +115,11 @@
 
         // Instantiate the charset and cache it
         try {
-            Class<?> c = Class.forName(packagePrefix + "." + cln,
+            @SuppressWarnings("deprecation")
+            Object o= Class.forName(packagePrefix + "." + cln,
                                     true,
-                                    this.getClass().getClassLoader());
-            cs = (Charset)c.newInstance();
+                                    this.getClass().getClassLoader()).newInstance();
+            cs = (Charset)o;
             cache.put(csn, cs);
             return cs;
         } catch (ClassNotFoundException |
--- a/jdk/src/java.base/share/classes/sun/nio/cs/StandardCharsets.java.template	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/sun/nio/cs/StandardCharsets.java.template	Tue May 03 12:25:20 2016 -0700
@@ -110,10 +110,11 @@
 
         // Instantiate the charset and cache it
         try {
-            Class<?> c = Class.forName(packagePrefix + "." + cln,
-                                    true,
-                                    this.getClass().getClassLoader());
-            cs = (Charset)c.newInstance();
+            @SuppressWarnings("deprecation")
+            Object o = Class.forName(packagePrefix + "." + cln,
+                                     true,
+                                     this.getClass().getClassLoader()).newInstance();
+            cs = (Charset)o;
             cache.put(csn, cs);
             return cs;
         } catch (ClassNotFoundException |
@@ -164,7 +165,7 @@
             return;
         initialized = true;
 
-        String map = getProperty("sun.nio.cs.map");
+        String map = GetPropertyAction.privilegedGetProperty("sun.nio.cs.map");
         if (map != null) {
             String[] maps = map.split(",");
             for (int i = 0; i < maps.length; i++) {
@@ -199,9 +200,4 @@
         }
     }
 
-    private static String getProperty(String key) {
-        return GetPropertyAction.getProperty(key);
-    }
-
-
 }
--- a/jdk/src/java.base/share/classes/sun/nio/fs/Util.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/sun/nio/fs/Util.java	Tue May 03 12:25:20 2016 -0700
@@ -38,7 +38,7 @@
     private Util() { }
 
     private static final Charset jnuEncoding = Charset.forName(
-        GetPropertyAction.getProperty("sun.jnu.encoding"));
+        GetPropertyAction.privilegedGetProperty("sun.jnu.encoding"));
 
     /**
      * Returns {@code Charset} corresponding to the sun.jnu.encoding property
--- a/jdk/src/java.base/share/classes/sun/security/action/GetIntegerAction.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/action/GetIntegerAction.java	Tue May 03 12:25:20 2016 -0700
@@ -118,9 +118,14 @@
      * if no security manager is present. This is unsafe for inclusion in a
      * public API but allowable here since this class is now encapsulated.
      *
+     * Note that this method performs a privileged action using caller-provided
+     * inputs. The caller of this method should take care to ensure that the
+     * inputs are not tainted and the returned property is not made accessible
+     * to untrusted code if it contains sensitive information.
+     *
      * @param theProp the name of the system property.
      */
-    public static Integer getProperty(String theProp) {
+    public static Integer privilegedGetProperty(String theProp) {
         if (System.getSecurityManager() == null) {
             return Integer.getInteger(theProp);
         } else {
@@ -134,10 +139,16 @@
      * if no security manager is present. This is unsafe for inclusion in a
      * public API but allowable here since this class is now encapsulated.
      *
+     * Note that this method performs a privileged action using caller-provided
+     * inputs. The caller of this method should take care to ensure that the
+     * inputs are not tainted and the returned property is not made accessible
+     * to untrusted code if it contains sensitive information.
+     *
      * @param theProp the name of the system property.
      * @param defaultVal the default value.
      */
-    public static Integer getProperty(String theProp, int defaultVal) {
+    public static Integer privilegedGetProperty(String theProp,
+            int defaultVal) {
         Integer value;
         if (System.getSecurityManager() == null) {
             value = Integer.getInteger(theProp);
--- a/jdk/src/java.base/share/classes/sun/security/action/GetPropertyAction.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/action/GetPropertyAction.java	Tue May 03 12:25:20 2016 -0700
@@ -93,9 +93,14 @@
      * if no security manager is present. This is unsafe for inclusion in a
      * public API but allowable here since this class is now encapsulated.
      *
+     * Note that this method performs a privileged action using caller-provided
+     * inputs. The caller of this method should take care to ensure that the
+     * inputs are not tainted and the returned property is not made accessible
+     * to untrusted code if it contains sensitive information.
+     *
      * @param theProp the name of the system property.
      */
-    public static String getProperty(String theProp) {
+    public static String privilegedGetProperty(String theProp) {
         if (System.getSecurityManager() == null) {
             return System.getProperty(theProp);
         } else {
@@ -109,10 +114,16 @@
      * if no security manager is present. This is unsafe for inclusion in a
      * public API but allowable here since this class is now encapsulated.
      *
+     * Note that this method performs a privileged action using caller-provided
+     * inputs. The caller of this method should take care to ensure that the
+     * inputs are not tainted and the returned property is not made accessible
+     * to untrusted code if it contains sensitive information.
+     *
      * @param theProp the name of the system property.
      * @param defaultVal the default value.
      */
-    public static String getProperty(String theProp, String defaultVal) {
+    public static String privilegedGetProperty(String theProp,
+            String defaultVal) {
         if (System.getSecurityManager() == null) {
             return System.getProperty(theProp, defaultVal);
         } else {
@@ -126,8 +137,13 @@
      * having to go through doPrivileged if no security manager is present.
      * This is unsafe for inclusion in a public API but allowable here since
      * this class is now encapsulated.
+     *
+     * Note that this method performs a privileged action, and callers of
+     * this method should take care to ensure that the returned properties
+     * are not made accessible to untrusted code since it may contain
+     * sensitive information.
      */
-    public static Properties getProperties() {
+    public static Properties privilegedGetProperties() {
         if (System.getSecurityManager() == null) {
             return System.getProperties();
         } else {
--- a/jdk/src/java.base/share/classes/sun/security/jca/ProviderConfig.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/jca/ProviderConfig.java	Tue May 03 12:25:20 2016 -0700
@@ -185,7 +185,9 @@
                     try {
                         Class<?> c = Class.forName("apple.security.AppleProvider");
                         if (Provider.class.isAssignableFrom(c)) {
-                            return (Provider) c.newInstance();
+                            @SuppressWarnings("deprecation")
+                            Object tmp = c.newInstance();
+                            return (Provider) tmp;
                         } else {
                             return null;
                         }
@@ -386,6 +388,7 @@
 
                 Provider p = AccessController.doPrivileged
                     (new PrivilegedExceptionAction<Provider>() {
+                    @SuppressWarnings("deprecation") // Class.newInstance
                     public Provider run() throws Exception {
                         return (Provider) provClass.newInstance();
                     }
--- a/jdk/src/java.base/share/classes/sun/security/pkcs/PKCS8Key.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/pkcs/PKCS8Key.java	Tue May 03 12:25:20 2016 -0700
@@ -218,11 +218,10 @@
                 }
             }
 
-            Object      inst = null;
+            @SuppressWarnings("deprecation")
+            Object      inst = (keyClass != null) ? keyClass.newInstance() : null;
             PKCS8Key    result;
 
-            if (keyClass != null)
-                inst = keyClass.newInstance();
             if (inst instanceof PKCS8Key) {
                 result = (PKCS8Key) inst;
                 result.algid = algid;
--- a/jdk/src/java.base/share/classes/sun/security/provider/DSAKeyFactory.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/provider/DSAKeyFactory.java	Tue May 03 12:25:20 2016 -0700
@@ -70,7 +70,7 @@
          * By default this is false.
          * This incompatibility was introduced by 4532506.
          */
-        String prop = GetPropertyAction.getProperty(SERIAL_PROP);
+        String prop = GetPropertyAction.privilegedGetProperty(SERIAL_PROP);
         SERIAL_INTEROP = "true".equalsIgnoreCase(prop);
     }
 
--- a/jdk/src/java.base/share/classes/sun/security/provider/certpath/AlgorithmChecker.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/provider/certpath/AlgorithmChecker.java	Tue May 03 12:25:20 2016 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -31,12 +31,10 @@
 import java.util.Collections;
 import java.util.Set;
 import java.util.EnumSet;
-import java.util.HashSet;
 import java.math.BigInteger;
 import java.security.PublicKey;
 import java.security.KeyFactory;
 import java.security.AlgorithmParameters;
-import java.security.NoSuchAlgorithmException;
 import java.security.GeneralSecurityException;
 import java.security.cert.Certificate;
 import java.security.cert.X509CRL;
@@ -48,10 +46,13 @@
 import java.security.cert.CertPathValidatorException;
 import java.security.cert.CertPathValidatorException.BasicReason;
 import java.security.cert.PKIXReason;
-import java.io.IOException;
-import java.security.interfaces.*;
-import java.security.spec.*;
+import java.security.interfaces.DSAParams;
+import java.security.interfaces.DSAPublicKey;
+import java.security.spec.DSAPublicKeySpec;
 
+import sun.security.util.AnchorCertificates;
+import sun.security.util.CertConstraintParameters;
+import sun.security.util.Debug;
 import sun.security.util.DisabledAlgorithmConstraints;
 import sun.security.x509.X509CertImpl;
 import sun.security.x509.X509CRLImpl;
@@ -69,6 +70,7 @@
  * @see PKIXParameters
  */
 public final class AlgorithmChecker extends PKIXCertPathChecker {
+    private static final Debug debug = Debug.getInstance("certpath");
 
     private final AlgorithmConstraints constraints;
     private final PublicKey trustedPubKey;
@@ -88,6 +90,14 @@
         certPathDefaultConstraints = new DisabledAlgorithmConstraints(
             DisabledAlgorithmConstraints.PROPERTY_CERTPATH_DISABLED_ALGS);
 
+    // If there is no "cacerts" keyword, then disable anchor checking
+    private static final boolean publicCALimits =
+            certPathDefaultConstraints.checkProperty("jdkCA");
+
+    // If anchor checking enabled, this will be true if the trust anchor
+    // has a match in the cacerts file
+    private boolean trustedMatch = false;
+
     /**
      * Create a new <code>AlgorithmChecker</code> with the algorithm
      * constraints specified in security property
@@ -136,6 +146,11 @@
 
         if (anchor.getTrustedCert() != null) {
             this.trustedPubKey = anchor.getTrustedCert().getPublicKey();
+            // Check for anchor certificate restrictions
+            trustedMatch = checkFingerprint(anchor.getTrustedCert());
+            if (trustedMatch && debug != null) {
+                debug.println("trustedMatch = true");
+            }
         } else {
             this.trustedPubKey = anchor.getCAPublicKey();
         }
@@ -144,6 +159,19 @@
         this.constraints = constraints;
     }
 
+    // Check this 'cert' for restrictions in the AnchorCertificates
+    // trusted certificates list
+    private static boolean checkFingerprint(X509Certificate cert) {
+        if (!publicCALimits) {
+            return false;
+        }
+
+        if (debug != null) {
+            debug.println("AlgorithmChecker.contains: " + cert.getSigAlgName());
+        }
+        return AnchorCertificates.contains(cert);
+    }
+
     @Override
     public void init(boolean forward) throws CertPathValidatorException {
         //  Note that this class does not support forward mode.
@@ -181,36 +209,8 @@
             return;
         }
 
-        X509CertImpl x509Cert = null;
-        try {
-            x509Cert = X509CertImpl.toImpl((X509Certificate)cert);
-        } catch (CertificateException ce) {
-            throw new CertPathValidatorException(ce);
-        }
-
-        PublicKey currPubKey = x509Cert.getPublicKey();
-        String currSigAlg = x509Cert.getSigAlgName();
-
-        AlgorithmId algorithmId = null;
-        try {
-            algorithmId = (AlgorithmId)x509Cert.get(X509CertImpl.SIG_ALG);
-        } catch (CertificateException ce) {
-            throw new CertPathValidatorException(ce);
-        }
-
-        AlgorithmParameters currSigAlgParams = algorithmId.getParameters();
-
-        // Check the current signature algorithm
-        if (!constraints.permits(
-                SIGNATURE_PRIMITIVE_SET,
-                currSigAlg, currSigAlgParams)) {
-            throw new CertPathValidatorException(
-                "Algorithm constraints check failed: " + currSigAlg,
-                null, null, -1, BasicReason.ALGORITHM_CONSTRAINED);
-        }
-
         // check the key usage and key size
-        boolean[] keyUsage = x509Cert.getKeyUsage();
+        boolean[] keyUsage = ((X509Certificate) cert).getKeyUsage();
         if (keyUsage != null && keyUsage.length < 9) {
             throw new CertPathValidatorException(
                 "incorrect KeyUsage extension",
@@ -248,27 +248,67 @@
 
             if (primitives.isEmpty()) {
                 throw new CertPathValidatorException(
-                    "incorrect KeyUsage extension",
+                    "incorrect KeyUsage extension bits",
                     null, null, -1, PKIXReason.INVALID_KEY_USAGE);
             }
         }
 
-        if (!constraints.permits(primitives, currPubKey)) {
-            throw new CertPathValidatorException(
-                "algorithm constraints check failed",
-                null, null, -1, BasicReason.ALGORITHM_CONSTRAINED);
+        PublicKey currPubKey = cert.getPublicKey();
+
+        // Check against DisabledAlgorithmConstraints certpath constraints.
+        // permits() will throw exception on failure.
+        certPathDefaultConstraints.permits(primitives,
+                new CertConstraintParameters((X509Certificate)cert,
+                        trustedMatch));
+                // new CertConstraintParameters(x509Cert, trustedMatch));
+        // If there is no previous key, set one and exit
+        if (prevPubKey == null) {
+            prevPubKey = currPubKey;
+            return;
+        }
+
+        X509CertImpl x509Cert;
+        AlgorithmId algorithmId;
+        try {
+            x509Cert = X509CertImpl.toImpl((X509Certificate)cert);
+            algorithmId = (AlgorithmId)x509Cert.get(X509CertImpl.SIG_ALG);
+        } catch (CertificateException ce) {
+            throw new CertPathValidatorException(ce);
+        }
+
+        AlgorithmParameters currSigAlgParams = algorithmId.getParameters();
+        String currSigAlg = x509Cert.getSigAlgName();
+
+        // If 'constraints' is not of DisabledAlgorithmConstraints, check all
+        // everything individually
+        if (!(constraints instanceof DisabledAlgorithmConstraints)) {
+            // Check the current signature algorithm
+            if (!constraints.permits(
+                    SIGNATURE_PRIMITIVE_SET,
+                    currSigAlg, currSigAlgParams)) {
+                throw new CertPathValidatorException(
+                        "Algorithm constraints check failed on signature " +
+                                "algorithm: " + currSigAlg, null, null, -1,
+                        BasicReason.ALGORITHM_CONSTRAINED);
+            }
+
+            if (!constraints.permits(primitives, currPubKey)) {
+                throw new CertPathValidatorException(
+                        "Algorithm constraints check failed on keysize: " +
+                                sun.security.util.KeyUtil.getKeySize(currPubKey),
+                        null, null, -1, BasicReason.ALGORITHM_CONSTRAINED);
+            }
         }
 
         // Check with previous cert for signature algorithm and public key
         if (prevPubKey != null) {
-            if (currSigAlg != null) {
-                if (!constraints.permits(
-                        SIGNATURE_PRIMITIVE_SET,
-                        currSigAlg, prevPubKey, currSigAlgParams)) {
-                    throw new CertPathValidatorException(
-                        "Algorithm constraints check failed: " + currSigAlg,
-                        null, null, -1, BasicReason.ALGORITHM_CONSTRAINED);
-                }
+            if (!constraints.permits(
+                    SIGNATURE_PRIMITIVE_SET,
+                    currSigAlg, prevPubKey, currSigAlgParams)) {
+                throw new CertPathValidatorException(
+                    "Algorithm constraints check failed on " +
+                            "signature algorithm: " + currSigAlg,
+                    null, null, -1, BasicReason.ALGORITHM_CONSTRAINED);
             }
 
             // Inherit key parameters from previous key
@@ -282,7 +322,7 @@
                 DSAParams params = ((DSAPublicKey)prevPubKey).getParams();
                 if (params == null) {
                     throw new CertPathValidatorException(
-                                    "Key parameters missing");
+                        "Key parameters missing from public key.");
                 }
 
                 try {
@@ -330,6 +370,11 @@
             // Don't bother to change the trustedPubKey.
             if (anchor.getTrustedCert() != null) {
                 prevPubKey = anchor.getTrustedCert().getPublicKey();
+                // Check for anchor certificate restrictions
+                trustedMatch = checkFingerprint(anchor.getTrustedCert());
+                if (trustedMatch && debug != null) {
+                    debug.println("trustedMatch = true");
+                }
             } else {
                 prevPubKey = anchor.getCAPublicKey();
             }
@@ -370,7 +415,8 @@
         if (!certPathDefaultConstraints.permits(
                 SIGNATURE_PRIMITIVE_SET, sigAlgName, key, sigAlgParams)) {
             throw new CertPathValidatorException(
-                "algorithm check failed: " + sigAlgName + " is disabled",
+                "Algorithm constraints check failed on signature algorithm: " +
+                sigAlgName + " is disabled",
                 null, null, -1, BasicReason.ALGORITHM_CONSTRAINED);
         }
     }
--- a/jdk/src/java.base/share/classes/sun/security/provider/certpath/PKIXMasterCertPathValidator.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/provider/certpath/PKIXMasterCertPathValidator.java	Tue May 03 12:25:20 2016 -0700
@@ -131,8 +131,8 @@
 
                 } catch (CertPathValidatorException cpve) {
                     throw new CertPathValidatorException(cpve.getMessage(),
-                        cpve.getCause(), cpOriginal, cpSize - (i + 1),
-                        cpve.getReason());
+                        (cpve.getCause() != null) ? cpve.getCause() : cpve,
+                            cpOriginal, cpSize - (i + 1), cpve.getReason());
                 }
             }
 
--- a/jdk/src/java.base/share/classes/sun/security/provider/certpath/RevocationChecker.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/provider/certpath/RevocationChecker.java	Tue May 03 12:25:20 2016 -0700
@@ -43,7 +43,6 @@
 
 import static sun.security.provider.certpath.OCSP.*;
 import static sun.security.provider.certpath.PKIX.*;
-import sun.security.action.GetPropertyAction;
 import sun.security.x509.*;
 import static sun.security.x509.PKIXExtensions.*;
 import sun.security.util.Debug;
--- a/jdk/src/java.base/share/classes/sun/security/rsa/RSAKeyFactory.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/rsa/RSAKeyFactory.java	Tue May 03 12:25:20 2016 -0700
@@ -84,7 +84,7 @@
     public static final int MAX_RESTRICTED_EXPLEN = 64;
 
     private static final boolean restrictExpLen =
-        "true".equalsIgnoreCase(GetPropertyAction.getProperty(
+        "true".equalsIgnoreCase(GetPropertyAction.privilegedGetProperty(
                 "sun.security.rsa.restrictRSAExponent", "true"));
 
     // instance used for static translateKey();
--- a/jdk/src/java.base/share/classes/sun/security/ssl/ClientKeyExchangeService.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/ClientKeyExchangeService.java	Tue May 03 12:25:20 2016 -0700
@@ -50,7 +50,7 @@
                 providers = new HashMap<>();
 
         static {
-            String path = GetPropertyAction.getProperty("java.home");
+            String path = GetPropertyAction.privilegedGetProperty("java.home");
             ServiceLoader<ClientKeyExchangeService> sc =
                     AccessController.doPrivileged(
                             (PrivilegedAction<ServiceLoader<ClientKeyExchangeService>>)
--- a/jdk/src/java.base/share/classes/sun/security/ssl/Debug.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/Debug.java	Tue May 03 12:25:20 2016 -0700
@@ -45,7 +45,7 @@
     private static String args;
 
     static {
-        args = GetPropertyAction.getProperty("javax.net.debug", "");
+        args = GetPropertyAction.privilegedGetProperty("javax.net.debug", "");
         args = args.toLowerCase(Locale.ENGLISH);
         if (args.equals("help")) {
             Help();
@@ -178,11 +178,11 @@
     /**
      * Return the value of the boolean System property propName.
      *
-     * Note use of doPrivileged(). Do make accessible to applications.
+     * Note use of privileged action. Do NOT make accessible to applications.
      */
     static boolean getBooleanProperty(String propName, boolean defaultValue) {
         // if set, require value of either true or false
-        String b = GetPropertyAction.getProperty(propName);
+        String b = GetPropertyAction.privilegedGetProperty(propName);
         if (b == null) {
             return defaultValue;
         } else if (b.equalsIgnoreCase("false")) {
--- a/jdk/src/java.base/share/classes/sun/security/ssl/SSLContextImpl.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/SSLContextImpl.java	Tue May 03 12:25:20 2016 -0700
@@ -656,7 +656,8 @@
         // the provider service. Instead, please handle the initialization
         // exception in the caller's constructor.
         static {
-            String property = GetPropertyAction.getProperty(PROPERTY_NAME);
+            String property = GetPropertyAction
+                    .privilegedGetProperty(PROPERTY_NAME);
             if (property != null && property.length() != 0) {
                 // remove double quote marks from beginning/end of the property
                 if (property.length() > 1 && property.charAt(0) == '"' &&
--- a/jdk/src/java.base/share/classes/sun/security/ssl/ServerHandshaker.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/ServerHandshaker.java	Tue May 03 12:25:20 2016 -0700
@@ -119,8 +119,8 @@
     private long statusRespTimeout;
 
     static {
-        String property =
-                GetPropertyAction.getProperty("jdk.tls.ephemeralDHKeySize");
+        String property = GetPropertyAction
+                .privilegedGetProperty("jdk.tls.ephemeralDHKeySize");
         if (property == null || property.length() == 0) {
             useLegacyEphemeralDHKeys = false;
             useSmartEphemeralDHKeys = false;
--- a/jdk/src/java.base/share/classes/sun/security/ssl/StatusResponseManager.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/ssl/StatusResponseManager.java	Tue May 03 12:25:20 2016 -0700
@@ -73,8 +73,8 @@
                     DEFAULT_CACHE_LIFETIME));
         cacheLifetime = life > 0 ? life : 0;
 
-        String uriStr =
-                GetPropertyAction.getProperty("jdk.tls.stapling.responderURI");
+        String uriStr = GetPropertyAction
+                .privilegedGetProperty("jdk.tls.stapling.responderURI");
         URI tmpURI;
         try {
             tmpURI = ((uriStr != null && !uriStr.isEmpty()) ?
--- a/jdk/src/java.base/share/classes/sun/security/tools/keytool/Main.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/tools/keytool/Main.java	Tue May 03 12:25:20 2016 -0700
@@ -728,6 +728,7 @@
                     provClass = Class.forName(provName);
                 }
 
+                @SuppressWarnings("deprecation")
                 Object obj = provClass.newInstance();
                 if (!(obj instanceof Provider)) {
                     MessageFormat form = new MessageFormat
--- a/jdk/src/java.base/share/classes/sun/security/util/AbstractAlgorithmConstraints.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/util/AbstractAlgorithmConstraints.java	Tue May 03 12:25:20 2016 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016 Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -29,7 +29,6 @@
 import java.security.AlgorithmConstraints;
 import java.security.PrivilegedAction;
 import java.security.Security;
-import java.util.Map;
 import java.util.Set;
 
 /**
@@ -45,8 +44,7 @@
     }
 
     // Get algorithm constraints from the specified security property.
-    private static void loadAlgorithmsMap(Map<String, String[]> algorithmsMap,
-            String propertyName) {
+    static String[] getAlgorithms(String propertyName) {
         String property = AccessController.doPrivileged(
                 (PrivilegedAction<String>) () -> Security.getProperty(
                         propertyName));
@@ -68,18 +66,7 @@
         if (algorithmsInProperty == null) {
             algorithmsInProperty = new String[0];
         }
-        algorithmsMap.put(propertyName, algorithmsInProperty);
-    }
-
-    static String[] getAlgorithms(Map<String, String[]> algorithmsMap,
-            String propertyName) {
-        synchronized (algorithmsMap) {
-            if (!algorithmsMap.containsKey(propertyName)) {
-                loadAlgorithmsMap(algorithmsMap, propertyName);
-            }
-
-            return algorithmsMap.get(propertyName);
-        }
+        return algorithmsInProperty;
     }
 
     static boolean checkAlgorithm(String[] algorithms, String algorithm,
--- a/jdk/src/java.base/share/classes/sun/security/util/AlgorithmDecomposer.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/util/AlgorithmDecomposer.java	Tue May 03 12:25:20 2016 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -40,19 +40,7 @@
     private static final Pattern pattern =
             Pattern.compile("with|and|(?<!padd)in", Pattern.CASE_INSENSITIVE);
 
-    /**
-     * Decompose the standard algorithm name into sub-elements.
-     * <p>
-     * For example, we need to decompose "SHA1WithRSA" into "SHA1" and "RSA"
-     * so that we can check the "SHA1" and "RSA" algorithm constraints
-     * separately.
-     * <p>
-     * Please override the method if need to support more name pattern.
-     */
-    public Set<String> decompose(String algorithm) {
-        if (algorithm == null || algorithm.length() == 0) {
-            return new HashSet<>();
-        }
+    private static Set<String> decomposeImpl(String algorithm) {
 
         // algorithm/mode/padding
         String[] transTockens = transPattern.split(algorithm);
@@ -79,6 +67,24 @@
                 elements.add(token);
             }
         }
+        return elements;
+    }
+
+    /**
+     * Decompose the standard algorithm name into sub-elements.
+     * <p>
+     * For example, we need to decompose "SHA1WithRSA" into "SHA1" and "RSA"
+     * so that we can check the "SHA1" and "RSA" algorithm constraints
+     * separately.
+     * <p>
+     * Please override the method if need to support more name pattern.
+     */
+    public Set<String> decompose(String algorithm) {
+        if (algorithm == null || algorithm.length() == 0) {
+            return new HashSet<>();
+        }
+
+        Set<String> elements = decomposeImpl(algorithm);
 
         // In Java standard algorithm name specification, for different
         // purpose, the SHA-1 and SHA-2 algorithm names are different. For
@@ -130,4 +136,40 @@
         return elements;
     }
 
+    private static void hasLoop(Set<String> elements, String find, String replace) {
+        if (elements.contains(find)) {
+            if (!elements.contains(replace)) {
+                elements.add(replace);
+            }
+            elements.remove(find);
+        }
+    }
+
+    /*
+     * This decomposes a standard name into sub-elements with a consistent
+     * message digest algorithm name to avoid overly complicated checking.
+     */
+    public static Set<String> decomposeOneHash(String algorithm) {
+        if (algorithm == null || algorithm.length() == 0) {
+            return new HashSet<>();
+        }
+
+        Set<String> elements = decomposeImpl(algorithm);
+
+        hasLoop(elements, "SHA-1", "SHA1");
+        hasLoop(elements, "SHA-224", "SHA224");
+        hasLoop(elements, "SHA-256", "SHA256");
+        hasLoop(elements, "SHA-384", "SHA384");
+        hasLoop(elements, "SHA-512", "SHA512");
+
+        return elements;
+    }
+
+    /*
+     * The provided message digest algorithm name will return a consistent
+     * naming scheme.
+     */
+    public static String hashName(String algorithm) {
+        return algorithm.replace("-", "");
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/classes/sun/security/util/AnchorCertificates.java	Tue May 03 12:25:20 2016 -0700
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.security.util;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.security.AccessController;
+import java.security.KeyStore;
+import java.security.PrivilegedAction;
+import java.security.cert.X509Certificate;
+import java.util.Enumeration;
+import java.util.HashSet;
+
+import sun.security.x509.X509CertImpl;
+
+/**
+ * The purpose of this class is to determine the trust anchor certificates is in
+ * the cacerts file.  This is used for PKIX CertPath checking.
+ */
+public class AnchorCertificates {
+
+    private static final Debug debug = Debug.getInstance("certpath");
+    private static final String HASH = "SHA-256";
+    private static HashSet<String> certs;
+
+    static  {
+        AccessController.doPrivileged(new PrivilegedAction<Void>() {
+            @Override
+            public Void run() {
+                File f = new File(System.getProperty("java.home"),
+                        "lib/security/cacerts");
+                KeyStore cacerts;
+                try {
+                    cacerts = KeyStore.getInstance("JKS");
+                    try (FileInputStream fis = new FileInputStream(f)) {
+                        cacerts.load(fis, "changeit".toCharArray());
+                        certs = new HashSet<>();
+                        Enumeration<String> list = cacerts.aliases();
+                        String alias;
+                        while (list.hasMoreElements()) {
+                            alias = list.nextElement();
+                            // Check if this cert is labeled a trust anchor.
+                            if (alias.contains(" [jdk")) {
+                                X509Certificate cert = (X509Certificate) cacerts
+                                        .getCertificate(alias);
+                                certs.add(X509CertImpl.getFingerprint(HASH, cert));
+                            }
+                        }
+                    }
+                } catch (Exception e) {
+                    if (debug != null) {
+                        debug.println("Error parsing cacerts");
+                    }
+                    e.printStackTrace();
+                }
+                return null;
+            }
+        });
+    }
+
+    /**
+     * Checks if a certificate is a trust anchor.
+     *
+     * @param cert the certificate to check
+     * @return true if the certificate is trusted.
+     */
+    public static boolean contains(X509Certificate cert) {
+        String key = X509CertImpl.getFingerprint(HASH, cert);
+        boolean result = certs.contains(key);
+        if (result && debug != null) {
+            debug.println("AnchorCertificate.contains: matched " +
+                    cert.getSubjectDN());
+        }
+        return result;
+    }
+
+    private AnchorCertificates() {}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/classes/sun/security/util/CertConstraintParameters.java	Tue May 03 12:25:20 2016 -0700
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.security.util;
+
+import java.security.cert.X509Certificate;
+
+/**
+ * This class is a wrapper for keeping state and passing objects between PKIX,
+ * AlgorithmChecker, and DisabledAlgorithmConstraints.
+ */
+public class CertConstraintParameters {
+    // A certificate being passed to check against constraints.
+    private final X509Certificate cert;
+
+    // This is true if the trust anchor in the certificate chain matches a cert
+    // in AnchorCertificates
+    private final boolean trustedMatch;
+
+    public CertConstraintParameters(X509Certificate c, boolean match) {
+        cert = c;
+        trustedMatch = match;
+    }
+
+    public CertConstraintParameters(X509Certificate c) {
+        this(c, false);
+    }
+
+    // Returns if the trust anchor has a match if anchor checking is enabled.
+    public boolean isTrustedMatch() {
+        return trustedMatch;
+    }
+
+    public X509Certificate getCertificate() {
+        return cert;
+    }
+}
--- a/jdk/src/java.base/share/classes/sun/security/util/Debug.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/util/Debug.java	Tue May 03 12:25:20 2016 -0700
@@ -43,10 +43,10 @@
     private static String args;
 
     static {
-        args = GetPropertyAction.getProperty("java.security.debug");
+        args = GetPropertyAction.privilegedGetProperty("java.security.debug");
 
-        String args2 =
-                GetPropertyAction.getProperty("java.security.auth.debug");
+        String args2 = GetPropertyAction
+                .privilegedGetProperty("java.security.auth.debug");
 
         if (args == null) {
             args = args2;
--- a/jdk/src/java.base/share/classes/sun/security/util/DisabledAlgorithmConstraints.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/util/DisabledAlgorithmConstraints.java	Tue May 03 12:25:20 2016 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -28,12 +28,14 @@
 import java.security.CryptoPrimitive;
 import java.security.AlgorithmParameters;
 import java.security.Key;
+import java.security.cert.CertPathValidatorException;
+import java.security.cert.CertPathValidatorException.BasicReason;
+import java.security.cert.X509Certificate;
+import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Locale;
+import java.util.Map;
 import java.util.Set;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.HashMap;
 import java.util.regex.Pattern;
 import java.util.regex.Matcher;
 
@@ -44,6 +46,7 @@
  * for the syntax of the disabled algorithm string.
  */
 public class DisabledAlgorithmConstraints extends AbstractAlgorithmConstraints {
+    private static final Debug debug = Debug.getInstance("certpath");
 
     // the known security property, jdk.certpath.disabledAlgorithms
     public static final String PROPERTY_CERTPATH_DISABLED_ALGS =
@@ -53,13 +56,8 @@
     public static final String PROPERTY_TLS_DISABLED_ALGS =
             "jdk.tls.disabledAlgorithms";
 
-    private static final Map<String, String[]> disabledAlgorithmsMap =
-                                                            new HashMap<>();
-    private static final Map<String, KeySizeConstraints> keySizeConstraintsMap =
-                                                            new HashMap<>();
-
     private final String[] disabledAlgorithms;
-    private final KeySizeConstraints keySizeConstraints;
+    private final Constraints algorithmConstraints;
 
     /**
      * Initialize algorithm constraints with the specified security property.
@@ -74,11 +72,14 @@
     public DisabledAlgorithmConstraints(String propertyName,
             AlgorithmDecomposer decomposer) {
         super(decomposer);
-        disabledAlgorithms = getAlgorithms(disabledAlgorithmsMap, propertyName);
-        keySizeConstraints = getKeySizeConstraints(disabledAlgorithms,
-                propertyName);
+        disabledAlgorithms = getAlgorithms(propertyName);
+        algorithmConstraints = new Constraints(disabledAlgorithms);
     }
 
+    /*
+     * This only checks if the algorithm has been completely disabled.  If
+     * there are keysize or other limit, this method allow the algorithm.
+     */
     @Override
     public final boolean permits(Set<CryptoPrimitive> primitives,
             String algorithm, AlgorithmParameters parameters) {
@@ -91,11 +92,19 @@
         return checkAlgorithm(disabledAlgorithms, algorithm, decomposer);
     }
 
+    /*
+     * Checks if the key algorithm has been disabled or constraints have been
+     * placed on the key.
+     */
     @Override
     public final boolean permits(Set<CryptoPrimitive> primitives, Key key) {
         return checkConstraints(primitives, "", key, null);
     }
 
+    /*
+     * Checks if the key algorithm has been disabled or if constraints have
+     * been placed on the key.
+     */
     @Override
     public final boolean permits(Set<CryptoPrimitive> primitives,
             String algorithm, Key key, AlgorithmParameters parameters) {
@@ -107,7 +116,39 @@
         return checkConstraints(primitives, algorithm, key, parameters);
     }
 
-    // Check algorithm constraints
+    /*
+     * Check if a x509Certificate object is permitted.  Check if all
+     * algorithms are allowed, certificate constraints, and the
+     * public key against key constraints.
+     *
+     * Uses new style permit() which throws exceptions.
+     */
+    public final void permits(Set<CryptoPrimitive> primitives,
+            CertConstraintParameters cp) throws CertPathValidatorException {
+        checkConstraints(primitives, cp);
+    }
+
+    /*
+     * Check if Certificate object is within the constraints.
+     * Uses new style permit() which throws exceptions.
+     */
+    public final void permits(Set<CryptoPrimitive> primitives,
+            X509Certificate cert) throws CertPathValidatorException {
+        checkConstraints(primitives, new CertConstraintParameters(cert));
+    }
+
+    // Check if a string is contained inside the property
+    public boolean checkProperty(String param) {
+        param = param.toLowerCase(Locale.ENGLISH);
+        for (String block : disabledAlgorithms) {
+            if (block.toLowerCase(Locale.ENGLISH).indexOf(param) >= 0) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    // Check algorithm constraints with key and algorithm
     private boolean checkConstraints(Set<CryptoPrimitive> primitives,
             String algorithm, Key key, AlgorithmParameters parameters) {
 
@@ -116,7 +157,7 @@
             throw new IllegalArgumentException("The key cannot be null");
         }
 
-        // check the target algorithm
+        // check the signature algorithm
         if (algorithm != null && algorithm.length() != 0) {
             if (!permits(primitives, algorithm, parameters)) {
                 return false;
@@ -129,97 +170,203 @@
         }
 
         // check the key constraints
-        if (keySizeConstraints.disables(key)) {
-            return false;
-        }
-
-        return true;
+        return algorithmConstraints.permits(key);
     }
 
-    private static KeySizeConstraints getKeySizeConstraints(
-            String[] disabledAlgorithms, String propertyName) {
-        synchronized (keySizeConstraintsMap) {
-            if(!keySizeConstraintsMap.containsKey(propertyName)) {
-                // map the key constraints
-                KeySizeConstraints keySizeConstraints =
-                        new KeySizeConstraints(disabledAlgorithms);
-                keySizeConstraintsMap.put(propertyName, keySizeConstraints);
-            }
+    /*
+     * Check algorithm constraints with Certificate
+     * Uses new style permit() which throws exceptions.
+     */
+    private void checkConstraints(Set<CryptoPrimitive> primitives,
+            CertConstraintParameters cp) throws CertPathValidatorException {
+
+        X509Certificate cert = cp.getCertificate();
+        String algorithm = cert.getSigAlgName();
 
-            return keySizeConstraintsMap.get(propertyName);
+        // Check signature algorithm is not disabled
+        if (!permits(primitives, algorithm, null)) {
+            throw new CertPathValidatorException(
+                    "Algorithm constraints check failed on disabled "+
+                            "signature algorithm: " + algorithm,
+                    null, null, -1, BasicReason.ALGORITHM_CONSTRAINED);
         }
+
+        // Check key algorithm is not disabled
+        if (!permits(primitives, cert.getPublicKey().getAlgorithm(), null)) {
+            throw new CertPathValidatorException(
+                    "Algorithm constraints check failed on disabled "+
+                            "public key algorithm: " + algorithm,
+                    null, null, -1, BasicReason.ALGORITHM_CONSTRAINED);
+        }
+
+        // Check the certificate and key constraints
+        algorithmConstraints.permits(cp);
+
     }
 
     /**
-     * key constraints
+     * Key and Certificate Constraints
+     *
+     * The complete disabling of an algorithm is not handled by Constraints or
+     * Constraint classes.  That is addressed with
+     *   permit(Set<CryptoPrimitive>, String, AlgorithmParameters)
+     *
+     * When passing a Key to permit(), the boolean return values follow the
+     * same as the interface class AlgorithmConstraints.permit().  This is to
+     * maintain compatibility:
+     * 'true' means the operation is allowed.
+     * 'false' means it failed the constraints and is disallowed.
+     *
+     * When passing CertConstraintParameters through permit(), an exception
+     * will be thrown on a failure to better identify why the operation was
+     * disallowed.
      */
-    private static class KeySizeConstraints {
-        private static final Pattern pattern = Pattern.compile(
-                "(\\S+)\\s+keySize\\s*(<=|<|==|!=|>|>=)\\s*(\\d+)");
 
-        private Map<String, Set<KeySizeConstraint>> constraintsMap =
-            Collections.synchronizedMap(
-                        new HashMap<String, Set<KeySizeConstraint>>());
+    private static class Constraints {
+        private Map<String, Set<Constraint>> constraintsMap = new HashMap<>();
+        private static final Pattern keySizePattern = Pattern.compile(
+                "keySize\\s*(<=|<|==|!=|>|>=)\\s*(\\d+)");
 
-        public KeySizeConstraints(String[] restrictions) {
-            for (String restriction : restrictions) {
-                if (restriction == null || restriction.isEmpty()) {
+        public Constraints(String[] constraintArray) {
+            for (String constraintEntry : constraintArray) {
+                if (constraintEntry == null || constraintEntry.isEmpty()) {
                     continue;
                 }
 
-                Matcher matcher = pattern.matcher(restriction);
-                if (matcher.matches()) {
-                    String algorithm = matcher.group(1);
+                constraintEntry = constraintEntry.trim();
+                if (debug != null) {
+                    debug.println("Constraints: " + constraintEntry);
+                }
 
-                    KeySizeConstraint.Operator operator =
-                             KeySizeConstraint.Operator.of(matcher.group(2));
-                    int length = Integer.parseInt(matcher.group(3));
+                // Check if constraint is a complete disabling of an
+                // algorithm or has conditions.
+                String algorithm;
+                String policy;
+                int space = constraintEntry.indexOf(' ');
+                if (space > 0) {
+                    algorithm = AlgorithmDecomposer.hashName(
+                            constraintEntry.substring(0, space).
+                                    toUpperCase(Locale.ENGLISH));
+                    policy = constraintEntry.substring(space + 1);
+                } else {
+                    constraintsMap.computeIfAbsent(
+                            constraintEntry.toUpperCase(Locale.ENGLISH),
+                            k -> new HashSet<>());
+                    continue;
+                }
 
-                    algorithm = algorithm.toLowerCase(Locale.ENGLISH);
+                // Convert constraint conditions into Constraint classes
+                Constraint c, lastConstraint = null;
+                // Allow only one jdkCA entry per constraint entry
+                boolean jdkCALimit = false;
+
+                for (String entry : policy.split("&")) {
+                    entry = entry.trim();
 
-                    synchronized (constraintsMap) {
-                        if (!constraintsMap.containsKey(algorithm)) {
-                            constraintsMap.put(algorithm,
-                                new HashSet<KeySizeConstraint>());
+                    Matcher matcher = keySizePattern.matcher(entry);
+                    if (matcher.matches()) {
+                        if (debug != null) {
+                            debug.println("Constraints set to keySize: " +
+                                    entry);
                         }
+                        c = new KeySizeConstraint(algorithm,
+                                KeySizeConstraint.Operator.of(matcher.group(1)),
+                                Integer.parseInt(matcher.group(2)));
 
-                        Set<KeySizeConstraint> constraintSet =
-                            constraintsMap.get(algorithm);
-                        KeySizeConstraint constraint =
-                            new KeySizeConstraint(operator, length);
-                        constraintSet.add(constraint);
+                    } else if (entry.equalsIgnoreCase("jdkCA")) {
+                        if (debug != null) {
+                            debug.println("Constraints set to jdkCA.");
+                        }
+                        if (jdkCALimit) {
+                            throw new IllegalArgumentException("Only one " +
+                                    "jdkCA entry allowed in property. " +
+                                    "Constraint: " + constraintEntry);
+                        }
+                        c = new jdkCAConstraint(algorithm);
+                        jdkCALimit = true;
+                    } else {
+                        throw new IllegalArgumentException("Error in security" +
+                                " property. Constraint unknown: " + entry);
                     }
+
+                    // Link multiple conditions for a single constraint
+                    // into a linked list.
+                    if (lastConstraint == null) {
+                        if (!constraintsMap.containsKey(algorithm)) {
+                            constraintsMap.putIfAbsent(algorithm,
+                                    new HashSet<>());
+                        }
+                        constraintsMap.get(algorithm).add(c);
+                    } else {
+                        lastConstraint.nextConstraint = c;
+                    }
+                    lastConstraint = c;
                 }
             }
         }
 
-        // Does this KeySizeConstraints disable the specified key?
-        public boolean disables(Key key) {
-            String algorithm = key.getAlgorithm().toLowerCase(Locale.ENGLISH);
-            synchronized (constraintsMap) {
-                if (constraintsMap.containsKey(algorithm)) {
-                    Set<KeySizeConstraint> constraintSet =
-                                        constraintsMap.get(algorithm);
-                    for (KeySizeConstraint constraint : constraintSet) {
-                        if (constraint.disables(key)) {
-                            return true;
-                        }
+        // Get applicable constraints based off the signature algorithm
+        private Set<Constraint> getConstraints(String algorithm) {
+            return constraintsMap.get(algorithm);
+        }
+
+        // Check if KeySizeConstraints permit the specified key
+        public boolean permits(Key key) {
+            Set<Constraint> set = getConstraints(key.getAlgorithm());
+            if (set == null) {
+                return true;
+            }
+            for (Constraint constraint : set) {
+                if (!constraint.permits(key)) {
+                    if (debug != null) {
+                        debug.println("keySizeConstraint: failed key " +
+                                "constraint check " + KeyUtil.getKeySize(key));
                     }
+                    return false;
                 }
             }
+            return true;
+        }
 
-            return false;
+        // Check if constraints permit this cert.
+        public void permits(CertConstraintParameters cp)
+                throws CertPathValidatorException {
+            X509Certificate cert = cp.getCertificate();
+
+            if (debug != null) {
+                debug.println("Constraints.permits(): " + cert.getSigAlgName());
+            }
+
+            // Get all signature algorithms to check for constraints
+            Set<String> algorithms =
+                    AlgorithmDecomposer.decomposeOneHash(cert.getSigAlgName());
+            if (algorithms == null || algorithms.isEmpty()) {
+                return;
+            }
+
+            // Attempt to add the public key algorithm to the set
+            algorithms.add(cert.getPublicKey().getAlgorithm());
+
+            // Check all applicable constraints
+            for (String algorithm : algorithms) {
+                Set<Constraint> set = getConstraints(algorithm);
+                if (set == null) {
+                    continue;
+                }
+                for (Constraint constraint : set) {
+                    constraint.permits(cp);
+                }
+            }
         }
     }
 
-    /**
-     * Key size constraint.
-     *
-     * e.g.  "keysize <= 1024"
-     */
-    private static class KeySizeConstraint {
+    // Abstract class for algorithm constraint checking
+    private abstract static class Constraint {
+        String algorithm;
+        Constraint nextConstraint = null;
+
         // operator
-        static enum Operator {
+        enum Operator {
             EQ,         // "=="
             NE,         // "!="
             LT,         // "<"
@@ -243,16 +390,77 @@
                         return GE;
                 }
 
-                throw new IllegalArgumentException(
-                        s + " is not a legal Operator");
+                throw new IllegalArgumentException("Error in security " +
+                        "property. " + s + " is not a legal Operator");
             }
         }
 
+        /**
+         * Check if an algorithm constraint permit this key to be used.
+         * @param key Public key
+         * @return true if constraints do not match
+         */
+        public boolean permits(Key key) {
+            return true;
+        }
+
+        /**
+         * Check if an algorithm constraint is permit this certificate to
+         * be used.
+         * @param cp CertificateParameter containing certificate and state info
+         * @return true if constraints do not match
+         */
+        public abstract void permits(CertConstraintParameters cp)
+                throws CertPathValidatorException;
+    }
+
+    /*
+     * This class contains constraints dealing with the certificate chain
+     * of the certificate.
+     */
+    private static class jdkCAConstraint extends Constraint {
+        jdkCAConstraint(String algo) {
+            algorithm = algo;
+        }
+
+        /*
+         * Check if each constraint fails and check if there is a linked
+         * constraint  Any permitted constraint will exit the linked list
+         * to allow the operation.
+         */
+        public void permits(CertConstraintParameters cp)
+                throws CertPathValidatorException {
+            if (debug != null) {
+                debug.println("jdkCAConstraints.permits(): " + algorithm);
+            }
+
+            // Return false if the chain has a trust anchor in cacerts
+            if (cp.isTrustedMatch()) {
+                if (nextConstraint != null) {
+                    nextConstraint.permits(cp);
+                    return;
+                }
+                throw new CertPathValidatorException(
+                        "Algorithm constraints check failed on certificate " +
+                                "anchor limits",
+                        null, null, -1, BasicReason.ALGORITHM_CONSTRAINED);
+            }
+        }
+    }
+
+
+    /*
+     * This class contains constraints dealing with the key size
+     * support limits per algorithm.   e.g.  "keySize <= 1024"
+     */
+    private static class KeySizeConstraint extends Constraint {
+
         private int minSize;            // the minimal available key size
         private int maxSize;            // the maximal available key size
         private int prohibitedSize = -1;    // unavailable key sizes
 
-        public KeySizeConstraint(Operator operator, int length) {
+        public KeySizeConstraint(String algo, Operator operator, int length) {
+            algorithm = algo;
             switch (operator) {
                 case EQ:      // an unavailable key size
                     this.minSize = 0;
@@ -286,21 +494,59 @@
             }
         }
 
-        // Does this key constraint disable the specified key?
-        public boolean disables(Key key) {
-            int size = KeyUtil.getKeySize(key);
+        /*
+         * If we are passed a certificate, extract the public key and use it.
+         *
+         * Check if each constraint fails and check if there is a linked
+         * constraint  Any permitted constraint will exit the linked list
+         * to allow the operation.
+         */
+        public void permits(CertConstraintParameters cp)
+                throws CertPathValidatorException {
+            if (!permitsImpl(cp.getCertificate().getPublicKey())) {
+                if (nextConstraint != null) {
+                    nextConstraint.permits(cp);
+                    return;
+                }
+                throw new CertPathValidatorException(
+                        "Algorithm constraints check failed on keysize limits",
+                        null, null, -1, BasicReason.ALGORITHM_CONSTRAINED);
+            }
+        }
+
 
+        // Check if key constraint disable the specified key
+        // Uses old style permit()
+        public boolean permits(Key key) {
+            // If we recursively find a constraint that permits us to use
+            // this key, return true and skip any other constraint checks.
+            if (nextConstraint != null && nextConstraint.permits(key)) {
+                return true;
+            }
+            if (debug != null) {
+                debug.println("KeySizeConstraints.permits(): " + algorithm);
+            }
+
+            return permitsImpl(key);
+        }
+
+        private boolean permitsImpl(Key key) {
+            // Verify this constraint is for this public key algorithm
+            if (algorithm.compareToIgnoreCase(key.getAlgorithm()) != 0) {
+                return true;
+            }
+
+            int size = KeyUtil.getKeySize(key);
             if (size == 0) {
-                return true;    // we don't allow any key of size 0.
+                return false;    // we don't allow any key of size 0.
             } else if (size > 0) {
-                return ((size < minSize) || (size > maxSize) ||
+                return !((size < minSize) || (size > maxSize) ||
                     (prohibitedSize == size));
             }   // Otherwise, the key size is not accessible. Conservatively,
                 // please don't disable such keys.
 
-            return false;
+            return true;
         }
     }
-
 }
 
--- a/jdk/src/java.base/share/classes/sun/security/util/KeyStoreDelegator.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/util/KeyStoreDelegator.java	Tue May 03 12:25:20 2016 -0700
@@ -196,8 +196,9 @@
         // A new keystore is always created in the primary keystore format
         if (stream == null) {
             try {
-                keystore = primaryKeyStore.newInstance();
-
+                @SuppressWarnings("deprecation")
+                KeyStoreSpi tmp = primaryKeyStore.newInstance();
+                keystore = tmp;
             } catch (InstantiationException | IllegalAccessException e) {
                 // can safely ignore
             }
@@ -214,7 +215,9 @@
             bufferedStream.mark(Integer.MAX_VALUE);
 
             try {
-                keystore = primaryKeyStore.newInstance();
+                @SuppressWarnings("deprecation")
+                KeyStoreSpi tmp = primaryKeyStore.newInstance();
+                keystore = tmp;
                 type = primaryType;
                 keystore.engineLoad(bufferedStream, password);
 
@@ -232,7 +235,9 @@
                         throw e;
                     }
 
-                    keystore = secondaryKeyStore.newInstance();
+                    @SuppressWarnings("deprecation")
+                    KeyStoreSpi tmp= secondaryKeyStore.newInstance();
+                    keystore = tmp;
                     type = secondaryType;
                     bufferedStream.reset();
                     keystore.engineLoad(bufferedStream, password);
@@ -284,7 +289,9 @@
         boolean result = false;
 
         try {
-            keystore = primaryKeyStore.newInstance();
+            @SuppressWarnings("deprecation")
+            KeyStoreSpi tmp = primaryKeyStore.newInstance();
+            keystore = tmp;
             type = primaryType;
             result = keystore.engineProbe(stream);
 
--- a/jdk/src/java.base/share/classes/sun/security/util/LegacyAlgorithmConstraints.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/util/LegacyAlgorithmConstraints.java	Tue May 03 12:25:20 2016 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -28,8 +28,6 @@
 import java.security.AlgorithmParameters;
 import java.security.CryptoPrimitive;
 import java.security.Key;
-import java.util.HashMap;
-import java.util.Map;
 import java.util.Set;
 import static sun.security.util.AbstractAlgorithmConstraints.getAlgorithms;
 
@@ -42,15 +40,12 @@
     public static final String PROPERTY_TLS_LEGACY_ALGS =
             "jdk.tls.legacyAlgorithms";
 
-    private static final Map<String, String[]> legacyAlgorithmsMap =
-                                                          new HashMap<>();
-
     private final String[] legacyAlgorithms;
 
     public LegacyAlgorithmConstraints(String propertyName,
             AlgorithmDecomposer decomposer) {
         super(decomposer);
-        legacyAlgorithms = getAlgorithms(legacyAlgorithmsMap, propertyName);
+        legacyAlgorithms = getAlgorithms(propertyName);
     }
 
     @Override
--- a/jdk/src/java.base/share/classes/sun/security/x509/X509CertImpl.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/x509/X509CertImpl.java	Tue May 03 12:25:20 2016 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -1924,17 +1924,18 @@
 
     public String getFingerprint(String algorithm) {
         return fingerprints.computeIfAbsent(algorithm,
-                x -> getCertificateFingerPrint(x));
+            x -> getFingerprint(x, this));
     }
 
     /**
      * Gets the requested finger print of the certificate. The result
      * only contains 0-9 and A-F. No small case, no colon.
      */
-    private String getCertificateFingerPrint(String mdAlg) {
+    public static String getFingerprint(String algorithm,
+            X509Certificate cert) {
         try {
-            byte[] encCertInfo = getEncoded();
-            MessageDigest md = MessageDigest.getInstance(mdAlg);
+            byte[] encCertInfo = cert.getEncoded();
+            MessageDigest md = MessageDigest.getInstance(algorithm);
             byte[] digest = md.digest(encCertInfo);
             StringBuilder sb = new StringBuilder(digest.length * 2);
             for (int i = 0; i < digest.length; i++) {
--- a/jdk/src/java.base/share/classes/sun/security/x509/X509Key.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/x509/X509Key.java	Tue May 03 12:25:20 2016 -0700
@@ -255,11 +255,10 @@
                 }
             }
 
-            Object      inst = null;
+            @SuppressWarnings("deprecation")
+            Object      inst = (keyClass != null) ? keyClass.newInstance() : null;
             X509Key     result;
 
-            if (keyClass != null)
-                inst = keyClass.newInstance();
             if (inst instanceof X509Key) {
                 result = (X509Key) inst;
                 result.algid = algid;
--- a/jdk/src/java.base/share/classes/sun/util/calendar/CalendarSystem.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/sun/util/calendar/CalendarSystem.java	Tue May 03 12:25:20 2016 -0700
@@ -157,8 +157,9 @@
             cal = LocalGregorianCalendar.getLocalGregorianCalendar(calendarName);
         } else {
             try {
-                Class<?> cl = Class.forName(className);
-                cal = (CalendarSystem) cl.newInstance();
+                @SuppressWarnings("deprecation")
+                Object tmp = Class.forName(className).newInstance();
+                cal = (CalendarSystem) tmp;
             } catch (Exception e) {
                 throw new InternalError(e);
             }
--- a/jdk/src/java.base/share/classes/sun/util/calendar/LocalGregorianCalendar.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/sun/util/calendar/LocalGregorianCalendar.java	Tue May 03 12:25:20 2016 -0700
@@ -144,7 +144,7 @@
 
         // Append an era to the predefined eras if it's given by the property.
         String prop = GetPropertyAction
-                .getProperty("jdk.calendar.japanese.supplemental.era");
+                .privilegedGetProperty("jdk.calendar.japanese.supplemental.era");
         if (prop != null) {
             Era era = parseEraEntry(prop);
             if (era != null) {
--- a/jdk/src/java.base/share/classes/sun/util/calendar/ZoneInfoFile.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/sun/util/calendar/ZoneInfoFile.java	Tue May 03 12:25:20 2016 -0700
@@ -246,7 +246,7 @@
 
     static {
         String oldmapping = GetPropertyAction
-                .getProperty("sun.timezone.ids.oldmapping", "false")
+                .privilegedGetProperty("sun.timezone.ids.oldmapping", "false")
                 .toLowerCase(Locale.ROOT);
         USE_OLDMAPPING = (oldmapping.equals("yes") || oldmapping.equals("true"));
         AccessController.doPrivileged(new PrivilegedAction<Void>() {
--- a/jdk/src/java.base/share/classes/sun/util/locale/provider/LocaleProviderAdapter.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/sun/util/locale/provider/LocaleProviderAdapter.java	Tue May 03 12:25:20 2016 -0700
@@ -116,7 +116,7 @@
         adapterCache = new ConcurrentHashMap<>();
 
     static {
-        String order = GetPropertyAction.getProperty("java.locale.providers");
+        String order = GetPropertyAction.privilegedGetProperty("java.locale.providers");
         List<Type> typeList = new ArrayList<>();
 
         // Check user specified adapter preference
@@ -171,8 +171,9 @@
             if (cached == null) {
                 try {
                     // lazily load adapters here
-                    adapter = (LocaleProviderAdapter)Class.forName(type.getAdapterClassName())
-                        .newInstance();
+                    @SuppressWarnings("deprecation")
+                    Object tmp = Class.forName(type.getAdapterClassName()).newInstance();
+                    adapter = (LocaleProviderAdapter)tmp;
                     cached = adapterInstances.putIfAbsent(type, adapter);
                     if (cached != null) {
                         adapter = cached;
--- a/jdk/src/java.base/share/classes/sun/util/locale/provider/SPILocaleProviderAdapter.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/classes/sun/util/locale/provider/SPILocaleProviderAdapter.java	Tue May 03 12:25:20 2016 -0700
@@ -73,7 +73,7 @@
         try {
             return AccessController.doPrivileged(new PrivilegedExceptionAction<P>() {
                 @Override
-                @SuppressWarnings("unchecked")
+                @SuppressWarnings(value={"unchecked", "deprecation"})
                 public P run() {
                     P delegate = null;
 
--- a/jdk/src/java.base/share/conf/security/java.security	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/share/conf/security/java.security	Tue May 03 12:25:20 2016 -0700
@@ -497,13 +497,13 @@
 #       " DisabledAlgorithm { , DisabledAlgorithm } "
 #
 #   DisabledAlgorithm:
-#       AlgorithmName [Constraint]
+#       AlgorithmName [Constraint] { '&' Constraint }
 #
 #   AlgorithmName:
 #       (see below)
 #
 #   Constraint:
-#       KeySizeConstraint
+#       KeySizeConstraint, CertConstraint
 #
 #   KeySizeConstraint:
 #       keySize Operator DecimalInteger
@@ -520,6 +520,9 @@
 #   DecimalDigit: one of
 #       1 2 3 4 5 6 7 8 9 0
 #
+#   CertConstraint
+#       jdkCA
+#
 # The "AlgorithmName" is the standard algorithm name of the disabled
 # algorithm. See "Java Cryptography Architecture Standard Algorithm Name
 # Documentation" for information about Standard Algorithm Names.  Matching
@@ -542,6 +545,29 @@
 # be disabled. Note that the "KeySizeConstraint" only makes sense to key
 # algorithms.
 #
+# "CertConstraint" specifies additional constraints for
+# certificates that contain algorithms that are restricted:
+#
+#   "jdkCA" prohibits the specified algorithm only if the algorithm is used
+#     in a certificate chain that terminates at a marked trust anchor in the
+#     lib/security/cacerts keystore.  All other chains are not affected.
+#     If the jdkCA constraint is not set, then all chains using the
+#     specified algorithm are restricted.  jdkCA may only be used once in
+#     a DisabledAlgorithm expression.
+#     Example:  To apply this constraint to SHA-1 certificates, include
+#     the following:  "SHA1 jdkCA"
+#
+# When an algorithm must satisfy more than one constraint, it must be
+# delimited by an ampersand '&'.  For example, to restrict certificates in a
+# chain that terminate at a distribution provided trust anchor and contain
+# RSA keys that are less than or equal to 1024 bits, add the following
+# constraint:  "RSA keySize <= 1024 & jdkCA".
+#
+# All DisabledAlgorithms expressions are processed in the order defined in the
+# property.  This requires lower keysize constraints to be specified
+# before larger keysize constraints of the same algorithm.  For example:
+# "RSA keySize < 1024 & jdkCA, RSA keySize < 2048".
+#
 # Note: This property is currently used by Oracle's PKIX implementation. It
 # is not guaranteed to be examined and used by other implementations.
 #
--- a/jdk/src/java.base/solaris/classes/sun/nio/fs/SolarisFileSystem.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/solaris/classes/sun/nio/fs/SolarisFileSystem.java	Tue May 03 12:25:20 2016 -0700
@@ -42,7 +42,7 @@
         super(provider, dir);
 
         // check os.version
-        String osversion = GetPropertyAction.getProperty("os.version");
+        String osversion = GetPropertyAction.privilegedGetProperty("os.version");
         String[] vers = Util.split(osversion, '.');
         assert vers.length >= 2;
         int majorVersion = Integer.parseInt(vers[0]);
--- a/jdk/src/java.base/solaris/classes/sun/nio/fs/SolarisFileSystemProvider.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/solaris/classes/sun/nio/fs/SolarisFileSystemProvider.java	Tue May 03 12:25:20 2016 -0700
@@ -85,7 +85,7 @@
     @Override
     FileTypeDetector getFileTypeDetector() {
         Path userMimeTypes = Paths.get(
-            GetPropertyAction.getProperty("user.home"), ".mime.types");
+            GetPropertyAction.privilegedGetProperty("user.home"), ".mime.types");
         Path etcMimeTypes = Paths.get("/etc/mime.types");
 
         return chain(new GioFileTypeDetector(),
--- a/jdk/src/java.base/unix/classes/java/io/UnixFileSystem.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/unix/classes/java/io/UnixFileSystem.java	Tue May 03 12:25:20 2016 -0700
@@ -36,7 +36,7 @@
     private final String javaHome;
 
     public UnixFileSystem() {
-        Properties props = GetPropertyAction.getProperties();
+        Properties props = GetPropertyAction.privilegedGetProperties();
         slash = props.getProperty("file.separator").charAt(0);
         colon = props.getProperty("path.separator").charAt(0);
         javaHome = props.getProperty("java.home");
--- a/jdk/src/java.base/unix/classes/java/lang/ProcessImpl.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/unix/classes/java/lang/ProcessImpl.java	Tue May 03 12:25:20 2016 -0700
@@ -125,7 +125,7 @@
         }
 
         String helperPath() {
-            Properties props = GetPropertyAction.getProperties();
+            Properties props = GetPropertyAction.privilegedGetProperties();
             return helperPath(props.getProperty("java.home"),
                               props.getProperty("os.arch"));
         }
@@ -159,7 +159,7 @@
         }
 
         static Platform get() {
-            String osName = GetPropertyAction.getProperty("os.name");
+            String osName = GetPropertyAction.privilegedGetProperty("os.name");
 
             if (osName.equals("Linux")) { return LINUX; }
             if (osName.contains("OS X")) { return BSD; }
--- a/jdk/src/java.base/unix/classes/java/net/DefaultDatagramSocketImplFactory.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/unix/classes/java/net/DefaultDatagramSocketImplFactory.java	Tue May 03 12:25:20 2016 -0700
@@ -40,7 +40,7 @@
     static {
         String prefix = null;
         try {
-            prefix = GetPropertyAction.getProperty("impl.prefix", null);
+            prefix = GetPropertyAction.privilegedGetProperty("impl.prefix");
             if (prefix != null)
                 prefixImplClass = Class.forName("java.net."+prefix+"DatagramSocketImpl");
         } catch (Exception e) {
@@ -61,7 +61,9 @@
         throws SocketException {
         if (prefixImplClass != null) {
             try {
-                return (DatagramSocketImpl)prefixImplClass.newInstance();
+                @SuppressWarnings("deprecation")
+                DatagramSocketImpl result = (DatagramSocketImpl)prefixImplClass.newInstance();
+                return result;
             } catch (Exception e) {
                 throw new SocketException("can't instantiate DatagramSocketImpl");
             }
--- a/jdk/src/java.base/unix/classes/sun/net/NetHooks.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/unix/classes/sun/net/NetHooks.java	Tue May 03 12:25:20 2016 -0700
@@ -28,9 +28,6 @@
 import java.net.InetAddress;
 import java.io.FileDescriptor;
 import java.io.IOException;
-import java.security.AccessController;
-import java.security.PrivilegedAction;
-import sun.security.action.GetPropertyAction;
 
 /**
  * Defines static methods to be invoked prior to binding or connecting TCP sockets.
--- a/jdk/src/java.base/unix/classes/sun/net/sdp/SdpProvider.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/unix/classes/sun/net/sdp/SdpProvider.java	Tue May 03 12:25:20 2016 -0700
@@ -55,8 +55,9 @@
     private PrintStream log;
 
     public SdpProvider() {
+        Properties props = GetPropertyAction.privilegedGetProperties();
         // if this property is not defined then there is nothing to do.
-        String file = GetPropertyAction.getProperty("com.sun.sdp.conf");
+        String file = props.getProperty("com.sun.sdp.conf");
         if (file == null) {
             this.enabled = false;
             this.rules = null;
@@ -65,17 +66,15 @@
 
         // load configuration file
         List<Rule> list = null;
-        if (file != null) {
-            try {
-                list = loadRulesFromFile(file);
-            } catch (IOException e) {
-                fail("Error reading %s: %s", file, e.getMessage());
-            }
+        try {
+            list = loadRulesFromFile(file);
+        } catch (IOException e) {
+            fail("Error reading %s: %s", file, e.getMessage());
         }
 
         // check if debugging is enabled
         PrintStream out = null;
-        String logfile = GetPropertyAction.getProperty("com.sun.sdp.debug");
+        String logfile = props.getProperty("com.sun.sdp.debug");
         if (logfile != null) {
             out = System.out;
             if (logfile.length() > 0) {
--- a/jdk/src/java.base/unix/classes/sun/net/www/protocol/http/ntlm/NTLMAuthentication.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/unix/classes/sun/net/www/protocol/http/ntlm/NTLMAuthentication.java	Tue May 03 12:25:20 2016 -0700
@@ -76,7 +76,7 @@
     private String hostname;
     /* Domain to use if not specified by user */
     private static String defaultDomain =
-            GetPropertyAction.getProperty("http.auth.ntlm.domain", "");
+            GetPropertyAction.privilegedGetProperty("http.auth.ntlm.domain", "");
 
     public static boolean supportsTransparentAuth () {
         return false;
@@ -141,7 +141,7 @@
         password = pw.getPassword();
         init0();
         try {
-            String version = GetPropertyAction.getProperty("ntlm.version");
+            String version = GetPropertyAction.privilegedGetProperty("ntlm.version");
             client = new Client(version, hostname, username, ntdomain, password);
         } catch (NTLMException ne) {
             try {
--- a/jdk/src/java.base/unix/classes/sun/nio/ch/DefaultAsynchronousChannelProvider.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/unix/classes/sun/nio/ch/DefaultAsynchronousChannelProvider.java	Tue May 03 12:25:20 2016 -0700
@@ -48,7 +48,9 @@
             throw new AssertionError(x);
         }
         try {
-            return c.newInstance();
+            @SuppressWarnings("deprecation")
+            AsynchronousChannelProvider result = c.newInstance();
+            return result;
         } catch (IllegalAccessException | InstantiationException x) {
             throw new AssertionError(x);
         }
@@ -59,7 +61,7 @@
      * Returns the default AsynchronousChannelProvider.
      */
     public static AsynchronousChannelProvider create() {
-        String osname = GetPropertyAction.getProperty("os.name");
+        String osname = GetPropertyAction.privilegedGetProperty("os.name");
         if (osname.equals("SunOS"))
             return createProvider("sun.nio.ch.SolarisAsynchronousChannelProvider");
         if (osname.equals("Linux"))
--- a/jdk/src/java.base/unix/classes/sun/nio/ch/UnixAsynchronousSocketChannelImpl.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/unix/classes/sun/nio/ch/UnixAsynchronousSocketChannelImpl.java	Tue May 03 12:25:20 2016 -0700
@@ -46,8 +46,8 @@
 
     private static final boolean disableSynchronousRead;
     static {
-        String propValue = GetPropertyAction
-                .getProperty("sun.nio.ch.disableSynchronousRead", "false");
+        String propValue = GetPropertyAction.privilegedGetProperty(
+            "sun.nio.ch.disableSynchronousRead", "false");
         disableSynchronousRead = (propValue.length() == 0) ?
             true : Boolean.valueOf(propValue);
     }
--- a/jdk/src/java.base/unix/classes/sun/nio/fs/DefaultFileSystemProvider.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/unix/classes/sun/nio/fs/DefaultFileSystemProvider.java	Tue May 03 12:25:20 2016 -0700
@@ -44,7 +44,9 @@
             throw new AssertionError(x);
         }
         try {
-            return c.newInstance();
+            @SuppressWarnings("deprecation")
+            FileSystemProvider result = c.newInstance();
+            return result;
         } catch (IllegalAccessException | InstantiationException x) {
             throw new AssertionError(x);
         }
@@ -54,7 +56,7 @@
      * Returns the default FileSystemProvider.
      */
     public static FileSystemProvider create() {
-        String osname = GetPropertyAction.getProperty("os.name");
+        String osname = GetPropertyAction.privilegedGetProperty("os.name");
         if (osname.equals("SunOS"))
             return createProvider("sun.nio.fs.SolarisFileSystemProvider");
         if (osname.equals("Linux"))
--- a/jdk/src/java.base/unix/classes/sun/nio/fs/UnixFileSystem.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/unix/classes/sun/nio/fs/UnixFileSystem.java	Tue May 03 12:25:20 2016 -0700
@@ -57,7 +57,7 @@
         // process working directory then paths must be resolved against the
         // default directory.
         String propValue = GetPropertyAction
-                .getProperty("sun.nio.fs.chdirAllowed", "false");
+                .privilegedGetProperty("sun.nio.fs.chdirAllowed", "false");
         boolean chdirAllowed = (propValue.length() == 0) ?
             true : Boolean.valueOf(propValue);
         if (chdirAllowed) {
--- a/jdk/src/java.base/windows/classes/java/io/WinNTFileSystem.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/windows/classes/java/io/WinNTFileSystem.java	Tue May 03 12:25:20 2016 -0700
@@ -42,7 +42,7 @@
     private final char semicolon;
 
     public WinNTFileSystem() {
-        Properties props = GetPropertyAction.getProperties();
+        Properties props = GetPropertyAction.privilegedGetProperties();
         slash = props.getProperty("file.separator").charAt(0);
         semicolon = props.getProperty("path.separator").charAt(0);
         altSlash = (this.slash == '\\') ? '/' : '\\';
--- a/jdk/src/java.base/windows/classes/java/net/DefaultDatagramSocketImplFactory.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/windows/classes/java/net/DefaultDatagramSocketImplFactory.java	Tue May 03 12:25:20 2016 -0700
@@ -56,7 +56,7 @@
     static {
         Class<?> prefixImplClassLocal = null;
 
-        Properties props = GetPropertyAction.getProperties();
+        Properties props = GetPropertyAction.privilegedGetProperties();
         preferIPv4Stack = Boolean.parseBoolean(
                 props.getProperty("java.net.preferIPv4Stack"));
 
@@ -90,7 +90,9 @@
         throws SocketException {
         if (prefixImplClass != null) {
             try {
-                return (DatagramSocketImpl) prefixImplClass.newInstance();
+                @SuppressWarnings("deprecation")
+                Object result = prefixImplClass.newInstance();
+                return (DatagramSocketImpl) result;
             } catch (Exception e) {
                 throw new SocketException("can't instantiate DatagramSocketImpl");
             }
--- a/jdk/src/java.base/windows/classes/sun/net/www/protocol/http/ntlm/NTLMAuthentication.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/windows/classes/sun/net/www/protocol/http/ntlm/NTLMAuthentication.java	Tue May 03 12:25:20 2016 -0700
@@ -53,8 +53,8 @@
     private static String defaultDomain; /* Domain to use if not specified by user */
 
     static {
-        defaultDomain = GetPropertyAction.getProperty("http.auth.ntlm.domain",
-                                                      "domain");
+        defaultDomain = GetPropertyAction
+                .privilegedGetProperty("http.auth.ntlm.domain", "domain");
     };
 
     private void init0() {
--- a/jdk/src/java.base/windows/classes/sun/nio/ch/FileDispatcherImpl.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/windows/classes/sun/nio/ch/FileDispatcherImpl.java	Tue May 03 12:25:20 2016 -0700
@@ -120,7 +120,7 @@
 
     static boolean isFastFileTransferRequested() {
         String fileTransferProp = GetPropertyAction
-                .getProperty("jdk.nio.enableFastFileTransfer");
+                .privilegedGetProperty("jdk.nio.enableFastFileTransfer");
         boolean enable;
         if ("".equals(fileTransferProp)) {
             enable = true;
--- a/jdk/src/java.base/windows/classes/sun/nio/fs/WindowsFileAttributes.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/windows/classes/sun/nio/fs/WindowsFileAttributes.java	Tue May 03 12:25:20 2016 -0700
@@ -114,8 +114,8 @@
     // indicates if accurate metadata is required (interesting on NTFS only)
     private static final boolean ensureAccurateMetadata;
     static {
-        String propValue = GetPropertyAction
-                .getProperty("sun.nio.fs.ensureAccurateMetadata", "false");
+        String propValue = GetPropertyAction.privilegedGetProperty(
+            "sun.nio.fs.ensureAccurateMetadata", "false");
         ensureAccurateMetadata = (propValue.length() == 0) ?
             true : Boolean.valueOf(propValue);
     }
--- a/jdk/src/java.base/windows/classes/sun/nio/fs/WindowsWatchService.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.base/windows/classes/sun/nio/fs/WindowsWatchService.java	Tue May 03 12:25:20 2016 -0700
@@ -113,6 +113,10 @@
         // completion key (used to map I/O completion to WatchKey)
         private int completionKey;
 
+        // flag indicates that ReadDirectoryChangesW failed
+        // and overlapped I/O operation wasn't started
+        private boolean errorStartingOverlapped;
+
         WindowsWatchKey(Path dir,
                         AbstractWatchService watcher,
                         FileKey fileKey)
@@ -175,6 +179,14 @@
             return completionKey;
         }
 
+        void setErrorStartingOverlapped(boolean value) {
+            errorStartingOverlapped = value;
+        }
+
+        boolean isErrorStartingOverlapped() {
+            return errorStartingOverlapped;
+        }
+
         // Invalidate the key, assumes that resources have been released
         void invalidate() {
             ((WindowsWatchService)watcher()).poller.releaseResources(this);
@@ -182,6 +194,7 @@
             buffer = null;
             countAddress = 0;
             overlappedAddress = 0;
+            errorStartingOverlapped = false;
         }
 
         @Override
@@ -455,11 +468,13 @@
          * resources.
          */
         private void releaseResources(WindowsWatchKey key) {
-            try {
-                CancelIo(key.handle());
-                GetOverlappedResult(key.handle(), key.overlappedAddress());
-            } catch (WindowsException expected) {
-                // expected as I/O operation has been cancelled
+            if (!key.isErrorStartingOverlapped()) {
+                try {
+                    CancelIo(key.handle());
+                    GetOverlappedResult(key.handle(), key.overlappedAddress());
+                } catch (WindowsException expected) {
+                    // expected as I/O operation has been cancelled
+                }
             }
             CloseHandle(key.handle());
             closeAttachedEvent(key.overlappedAddress());
@@ -628,6 +643,7 @@
                     } catch (WindowsException x) {
                         // no choice but to cancel key
                         criticalError = true;
+                        key.setErrorStartingOverlapped(true);
                     }
                 }
                 if (criticalError) {
--- a/jdk/src/java.desktop/unix/native/libawt_xawt/awt/awt_InputMethod.c	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.desktop/unix/native/libawt_xawt/awt/awt_InputMethod.c	Tue May 03 12:25:20 2016 -0700
@@ -30,6 +30,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <X11/Xlib.h>
+#include <X11/keysym.h>
 #include <sys/time.h>
 
 #include "awt.h"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/AsyncConnection.java	Tue May 03 12:25:20 2016 -0700
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ */
+package java.net.http;
+
+import java.nio.ByteBuffer;
+import java.util.function.Consumer;
+
+/**
+ * Implemented by classes that offer an asynchronous interface.
+ *
+ * PlainHttpConnection, AsyncSSLConnection AsyncSSLDelegate.
+ *
+ * setAsyncCallbacks() is called to set the callback for reading
+ * and error notification. Reads all happen on the selector thread, which
+ * must not block.
+ *
+ * Writing uses the same write() methods as used in blocking mode.
+ * Queues are employed on the writing side to buffer data while it is waiting
+ * to be sent. This strategy relies on HTTP/2 protocol flow control to stop
+ * outgoing queue from continually growing. Writes can be initiated by the
+ * calling thread, but if socket becomes full then the queue is emptied by
+ * the selector thread
+ *
+ */
+interface AsyncConnection {
+
+    /**
+     * Enables asynchronous sending and receiving mode. The given async
+     * receiver will receive all incoming data. asyncInput() will be called
+     * to trigger reads. asyncOutput() will be called to drive writes.
+     *
+     * The errorReceiver callback must be called when any fatal exception
+     * occurs. Connection is assumed to be closed afterwards.
+     *
+     * @param asyncReceiver
+     * @param errorReceiver
+     */
+    void setAsyncCallbacks(
+            Consumer<ByteBuffer> asyncReceiver,
+            Consumer<Throwable> errorReceiver);
+
+    /**
+     * Does whatever is required to start reading. Usually registers
+     * an event with the selector thread.
+     */
+    void startReading();
+}
--- a/jdk/src/java.httpclient/share/classes/java/net/http/AsyncEvent.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/AsyncEvent.java	Tue May 03 12:25:20 2016 -0700
@@ -25,24 +25,27 @@
 package java.net.http;
 
 import java.nio.channels.SelectableChannel;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.SocketChannel;
 
 /**
  * Event handling interface from HttpClientImpl's selector.
  *
- * <p> If blockingChannel is true, then the channel will be put in blocking
+ * If BLOCKING is set, then the channel will be put in blocking
  * mode prior to handle() being called. If false, then it remains non-blocking.
+ *
+ * If REPEATING is set then the event is not cancelled after being posted.
  */
 abstract class AsyncEvent {
 
-    /**
-     * Implement this if channel should be made blocking before calling handle()
-     */
-    public interface Blocking { }
+    public static final int BLOCKING = 0x1; // non blocking if not set
+    public static final int REPEATING = 0x2; // one off event if not set
 
-    /**
-     * Implement this if channel should remain non-blocking before calling handle()
-     */
-    public interface NonBlocking { }
+    protected final int flags;
+
+    AsyncEvent(int flags) {
+        this.flags = flags;
+    }
 
     /** Returns the channel */
     public abstract SelectableChannel channel();
@@ -55,4 +58,12 @@
 
     /** Called when selector is shutting down. Abort all exchanges. */
     public abstract void abort();
+
+    public boolean blocking() {
+        return (flags & BLOCKING) != 0;
+    }
+
+    public boolean repeating() {
+        return (flags & REPEATING) != 0;
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/AsyncSSLConnection.java	Tue May 03 12:25:20 2016 -0700
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ */
+package java.net.http;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.nio.ByteBuffer;
+import java.nio.channels.SocketChannel;
+import java.util.concurrent.CompletableFuture;
+import java.util.function.Consumer;
+
+/**
+ * Asynchronous version of SSLConnection.
+ */
+class AsyncSSLConnection extends HttpConnection implements AsyncConnection {
+    final AsyncSSLDelegate sslDelegate;
+    final PlainHttpConnection delegate;
+
+    AsyncSSLConnection(InetSocketAddress addr, HttpClientImpl client, String[] ap) {
+        super(addr, client);
+        delegate = new PlainHttpConnection(addr, client);
+        sslDelegate = new AsyncSSLDelegate(delegate, client, ap);
+    }
+
+    @Override
+    public void connect() throws IOException, InterruptedException {
+        delegate.connect();
+    }
+
+    @Override
+    public CompletableFuture<Void> connectAsync() {
+        return delegate.connectAsync();
+    }
+
+    @Override
+    boolean connected() {
+        return delegate.connected();
+    }
+
+    @Override
+    boolean isSecure() {
+        return true;
+    }
+
+    @Override
+    boolean isProxied() {
+        return false;
+    }
+
+    @Override
+    SocketChannel channel() {
+        return delegate.channel();
+    }
+
+    @Override
+    ConnectionPool.CacheKey cacheKey() {
+        return ConnectionPool.cacheKey(address, null);
+    }
+
+    @Override
+    synchronized long write(ByteBuffer[] buffers, int start, int number) throws IOException {
+        ByteBuffer[] bufs = Utils.reduce(buffers, start, number);
+        long n = Utils.remaining(bufs);
+        sslDelegate.write(bufs);
+        return n;
+    }
+
+    @Override
+    long write(ByteBuffer buffer) throws IOException {
+        long n = buffer.remaining();
+        sslDelegate.write(buffer);
+        return n;
+    }
+
+    @Override
+    public void close() {
+        Utils.close(sslDelegate, delegate.channel());
+    }
+
+    @Override
+    public void setAsyncCallbacks(Consumer<ByteBuffer> asyncReceiver, Consumer<Throwable> errorReceiver) {
+        sslDelegate.setAsyncCallbacks(asyncReceiver, errorReceiver);
+        delegate.setAsyncCallbacks(sslDelegate::lowerRead, errorReceiver);
+    }
+
+    // Blocking read functions not used here
+
+    @Override
+    protected ByteBuffer readImpl(int length) throws IOException {
+        throw new UnsupportedOperationException("Not supported.");
+    }
+
+    @Override
+    protected int readImpl(ByteBuffer buffer) throws IOException {
+        throw new UnsupportedOperationException("Not supported.");
+    }
+
+    @Override
+    CompletableFuture<Void> whenReceivingResponse() {
+        throw new UnsupportedOperationException("Not supported.");
+    }
+
+    @Override
+    public void startReading() {
+        delegate.startReading();
+        sslDelegate.startReading();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/AsyncSSLDelegate.java	Tue May 03 12:25:20 2016 -0700
@@ -0,0 +1,598 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ */
+package java.net.http;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.LinkedList;
+import java.util.concurrent.ExecutorService;
+import java.util.function.Consumer;
+import static javax.net.ssl.SSLEngineResult.Status.*;
+import javax.net.ssl.*;
+import static javax.net.ssl.SSLEngineResult.HandshakeStatus.*;
+
+/**
+ * Asynchronous wrapper around SSLEngine. send and receive is fully non
+ * blocking. When handshaking is required, a thread is created to perform
+ * the handshake and application level sends do not take place during this time.
+ *
+ * Is implemented using queues and functions operating on the receiving end
+ * of each queue.
+ *
+ * Application writes to:
+ *        ||
+ *        \/
+ *     appOutputQ
+ *        ||
+ *        \/
+ * appOutputQ read by "upperWrite" method which does SSLEngine.wrap
+ * and writes to
+ *        ||
+ *        \/
+ *     channelOutputQ
+ *        ||
+ *        \/
+ * channelOutputQ is read by "lowerWrite" method which is invoked from
+ * OP_WRITE events on the socket (from selector thread)
+ *
+ * Reading side is as follows
+ * --------------------------
+ *
+ * "upperRead" method reads off channelInputQ and calls SSLEngine.unwrap and
+ * when decrypted data is returned, it is passed to the user's Consumer<ByteBuffer>
+ *        /\
+ *        ||
+ *     channelInputQ
+ *        /\
+ *        ||
+ * "lowerRead" method puts buffers into channelInputQ. It is invoked from
+ * OP_READ events from the selector.
+ *
+ * Whenever handshaking is required, the doHandshaking() method is called
+ * which creates a thread to complete the handshake. It takes over the
+ * channelInputQ from upperRead, and puts outgoing packets on channelOutputQ.
+ * Selector events are delivered to lowerRead and lowerWrite as normal.
+ *
+ * Errors
+ *
+ * Any exception thrown by the engine or channel, causes all Queues to be closed
+ * the channel to be closed, and the error is reported to the user's
+ * Consumer<Throwable>
+ */
+public class AsyncSSLDelegate implements Closeable, AsyncConnection {
+
+    // outgoing buffers put in this queue first and may remain here
+    // while SSL handshaking happening.
+    final Queue<ByteBuffer> appOutputQ;
+
+    // queue of wrapped ByteBuffers waiting to be sent on socket channel
+    //final Queue<ByteBuffer> channelOutputQ;
+
+    // Bytes read into this queue before being unwrapped. Backup on this
+    // Q should only happen when the engine is stalled due to delegated tasks
+    final Queue<ByteBuffer> channelInputQ;
+
+    // input occurs through the read() method which is expected to be called
+    // when the selector signals some data is waiting to be read. All incoming
+    // handshake data is handled in this method, which means some calls to
+    // read() may return zero bytes of user data. This is not a sign of spinning,
+    // just that the handshake mechanics are being executed.
+
+    final SSLEngine engine;
+    final SSLParameters sslParameters;
+    //final SocketChannel chan;
+    final HttpConnection lowerOutput;
+    final HttpClientImpl client;
+    final ExecutorService executor;
+    final BufferHandler bufPool;
+    Consumer<ByteBuffer> receiver;
+    Consumer<Throwable> errorHandler;
+    // Locks.
+    final Object reader = new Object();
+    final Object writer = new Object();
+    // synchronizing handshake state
+    final Object handshaker = new Object();
+    // flag set when reader or writer is blocked waiting for handshake to finish
+    boolean writerBlocked;
+    boolean readerBlocked;
+
+    // some thread is currently doing the handshake
+    boolean handshaking;
+
+    // alpn[] may be null. upcall is callback which receives incoming decoded bytes off socket
+
+    AsyncSSLDelegate(HttpConnection lowerOutput, HttpClientImpl client, String[] alpn)
+    {
+        SSLContext context = client.sslContext();
+        executor = client.executorService();
+        bufPool = client;
+        appOutputQ = new Queue<>();
+        appOutputQ.registerPutCallback(this::upperWrite);
+        //channelOutputQ = new Queue<>();
+        //channelOutputQ.registerPutCallback(this::lowerWrite);
+        engine = context.createSSLEngine();
+        engine.setUseClientMode(true);
+        SSLParameters sslp = client.sslParameters().orElse(null);
+        if (sslp == null) {
+            sslp = context.getSupportedSSLParameters();
+            //sslp = context.getDefaultSSLParameters();
+            //printParams(sslp);
+        }
+        sslParameters = Utils.copySSLParameters(sslp);
+        if (alpn != null) {
+            sslParameters.setApplicationProtocols(alpn);
+            Log.logSSL("Setting application protocols: " + Arrays.toString(alpn));
+        } else {
+            Log.logSSL("No application protocols proposed");
+        }
+        engine.setSSLParameters(sslParameters);
+        engine.setEnabledCipherSuites(sslp.getCipherSuites());
+        engine.setEnabledProtocols(sslp.getProtocols());
+        this.lowerOutput = lowerOutput;
+        this.client = client;
+        this.channelInputQ = new Queue<>();
+        this.channelInputQ.registerPutCallback(this::upperRead);
+    }
+
+    /**
+     * Put buffers to appOutputQ, and call upperWrite() if q was empty.
+     *
+     * @param src
+     */
+    public void write(ByteBuffer[] src) throws IOException {
+        appOutputQ.putAll(src);
+    }
+
+    public void write(ByteBuffer buf) throws IOException {
+        ByteBuffer[] a = new ByteBuffer[1];
+        a[0] = buf;
+        write(a);
+    }
+
+    @Override
+    public void close() {
+        Utils.close(appOutputQ, channelInputQ, lowerOutput);
+    }
+
+    /**
+     * Attempts to wrap buffers from appOutputQ and place them on the
+     * channelOutputQ for writing. If handshaking is happening, then the
+     * process stalls and last buffers taken off the appOutputQ are put back
+     * into it until handshaking completes.
+     *
+     * This same method is called to try and resume output after a blocking
+     * handshaking operation has completed.
+     */
+    private void upperWrite() {
+        try {
+            EngineResult r = null;
+            ByteBuffer[] buffers = appOutputQ.pollAll(Utils.EMPTY_BB_ARRAY);
+            int bytes = Utils.remaining(buffers);
+            while (bytes > 0) {
+                synchronized (writer) {
+                    r = wrapBuffers(buffers);
+                    int bytesProduced = r.bytesProduced();
+                    int bytesConsumed = r.bytesConsumed();
+                    bytes -= bytesConsumed;
+                    if (bytesProduced > 0) {
+                        // pass destination buffer to channelOutputQ.
+                        lowerOutput.write(r.destBuffer);
+                    }
+                    synchronized (handshaker) {
+                        if (r.handshaking()) {
+                            // handshaking is happening or is needed
+                            // so we put the buffers back on Q to process again
+                            // later. It's possible that some may have already
+                            // been processed, which is ok.
+                            appOutputQ.pushbackAll(buffers);
+                            writerBlocked = true;
+                            if (!handshaking()) {
+                                // execute the handshake in another thread.
+                                // This method will be called again to resume sending
+                                // later
+                                doHandshake(r);
+                            }
+                            return;
+                        }
+                    }
+                }
+            }
+            returnBuffers(buffers);
+        } catch (Throwable t) {
+            t.printStackTrace();
+            close();
+        }
+    }
+
+    private void doHandshake(EngineResult r) {
+        handshaking = true;
+        channelInputQ.registerPutCallback(null);
+        executor.execute(() -> {
+            try {
+                doHandshakeImpl(r);
+                channelInputQ.registerPutCallback(this::upperRead);
+            } catch (Throwable t) {
+                t.printStackTrace();
+                close();
+            }
+        });
+    }
+
+    private void returnBuffers(ByteBuffer[] bufs) {
+        for (ByteBuffer buf : bufs)
+            client.returnBuffer(buf);
+    }
+
+    /**
+     * Return true if some thread is currently doing the handshake
+     *
+     * @return
+     */
+    boolean handshaking() {
+        synchronized(handshaker) {
+            return handshaking;
+        }
+    }
+
+    /**
+     * Executes entire handshake in calling thread.
+     * Returns after handshake is completed or error occurs
+     * @param r
+     * @throws IOException
+     */
+    private void doHandshakeImpl(EngineResult r) throws IOException {
+        while (true) {
+            SSLEngineResult.HandshakeStatus status = r.handshakeStatus();
+            if (status == NEED_TASK) {
+                LinkedList<Runnable> tasks = obtainTasks();
+                for (Runnable task : tasks)
+                    task.run();
+                r = handshakeWrapAndSend();
+            } else if (status == NEED_WRAP) {
+                r = handshakeWrapAndSend();
+            } else if (status == NEED_UNWRAP) {
+                r = handshakeReceiveAndUnWrap();
+            }
+            if (!r.handshaking())
+                break;
+        }
+        boolean dowrite = false;
+        boolean doread = false;
+        // Handshake is finished. Now resume reading and/or writing
+        synchronized(handshaker) {
+            handshaking = false;
+            if (writerBlocked) {
+                writerBlocked = false;
+                dowrite = true;
+            }
+            if (readerBlocked) {
+                readerBlocked = false;
+                doread = true;
+            }
+        }
+        if (dowrite)
+            upperWrite();
+        if (doread)
+            upperRead();
+    }
+
+    // acknowledge a received CLOSE request from peer
+    void doClosure() throws IOException {
+        //while (!wrapAndSend(emptyArray))
+            //;
+    }
+
+    LinkedList<Runnable> obtainTasks() {
+        LinkedList<Runnable> l = new LinkedList<>();
+        Runnable r;
+        while ((r = engine.getDelegatedTask()) != null)
+            l.add(r);
+        return l;
+    }
+
+    @Override
+    public synchronized void setAsyncCallbacks(Consumer<ByteBuffer> asyncReceiver, Consumer<Throwable> errorReceiver) {
+        this.receiver = asyncReceiver;
+        this.errorHandler = errorReceiver;
+    }
+
+    @Override
+    public void startReading() {
+        // maybe this class does not need to implement AsyncConnection
+    }
+
+    static class EngineResult {
+        ByteBuffer destBuffer;
+        ByteBuffer srcBuffer;
+        SSLEngineResult result;
+        Throwable t;
+
+        boolean handshaking() {
+            SSLEngineResult.HandshakeStatus s = result.getHandshakeStatus();
+            return s != FINISHED && s != NOT_HANDSHAKING;
+        }
+
+        int bytesConsumed() {
+            return result.bytesConsumed();
+        }
+
+        int bytesProduced() {
+            return result.bytesProduced();
+        }
+
+        Throwable exception() {
+            return t;
+        }
+
+        SSLEngineResult.HandshakeStatus handshakeStatus() {
+            return result.getHandshakeStatus();
+        }
+
+        SSLEngineResult.Status status() {
+            return result.getStatus();
+        }
+    }
+
+    EngineResult handshakeWrapAndSend() throws IOException {
+        EngineResult r = wrapBuffer(Utils.EMPTY_BYTEBUFFER);
+        if (r.bytesProduced() > 0) {
+            lowerOutput.write(r.destBuffer);
+        }
+        return r;
+    }
+
+    // called during handshaking. It blocks until a complete packet
+    // is available, unwraps it and returns.
+    EngineResult handshakeReceiveAndUnWrap() throws IOException {
+        ByteBuffer buf = channelInputQ.take();
+        while (true) {
+            // block waiting for input
+            EngineResult r = unwrapBuffer(buf);
+            SSLEngineResult.Status status = r.status();
+            if (status == BUFFER_UNDERFLOW) {
+                // wait for another buffer to arrive
+                ByteBuffer buf1 = channelInputQ.take();
+                buf = combine (buf, buf1);
+                continue;
+            }
+            // OK
+            // theoretically possible we could receive some user data
+            if (r.bytesProduced() > 0) {
+                receiver.accept(r.destBuffer);
+            }
+            if (!buf.hasRemaining())
+                return r;
+        }
+    }
+
+    EngineResult wrapBuffer(ByteBuffer src) throws SSLException {
+        ByteBuffer[] bufs = new ByteBuffer[1];
+        bufs[0] = src;
+        return wrapBuffers(bufs);
+    }
+
+    EngineResult wrapBuffers(ByteBuffer[] src) throws SSLException {
+        EngineResult r = new EngineResult();
+        ByteBuffer dst = bufPool.getBuffer();
+        while (true) {
+            r.result = engine.wrap(src, dst);
+            switch (r.result.getStatus()) {
+                case BUFFER_OVERFLOW:
+                    dst = getPacketBuffer();
+                    break;
+                case CLOSED:
+                case OK:
+                    dst.flip();
+                    r.destBuffer = dst;
+                    return r;
+                case BUFFER_UNDERFLOW:
+                    // underflow handled externally
+                    bufPool.returnBuffer(dst);
+                    return r;
+                default:
+                    assert false;
+            }
+        }
+    }
+
+    EngineResult unwrapBuffer(ByteBuffer srcbuf) throws IOException {
+        EngineResult r = new EngineResult();
+        r.srcBuffer = srcbuf;
+
+        ByteBuffer dst = bufPool.getBuffer();
+        while (true) {
+            r.result = engine.unwrap(srcbuf, dst);
+            switch (r.result.getStatus()) {
+                case BUFFER_OVERFLOW:
+                    // dest buffer not big enough. Reallocate
+                    int oldcap = dst.capacity();
+                    dst = getApplicationBuffer();
+                    assert dst.capacity() > oldcap;
+                    break;
+                case CLOSED:
+                    doClosure();
+                    throw new IOException("Engine closed");
+                case BUFFER_UNDERFLOW:
+                    bufPool.returnBuffer(dst);
+                    return r;
+                case OK:
+                    dst.flip();
+                    r.destBuffer = dst;
+                    return r;
+            }
+        }
+    }
+
+    /**
+     * Asynchronous read input. Call this when selector fires.
+     * Unwrap done in upperRead because it also happens in
+     * doHandshake() when handshake taking place
+     */
+    public void lowerRead(ByteBuffer buffer) {
+        try {
+            channelInputQ.put(buffer);
+        } catch (Throwable t) {
+            close();
+            errorHandler.accept(t);
+        }
+    }
+
+    public void upperRead() {
+        EngineResult r;
+        ByteBuffer srcbuf;
+        synchronized (reader) {
+            try {
+                srcbuf = channelInputQ.poll();
+                if (srcbuf == null) {
+                    return;
+                }
+                while (true) {
+                    r = unwrapBuffer(srcbuf);
+                    switch (r.result.getStatus()) {
+                        case BUFFER_UNDERFLOW:
+                            // Buffer too small. Need to combine with next buf
+                            ByteBuffer nextBuf = channelInputQ.poll();
+                            if (nextBuf == null) {
+                                // no data available. push buffer back until more data available
+                                channelInputQ.pushback(srcbuf);
+                                return;
+                            } else {
+                                srcbuf = combine(srcbuf, nextBuf);
+                            }
+                            break;
+                        case OK:
+                            // check for any handshaking work
+                            synchronized (handshaker) {
+                                if (r.handshaking()) {
+                                    // handshaking is happening or is needed
+                                    // so we put the buffer back on Q to process again
+                                    // later.
+                                    channelInputQ.pushback(srcbuf);
+                                    readerBlocked = true;
+                                    if (!handshaking()) {
+                                        // execute the handshake in another thread.
+                                        // This method will be called again to resume sending
+                                        // later
+                                        doHandshake(r);
+                                    }
+                                    return;
+                                }
+                            }
+                            ByteBuffer dst = r.destBuffer;
+                            if (dst.hasRemaining()) {
+                                receiver.accept(dst);
+                            }
+                    }
+                    if (srcbuf.hasRemaining()) {
+                        continue;
+                    }
+                    srcbuf = channelInputQ.poll();
+                    if (srcbuf == null) {
+                        return;
+                    }
+                }
+            } catch (Throwable t) {
+                Utils.close(lowerOutput);
+                errorHandler.accept(t);
+            }
+        }
+    }
+
+    /**
+     * Get a new buffer that is the right size for application buffers.
+     *
+     * @return
+     */
+    ByteBuffer getApplicationBuffer() {
+        SSLSession session = engine.getSession();
+        int appBufsize = session.getApplicationBufferSize();
+        bufPool.setMinBufferSize(appBufsize);
+        return bufPool.getBuffer(appBufsize);
+    }
+
+    ByteBuffer getPacketBuffer() {
+        SSLSession session = engine.getSession();
+        int packetBufSize = session.getPacketBufferSize();
+        bufPool.setMinBufferSize(packetBufSize);
+        return bufPool.getBuffer(packetBufSize);
+    }
+
+    ByteBuffer combine(ByteBuffer buf1, ByteBuffer buf2) {
+        int avail1 = buf1.capacity() - buf1.remaining();
+        if (buf2.remaining() < avail1) {
+            buf1.compact();
+            buf1.put(buf2);
+            buf1.flip();
+            return buf1;
+        }
+        int newsize = buf1.remaining() + buf2.remaining();
+        ByteBuffer newbuf = bufPool.getBuffer(newsize);
+        newbuf.put(buf1);
+        newbuf.put(buf2);
+        newbuf.flip();
+        return newbuf;
+    }
+
+    SSLParameters getSSLParameters() {
+        return sslParameters;
+    }
+
+    static void printParams(SSLParameters p) {
+        System.out.println("SSLParameters:");
+        if (p == null) {
+            System.out.println("Null params");
+            return;
+        }
+        for (String cipher : p.getCipherSuites()) {
+                System.out.printf("cipher: %s\n", cipher);
+        }
+        for (String approto : p.getApplicationProtocols()) {
+                System.out.printf("application protocol: %s\n", approto);
+        }
+        for (String protocol : p.getProtocols()) {
+                System.out.printf("protocol: %s\n", protocol);
+        }
+        if (p.getServerNames() != null)
+        for (SNIServerName sname : p.getServerNames()) {
+                System.out.printf("server name: %s\n", sname.toString());
+        }
+    }
+
+    String getSessionInfo() {
+        StringBuilder sb = new StringBuilder();
+        String application = engine.getApplicationProtocol();
+        SSLSession sess = engine.getSession();
+        String cipher = sess.getCipherSuite();
+        String protocol = sess.getProtocol();
+        sb.append("Handshake complete alpn: ")
+                .append(application)
+                .append(", Cipher: ")
+                .append(cipher)
+                .append(", Protocol: ")
+                .append(protocol);
+        return sb.toString();
+    }
+}
--- a/jdk/src/java.httpclient/share/classes/java/net/http/AuthenticationFilter.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/AuthenticationFilter.java	Tue May 03 12:25:20 2016 -0700
@@ -45,7 +45,7 @@
     static final int DEFAULT_RETRY_LIMIT = 3;
 
     static final int retry_limit = Utils.getIntegerNetProperty(
-            "sun.net.httpclient.auth.retrylimit", DEFAULT_RETRY_LIMIT);
+            "java.net.httpclient.auth.retrylimit", DEFAULT_RETRY_LIMIT);
 
     static final int UNAUTHORIZED = 401;
     static final int PROXY_UNAUTHORIZED = 407;
--- a/jdk/src/java.httpclient/share/classes/java/net/http/BufferHandler.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/BufferHandler.java	Tue May 03 12:25:20 2016 -0700
@@ -27,11 +27,23 @@
 import java.nio.ByteBuffer;
 
 /**
- * Implemented by buffer pools.
+ * Implemented by buffer pools. A buffer pool has a current buffer size
+ * (number of bytes in each buffer) which may increase over time.
  */
 interface BufferHandler {
 
-    ByteBuffer getBuffer();
+    default ByteBuffer getBuffer() {
+        return getBuffer(-1);
+    }
+
+    void setMinBufferSize(int size);
+
+    /**
+     * size == -1 means return any sized buffer. Any other value means
+     * @param size
+     * @return
+     */
+    ByteBuffer getBuffer(int size);
 
     void returnBuffer(ByteBuffer buffer);
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/ByteBufferConsumer.java	Tue May 03 12:25:20 2016 -0700
@@ -0,0 +1,188 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ */
+
+package java.net.http;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.function.Supplier;
+
+/**
+ * Takes a List<ByteBuffer> which is assumed to contain at least one HTTP/2
+ * frame and allows it to be processed supplying bytes, ints, shorts, byte[] etc.
+ * from the list. As each ByteBuffer is consumed it is removed from the List<>.
+ *
+ * NOTE. shorts and bytes returned are UNSIGNED ints
+ *
+ * When finished processing the frame, the List may be empty or may contain
+ * partially read or unread ByteBuffers. A new ByteBufferConsumer can be
+ * created with the List<>
+ */
+class ByteBufferConsumer {
+
+    ByteBuffer currentBuffer;
+
+    final List<ByteBuffer> buffers;
+    final ListIterator<ByteBuffer> iterator;
+    final Supplier<ByteBuffer> newBufferSupplier;
+
+    ByteBufferConsumer(List<ByteBuffer> buffers,
+                       Supplier<ByteBuffer> newBufferSupplier) {
+        this.buffers = buffers;
+        this.newBufferSupplier = newBufferSupplier;
+        this.iterator = buffers.listIterator();
+        if (!iterator.hasNext()) {
+            throw new IllegalArgumentException("Empty buffer list");
+        }
+        currentBuffer = iterator.next();
+    }
+
+    private void dump() {
+        int l = 0;
+        System.err.printf("ByteBufferConsumer:\n");
+        for (ByteBuffer buf : buffers) {
+            System.err.printf("\t%s\n", buf.toString());
+            l+= buf.remaining();
+        }
+        System.err.printf("BBC contains %d bytes\n", l);
+    }
+
+    private synchronized ByteBuffer getBuffer(boolean exception) throws IOException {
+        while (currentBuffer == null || !currentBuffer.hasRemaining()) {
+            if (currentBuffer != null) {
+                iterator.remove();
+            }
+            if (!iterator.hasNext()) {
+                currentBuffer = null;
+                if (exception) {
+                    throw new IOException ("Connection closed unexpectedly");
+                }
+                return null;
+            }
+            currentBuffer = iterator.next();
+        }
+        return currentBuffer;
+    }
+
+    // call this to check if the data has all been consumed
+
+    public boolean consumed() {
+        try {
+            return getBuffer(false) == null;
+        } catch (IOException e) {
+            /* CAN'T HAPPEN */
+            throw new InternalError();
+        }
+    }
+
+    public int getByte() throws IOException {
+        // TODO: what to do if connection is closed. Throw NPE?
+        ByteBuffer buf = getBuffer(true);
+        return buf.get() & 0xff;
+    }
+
+    public byte[] getBytes(int n) throws IOException {
+        return getBytes(n, null);
+    }
+
+    public byte[] getBytes(int n, byte[] buf) throws IOException {
+        if (buf == null) {
+            buf = new byte[n];
+        } else if (buf.length < n) {
+            throw new IllegalArgumentException("getBytes: buffer too small");
+        }
+        int offset = 0;
+        while (n > 0) {
+            ByteBuffer b = getBuffer(true);
+            int length = Math.min(n, b.remaining());
+            b.get(buf, offset, length);
+            offset += length;
+            n -= length;
+        }
+        return buf;
+    }
+
+    public int getShort() throws IOException {
+        ByteBuffer buf = getBuffer(true);
+        int rem = buf.remaining();
+        if (rem >= 2) {
+            return buf.getShort() & 0xffff;
+        }
+        // Slow path. Not common
+        int val = 0;
+        val = (val << 8) + getByte();
+        val = (val << 8) + getByte();
+        return val;
+    }
+
+    public int getInt() throws IOException {
+        ByteBuffer buf = getBuffer(true);
+        int rem = buf.remaining();
+        if (rem >= 4) {
+            return buf.getInt();
+        }
+        // Slow path. Not common
+        int val = 0;
+        for (int nbytes = 0; nbytes < 4; nbytes++) {
+            val = (val << 8) + getByte();
+        }
+        return val;
+    }
+
+    private static final ByteBuffer[] EMPTY = new ByteBuffer[0];
+
+    /**
+     * Extracts whatever number of ByteBuffers from list to get required number
+     * of bytes. Any remaining buffers are 'tidied up' so reading can continue.
+     */
+    public ByteBuffer[] getBuffers(int bytecount) throws IOException {
+        LinkedList<ByteBuffer> l = new LinkedList<>();
+        while (bytecount > 0) {
+            ByteBuffer buffer = getBuffer(true);
+            int remaining = buffer.remaining();
+            if (remaining > bytecount) {
+                int difference = remaining - bytecount;
+                // split
+                ByteBuffer newb = newBufferSupplier.get();
+                newb.clear();
+                int limit = buffer.limit();
+                buffer.limit(limit - difference);
+                newb.put(buffer);
+                newb.flip();
+                buffer.limit(limit);
+                l.add(newb);
+                bytecount = 0;
+            } else {
+                l.add(buffer);
+                currentBuffer = null;
+                iterator.remove();
+                bytecount -= remaining;
+            }
+        }
+        return l.toArray(EMPTY);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/ByteBufferGenerator.java	Tue May 03 12:25:20 2016 -0700
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ */
+
+package java.net.http;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+
+/**
+ * Manages a ByteBuffer[] for writing frames into for output. The last
+ * ByteBuffer in the list is always unflipped (able to receive more bytes for
+ * sending) until getBufferArray() is called, which calls finish().
+ *
+ * This allows multiple frames to be written to the same BBG.
+ *
+ * Buffers added with addByteBuffer() must be already flipped.
+ */
+class ByteBufferGenerator {
+
+    ByteBuffer currentBuffer;
+    // source is assumed to always return the same sized buffer
+    final BufferHandler pool;
+    final ArrayList<ByteBuffer> buflist;
+    final int bufsize;
+    boolean finished;
+
+    ByteBufferGenerator(BufferHandler pool) {
+        this.buflist = new ArrayList<>();
+        this.pool = pool;
+        this.currentBuffer = pool.getBuffer();
+        this.bufsize = currentBuffer.capacity();
+    }
+
+    private static final ByteBuffer[] EMPTY = new ByteBuffer[0];
+
+    public ByteBuffer[] getBufferArray() {
+        finish();
+        return buflist.toArray(EMPTY);
+    }
+
+    public ArrayList<ByteBuffer> getBufferList() {
+        finish();
+        return buflist;
+    }
+
+    private synchronized void finish() {
+        if (finished) {
+            return;
+        }
+        finished = true;
+        currentBuffer.flip();
+        if (currentBuffer.hasRemaining()) {
+            buflist.add(currentBuffer);
+        } else {
+            pool.returnBuffer(currentBuffer);
+        }
+    }
+
+    // only used for SettingsFrame: offset is number of bytes to
+    // ignore at start (we only want the payload of the settings frame)
+    public byte[] asByteArray(int offset) {
+        ByteBuffer[] bufs = getBufferArray();
+        int size = 0;
+        for (ByteBuffer buf : bufs) {
+            size += buf.remaining();
+        }
+        byte[] bytes = new byte[size-offset];
+        int pos = 0;
+        for (ByteBuffer buf : bufs) {
+            int rem = buf.remaining();
+            int ignore = Math.min(rem, offset);
+            buf.position(buf.position()+ignore);
+            rem -= ignore;
+            offset -= ignore;
+            buf.get(bytes, pos, rem);
+            pos += rem;
+        }
+        return bytes;
+    }
+
+    ByteBuffer getBuffer(long n) {
+        if (currentBuffer.remaining() < n) {
+            getNewBuffer();
+            if (n > currentBuffer.capacity()) {
+                throw new IllegalArgumentException("requested buffer too large");
+            }
+        }
+        return currentBuffer;
+    }
+
+    void getNewBuffer() {
+        currentBuffer.flip();
+        if (currentBuffer.hasRemaining()) {
+            buflist.add(currentBuffer);
+        } else {
+            pool.returnBuffer(currentBuffer);
+        }
+        currentBuffer = pool.getBuffer();
+    }
+
+    void addByteBuffer(ByteBuffer buf) {
+        getNewBuffer();
+        buflist.add(buf);
+    }
+
+    void addPadding(int length) {
+        while (length > 0) {
+            int n = Math.min(length, bufsize);
+            ByteBuffer b = getBuffer(n);
+            // TODO: currently zeroed?
+            b.position(b.position() + n);
+            length -= n;
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/CharsetToolkit.java	Tue May 03 12:25:20 2016 -0700
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ */
+package java.net.http;
+
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.CharacterCodingException;
+import java.nio.charset.CharsetDecoder;
+import java.nio.charset.CharsetEncoder;
+import java.nio.charset.CoderResult;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+
+// The purpose of this class is to separate charset-related tasks from the main
+// WebSocket logic, simplifying where possible.
+//
+//     * Coders hide the differences between coding and flushing stages on the
+//       API level
+//     * Verifier abstracts the way the verification is performed
+//       (spoiler: it's a decoding into a throw-away buffer)
+//
+// Coding methods throw exceptions instead of returning coding result denoting
+// errors, since any kind of handling and recovery is not expected.
+final class CharsetToolkit {
+
+    private CharsetToolkit() { }
+
+    static final class Verifier {
+
+        private final CharsetDecoder decoder = UTF_8.newDecoder();
+        // A buffer used to check validity of UTF-8 byte stream by decoding it.
+        // The contents of this buffer are never used.
+        // The size is arbitrary, though it should probably be chosen from the
+        // performance perspective since it affects the total number of calls to
+        // decoder.decode() and amount of work in each of these calls
+        private final CharBuffer blackHole = CharBuffer.allocate(1024);
+
+        void verify(ByteBuffer in, boolean endOfInput)
+                throws CharacterCodingException {
+            while (true) {
+                // Since decoder.flush() cannot produce an error, it's not
+                // helpful for verification. Therefore this step is skipped.
+                CoderResult r = decoder.decode(in, blackHole, endOfInput);
+                if (r.isOverflow()) {
+                    blackHole.clear();
+                } else if (r.isUnderflow()) {
+                    break;
+                } else if (r.isError()) {
+                    r.throwException();
+                } else {
+                    // Should not happen
+                    throw new InternalError();
+                }
+            }
+        }
+
+        Verifier reset() {
+            decoder.reset();
+            return this;
+        }
+    }
+
+    static final class Encoder {
+
+        private final CharsetEncoder encoder = UTF_8.newEncoder();
+        private boolean coding = true;
+
+        CoderResult encode(CharBuffer in, ByteBuffer out, boolean endOfInput)
+                throws CharacterCodingException {
+
+            if (coding) {
+                CoderResult r = encoder.encode(in, out, endOfInput);
+                if (r.isOverflow()) {
+                    return r;
+                } else if (r.isUnderflow()) {
+                    if (endOfInput) {
+                        coding = false;
+                    } else {
+                        return r;
+                    }
+                } else if (r.isError()) {
+                    r.throwException();
+                } else {
+                    // Should not happen
+                    throw new InternalError();
+                }
+            }
+            assert !coding;
+            return encoder.flush(out);
+        }
+
+        Encoder reset() {
+            coding = true;
+            encoder.reset();
+            return this;
+        }
+    }
+
+    static CharBuffer decode(ByteBuffer in) throws CharacterCodingException {
+        return UTF_8.newDecoder().decode(in);
+    }
+
+    static final class Decoder {
+
+        private final CharsetDecoder decoder = UTF_8.newDecoder();
+        private boolean coding = true; // Either coding or flushing
+
+        CoderResult decode(ByteBuffer in, CharBuffer out, boolean endOfInput)
+                throws CharacterCodingException {
+
+            if (coding) {
+                CoderResult r = decoder.decode(in, out, endOfInput);
+                if (r.isOverflow()) {
+                    return r;
+                } else if (r.isUnderflow()) {
+                    if (endOfInput) {
+                        coding = false;
+                    } else {
+                        return r;
+                    }
+                } else if (r.isError()) {
+                    r.throwException();
+                } else {
+                    // Should not happen
+                    throw new InternalError();
+                }
+            }
+            assert !coding;
+            return decoder.flush(out);
+        }
+
+        Decoder reset() {
+            coding = true;
+            decoder.reset();
+            return this;
+        }
+    }
+}
--- a/jdk/src/java.httpclient/share/classes/java/net/http/ConnectionPool.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/ConnectionPool.java	Tue May 03 12:25:20 2016 -0700
@@ -35,7 +35,7 @@
 class ConnectionPool {
 
     static final long KEEP_ALIVE = Utils.getIntegerNetProperty(
-            "sun.net.httpclient.keepalive.timeout", 1200); // seconds
+            "java.net.httpclient.keepalive.timeout", 1200); // seconds
 
     // Pools of idle connections
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/ContinuationFrame.java	Tue May 03 12:25:20 2016 -0700
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ */
+
+package java.net.http;
+
+import java.io.IOException;
+
+class ContinuationFrame extends HeaderFrame {
+
+    public static final int TYPE = 0x9;
+
+    ContinuationFrame() {
+        type = TYPE;
+    }
+
+    @Override
+    void readIncomingImpl(ByteBufferConsumer bc) throws IOException {
+        headerBlocks = bc.getBuffers(length);
+    }
+
+    @Override
+    void writeOutgoing(ByteBufferGenerator bg) {
+        super.writeOutgoing(bg);
+        for (int i=0; i<headerBlocks.length; i++) {
+            bg.addByteBuffer(headerBlocks[i]);
+        }
+    }
+
+    @Override
+    public boolean endHeaders() {
+        return getFlag(END_HEADERS);
+    }
+
+    @Override
+    void computeLength() {
+        length = headerLength;
+    }
+}
--- a/jdk/src/java.httpclient/share/classes/java/net/http/CookieFilter.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/CookieFilter.java	Tue May 03 12:25:20 2016 -0700
@@ -44,7 +44,7 @@
     @Override
     public void request(HttpRequestImpl r) throws IOException {
         Map<String,List<String>> userheaders, cookies;
-        userheaders = r.getUserHeaders().directMap();
+        userheaders = r.getUserHeaders().map();
         cookies = cookieMan.get(r.uri(), userheaders);
         // add the returned cookies
         HttpHeadersImpl systemHeaders = r.getSystemHeaders();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/DataFrame.java	Tue May 03 12:25:20 2016 -0700
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ */
+
+package java.net.http;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+class DataFrame extends Http2Frame {
+
+    public final static int TYPE = 0x0;
+
+    DataFrame() {
+        type = TYPE;
+    }
+
+    // Flags
+    public static final int END_STREAM = 0x1;
+    public static final int PADDED = 0x8;
+
+    int padLength;
+    int dataLength;
+    ByteBuffer[] data;
+
+    public void setData(ByteBuffer[] data) {
+        this.data = data;
+        setDataLength();
+    }
+
+    @Override
+    String flagAsString(int flag) {
+        switch (flag) {
+        case END_STREAM:
+            return "END_STREAM";
+        case PADDED:
+            return "PADDED";
+        }
+        return super.flagAsString(flag);
+    }
+
+    public synchronized void setData(ByteBuffer data) {
+        ByteBuffer[] bb;
+        if (data == null) {
+            bb = new ByteBuffer[0];
+        } else {
+            bb = new ByteBuffer[1];
+            bb[0] = data;
+        }
+        setData(bb);
+    }
+
+    public synchronized ByteBuffer[] getData() {
+        return data;
+    }
+
+    private void setDataLength() {
+        int len = 0;
+        for (ByteBuffer buf : data) {
+            len += buf.remaining();
+        }
+        dataLength = len;
+    }
+
+    @Override
+    void readIncomingImpl(ByteBufferConsumer bc) throws IOException {
+        if ((flags & PADDED) != 0) {
+            padLength = bc.getByte();
+            dataLength = length - (padLength + 1);
+        } else {
+            dataLength = length;
+        }
+        data = bc.getBuffers(dataLength);
+    }
+
+    int getPadLength() {
+        return padLength;
+    }
+
+    int getDataLength() {
+        return dataLength;
+    }
+
+    @Override
+    void writeOutgoing(ByteBufferGenerator bg) {
+        super.writeOutgoing(bg);
+        if ((flags & PADDED) != 0) {
+            ByteBuffer buf = bg.getBuffer(1);
+            buf.put((byte)getPadLength());
+        }
+        for (int i=0; i<data.length; i++) {
+            bg.addByteBuffer(data[i]);
+        }
+        if ((flags & PADDED) != 0) {
+            bg.addPadding(padLength);
+        }
+    }
+
+    @Override
+    void computeLength() {
+        length = dataLength;
+        if ((flags & PADDED) != 0) {
+            length += (1 + padLength);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/ErrorFrame.java	Tue May 03 12:25:20 2016 -0700
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ */
+
+package java.net.http;
+
+abstract class ErrorFrame extends Http2Frame {
+
+    // error codes
+    public static final int NO_ERROR = 0x0;
+    public static final int PROTOCOL_ERROR = 0x1;
+    public static final int INTERNAL_ERROR = 0x2;
+    public static final int FLOW_CONTROL_ERROR = 0x3;
+    public static final int SETTINGS_TIMEOUT = 0x4;
+    public static final int STREAM_CLOSED = 0x5;
+    public static final int FRAME_SIZE_ERROR = 0x6;
+    public static final int REFUSED_STREAM = 0x7;
+    public static final int CANCEL = 0x8;
+    public static final int COMPRESSION_ERROR = 0x9;
+    public static final int CONNECT_ERROR = 0xa;
+    public static final int ENHANCE_YOUR_CALM = 0xb;
+    public static final int INADEQUATE_SECURITY = 0xc;
+    public static final int HTTP_1_1_REQUIRED = 0xd;
+    static final int LAST_ERROR = 0xd;
+
+    static final String[] errorStrings = {
+        "Not an error",
+        "Protocol error",
+        "Internal error",
+        "Flow control error",
+        "Settings timeout",
+        "Stream is closed",
+        "Frame size error",
+        "Stream not processed",
+        "Stream cancelled",
+        "Compression state not updated",
+        "TCP Connection error on CONNECT",
+        "Processing capacity exceeded",
+        "Negotiated TLS parameters not acceptable",
+        "Use HTTP/1.1 for request"
+    };
+
+    public static String stringForCode(int code) {
+        if (code < 0)
+            throw new IllegalArgumentException();
+
+        if (code > LAST_ERROR) {
+            return "Error: " + Integer.toString(code);
+        } else {
+            return errorStrings[code];
+        }
+    }
+
+    int errorCode;
+
+    @Override
+    public String toString() {
+        return super.toString() + " Error: " + stringForCode(errorCode);
+    }
+
+    public int getErrorCode() {
+        return this.errorCode;
+    }
+
+    public void setErrorCode(int errorCode) {
+        this.errorCode = errorCode;
+    }
+}
--- a/jdk/src/java.httpclient/share/classes/java/net/http/Exchange.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/Exchange.java	Tue May 03 12:25:20 2016 -0700
@@ -128,7 +128,7 @@
         }
     }
 
-    HttpResponseImpl responseImpl0(HttpConnection connection)
+    private HttpResponseImpl responseImpl0(HttpConnection connection)
         throws IOException, InterruptedException
     {
         exchImpl = ExchangeImpl.get(this, connection);
@@ -136,7 +136,7 @@
             request.addSystemHeader("Expect", "100-Continue");
             exchImpl.sendHeadersOnly();
             HttpResponseImpl resp = exchImpl.getResponse();
-            logResponse(resp);
+            Utils.logResponse(resp);
             if (resp.statusCode() != 100) {
                 return resp;
             }
@@ -145,7 +145,7 @@
         } else {
             exchImpl.sendRequest();
             HttpResponseImpl resp = exchImpl.getResponse();
-            logResponse(resp);
+            Utils.logResponse(resp);
             return checkForUpgrade(resp, exchImpl);
         }
     }
@@ -163,9 +163,7 @@
         }
         SecurityException e = securityCheck(acc);
         if (e != null) {
-            CompletableFuture<HttpResponseImpl> cf = new CompletableFuture<>();
-            cf.completeExceptionally(e);
-            return cf;
+            return CompletableFuture.failedFuture(e);
         }
         if (permissions.size() > 0) {
             return AccessController.doPrivileged(
@@ -182,9 +180,7 @@
         try {
             exchImpl = ExchangeImpl.get(this, connection);
         } catch (IOException | InterruptedException e) {
-            CompletableFuture<HttpResponseImpl> cf = new CompletableFuture<>();
-            cf.completeExceptionally(e);
-            return cf;
+            return CompletableFuture.failedFuture(e);
         }
         if (request.expectContinue()) {
             request.addSystemHeader("Expect", "100-Continue");
@@ -200,23 +196,19 @@
                             return exchImpl.sendBodyAsync()
                                 .thenCompose(exchImpl::getResponseAsync)
                                 .thenApply((r) -> {
-                                    logResponse(r);
+                                    Utils.logResponse(r);
                                     return r;
                                 });
                         } else {
                             Exchange.this.response = r1;
-                            logResponse(r1);
+                            Utils.logResponse(r1);
                             return CompletableFuture.completedFuture(r1);
                         }
                     });
         } else {
             return exchImpl
-                .sendHeadersAsync()
-                .thenCompose((Void v) -> {
-                    // send body and get response at same time
-                    return exchImpl.sendBodyAsync()
-                                   .thenCompose(exchImpl::getResponseAsync);
-                })
+                .sendRequestAsync()
+                .thenCompose(exchImpl::getResponseAsync)
                 .thenCompose((HttpResponseImpl r1) -> {
                     int rcode = r1.statusCode();
                     CompletableFuture<HttpResponseImpl> cf =
@@ -225,13 +217,13 @@
                         return cf;
                     } else {
                         Exchange.this.response = r1;
-                        logResponse(r1);
+                        Utils.logResponse(r1);
                         return CompletableFuture.completedFuture(r1);
                     }
                 })
                 .thenApply((HttpResponseImpl response) -> {
                     this.response = response;
-                    logResponse(response);
+                    Utils.logResponse(response);
                     return response;
                 });
         }
@@ -254,9 +246,9 @@
                                                  client.client2(),
                                                  this)
                         .thenCompose((Http2Connection c) -> {
+                            c.putConnection();
                             Stream s = c.getStream(1);
                             exchImpl = s;
-                            c.putConnection();
                             return s.getResponseAsync(null);
                         })
                 );
@@ -294,21 +286,6 @@
     }
 
 
-    private void logResponse(HttpResponseImpl r) {
-        if (!Log.requests())
-            return;
-        StringBuilder sb = new StringBuilder();
-        String method = r.request().method();
-        URI uri = r.uri();
-        String uristring = uri == null ? "" : uri.toString();
-        sb.append('(')
-          .append(method)
-          .append(" ")
-          .append(uristring)
-          .append(") ")
-          .append(Integer.toString(r.statusCode()));
-        Log.logResponse(sb.toString());
-    }
 
     <T> CompletableFuture<T> responseBodyAsync(HttpResponse.BodyProcessor<T> processor) {
         return exchImpl.responseBodyAsync(processor);
@@ -352,9 +329,9 @@
         }
 
         String method = request.method();
-        HttpHeadersImpl userHeaders = request.getUserHeaders();
+        HttpHeaders userHeaders = request.getUserHeaders();
         URI u = getURIForSecurityCheck();
-        URLPermission p = Utils.getPermission(u, method, userHeaders.directMap());
+        URLPermission p = Utils.getPermission(u, method, userHeaders.map());
 
         try {
             assert acc != null;
--- a/jdk/src/java.httpclient/share/classes/java/net/http/FilterFactory.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/FilterFactory.java	Tue May 03 12:25:20 2016 -0700
@@ -39,7 +39,9 @@
         List<HeaderFilter> l = new LinkedList<>();
         for (Class<? extends HeaderFilter> clazz : filterClasses) {
             try {
-                l.add(clazz.newInstance());
+                @SuppressWarnings("deprecation")
+                HeaderFilter headerFilter = clazz.newInstance();
+                l.add(headerFilter);
             } catch (ReflectiveOperationException e) {
                 throw new InternalError(e);
             }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/FrameReader.java	Tue May 03 12:25:20 2016 -0700
@@ -0,0 +1,70 @@
+/*
+ * To change this license header, choose License Headers in Project Properties.
+ * To change this template file, choose Tools | Templates
+ * and open the template in the editor.
+ */
+package java.net.http;
+
+import java.nio.ByteBuffer;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Represents one frame. May be initialized with a leftover buffer from previous
+ * frame. Call {@code haveFrame()} to determine if buffers contains at least one
+ * frame. If false, the obtain another buffer and call {@code}input(ByteBuffer)}.
+ * There may be additional bytes at end of the frame list.
+ */
+class FrameReader {
+
+    final List<ByteBuffer> buffers;
+
+    FrameReader() {
+        buffers = new LinkedList<>();
+    }
+
+    FrameReader(FrameReader that) {
+        this.buffers = that.buffers;
+    }
+
+    FrameReader(ByteBuffer remainder) {
+        buffers = new LinkedList<>();
+        if (remainder != null) {
+            buffers.add(remainder);
+        }
+    }
+
+    public synchronized void input(ByteBuffer buffer) {
+        buffers.add(buffer);
+    }
+
+    public synchronized boolean haveFrame() {
+        //buffers = Utils.superCompact(buffers, () -> ByteBuffer.allocate(Utils.BUFSIZE));
+        int size = 0;
+        for (ByteBuffer buffer : buffers) {
+            size += buffer.remaining();
+        }
+        if (size < 3) {
+            return false; // don't have length yet
+        }
+        // we at least have length field
+        int length = 0;
+        int j = 0;
+        ByteBuffer b = buffers.get(j);
+        b.mark();
+        for (int i=0; i<3; i++) {
+            while (!b.hasRemaining()) {
+                b.reset();
+                b = buffers.get(++j);
+                b.mark();
+            }
+            length = (length << 8) + (b.get() & 0xff);
+        }
+        b.reset();
+        return (size >= length + 9); // frame length
+    }
+
+    synchronized List<ByteBuffer> frame() {
+        return buffers;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/GoAwayFrame.java	Tue May 03 12:25:20 2016 -0700
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ */
+
+package java.net.http;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+class GoAwayFrame extends ErrorFrame {
+
+    GoAwayFrame() {
+        type = TYPE;
+    }
+
+    int lastStream;
+    byte[] debugData = new byte[0];
+
+    public static final int TYPE = 0x7;
+
+    // Flags
+    public static final int ACK = 0x1;
+
+    public void setDebugData(byte[] debugData) {
+        this.debugData = debugData;
+    }
+
+    @Override
+    public String toString() {
+        return super.toString() + " Debugdata: " + new String(debugData);
+    }
+
+    @Override
+    String flagAsString(int flag) {
+        switch (flag) {
+        case ACK:
+            return "ACK";
+        }
+        return super.flagAsString(flag);
+    }
+
+    public void setLastStream(int lastStream) {
+        this.lastStream = lastStream;
+    }
+
+    public int getLastStream() {
+        return this.lastStream;
+    }
+
+    public byte[] getDebugData() {
+        return debugData;
+    }
+
+    @Override
+    void readIncomingImpl(ByteBufferConsumer bc) throws IOException {
+        if (length < 8) {
+            throw new IOException("Invalid GoAway frame");
+        }
+        lastStream = bc.getInt() & 0x7fffffff;
+        errorCode = bc.getInt();
+        //debugData = bc.getBytes(8);
+        int datalen = length - 8;
+        if (datalen > 0) {
+            debugData = bc.getBytes(datalen);
+            Log.logError("GoAway debugData " + new String(debugData));
+        }
+    }
+
+    @Override
+    void writeOutgoing(ByteBufferGenerator bg) {
+        super.writeOutgoing(bg);
+        ByteBuffer buf = bg.getBuffer(length);
+        buf.putInt(lastStream);
+        buf.putInt(errorCode);
+        if (length > 8) {
+            buf.put(debugData);
+        }
+    }
+
+    @Override
+    void computeLength() {
+        length = 8 + debugData.length;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/HeaderFrame.java	Tue May 03 12:25:20 2016 -0700
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ */
+
+package java.net.http;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Either a HeadersFrame or a ContinuationFrame
+ */
+abstract class HeaderFrame extends Http2Frame {
+
+    int offset;
+    int number;
+    int headerLength;
+    ByteBuffer[] headerBlocks;
+
+    public static final int END_HEADERS = 0x4;
+
+    @Override
+    String flagAsString(int flag) {
+        switch (flag) {
+        case END_HEADERS:
+            return "END_HEADERS";
+        }
+        return super.flagAsString(flag);
+    }
+
+    /**
+     * Sets the array of hpack encoded ByteBuffers
+     */
+    public void setHeaderBlock(ByteBuffer bufs[], int offset, int number) {
+        this.headerBlocks = bufs;
+        this.offset = offset;
+        this.number = number;
+        int length = 0;
+        for (int i=offset; i<offset+number; i++) {
+            length += headerBlocks[i].remaining();
+        }
+        this.headerLength = length;
+    }
+
+    public void setHeaderBlock(ByteBuffer bufs[]) {
+        setHeaderBlock(bufs, 0, bufs.length);
+    }
+
+    public ByteBuffer[] getHeaderBlock() {
+        return headerBlocks;
+    }
+
+    /**
+     * Returns true if this block is the final block of headers
+     */
+    public abstract boolean endHeaders();
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/HeadersFrame.java	Tue May 03 12:25:20 2016 -0700
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ */
+
+package java.net.http;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+class HeadersFrame extends HeaderFrame {
+
+    public final static int TYPE = 0x1;
+
+    // Flags
+    public static final int END_STREAM = 0x1;
+    public static final int PADDED = 0x8;
+    public static final int PRIORITY = 0x20;
+
+
+    int padLength;
+    int streamDependency;
+    int weight;
+    boolean exclusive;
+
+    HeadersFrame() {
+        type = TYPE;
+    }
+
+    @Override
+    String flagAsString(int flag) {
+        switch (flag) {
+            case END_STREAM:
+                return "END_STREAM";
+            case PADDED:
+                return "PADDED";
+            case PRIORITY:
+                return "PRIORITY";
+        }
+        return super.flagAsString(flag);
+    }
+
+    public void setPadLength(int padLength) {
+        this.padLength = padLength;
+        flags |= PADDED;
+    }
+
+    public void setPriority(int streamDependency, boolean exclusive, int weight) {
+        this.streamDependency = streamDependency;
+        this.exclusive = exclusive;
+        this.weight = weight;
+        this.flags |= PRIORITY;
+    }
+
+    public int getStreamDependency() {
+        return streamDependency;
+    }
+
+    public int getWeight() {
+        return weight;
+    }
+
+    @Override
+    public boolean endHeaders() {
+        return getFlag(END_HEADERS);
+    }
+
+    public boolean getExclusive() {
+        return exclusive;
+    }
+
+    @Override
+    void readIncomingImpl(ByteBufferConsumer bc) throws IOException {
+        if ((flags & PADDED) != 0) {
+            padLength = bc.getByte();
+        }
+        if ((flags & PRIORITY) != 0) {
+            int x = bc.getInt();
+            exclusive = (x & 0x80000000) != 0;
+            streamDependency = x & 0x7fffffff;
+            weight = bc.getByte();
+        }
+        headerLength = length - padLength;
+        headerBlocks = bc.getBuffers(headerLength);
+    }
+
+    @Override
+    void computeLength() {
+        int len = 0;
+        if ((flags & PADDED) != 0) {
+            len += (1 + padLength);
+        }
+        if ((flags & PRIORITY) != 0) {
+            len += 5;
+        }
+        len += headerLength;
+        this.length = len;
+    }
+
+    @Override
+    void writeOutgoing(ByteBufferGenerator bg) {
+        super.writeOutgoing(bg);
+        ByteBuffer buf = bg.getBuffer(6);
+        if ((flags & PADDED) != 0) {
+            buf.put((byte)padLength);
+        }
+        if ((flags & PRIORITY) != 0) {
+            int x = exclusive ? 1 << 31 + streamDependency : streamDependency;
+            buf.putInt(x);
+            buf.put((byte)weight);
+        }
+        for (int i=0; i<headerBlocks.length; i++) {
+            bg.addByteBuffer(headerBlocks[i]);
+        }
+        if ((flags & PADDED) != 0) {
+            bg.addPadding(padLength);
+        }
+    }
+}
--- a/jdk/src/java.httpclient/share/classes/java/net/http/Http1Exchange.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/Http1Exchange.java	Tue May 03 12:25:20 2016 -0700
@@ -64,32 +64,12 @@
         if (connection != null) {
             this.connection = connection;
         } else {
-            InetSocketAddress addr = getAddress(request);
+            InetSocketAddress addr = Utils.getAddress(request);
             this.connection = HttpConnection.getConnection(addr, request);
         }
         this.requestAction = new Http1Request(request, this.connection);
     }
 
-    private static InetSocketAddress getAddress(HttpRequestImpl req) {
-        URI uri = req.uri();
-        if (uri == null) {
-            return req.authority();
-        }
-        int port = uri.getPort();
-        if (port == -1) {
-            if (uri.getScheme().equalsIgnoreCase("https")) {
-                port = 443;
-            } else {
-                port = 80;
-            }
-        }
-        String host = uri.getHost();
-        if (req.proxy() == null) {
-            return new InetSocketAddress(host, port);
-        } else {
-            return InetSocketAddress.createUnresolved(host, port);
-        }
-    }
 
     HttpConnection connection() {
         return connection;
@@ -211,7 +191,7 @@
                                 connection.close();
                             }
                          },
-                         () -> request.getAccessControlContext());
+                request::getAccessControlContext);
         operations.add(cf);
         return cf;
     }
@@ -269,7 +249,7 @@
                 cf.completeExceptionally(e);
                 connection.close();
             }
-        }, () -> request.getAccessControlContext());
+        }, request::getAccessControlContext);
         operations.add(cf);
         return cf;
     }
@@ -302,7 +282,7 @@
                 cf.completeExceptionally(e);
                 connection.close();
             }
-        }, () -> request.getAccessControlContext());
+        }, request::getAccessControlContext);
         operations.add(cf);
         return cf;
     }
--- a/jdk/src/java.httpclient/share/classes/java/net/http/Http1Request.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/Http1Request.java	Tue May 03 12:25:20 2016 -0700
@@ -30,6 +30,7 @@
 import java.util.Map;
 import java.util.Set;
 import java.net.InetSocketAddress;
+import java.net.http.HttpConnection.Mode;
 import java.nio.charset.StandardCharsets;
 import java.util.function.LongConsumer;
 import static java.nio.charset.StandardCharsets.US_ASCII;
@@ -48,7 +49,8 @@
     // See line 206 and below for description
     final ByteBuffer[] buffers;
     final HttpRequest.BodyProcessor requestProc;
-    final HttpHeadersImpl userHeaders, systemHeaders;
+    final HttpHeaders userHeaders;
+    final HttpHeadersImpl systemHeaders;
     final LongConsumer flowController;
     boolean streaming;
     long contentLength;
@@ -91,10 +93,10 @@
 
     private void collectHeaders1(StringBuilder sb,
                                  HttpRequestImpl request,
-                                 HttpHeadersImpl headers)
+                                 HttpHeaders headers)
         throws IOException
     {
-        Map<String,List<String>> h = headers.directMap();
+        Map<String,List<String>> h = headers.map();
         Set<Map.Entry<String,List<String>>> entries = h.entrySet();
 
         for (Map.Entry<String,List<String>> entry : entries) {
@@ -112,8 +114,6 @@
         }
     }
 
-    private static final int BUFSIZE = 64 * 1024; // TODO: configurable?
-
     private String getPathAndQuery(URI uri) {
         String path = uri.getPath();
         String query = uri.getQuery();
@@ -134,6 +134,25 @@
         return addr.getHostString() + ":" + addr.getPort();
     }
 
+    private String hostString() {
+        URI uri = request.uri();
+        int port = uri.getPort();
+        String host = uri.getHost();
+
+        boolean defaultPort;
+        if (port == -1)
+            defaultPort = true;
+        else if (request.secure())
+            defaultPort = port == 443;
+        else
+            defaultPort = port == 80;
+
+        if (defaultPort)
+            return host;
+        else
+            return host + ":" + Integer.toString(port);
+    }
+
     private String requestURI() {
         URI uri = request.uri();
         String method = request.method();
@@ -161,6 +180,7 @@
 
     void sendRequest() throws IOException {
         collectHeaders();
+        chan.configureMode(Mode.BLOCKING);
         if (contentLength == 0) {
             chan.write(buffers, 0, 2);
         } else if (contentLength > 0) {
@@ -196,7 +216,7 @@
         buffers[0] = ByteBuffer.wrap(cmd.getBytes(StandardCharsets.US_ASCII));
         URI uri = request.uri();
         if (uri != null) {
-            systemHeaders.setHeader("Host", uri.getHost());
+            systemHeaders.setHeader("Host", hostString());
         }
         if (request == null) {
             // this is not a user request. No content
--- a/jdk/src/java.httpclient/share/classes/java/net/http/Http1Response.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/Http1Response.java	Tue May 03 12:25:20 2016 -0700
@@ -24,7 +24,6 @@
 package java.net.http;
 
 import java.io.IOException;
-import java.net.URI;
 import java.nio.ByteBuffer;
 import java.util.List;
 import java.util.Map;
--- a/jdk/src/java.httpclient/share/classes/java/net/http/Http2ClientImpl.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/Http2ClientImpl.java	Tue May 03 12:25:20 2016 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -23,11 +23,133 @@
  */
 package java.net.http;
 
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.net.URI;
+import static java.net.http.SettingsFrame.INITIAL_WINDOW_SIZE;
+import static java.net.http.SettingsFrame.ENABLE_PUSH;
+import static java.net.http.SettingsFrame.HEADER_TABLE_SIZE;
+import static java.net.http.SettingsFrame.MAX_CONCURRENT_STREAMS;
+import static java.net.http.SettingsFrame.MAX_FRAME_SIZE;
+import java.util.Base64;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ *  Http2 specific aspects of HttpClientImpl
+ */
 class Http2ClientImpl {
-    Http2ClientImpl(HttpClientImpl t) {}
-    String getSettingsString() {return "";}
-    void debugPrint() {}
-    Http2Connection getConnectionFor(HttpRequestImpl r) {
-        return null;
+
+    final private HttpClientImpl client;
+
+    Http2ClientImpl(HttpClientImpl client) {
+        this.client = client;
+    }
+
+    /* Map key is "scheme:host:port" */
+    final private Map<String,Http2Connection> connections =
+            Collections.synchronizedMap(new HashMap<>());
+
+    final private Set<String> opening = Collections.synchronizedSet(new HashSet<>());
+
+    synchronized boolean haveConnectionFor(URI uri, InetSocketAddress proxy) {
+        return connections.containsKey(Http2Connection.keyFor(uri,proxy));
+    }
+
+    /**
+     * If a https request then blocks and waits until a connection is opened.
+     * Returns null if the request is 'http' as a different (upgrade)
+     * mechanism is used.
+     *
+     * Only one connection per destination is created. Blocks when opening
+     * connection, or when waiting for connection to be opened.
+     * First thread opens the connection and notifies the others when done.
+     *
+     * If the request is secure (https) then we open the connection here.
+     * If not, then the more complicated upgrade from 1.1 to 2 happens (not here)
+     * In latter case, when the Http2Connection is connected, putConnection() must
+     * be called to store it.
+     */
+    Http2Connection getConnectionFor(HttpRequestImpl req)
+            throws IOException, InterruptedException {
+        URI uri = req.uri();
+        InetSocketAddress proxy = req.proxy();
+        String key = Http2Connection.keyFor(uri, proxy);
+        Http2Connection connection;
+        synchronized (opening) {
+            while ((connection = connections.get(key)) == null) {
+                if (!req.secure()) {
+                    return null;
+                }
+                if (!opening.contains(key)) {
+                    opening.add(key);
+                    break;
+                } else {
+                    opening.wait();
+                }
+            }
+        }
+        if (connection != null) {
+            return connection;
+        }
+        // we are opening the connection here blocking until it is done.
+        connection = new Http2Connection(req);
+        synchronized (opening) {
+            connections.put(key, connection);
+            opening.remove(key);
+            opening.notifyAll();
+        }
+        return connection;
+    }
+
+
+    /*
+     * TODO: If there isn't a connection to the same destination, then
+     * store it. If there is already a connection, then close it
+     */
+    synchronized void putConnection(Http2Connection c) {
+        String key = c.key();
+        connections.put(key, c);
+    }
+
+    synchronized void deleteConnection(Http2Connection c) {
+        String key = c.key();
+        connections.remove(key);
+    }
+
+    HttpClientImpl client() {
+        return client;
+    }
+
+    /** Returns the client settings as a base64 (url) encoded string */
+    String getSettingsString() {
+        SettingsFrame sf = getClientSettings();
+        ByteBufferGenerator bg = new ByteBufferGenerator(client);
+        sf.writeOutgoing(bg);
+        byte[] settings = bg.asByteArray(9); // without the header
+        Base64.Encoder encoder = Base64.getUrlEncoder()
+                                       .withoutPadding();
+        return encoder.encodeToString(settings);
+    }
+
+    private static final int K = 1024;
+
+    SettingsFrame getClientSettings() {
+        SettingsFrame frame = new SettingsFrame();
+        frame.setParameter(HEADER_TABLE_SIZE, Utils.getIntegerNetProperty(
+            "java.net.httpclient.hpack.maxheadertablesize", 16 * K));
+        frame.setParameter(ENABLE_PUSH, Utils.getIntegerNetProperty(
+            "java.net.httpclient.enablepush", 1));
+        frame.setParameter(MAX_CONCURRENT_STREAMS, Utils.getIntegerNetProperty(
+            "java.net.httpclient.maxstreams", 16));
+        frame.setParameter(INITIAL_WINDOW_SIZE, Utils.getIntegerNetProperty(
+            "java.net.httpclient.windowsize", 32 * K));
+        frame.setParameter(MAX_FRAME_SIZE, Utils.getIntegerNetProperty(
+            "java.net.httpclient.maxframesize", 16 * K));
+        frame.computeLength();
+        return frame;
     }
 }
--- a/jdk/src/java.httpclient/share/classes/java/net/http/Http2Connection.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/Http2Connection.java	Tue May 03 12:25:20 2016 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -24,42 +24,767 @@
 package java.net.http;
 
 import java.io.IOException;
-import java.net.Authenticator;
-import java.net.CookieManager;
-import java.net.ProxySelector;
+import java.net.InetSocketAddress;
 import java.net.URI;
-import static java.net.http.Utils.BUFSIZE;
+import java.net.http.HttpConnection.Mode;
 import java.nio.ByteBuffer;
-import java.nio.channels.SelectableChannel;
-import java.nio.channels.SelectionKey;
-import static java.nio.channels.SelectionKey.OP_CONNECT;
-import static java.nio.channels.SelectionKey.OP_READ;
-import static java.nio.channels.SelectionKey.OP_WRITE;
-import java.nio.channels.Selector;
+import java.nio.charset.StandardCharsets;
+import java.util.Collection;
 import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.List;
-import java.util.Set;
-import java.util.concurrent.*;
-import java.security.NoSuchAlgorithmException;
-import java.util.ListIterator;
-import java.util.Optional;
-import java.util.concurrent.Executors;
-import java.util.concurrent.ThreadFactory;
-import javax.net.ssl.SSLContext;
-import javax.net.ssl.SSLParameters;
+import java.util.Map;
+import java.util.concurrent.CompletableFuture;
+import sun.net.httpclient.hpack.Encoder;
+import sun.net.httpclient.hpack.Decoder;
+import static java.net.http.SettingsFrame.*;
+import static java.net.http.Utils.BUFSIZE;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Formatter;
+import java.util.stream.Collectors;
+import sun.net.httpclient.hpack.DecodingCallback;
+
+/**
+ * An Http2Connection. Encapsulates the socket(channel) and any SSLEngine used
+ * over it. Contains an HttpConnection which hides the SocketChannel SSL stuff.
+ *
+ * Http2Connections belong to a Http2ClientImpl, (one of) which belongs
+ * to a HttpClientImpl.
+ *
+ * Creation cases:
+ * 1) upgraded HTTP/1.1 plain tcp connection
+ * 2) prior knowledge directly created plain tcp connection
+ * 3) directly created HTTP/2 SSL connection which uses ALPN.
+ *
+ * Sending is done by writing directly to underlying HttpConnection object which
+ * is operating in async mode. No flow control applies on output at this level
+ * and all writes are just executed as puts to an output Q belonging to HttpConnection
+ * Flow control is implemented by HTTP/2 protocol itself.
+ *
+ * Hpack header compression
+ * and outgoing stream creation is also done here, because these operations
+ * must be synchronized at the socket level. Stream objects send frames simply
+ * by placing them on the connection's output Queue. sendFrame() is called
+ * from a higher level (Stream) thread.
+ *
+ * asyncReceive(ByteBuffer) is always called from the selector thread. It assembles
+ * incoming Http2Frames, and directs them to the appropriate Stream.incoming()
+ * or handles them directly itself. This thread performs hpack decompression
+ * and incoming stream creation (Server push). Incoming frames destined for a
+ * stream are provided by calling Stream.incoming().
+ */
+class Http2Connection implements BufferHandler {
+
+    final Queue<Http2Frame> outputQ;
+    volatile boolean closed;
+
+    //-------------------------------------
+    final HttpConnection connection;
+    HttpClientImpl client;
+    final Http2ClientImpl client2;
+    Map<Integer,Stream> streams;
+    int nextstreamid = 3; // stream 1 is registered separately
+    int nextPushStream = 2;
+    Encoder hpackOut;
+    Decoder hpackIn;
+    SettingsFrame clientSettings, serverSettings;
+    ByteBufferConsumer bbc;
+    final LinkedList<ByteBuffer> freeList;
+    final String key; // for HttpClientImpl.connections map
+    FrameReader reader;
+
+    // Connection level flow control windows
+    int sendWindow = INITIAL_WINDOW_SIZE;
+
+    final static int DEFAULT_FRAME_SIZE = 16 * 1024;
+    private static ByteBuffer[] empty = Utils.EMPTY_BB_ARRAY;
+
+    final ExecutorWrapper executor;
+
+    /**
+     * This is established by the protocol spec and the peer will update it with
+     * WINDOW_UPDATEs, which affects the sendWindow.
+     */
+    final static int INITIAL_WINDOW_SIZE = 64 * 1024 - 1;
+
+    // TODO: need list of control frames from other threads
+    // that need to be sent
+
+    /**
+     * Case 1) Create from upgraded HTTP/1.1 connection.
+     * Is ready to use. Will not be SSL. exchange is the Exchange
+     * that initiated the connection, whose response will be delivered
+     * on a Stream.
+     */
+    Http2Connection(HttpConnection connection, Http2ClientImpl client2,
+            Exchange exchange) throws IOException, InterruptedException {
+        this.outputQ = new Queue<>();
+        String msg = "Connection send window size " + Integer.toString(sendWindow);
+        Log.logTrace(msg);
+
+        //this.initialExchange = exchange;
+        assert !(connection instanceof SSLConnection);
+        this.connection = connection;
+        this.client = client2.client();
+        this.client2 = client2;
+        this.executor = client.executorWrapper();
+        this.freeList = new LinkedList<>();
+        this.key = keyFor(connection);
+        streams = Collections.synchronizedMap(new HashMap<>());
+        initCommon();
+        //sendConnectionPreface();
+        Stream initialStream = createStream(exchange);
+        initialStream.registerStream(1);
+        initialStream.requestSent();
+        sendConnectionPreface();
+        connection.configureMode(Mode.ASYNC);
+        // start reading and writing
+        // start reading
+        AsyncConnection asyncConn = (AsyncConnection)connection;
+        asyncConn.setAsyncCallbacks(this::asyncReceive, this::shutdown);
+        asyncReceive(connection.getRemaining());
+        asyncConn.startReading();
+    }
+
+    // async style but completes immediately
+    static CompletableFuture<Http2Connection> createAsync(HttpConnection connection,
+            Http2ClientImpl client2, Exchange exchange) {
+        CompletableFuture<Http2Connection> cf = new CompletableFuture<>();
+        try {
+            Http2Connection c = new Http2Connection(connection, client2, exchange);
+            cf.complete(c);
+        } catch (IOException | InterruptedException e) {
+            cf.completeExceptionally(e);
+        }
+        return cf;
+    }
+
+    /**
+     * Cases 2) 3)
+     *
+     * request is request to be sent.
+     */
+    Http2Connection(HttpRequestImpl request) throws IOException, InterruptedException {
+        InetSocketAddress proxy = request.proxy();
+        URI uri = request.uri();
+        InetSocketAddress addr = Utils.getAddress(request);
+        String msg = "Connection send window size " + Integer.toString(sendWindow);
+        Log.logTrace(msg);
+        this.key = keyFor(uri, proxy);
+        this.connection = HttpConnection.getConnection(addr, request, this);
+        streams = Collections.synchronizedMap(new HashMap<>());
+        this.client = request.client();
+        this.client2 = client.client2();
+        this.executor = client.executorWrapper();
+        this.freeList = new LinkedList<>();
+        this.outputQ = new Queue<>();
+        nextstreamid = 1;
+        initCommon();
+        connection.connect();
+        connection.configureMode(Mode.ASYNC);
+        // start reading
+        AsyncConnection asyncConn = (AsyncConnection)connection;
+        asyncConn.setAsyncCallbacks(this::asyncReceive, this::shutdown);
+        sendConnectionPreface();
+        asyncConn.startReading();
+    }
+
+    // NEW
+    synchronized void obtainSendWindow(int amount) throws InterruptedException {
+        while (amount > 0) {
+            int n = Math.min(amount, sendWindow);
+            sendWindow -= n;
+            amount -= n;
+            if (amount > 0)
+                wait();
+        }
+    }
+
+    synchronized void updateSendWindow(int amount) {
+        if (sendWindow == 0) {
+            sendWindow += amount;
+            notifyAll();
+        } else
+            sendWindow += amount;
+    }
+
+    synchronized int sendWindow() {
+        return sendWindow;
+    }
+
+    static String keyFor(HttpConnection connection) {
+        boolean isProxy = connection.isProxied();
+        boolean isSecure = connection.isSecure();
+        InetSocketAddress addr = connection.address();
+
+        return keyString(isSecure, isProxy, addr.getHostString(), addr.getPort());
+    }
+
+    static String keyFor(URI uri, InetSocketAddress proxy) {
+        boolean isSecure = uri.getScheme().equalsIgnoreCase("https");
+        boolean isProxy = proxy != null;
+
+        String host;
+        int port;
+
+        if (isProxy) {
+            host = proxy.getHostString();
+            port = proxy.getPort();
+        } else {
+            host = uri.getHost();
+            port = uri.getPort();
+        }
+        return keyString(isSecure, isProxy, host, port);
+    }
+
+    // {C,S}:{H:P}:host:port
+    // C indicates clear text connection "http"
+    // S indicates secure "https"
+    // H indicates host (direct) connection
+    // P indicates proxy
+    // Eg: "S:H:foo.com:80"
+    static String keyString(boolean secure, boolean proxy, String host, int port) {
+        char c1 = secure ? 'S' : 'C';
+        char c2 = proxy ? 'P' : 'H';
+
+        StringBuilder sb = new StringBuilder(128);
+        sb.append(c1).append(':').append(c2).append(':')
+                .append(host).append(':').append(port);
+        return sb.toString();
+    }
+
+    String key() {
+        return this.key;
+    }
+
+    void putConnection() {
+        client2.putConnection(this);
+    }
+
+    private static String toHexdump1(ByteBuffer bb) {
+        bb.mark();
+        StringBuilder sb = new StringBuilder(512);
+        Formatter f = new Formatter(sb);
+
+        while (bb.hasRemaining()) {
+            int i =  Byte.toUnsignedInt(bb.get());
+            f.format("%02x:", i);
+        }
+        sb.deleteCharAt(sb.length()-1);
+        bb.reset();
+        return sb.toString();
+    }
+
+    private static String toHexdump(ByteBuffer bb) {
+        List<String> words = new ArrayList<>();
+        int i = 0;
+        bb.mark();
+        while (bb.hasRemaining()) {
+            if (i % 2 == 0) {
+                words.add("");
+            }
+            byte b = bb.get();
+            String hex = Integer.toHexString(256 + Byte.toUnsignedInt(b)).substring(1);
+            words.set(i / 2, words.get(i / 2) + hex);
+            i++;
+        }
+        bb.reset();
+        return words.stream().collect(Collectors.joining(" "));
+    }
+
+    private void decodeHeaders(HeaderFrame frame, DecodingCallback decoder) {
+        boolean endOfHeaders = frame.getFlag(HeaderFrame.END_HEADERS);
+
+        ByteBuffer[] buffers = frame.getHeaderBlock();
+        for (int i = 0; i < buffers.length; i++) {
+            hpackIn.decode(buffers[i], endOfHeaders, decoder);
+        }
+    }
+
+    int getInitialSendWindowSize() {
+        return serverSettings.getParameter(SettingsFrame.INITIAL_WINDOW_SIZE);
+    }
+
+    void close() {
+        GoAwayFrame f = new GoAwayFrame();
+        f.setDebugData("Requested by user".getBytes());
+        // TODO: set last stream. For now zero ok.
+        sendFrame(f);
+    }
+
+    // BufferHandler methods
+
+    @Override
+    public ByteBuffer getBuffer(int n) {
+        return client.getBuffer(n);
+    }
+
+    @Override
+    public void returnBuffer(ByteBuffer buf) {
+        client.returnBuffer(buf);
+    }
 
-class Http2Connection {
-    static CompletableFuture<Http2Connection> createAsync(
-        HttpConnection connection, Http2ClientImpl client2, Exchange exchange) {
-            return null;
+    @Override
+    public void setMinBufferSize(int n) {
+        client.setMinBufferSize(n);
+    }
+
+    private final Object readlock = new Object();
+
+    void asyncReceive(ByteBuffer buffer) {
+        synchronized (readlock) {
+            try {
+                if (reader == null) {
+                    reader = new FrameReader(buffer);
+                } else {
+                    reader.input(buffer);
+                }
+                while (true) {
+                    if (reader.haveFrame()) {
+                        List<ByteBuffer> buffers = reader.frame();
+
+                        ByteBufferConsumer bbc = new ByteBufferConsumer(buffers, this::getBuffer);
+                        processFrame(bbc);
+                        if (bbc.consumed()) {
+                            reader = new FrameReader();
+                            return;
+                        } else {
+                            reader = new FrameReader(reader);
+                        }
+                    } else
+                        return;
+                }
+            } catch (Throwable e) {
+                String msg = Utils.stackTrace(e);
+                Log.logTrace(msg);
+                shutdown(e);
+            }
+        }
+    }
+
+    void shutdown(Throwable t) {
+        System.err.println("Shutdown: " + t);
+        t.printStackTrace();
+        closed = true;
+        client2.deleteConnection(this);
+        Collection<Stream> c = streams.values();
+        for (Stream s : c) {
+            s.cancelImpl(t);
+        }
+        connection.close();
+    }
+
+    /**
+     * Handles stream 0 (common) frames that apply to whole connection and passes
+     * other stream specific frames to that Stream object.
+     *
+     * Invokes Stream.incoming() which is expected to process frame without
+     * blocking.
+     */
+    void processFrame(ByteBufferConsumer bbc) throws IOException, InterruptedException {
+        Http2Frame frame = Http2Frame.readIncoming(bbc);
+        Log.logFrames(frame, "IN");
+        int streamid = frame.streamid();
+        if (streamid == 0) {
+            handleCommonFrame(frame);
+        } else {
+            Stream stream = getStream(streamid);
+            if (stream == null) {
+                // should never receive a frame with unknown stream id
+                resetStream(streamid, ResetFrame.PROTOCOL_ERROR);
+            }
+            if (frame instanceof PushPromiseFrame) {
+                PushPromiseFrame pp = (PushPromiseFrame)frame;
+                handlePushPromise(stream, pp);
+            } else if (frame instanceof HeaderFrame) {
+                // decode headers (or continuation)
+                decodeHeaders((HeaderFrame) frame, stream.rspHeadersConsumer());
+                stream.incoming(frame);
+            } else
+                stream.incoming(frame);
+        }
+    }
+
+    private void handlePushPromise(Stream parent, PushPromiseFrame pp)
+            throws IOException, InterruptedException {
+
+        HttpRequestImpl parentReq = parent.request;
+        int promisedStreamid = pp.getPromisedStream();
+        if (promisedStreamid != nextPushStream) {
+            resetStream(promisedStreamid, ResetFrame.PROTOCOL_ERROR);
+            return;
+        } else {
+            nextPushStream += 2;
+        }
+        HeaderDecoder decoder = new HeaderDecoder();
+        decodeHeaders(pp, decoder);
+        HttpHeadersImpl headers = decoder.headers();
+        HttpRequestImpl pushReq = HttpRequestImpl.createPushRequest(parentReq, headers);
+
+        Stream.PushedStream pushStream = createPushStream(parent, pushReq);
+        pushStream.registerStream(promisedStreamid);
+        parent.incoming_pushPromise(pushReq, pushStream);
+    }
+
+    private void handleCommonFrame(Http2Frame frame)
+            throws IOException, InterruptedException {
+
+        switch (frame.type()) {
+          case SettingsFrame.TYPE:
+          { SettingsFrame f = (SettingsFrame)frame;
+            handleSettings(f);}
+            break;
+          case PingFrame.TYPE:
+          { PingFrame f = (PingFrame)frame;
+            handlePing(f);}
+            break;
+          case GoAwayFrame.TYPE:
+          { GoAwayFrame f = (GoAwayFrame)frame;
+            handleGoAway(f);}
+            break;
+          case WindowUpdateFrame.TYPE:
+          { WindowUpdateFrame f = (WindowUpdateFrame)frame;
+            handleWindowUpdate(f);}
+            break;
+          default:
+            protocolError(ErrorFrame.PROTOCOL_ERROR);
+        }
+    }
+
+    void resetStream(int streamid, int code) throws IOException, InterruptedException {
+        Log.logError(
+            "Resetting stream {0,number,integer} with error code {1,number,integer}",
+            streamid, code);
+        ResetFrame frame = new ResetFrame();
+        frame.streamid(streamid);
+        frame.setErrorCode(code);
+        sendFrame(frame);
+        streams.remove(streamid);
+    }
+
+    private void handleWindowUpdate(WindowUpdateFrame f)
+            throws IOException, InterruptedException {
+        updateSendWindow(f.getUpdate());
+    }
+
+    private void protocolError(int errorCode)
+            throws IOException, InterruptedException {
+        GoAwayFrame frame = new GoAwayFrame();
+        frame.setErrorCode(errorCode);
+        sendFrame(frame);
+        String msg = "Error code: " + errorCode;
+        shutdown(new IOException("protocol error"));
+    }
+
+    private void handleSettings(SettingsFrame frame)
+            throws IOException, InterruptedException {
+        if (frame.getFlag(SettingsFrame.ACK)) {
+            // ignore ack frames for now.
+            return;
+        }
+        serverSettings = frame;
+        SettingsFrame ack = getAckFrame(frame.streamid());
+        sendFrame(ack);
+    }
+
+    private void handlePing(PingFrame frame)
+            throws IOException, InterruptedException {
+        frame.setFlag(PingFrame.ACK);
+        sendFrame(frame);
+    }
+
+    private void handleGoAway(GoAwayFrame frame)
+            throws IOException, InterruptedException {
+        //System.err.printf("GoAWAY: %s\n", ErrorFrame.stringForCode(frame.getErrorCode()));
+        shutdown(new IOException("GOAWAY received"));
+    }
+
+    private void initCommon() {
+        clientSettings = client2.getClientSettings();
+
+        // serverSettings will be updated by server
+        serverSettings = SettingsFrame.getDefaultSettings();
+        hpackOut = new Encoder(serverSettings.getParameter(HEADER_TABLE_SIZE));
+        hpackIn = new Decoder(clientSettings.getParameter(HEADER_TABLE_SIZE));
+    }
+
+    /**
+     * Max frame size we are allowed to send
+     */
+    public int getMaxSendFrameSize() {
+        int param = serverSettings.getParameter(MAX_FRAME_SIZE);
+        if (param == -1) {
+            param = DEFAULT_FRAME_SIZE;
+        }
+        return param;
+    }
+
+    /**
+     * Max frame size we will receive
+     */
+    public int getMaxReceiveFrameSize() {
+        return clientSettings.getParameter(MAX_FRAME_SIZE);
+    }
+
+    // Not sure how useful this is.
+    public int getMaxHeadersSize() {
+        return serverSettings.getParameter(MAX_HEADER_LIST_SIZE);
+    }
+
+    private static final String CLIENT_PREFACE = "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n";
+
+    private static final byte[] PREFACE_BYTES =
+        CLIENT_PREFACE.getBytes(StandardCharsets.ISO_8859_1);
+
+    /**
+     * Sends Connection preface and Settings frame with current preferred
+     * values
+     */
+    private void sendConnectionPreface() throws IOException {
+        ByteBufferGenerator bg = new ByteBufferGenerator(this);
+        bg.getBuffer(PREFACE_BYTES.length).put(PREFACE_BYTES);
+        ByteBuffer[] ba = bg.getBufferArray();
+        connection.write(ba, 0, ba.length);
+
+        bg = new ByteBufferGenerator(this);
+        SettingsFrame sf = client2.getClientSettings();
+        Log.logFrames(sf, "OUT");
+        sf.writeOutgoing(bg);
+        WindowUpdateFrame wup = new WindowUpdateFrame();
+        wup.streamid(0);
+        // send a Window update for the receive buffer we are using
+        // minus the initial 64 K specified in protocol
+        wup.setUpdate(client2.client().getReceiveBufferSize() - (64 * 1024 - 1));
+        wup.computeLength();
+        wup.writeOutgoing(bg);
+        Log.logFrames(wup, "OUT");
+        ba = bg.getBufferArray();
+        connection.write(ba, 0, ba.length);
+    }
+
+    /**
+     * Returns an existing Stream with given id, or null if doesn't exist
+     */
+    Stream getStream(int streamid) {
+        return streams.get(streamid);
+    }
+
+    /**
+     * Creates Stream with given id.
+     */
+    Stream createStream(Exchange exchange) {
+        Stream stream = new Stream(client, this, exchange);
+        return stream;
+    }
+
+    Stream.PushedStream createPushStream(Stream parent, HttpRequestImpl pushReq) {
+        Stream.PushGroup<?> pg = parent.request.pushGroup();
+        return new Stream.PushedStream(pg, client, this, parent, pushReq);
+    }
+
+    void putStream(Stream stream, int streamid) {
+        streams.put(streamid, stream);
+    }
+
+    void deleteStream(Stream stream) {
+        streams.remove(stream.streamid);
+    }
+
+    static final int MAX_STREAM = Integer.MAX_VALUE - 2;
+
+    // Number of header bytes in a Headers Frame
+    final static int HEADERS_HEADER_SIZE = 15;
+
+    // Number of header bytes in a Continuation frame
+    final static int CONTIN_HEADER_SIZE = 9;
+
+    /**
+     * Encode the headers into a List<ByteBuffer> and then create HEADERS
+     * and CONTINUATION frames from the list and return the List<Http2Frame>.
+     *
+     * @param frame
+     * @return
+     */
+    private LinkedList<Http2Frame> encodeHeaders(OutgoingHeaders frame) {
+        LinkedList<ByteBuffer> buffers = new LinkedList<>();
+        ByteBuffer buf = getBuffer();
+        buffers.add(buf);
+        encodeHeadersImpl(frame.stream.getRequestPseudoHeaders(), buffers);
+        encodeHeadersImpl(frame.getUserHeaders(), buffers);
+        encodeHeadersImpl(frame.getSystemHeaders(), buffers);
+
+        for (ByteBuffer b : buffers) {
+            b.flip();
         }
 
-    Http2Connection(HttpConnection connection, Http2ClientImpl client2,
-            Exchange exchange) throws IOException, InterruptedException {
+        LinkedList<Http2Frame> frames = new LinkedList<>();
+        int maxframesize = getMaxSendFrameSize();
+
+        HeadersFrame oframe = new HeadersFrame();
+        oframe.setFlags(frame.getFlags());
+        oframe.streamid(frame.streamid());
+
+        oframe.setHeaderBlock(getBufferArray(buffers, maxframesize));
+        frames.add(oframe);
+        // Any buffers left?
+        boolean done = buffers.isEmpty();
+        if (done) {
+            oframe.setFlag(HeaderFrame.END_HEADERS);
+        } else {
+            ContinuationFrame cf = null;
+            while (!done) {
+                cf = new ContinuationFrame();
+                cf.streamid(frame.streamid());
+                cf.setHeaderBlock(getBufferArray(buffers, maxframesize));
+                frames.add(cf);
+                done = buffers.isEmpty();
+            }
+            cf.setFlag(HeaderFrame.END_HEADERS);
+        }
+        return frames;
+    }
+
+    // should always return at least one buffer
+    private static ByteBuffer[] getBufferArray(LinkedList<ByteBuffer> list, int maxsize) {
+        assert maxsize >= BUFSIZE;
+        LinkedList<ByteBuffer> newlist = new LinkedList<>();
+        int size = list.size();
+        int nbytes = 0;
+        for (int i=0; i<size; i++) {
+            ByteBuffer buf = list.getFirst();
+            if (nbytes + buf.remaining() <= maxsize) {
+                nbytes += buf.remaining();
+                newlist.add(buf);
+                list.remove();
+            } else {
+                break;
+            }
+        }
+        return newlist.toArray(empty);
+    }
+
+    /**
+     * Encode all the headers from the given HttpHeadersImpl into the given List.
+     */
+    private void encodeHeadersImpl(HttpHeaders hdrs, LinkedList<ByteBuffer> buffers) {
+        ByteBuffer buffer;
+        if (!(buffer = buffers.getLast()).hasRemaining()) {
+            buffer = getBuffer();
+            buffers.add(buffer);
+        }
+        for (Map.Entry<String, List<String>> e : hdrs.map().entrySet()) {
+            String key = e.getKey();
+            String lkey = key.toLowerCase();
+            List<String> values = e.getValue();
+            for (String value : values) {
+                hpackOut.header(lkey, value);
+                boolean encoded = false;
+                do {
+                    encoded = hpackOut.encode(buffer);
+                    if (!encoded) {
+                        buffer = getBuffer();
+                        buffers.add(buffer);
+                    }
+                } while (!encoded);
+            }
+        }
+    }
+
+    public void sendFrames(List<Http2Frame> frames) throws IOException, InterruptedException {
+        for (Http2Frame frame : frames) {
+            sendFrame(frame);
+        }
     }
 
-    Stream getStream(int i) {return null;}
-    Stream createStream(Exchange ex) {return null;}
-    void putConnection() {}
+    static Throwable getExceptionFrom(CompletableFuture<?> cf) {
+        try {
+            cf.get();
+            return null;
+        } catch (Throwable e) {
+            if (e.getCause() != null)
+                return e.getCause();
+            else
+                return e;
+        }
+    }
+
+
+    void execute(Runnable r) {
+        executor.execute(r, null);
+    }
+
+    private final Object sendlock = new Object();
+
+    /**
+     *
+     */
+    void sendFrame(Http2Frame frame) {
+        synchronized (sendlock) {
+            try {
+                if (frame instanceof OutgoingHeaders) {
+                    OutgoingHeaders oh = (OutgoingHeaders) frame;
+                    Stream stream = oh.getStream();
+                    stream.registerStream(nextstreamid);
+                    oh.streamid(nextstreamid);
+                    nextstreamid += 2;
+                    // set outgoing window here. This allows thread sending
+                    // body to proceed.
+                    stream.updateOutgoingWindow(getInitialSendWindowSize());
+                    LinkedList<Http2Frame> frames = encodeHeaders(oh);
+                    for (Http2Frame f : frames) {
+                        sendOneFrame(f);
+                    }
+                } else {
+                    sendOneFrame(frame);
+                }
+
+            } catch (IOException e) {
+                if (!closed) {
+                    Log.logError(e);
+                    shutdown(e);
+                }
+            }
+        }
+    }
+
+    /**
+     * Send a frame.
+     *
+     * @param frame
+     * @throws IOException
+     */
+    private void sendOneFrame(Http2Frame frame) throws IOException {
+        ByteBufferGenerator bbg = new ByteBufferGenerator(this);
+        frame.computeLength();
+        Log.logFrames(frame, "OUT");
+        frame.writeOutgoing(bbg);
+        ByteBuffer[] currentBufs = bbg.getBufferArray();
+        connection.write(currentBufs, 0, currentBufs.length);
+    }
+
+
+    private SettingsFrame getAckFrame(int streamid) {
+        SettingsFrame frame = new SettingsFrame();
+        frame.setFlag(SettingsFrame.ACK);
+        frame.streamid(streamid);
+        return frame;
+    }
+
+    static class HeaderDecoder implements DecodingCallback {
+        HttpHeadersImpl headers;
+
+        HeaderDecoder() {
+            this.headers = new HttpHeadersImpl();
+        }
+
+        @Override
+        public void onDecoded(CharSequence name, CharSequence value) {
+            headers.addHeader(name.toString(), value.toString());
+        }
+
+        HttpHeadersImpl headers() {
+            return headers;
+        }
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/Http2Frame.java	Tue May 03 12:25:20 2016 -0700
@@ -0,0 +1,211 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ */
+package java.net.http;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+/**
+ * When sending a frame, the length field must be set in sub-class
+ * by calling computeLength()
+ */
+abstract class Http2Frame {
+
+    int length = -1;
+    int type;
+    int streamid;
+    int flags;
+
+    // called when reading in only
+    void initCommon(int length, int type, int streamid, int flags) {
+        this.length = length;
+        this.type = type;
+        this.streamid = streamid;
+        this.flags = flags;
+    }
+
+    public int length() {
+        return length;
+    }
+
+    public int type() {
+        return type;
+    }
+
+    public int streamid() {
+        return streamid;
+    }
+
+    public void setFlag(int flag) {
+        flags |= flag;
+    }
+
+    public void setFlags(int flags) {
+        this.flags = flags;
+    }
+
+    public int getFlags() {
+        return flags;
+    }
+
+    public boolean getFlag(int flag) {
+        return (flags & flag) != 0;
+    }
+
+    public void clearFlag(int flag) {
+        flags &= 0xffffffff ^ flag;
+    }
+
+    public void streamid(int streamid) {
+        this.streamid = streamid;
+    }
+
+    abstract void readIncomingImpl(ByteBufferConsumer bc) throws IOException;
+
+    /**
+     * assume given array contains at least one complete frame.
+     */
+    static Http2Frame readIncoming(ByteBufferConsumer bc) throws IOException {
+        int x = bc.getInt();
+        int length = x >> 8;
+        int type = x & 0xff;
+        int flags = bc.getByte();
+        int streamid = bc.getInt();
+        Http2Frame f = null;
+        switch (type) {
+          case DataFrame.TYPE:
+            f = new DataFrame();
+            break;
+          case HeadersFrame.TYPE:
+            f = new HeadersFrame();
+            break;
+          case ContinuationFrame.TYPE:
+            f = new ContinuationFrame();
+            break;
+          case ResetFrame.TYPE:
+            f = new ResetFrame();
+            break;
+          case PriorityFrame.TYPE:
+            f = new PriorityFrame();
+            break;
+          case SettingsFrame.TYPE:
+            f = new SettingsFrame();
+            break;
+          case GoAwayFrame.TYPE:
+            f = new GoAwayFrame();
+            break;
+          case PingFrame.TYPE:
+            f = new PingFrame();
+            break;
+          case PushPromiseFrame.TYPE:
+            f = new PushPromiseFrame();
+            break;
+          case WindowUpdateFrame.TYPE:
+            f = new WindowUpdateFrame();
+            break;
+          default:
+            String msg = Integer.toString(type);
+            throw new IOException("unknown frame type " + msg);
+        }
+        f.initCommon(length, type, streamid, flags);
+        f.readIncomingImpl(bc);
+        return f;
+    }
+
+    public String typeAsString() {
+        return asString(this.type);
+    }
+
+    public static String asString(int type) {
+        switch (type) {
+          case DataFrame.TYPE:
+            return "DATA";
+          case HeadersFrame.TYPE:
+            return "HEADERS";
+          case ContinuationFrame.TYPE:
+            return "CONTINUATION";
+          case ResetFrame.TYPE:
+            return "RESET";
+          case PriorityFrame.TYPE:
+            return "PRIORITY";
+          case SettingsFrame.TYPE:
+            return "SETTINGS";
+          case GoAwayFrame.TYPE:
+            return "GOAWAY";
+          case PingFrame.TYPE:
+            return "PING";
+          case PushPromiseFrame.TYPE:
+            return "PUSH_PROMISE";
+          case WindowUpdateFrame.TYPE:
+            return "WINDOW_UPDATE";
+          default:
+            return "UNKNOWN";
+        }
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append(typeAsString())
+                .append(": length=")
+                .append(Integer.toString(length))
+                .append(", streamid=")
+                .append(streamid)
+                .append(", flags=");
+
+        int f = flags;
+        int i = 0;
+        if (f == 0) {
+            sb.append("0 ");
+        } else {
+            while (f != 0) {
+                if ((f & 1) == 1) {
+                    sb.append(flagAsString(1 << i))
+                      .append(' ');
+                }
+                f = f >> 1;
+                i++;
+            }
+        }
+        return sb.toString();
+    }
+
+    // Override
+    String flagAsString(int f) {
+        return "unknown";
+    }
+
+    abstract void computeLength();
+
+    void writeOutgoing(ByteBufferGenerator bg) {
+        if (length == -1) {
+            throw new InternalError("Length not set on outgoing frame");
+        }
+        ByteBuffer buf = bg.getBuffer(9);
+        int x = (length << 8) + type;
+        buf.putInt(x);
+        buf.put((byte)flags);
+        buf.putInt(streamid);
+    }
+}
--- a/jdk/src/java.httpclient/share/classes/java/net/http/HttpClientImpl.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/HttpClientImpl.java	Tue May 03 12:25:20 2016 -0700
@@ -23,28 +23,32 @@
  */
 package java.net.http;
 
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLParameters;
 import java.io.IOException;
 import java.net.Authenticator;
 import java.net.CookieManager;
 import java.net.ProxySelector;
 import java.net.URI;
-import static java.net.http.Utils.BUFSIZE;
 import java.nio.ByteBuffer;
 import java.nio.channels.ClosedChannelException;
 import java.nio.channels.SelectableChannel;
 import java.nio.channels.SelectionKey;
-import static java.nio.channels.SelectionKey.OP_CONNECT;
-import static java.nio.channels.SelectionKey.OP_READ;
-import static java.nio.channels.SelectionKey.OP_WRITE;
 import java.nio.channels.Selector;
-import java.util.*;
-import java.util.stream.Stream;
+import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Optional;
+import java.util.Set;
 import java.util.concurrent.ExecutorService;
-import java.security.NoSuchAlgorithmException;
 import java.util.concurrent.Executors;
 import java.util.concurrent.ThreadFactory;
-import javax.net.ssl.SSLContext;
-import javax.net.ssl.SSLParameters;
+import java.util.stream.Stream;
+
+import static java.net.http.Utils.BUFSIZE;
 
 /**
  * Client implementation. Contains all configuration information and also
@@ -53,6 +57,9 @@
  */
 class HttpClientImpl extends HttpClient implements BufferHandler {
 
+    private static final ThreadFactory defaultFactory =
+            (r -> new Thread(null, r, "HttpClient_worker", 0, true));
+
     private final CookieManager cookieManager;
     private final Redirect followRedirects;
     private final ProxySelector proxySelector;
@@ -67,7 +74,6 @@
     private final SelectorManager selmgr;
     private final FilterFactory filters;
     private final Http2ClientImpl client2;
-    private static final ThreadFactory defaultFactory = Executors.defaultThreadFactory();
     private final LinkedList<TimeoutEvent> timeouts;
 
     public static HttpClientImpl create(HttpClientBuilderImpl builder) {
@@ -115,7 +121,6 @@
             throw new InternalError(e);
         }
         selmgr.setDaemon(true);
-        selmgr.setName("HttpSelector");
         filters = new FilterFactory();
         initFilters();
     }
@@ -135,7 +140,7 @@
      *  4)   - mark connection as blocking
      *  5)   - call AsyncEvent.handle()
      *
-     *  If exchange needs to block again, then call registerEvent() again
+     * If exchange needs to block again, then call registerEvent() again
      */
     void registerEvent(AsyncEvent exchange) throws IOException {
         selmgr.register(exchange);
@@ -145,35 +150,56 @@
         return client2;
     }
 
-    LinkedList<ByteBuffer> freelist = new LinkedList<>();
+    /**
+     * We keep one size of buffer on free list. That size may increase
+     * depending on demand. If that happens we dispose of free buffers
+     * that are smaller than new size.
+     */
+    private final LinkedList<ByteBuffer> freelist = new LinkedList<>();
+    int currentSize = BUFSIZE;
 
     @Override
-    public synchronized ByteBuffer getBuffer() {
-        if (freelist.isEmpty()) {
-            return ByteBuffer.allocate(BUFSIZE);
+    public synchronized ByteBuffer getBuffer(int size) {
+
+        ByteBuffer buf;
+        if (size == -1)
+            size = currentSize;
+
+        if (size > currentSize)
+            currentSize = size;
+
+        while (!freelist.isEmpty()) {
+            buf = freelist.removeFirst();
+            if (buf.capacity() < currentSize)
+                continue;
+            buf.clear();
+            return buf;
         }
-        return freelist.removeFirst();
+        return ByteBuffer.allocate(size);
     }
 
     @Override
     public synchronized void returnBuffer(ByteBuffer buffer) {
-        buffer.clear();
         freelist.add(buffer);
     }
 
+    @Override
+    public synchronized void setMinBufferSize(int n) {
+        currentSize = Math.max(n, currentSize);
+    }
 
     // Main loop for this client's selector
+    private final class SelectorManager extends Thread {
 
-    class SelectorManager extends Thread {
-        final Selector selector;
-        boolean closed;
-
-        final List<AsyncEvent> readyList;
-        final List<AsyncEvent> registrations;
+        private final Selector selector;
+        private volatile boolean closed;
+        private final List<AsyncEvent> readyList;
+        private final List<AsyncEvent> registrations;
 
         SelectorManager() throws IOException {
-            readyList = new LinkedList<>();
-            registrations = new LinkedList<>();
+            super(null, null, "SelectorManager", 0, false);
+            readyList = new ArrayList<>();
+            registrations = new ArrayList<>();
             selector = Selector.open();
         }
 
@@ -193,32 +219,13 @@
             closed = true;
             try {
                 selector.close();
-            } catch (IOException e) {}
-        }
-
-        private List<AsyncEvent> copy(List<AsyncEvent> list) {
-            LinkedList<AsyncEvent> c = new LinkedList<>();
-            for (AsyncEvent e : list) {
-                c.add(e);
-            }
-            return c;
-        }
-
-        String opvals(int i) {
-            StringBuilder sb = new StringBuilder();
-            if ((i & OP_READ) != 0)
-                sb.append("OP_READ ");
-            if ((i & OP_CONNECT) != 0)
-                sb.append("OP_CONNECT ");
-            if ((i & OP_WRITE) != 0)
-                sb.append("OP_WRITE ");
-            return sb.toString();
+            } catch (IOException ignored) { }
         }
 
         @Override
         public void run() {
             try {
-                while (true) {
+                while (!Thread.currentThread().isInterrupted()) {
                     synchronized (this) {
                         for (AsyncEvent exchange : registrations) {
                             SelectableChannel c = exchange.channel();
@@ -229,7 +236,7 @@
                                 if (key == null) {
                                     sa = new SelectorAttachment(c, selector);
                                 } else {
-                                    sa = (SelectorAttachment)key.attachment();
+                                    sa = (SelectorAttachment) key.attachment();
                                 }
                                 sa.register(exchange);
                             } catch (IOException e) {
@@ -243,6 +250,7 @@
                     }
                     long timeval = getTimeoutValue();
                     long now = System.currentTimeMillis();
+                    //debugPrint(selector);
                     int n = selector.select(timeval);
                     if (n == 0) {
                         signalTimeouts(now);
@@ -251,7 +259,7 @@
                     Set<SelectionKey> keys = selector.selectedKeys();
 
                     for (SelectionKey key : keys) {
-                        SelectorAttachment sa = (SelectorAttachment)key.attachment();
+                        SelectorAttachment sa = (SelectorAttachment) key.attachment();
                         int eventsOccurred = key.readyOps();
                         sa.events(eventsOccurred).forEach(readyList::add);
                         sa.resetInterestOps(eventsOccurred);
@@ -260,10 +268,8 @@
                     selector.selectedKeys().clear();
 
                     for (AsyncEvent exchange : readyList) {
-                        if (exchange instanceof AsyncEvent.Blocking) {
+                        if (exchange.blocking()) {
                             exchange.channel().configureBlocking(true);
-                        } else {
-                            assert exchange instanceof AsyncEvent.NonBlocking;
                         }
                         executor.synchronize();
                         handleEvent(exchange); // will be delegated to executor
@@ -272,14 +278,26 @@
                 }
             } catch (Throwable e) {
                 if (!closed) {
-                    System.err.println("HttpClientImpl terminating on error");
                     // This terminates thread. So, better just print stack trace
                     String err = Utils.stackTrace(e);
                     Log.logError("HttpClientImpl: fatal error: " + err);
                 }
+            } finally {
+                shutdown();
             }
         }
 
+        void debugPrint(Selector selector) {
+            System.err.println("Selector: debugprint start");
+            Set<SelectionKey> keys = selector.keys();
+            for (SelectionKey key : keys) {
+                SelectableChannel c = key.channel();
+                int ops = key.interestOps();
+                System.err.printf("selector chan:%s ops:%d\n", c, ops);
+            }
+            System.err.println("Selector: debugprint end");
+        }
+
         void handleEvent(AsyncEvent e) {
             if (closed) {
                 e.abort();
@@ -303,7 +321,7 @@
         private final SelectableChannel chan;
         private final Selector selector;
         private final ArrayList<AsyncEvent> pending;
-        private int interestops;
+        private int interestOps;
 
         SelectorAttachment(SelectableChannel chan, Selector selector) {
             this.pending = new ArrayList<>();
@@ -312,53 +330,53 @@
         }
 
         void register(AsyncEvent e) throws ClosedChannelException {
-            int newops = e.interestOps();
-            boolean reRegister = (interestops & newops) != newops;
-            interestops |= newops;
+            int newOps = e.interestOps();
+            boolean reRegister = (interestOps & newOps) != newOps;
+            interestOps |= newOps;
             pending.add(e);
             if (reRegister) {
                 // first time registration happens here also
-                chan.register(selector, interestops, this);
+                chan.register(selector, interestOps, this);
             }
         }
 
-        int interestOps() {
-            return interestops;
-        }
-
         /**
          * Returns a Stream<AsyncEvents> containing only events that are
-         * registered with the given {@code interestop}.
+         * registered with the given {@code interestOps}.
          */
-        Stream<AsyncEvent> events(int interestop) {
+        Stream<AsyncEvent> events(int interestOps) {
             return pending.stream()
-                          .filter(ev -> (ev.interestOps() & interestop) != 0);
+                    .filter(ev -> (ev.interestOps() & interestOps) != 0);
         }
 
         /**
-         * Removes any events with the given {@code interestop}, and if no
+         * Removes any events with the given {@code interestOps}, and if no
          * events remaining, cancels the associated SelectionKey.
          */
-        void resetInterestOps(int interestop) {
-            int newops = 0;
+        void resetInterestOps(int interestOps) {
+            int newOps = 0;
 
             Iterator<AsyncEvent> itr = pending.iterator();
             while (itr.hasNext()) {
                 AsyncEvent event = itr.next();
                 int evops = event.interestOps();
-                if ((evops & interestop) != 0) {
+                if (event.repeating()) {
+                    newOps |= evops;
+                    continue;
+                }
+                if ((evops & interestOps) != 0) {
                     itr.remove();
                 } else {
-                    newops |= evops;
+                    newOps |= evops;
                 }
             }
 
-            interestops = newops;
+            this.interestOps = newOps;
             SelectionKey key = chan.keyFor(selector);
-            if (newops == 0) {
+            if (newOps == 0) {
                 key.cancel();
             } else {
-                key.interestOps(newops);
+                key.interestOps(newOps);
             }
         }
     }
@@ -366,7 +384,8 @@
     /**
      * Creates a HttpRequest associated with this group.
      *
-     * @throws IllegalStateException if the group has been stopped
+     * @throws IllegalStateException
+     *         if the group has been stopped
      */
     @Override
     public HttpRequestBuilderImpl request() {
@@ -376,7 +395,8 @@
     /**
      * Creates a HttpRequest associated with this group.
      *
-     * @throws IllegalStateException if the group has been stopped
+     * @throws IllegalStateException
+     *         if the group has been stopped
      */
     @Override
     public HttpRequestBuilderImpl request(URI uri) {
@@ -444,16 +464,12 @@
         return version.equals(Version.HTTP_2);
     }
 
-    //void setHttp2NotSupported(String host) {
-        //http2NotSupported.put(host, false);
-    //}
-
-    final void initFilters() {
+    private void initFilters() {
         addFilter(AuthenticationFilter.class);
         addFilter(RedirectFilter.class);
     }
 
-    final void addFilter(Class<? extends HeaderFilter> f) {
+    private void addFilter(Class<? extends HeaderFilter> f) {
         filters.addFilter(f);
     }
 
@@ -479,14 +495,14 @@
                 iter.previous();
                 break;
             } else if (!iter.hasNext()) {
-                event.delta = event.timeval - listval ;
+                event.delta = event.timeval - listval;
             }
         }
         iter.add(event);
         selmgr.wakeupSelector();
     }
 
-    synchronized void signalTimeouts(long then) {
+    private synchronized void signalTimeouts(long then) {
         if (timeouts.isEmpty()) {
             return;
         }
@@ -532,12 +548,12 @@
     // used for the connection window
     int getReceiveBufferSize() {
         return Utils.getIntegerNetProperty(
-                "sun.net.httpclient.connectionWindowSize", 256 * 1024
+                "java.net.httpclient.connectionWindowSize", 256 * 1024
         );
     }
 
     // returns 0 meaning block forever, or a number of millis to block for
-    synchronized long getTimeoutValue() {
+    private synchronized long getTimeoutValue() {
         if (timeouts.isEmpty()) {
             return 0;
         } else {
--- a/jdk/src/java.httpclient/share/classes/java/net/http/HttpConnection.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/HttpConnection.java	Tue May 03 12:25:20 2016 -0700
@@ -23,9 +23,8 @@
  */
 package java.net.http;
 
-import java.io.FileOutputStream;
+import java.io.Closeable;
 import java.io.IOException;
-import java.io.PrintStream;
 import java.net.InetSocketAddress;
 import java.nio.ByteBuffer;
 import java.nio.channels.SocketChannel;
@@ -42,7 +41,17 @@
  *      SSLConnection: TLS channel direct to server
  *      SSLTunnelConnection: TLS channel via (CONNECT) proxy tunnel
  */
-abstract class HttpConnection implements BufferHandler {
+abstract class HttpConnection implements BufferHandler, Closeable {
+
+    protected final static ByteBuffer emptyBuf = Utils.EMPTY_BYTEBUFFER;
+
+    enum Mode {
+        BLOCKING,
+        NON_BLOCKING,
+        ASYNC
+    }
+
+    protected Mode mode;
 
     // address we are connected to. Could be a server or a proxy
     final InetSocketAddress address;
@@ -52,6 +61,7 @@
     HttpConnection(InetSocketAddress address, HttpClientImpl client) {
         this.address = address;
         this.client = client;
+        this.buffer = emptyBuf;
     }
 
     /**
@@ -68,7 +78,21 @@
      */
     public static HttpConnection getConnection(InetSocketAddress addr,
                                                HttpRequestImpl request) {
-        return getConnectionImpl(addr, request);
+        return getConnectionImpl(addr, request, null);
+    }
+
+    /**
+     * Called specifically to get an async connection for HTTP/2 over SSL.
+     *
+     * @param addr
+     * @param request
+     * @param http2
+     * @return
+     */
+    public static HttpConnection getConnection(InetSocketAddress addr,
+        HttpRequestImpl request, Http2Connection http2) {
+
+        return getConnectionImpl(addr, request, http2);
     }
 
     public abstract void connect() throws IOException, InterruptedException;
@@ -93,7 +117,7 @@
     // at beginning of response.
     ByteBuffer getRemaining() {
         ByteBuffer b = buffer;
-        buffer = null;
+        buffer = emptyBuf;
         return b;
     }
 
@@ -123,17 +147,18 @@
     }
 
     private static HttpConnection getSSLConnection(InetSocketAddress addr,
-                                                   InetSocketAddress proxy,
-                                                   HttpRequestImpl request,
-                                                   String[] alpn) {
+            InetSocketAddress proxy, HttpRequestImpl request,
+            String[] alpn, Http2Connection http2) {
         HttpClientImpl client = request.client();
         if (proxy != null) {
             return new SSLTunnelConnection(addr,
                                            client,
                                            proxy,
                                            request.getAccessControlContext());
+        } else if (http2 == null) {
+            return new SSLConnection(addr, client, alpn);
         } else {
-            return new SSLConnection(addr, client, alpn);
+            return new AsyncSSLConnection(addr, client, alpn);
         }
     }
 
@@ -142,7 +167,8 @@
      * none available.
      */
     private static HttpConnection getConnectionImpl(InetSocketAddress addr,
-                                                    HttpRequestImpl request) {
+            HttpRequestImpl request, Http2Connection http2) {
+
         HttpConnection c;
         HttpClientImpl client = request.client();
         InetSocketAddress proxy = request.proxy();
@@ -167,7 +193,7 @@
             if (c != null) {
                 return c;
             } else {
-                return getSSLConnection(addr, proxy, request, alpn);
+                return getSSLConnection(addr, proxy, request, alpn, http2);
             }
         }
     }
@@ -223,64 +249,16 @@
         return address;
     }
 
-    void configureBlocking(boolean mode) throws IOException {
-        channel().configureBlocking(mode);
+    synchronized void configureMode(Mode mode) throws IOException {
+        this.mode = mode;
+        if (mode == Mode.BLOCKING)
+            channel().configureBlocking(true);
+        else
+            channel().configureBlocking(false);
     }
 
     abstract ConnectionPool.CacheKey cacheKey();
 
-    /*
-    static PrintStream ps;
-
-    static {
-        try {
-            String propval = Utils.getNetProperty("java.net.httpclient.showData");
-            if (propval != null && propval.equalsIgnoreCase("true")) {
-                ps = new PrintStream(new FileOutputStream("/tmp/httplog.txt"), false);
-            }
-        } catch (IOException e) {
-            e.printStackTrace();
-        }
-    }
-
-    synchronized final void debugPrint(String s, ByteBuffer b) {
-        ByteBuffer[] bufs = new ByteBuffer[1];
-        bufs[0] = b;
-        debugPrint(s, bufs, 0, 1);
-    }
-
-    synchronized final void debugPrint(String s,
-                                       ByteBuffer[] bufs,
-                                       int start,
-                                       int number) {
-        if (ps == null) {
-            return;
-        }
-
-        ps.printf("\n%s:\n", s);
-
-        for (int i=start; i<start+number; i++) {
-            ByteBuffer b = bufs[i].duplicate();
-            while (b.hasRemaining()) {
-                int c = b.get();
-                if (c == 10) {
-                    ps.printf("LF \n");
-                } else if (c == 13) {
-                    ps.printf(" CR ");
-                } else if (c == 0x20) {
-                    ps.printf("_");
-                } else if (c > 0x20 && c <= 0x7F) {
-                    ps.printf("%c", (char)c);
-                } else {
-                    ps.printf("0x%02x ", c);
-                }
-            }
-        }
-        ps.printf("\n---------------------\n");
-    }
-
-    */
-
     // overridden in SSL only
     SSLParameters sslParameters() {
         return null;
@@ -296,7 +274,8 @@
     /**
      * Closes this connection, by returning the socket to its connection pool.
      */
-    abstract void close();
+    @Override
+    public abstract void close();
 
     /**
      * Returns a ByteBuffer with data, or null if EOF.
@@ -356,12 +335,17 @@
     }
 
     @Override
-    public final ByteBuffer getBuffer() {
-        return client.getBuffer();
+    public final ByteBuffer getBuffer(int n) {
+        return client.getBuffer(n);
     }
 
     @Override
     public final void returnBuffer(ByteBuffer buffer) {
         client.returnBuffer(buffer);
     }
+
+    @Override
+    public final void setMinBufferSize(int n) {
+        client.setMinBufferSize(n);
+    }
 }
--- a/jdk/src/java.httpclient/share/classes/java/net/http/HttpHeadersImpl.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/HttpHeadersImpl.java	Tue May 03 12:25:20 2016 -0700
@@ -24,44 +24,22 @@
 package java.net.http;
 
 import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
 import java.util.Set;
+import java.util.TreeMap;
 
 /**
  * Implementation of HttpHeaders.
  */
-class HttpHeadersImpl implements HttpHeaders1 {
+class HttpHeadersImpl implements HttpHeaders {
 
-    private final HashMap<String,List<String>> headers;
-    private boolean isUnmodifiable = false;
+    private final TreeMap<String,List<String>> headers;
 
     public HttpHeadersImpl() {
-        headers = new HashMap<>();
-    }
-
-    /**
-     * Replace all List<String> in headers with unmodifiable Lists. Call
-     * this only after all headers are added. The headers HashMap
-     * is wrapped with an unmodifiable HashMap in map()
-     */
-    @Override
-    public void makeUnmodifiable() {
-        if (isUnmodifiable)
-            return;
-
-        Set<String> keys = new HashSet<>(headers.keySet());
-        for (String key : keys) {
-            List<String> values = headers.remove(key);
-            if (values != null) {
-                headers.put(key, Collections.unmodifiableList(values));
-            }
-        }
-        isUnmodifiable = true;
+        headers = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
     }
 
     @Override
@@ -88,7 +66,7 @@
 
     public HttpHeadersImpl deepCopy() {
         HttpHeadersImpl h1 = new HttpHeadersImpl();
-        HashMap<String,List<String>> headers1 = h1.headers;
+        TreeMap<String,List<String>> headers1 = h1.headers;
         Set<String> keys = headers.keySet();
         for (String key : keys) {
             List<String> vals = headers.get(key);
@@ -98,22 +76,13 @@
         return h1;
     }
 
-    private List<String> getOrCreate(String name) {
-        List<String> l = headers.get(name);
-        if (l == null) {
-            l = new LinkedList<>();
-            headers.put(name, l);
-        }
-        return l;
-    }
-
     void addHeader(String name, String value) {
-        List<String> l = getOrCreate(name);
-        l.add(value);
+        headers.computeIfAbsent(name, k -> new LinkedList<>())
+               .add(value);
     }
 
     void setHeader(String name, String value) {
-        List<String> l = getOrCreate(name);
+        List<String> l = headers.computeIfAbsent(name, k -> new LinkedList<>());
         l.clear();
         l.add(value);
     }
@@ -122,7 +91,7 @@
     public Optional<Long> firstValueAsLong(String name) {
         List<String> l = headers.get(name);
         if (l == null) {
-            return Optional.ofNullable(null);
+            return Optional.empty();
         } else {
             String v = l.get(0);
             Long lv = Long.parseLong(v);
@@ -133,4 +102,4 @@
     void clear() {
         headers.clear();
     }
-}
+}
\ No newline at end of file
--- a/jdk/src/java.httpclient/share/classes/java/net/http/HttpRequestBuilderImpl.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/HttpRequestBuilderImpl.java	Tue May 03 12:25:20 2016 -0700
@@ -39,10 +39,11 @@
     private HttpClient.Version version;
     private final HttpClientImpl client;
     private ProxySelector proxy;
-    private long timeval = 0;
+    private long timeval;
 
     public HttpRequestBuilderImpl(HttpClientImpl client, URI uri) {
         this.client = client;
+        checkURI(uri);
         this.uri = uri;
         this.version = client.version();
         this.userHeaders = new HttpHeadersImpl();
@@ -58,10 +59,17 @@
     @Override
     public HttpRequestBuilderImpl uri(URI uri) {
         Objects.requireNonNull(uri);
+        checkURI(uri);
         this.uri = uri;
         return this;
     }
 
+    private static void checkURI(URI uri) {
+        String scheme = uri.getScheme().toLowerCase();
+        if (!scheme.equals("https") && !scheme.equals("http"))
+            throw new IllegalArgumentException("invalid URI scheme");
+    }
+
     @Override
     public HttpRequestBuilderImpl followRedirects(HttpClient.Redirect follow) {
         Objects.requireNonNull(follow);
--- a/jdk/src/java.httpclient/share/classes/java/net/http/HttpRequestImpl.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/HttpRequestImpl.java	Tue May 03 12:25:20 2016 -0700
@@ -30,16 +30,14 @@
 import java.net.http.HttpClient.Version;
 import java.net.http.HttpResponse.MultiProcessor;
 import java.util.concurrent.CompletableFuture;
-import java.net.SocketPermission;
 import java.security.AccessControlContext;
 import java.security.AccessController;
-import java.util.Set;
 import static java.net.http.HttpRedirectImpl.getRedirects;
 import java.util.Locale;
 
 class HttpRequestImpl extends HttpRequest {
 
-    private final HttpHeadersImpl userHeaders;
+    private final ImmutableHeaders userHeaders;
     private final HttpHeadersImpl systemHeaders;
     private final URI uri;
     private InetSocketAddress authority; // only used when URI not specified
@@ -56,6 +54,7 @@
     private boolean receiving;
     private AccessControlContext acc;
     private final long timeval;
+    private Stream.PushGroup<?> pushGroup;
 
     public HttpRequestImpl(HttpClientImpl client,
                            String method,
@@ -63,8 +62,8 @@
         this.client = client;
         this.method = method == null? "GET" : method;
         this.userHeaders = builder.headers() == null ?
-                new HttpHeadersImpl() : builder.headers();
-        dropDisallowedHeaders();
+                new ImmutableHeaders() :
+                new ImmutableHeaders(builder.headers(), Utils.ALLOWED_HEADERS);
         this.followRedirects = getRedirects(builder.followRedirects() == null ?
                 client.followRedirects() : builder.followRedirects());
         this.systemHeaders = new HttpHeadersImpl();
@@ -90,15 +89,13 @@
                            HttpRequestImpl other) {
         this.client = client;
         this.method = method == null? "GET" : method;
-        this.userHeaders = other.userHeaders == null ?
-                new HttpHeadersImpl() : other.userHeaders;
-        dropDisallowedHeaders();
+        this.userHeaders = other.userHeaders;
         this.followRedirects = getRedirects(other.followRedirects() == null ?
                 client.followRedirects() : other.followRedirects());
         this.systemHeaders = other.systemHeaders;
         this.uri = uri;
         this.expectContinue = other.expectContinue;
-        this.secure = other.secure;
+        this.secure = uri.getScheme().toLowerCase(Locale.US).equals("https");
         this.requestProcessor = other.requestProcessor;
         this.proxy = other.proxy;
         this.version = other.version;
@@ -115,7 +112,7 @@
         this.method = method;
         this.followRedirects = getRedirects(client.followRedirects());
         this.systemHeaders = new HttpHeadersImpl();
-        this.userHeaders = new HttpHeadersImpl();
+        this.userHeaders = new ImmutableHeaders();
         this.uri = null;
         this.proxy = null;
         this.requestProcessor = HttpRequest.noBody();
@@ -132,16 +129,52 @@
         return client;
     }
 
+    /**
+     * Creates a HttpRequestImpl from the given set of Headers and the associated
+     * "parent" request. Fields not taken from the headers are taken from the
+     * parent.
+     */
+    static HttpRequestImpl createPushRequest(HttpRequestImpl parent,
+            HttpHeadersImpl headers) throws IOException {
+
+        return new HttpRequestImpl(parent, headers);
+    }
+
+    // only used for push requests
+    private HttpRequestImpl(HttpRequestImpl parent, HttpHeadersImpl headers) throws IOException {
+        this.method = headers.firstValue(":method")
+                .orElseThrow(() -> new IOException("No method in Push Promise"));
+        String path = headers.firstValue(":path")
+                .orElseThrow(() -> new IOException("No path in Push Promise"));
+        String scheme = headers.firstValue(":scheme")
+                .orElseThrow(() -> new IOException("No scheme in Push Promise"));
+        String authority = headers.firstValue(":authority")
+                .orElseThrow(() -> new IOException("No authority in Push Promise"));
+        StringBuilder sb = new StringBuilder();
+        sb.append(scheme).append("://").append(authority).append(path);
+        this.uri = URI.create(sb.toString());
+
+        this.client = parent.client;
+        this.userHeaders = new ImmutableHeaders(headers, Utils.ALLOWED_HEADERS);
+        this.followRedirects = parent.followRedirects;
+        this.systemHeaders = parent.systemHeaders;
+        this.expectContinue = parent.expectContinue;
+        this.secure = parent.secure;
+        this.requestProcessor = parent.requestProcessor;
+        this.proxy = parent.proxy;
+        this.version = parent.version;
+        this.acc = parent.acc;
+        this.exchange = parent.exchange;
+        this.timeval = parent.timeval;
+    }
 
     @Override
     public String toString() {
-        return (uri == null ? "" : uri.toString()) + "/" + method + "("
-                + hashCode() + ")";
+        return (uri == null ? "" : uri.toString()) + " " + method;
     }
 
     @Override
     public HttpHeaders headers() {
-        userHeaders.makeUnmodifiable();
         return userHeaders;
     }
 
@@ -154,21 +187,6 @@
         systemHeaders.setHeader("HTTP2-Settings", h2client.getSettingsString());
     }
 
-    private static final Set<String>  DISALLOWED_HEADERS_SET = Set.of(
-        "authorization", "connection", "cookie", "content-length",
-        "date", "expect", "from", "host", "origin", "proxy-authorization",
-        "referer", "user-agent", "upgrade", "via", "warning");
-
-
-    // we silently drop headers that are disallowed
-    private void dropDisallowedHeaders() {
-        Set<String> hdrnames = userHeaders.directMap().keySet();
-
-        hdrnames.removeIf((s) ->
-              DISALLOWED_HEADERS_SET.contains(s.toLowerCase())
-        );
-    }
-
     private synchronized void receiving() {
         if (receiving) {
             throw new IllegalStateException("already receiving response");
@@ -176,6 +194,10 @@
         receiving = true;
     }
 
+    synchronized Stream.PushGroup<?> pushGroup() {
+        return pushGroup;
+    }
+
     /*
      * Response filters may result in a new HttpRequestImpl being created
      * (but still associated with the same API HttpRequest) and the process
@@ -200,10 +222,25 @@
             .thenApply((r) -> (HttpResponse)r);
     }
 
-    public <U> CompletableFuture<U>
-    sendAsyncMulti(HttpResponse.MultiProcessor<U> rspproc) {
-        // To change body of generated methods, choose Tools | Templates.
-        throw new UnsupportedOperationException("Not supported yet.");
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public synchronized <U> CompletableFuture<U>
+    multiResponseAsync(MultiProcessor<U> rspproc) {
+        if (System.getSecurityManager() != null) {
+            acc = AccessController.getContext();
+        }
+        this.pushGroup = new Stream.PushGroup<>(rspproc, this);
+        CompletableFuture<HttpResponse> cf = pushGroup.mainResponse();
+        responseAsync()
+            .whenComplete((HttpResponse r, Throwable t) -> {
+                if (r != null)
+                    cf.complete(r);
+                else
+                    cf.completeExceptionally(t);
+                pushGroup.pushError(t);
+            });
+        return (CompletableFuture<U>)pushGroup.groupResult();
     }
 
     @Override
@@ -255,7 +292,7 @@
     @Override
     public URI uri() { return uri; }
 
-    HttpHeadersImpl getUserHeaders() { return userHeaders; }
+    HttpHeaders getUserHeaders() { return userHeaders; }
 
     HttpHeadersImpl getSystemHeaders() { return systemHeaders; }
 
@@ -275,11 +312,4 @@
     }
 
     long timeval() { return timeval; }
-
-    @Override
-    public <U> CompletableFuture<U>
-    multiResponseAsync(MultiProcessor<U> rspproc) {
-        //To change body of generated methods, choose Tools | Templates.
-        throw new UnsupportedOperationException("Not supported yet.");
-    }
 }
--- a/jdk/src/java.httpclient/share/classes/java/net/http/HttpResponse.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/HttpResponse.java	Tue May 03 12:25:20 2016 -0700
@@ -200,8 +200,12 @@
                 if (n == -1) {
                     throw new IOException("Bad Content-Disposition type");
                 }
-                String disposition = dispoHeader.substring(n + 9,
-                                                           dispoHeader.lastIndexOf(';'));
+                int lastsemi = dispoHeader.lastIndexOf(';');
+                String disposition;
+                if (lastsemi < n)
+                    disposition = dispoHeader.substring(n + 9);
+                else
+                    disposition = dispoHeader.substring(n + 9, lastsemi);
                 file = Paths.get(directory.toString(), disposition);
                 fc = FileChannel.open(file, openOptions);
                 return null;
@@ -727,11 +731,14 @@
             }
 
             private CompletableFuture<Path> getBody(HttpRequest req,
-                                                    CompletableFuture<HttpResponse> cf) {
+                                                    CompletableFuture<? extends HttpResponse> cf) {
                 URI u = req.uri();
                 String path = u.getPath();
+                if (path.startsWith("/"))
+                    path = path.substring(1);
+                final String fpath = path;
                 return cf.thenCompose((HttpResponse resp) -> {
-                    return resp.bodyAsync(HttpResponse.asFile(destination.resolve(path)));
+                    return resp.bodyAsync(HttpResponse.asFile(destination.resolve(fpath)));
                 });
             }
 
--- a/jdk/src/java.httpclient/share/classes/java/net/http/HttpResponseImpl.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/HttpResponseImpl.java	Tue May 03 12:25:20 2016 -0700
@@ -26,6 +26,7 @@
 package java.net.http;
 
 import java.io.IOException;
+import java.io.UncheckedIOException;
 import java.net.URI;
 import java.nio.ByteBuffer;
 import java.security.AccessControlContext;
@@ -42,17 +43,18 @@
     int responseCode;
     Exchange exchange;
     HttpRequestImpl request;
-    HttpHeaders1 headers;
-    HttpHeaders1 trailers;
+    HttpHeaders headers;
+    HttpHeaders trailers;
     SSLParameters sslParameters;
     URI uri;
     HttpClient.Version version;
     AccessControlContext acc;
     RawChannel rawchan;
     HttpConnection connection;
+    final Stream stream;
 
-    public HttpResponseImpl(int responseCode, Exchange exch, HttpHeaders1 headers,
-            HttpHeaders1 trailers, SSLParameters sslParameters,
+    public HttpResponseImpl(int responseCode, Exchange exch, HttpHeaders headers,
+            HttpHeaders trailers, SSLParameters sslParameters,
             HttpClient.Version version, HttpConnection connection) {
         this.responseCode = responseCode;
         this.exchange = exch;
@@ -63,6 +65,23 @@
         this.uri = request.uri();
         this.version = version;
         this.connection = connection;
+        this.stream = null;
+    }
+
+    // A response to a PUSH_PROMISE
+    public HttpResponseImpl(int responseCode, HttpRequestImpl pushRequest,
+            ImmutableHeaders headers,
+            Stream stream, SSLParameters sslParameters) {
+        this.responseCode = responseCode;
+        this.exchange = null;
+        this.request = pushRequest;
+        this.headers = headers;
+        this.trailers = null;
+        this.sslParameters = sslParameters;
+        this.uri = request.uri(); // TODO: take from headers
+        this.version = HttpClient.Version.HTTP_2;
+        this.connection = null;
+        this.stream = stream;
     }
 
     @Override
@@ -77,26 +96,35 @@
 
     @Override
     public HttpHeaders headers() {
-        headers.makeUnmodifiable();
         return headers;
     }
 
     @Override
     public HttpHeaders trailers() {
-        trailers.makeUnmodifiable();
         return trailers;
     }
 
 
     @Override
     public <T> T body(java.net.http.HttpResponse.BodyProcessor<T> processor) {
-        return exchange.responseBody(processor);
+        try {
+            if (exchange != null) {
+                return exchange.responseBody(processor);
+            } else {
+                return stream.responseBody(processor);
+            }
+        } catch (IOException e) {
+            throw new UncheckedIOException(e);
+        }
     }
 
     @Override
     public <T> CompletableFuture<T> bodyAsync(java.net.http.HttpResponse.BodyProcessor<T> processor) {
         acc = AccessController.getContext();
-        return exchange.responseBodyAsync(processor);
+        if (exchange != null)
+            return exchange.responseBodyAsync(processor);
+        else
+            return stream.responseBodyAsync(processor);
     }
 
     @Override
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/ImmutableHeaders.java	Tue May 03 12:25:20 2016 -0700
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ */
+
+package java.net.http;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.TreeMap;
+import java.util.function.Predicate;
+
+/**
+ * Immutable HttpHeaders constructed from mutable HttpHeadersImpl.
+ */
+
+class ImmutableHeaders implements HttpHeaders {
+
+    private final Map<String,List<String>> map;
+
+    @SuppressWarnings("unchecked")
+    ImmutableHeaders() {
+        map = (Map<String,List<String>>)Collections.EMPTY_MAP;
+    }
+    // TODO: fix lower case issue. Must be lc for http/2 compares ignoreCase for http/1
+    ImmutableHeaders(HttpHeadersImpl h, Predicate<String> keyAllowed) {
+        Map<String,List<String>> src = h.directMap();
+        Map<String,List<String>> m = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
+
+        src.forEach((key, value) -> {
+            if (keyAllowed.test(key))
+                m.put(key, Collections.unmodifiableList(value));
+        });
+        map = Collections.unmodifiableMap(m);
+    }
+
+    @Override
+    public Optional<String> firstValue(String name) {
+        List<String> l = map.get(name);
+        String v = l == null ? null : l.get(0);
+        return Optional.ofNullable(v);
+    }
+
+    @Override
+    public Optional<Long> firstValueAsLong(String name) {
+        return firstValue(name).map((v -> Long.parseLong(v)));
+    }
+
+    @Override
+    public List<String> allValues(String name) {
+        return map.get(name);
+    }
+
+    @Override
+    public Map<String, List<String>> map() {
+        return map;
+    }
+}
--- a/jdk/src/java.httpclient/share/classes/java/net/http/Log.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/Log.java	Tue May 03 12:25:20 2016 -0700
@@ -26,7 +26,9 @@
 import java.util.Locale;
 
 /**
- * -Djava.net.HttpClient.log=errors,requests,headers,frames[:type:type2:..],content
+ * -Djava.net.HttpClient.log=
+ *          errors,requests,headers,
+ *          frames[:type:type2:..],content,ssl,trace
  *
  * Any of errors, requests, headers or content are optional.
  *
@@ -47,6 +49,7 @@
     public static final int CONTENT = 0x8;
     public static final int FRAMES = 0x10;
     public static final int SSL = 0x20;
+    public static final int TRACE = 0x40;
     static int logging;
 
     // Frame types: "control", "data", "window", "all"
@@ -81,8 +84,11 @@
                     case "ssl":
                         logging |= SSL;
                         break;
+                    case "trace":
+                        logging |= TRACE;
+                        break;
                     case "all":
-                        logging |= CONTENT|HEADERS|REQUESTS|FRAMES|ERRORS;
+                        logging |= CONTENT|HEADERS|REQUESTS|FRAMES|ERRORS|TRACE;
                         break;
                 }
                 if (val.startsWith("frames")) {
@@ -130,6 +136,10 @@
         return (logging & HEADERS) != 0;
     }
 
+    static boolean trace() {
+        return (logging & TRACE) != 0;
+    }
+
     static boolean ssl() {
         return (logging & SSL) != 0;
     }
@@ -138,9 +148,9 @@
         return (logging & FRAMES) != 0;
     }
 
-    static void logError(String s) {
+    static void logError(String s, Object... s1) {
         if (errors())
-            logger.log(Level.INFO, "ERROR: " + s);
+            logger.log(Level.INFO, "ERROR: " + s, s1);
     }
 
     static void logError(Throwable t) {
@@ -150,24 +160,50 @@
         }
     }
 
-    static void logSSL(String s) {
+    static void logSSL(String s, Object... s1) {
         if (ssl())
-            logger.log(Level.INFO, "SSL: " + s);
+            logger.log(Level.INFO, "SSL: " + s, s1);
+    }
+
+    static void logTrace(String s, Object... s1) {
+        if (trace()) {
+            String format = "TRACE: " + s;
+            logger.log(Level.INFO, format, s1);
+        }
+    }
+
+    static void logRequest(String s, Object... s1) {
+        if (requests())
+            logger.log(Level.INFO, "REQUEST: " + s, s1);
+    }
+
+    static void logResponse(String s, Object... s1) {
+        if (requests())
+            logger.log(Level.INFO, "RESPONSE: " + s, s1);
     }
 
-    static void logRequest(String s) {
-        if (requests())
-            logger.log(Level.INFO, "REQUEST: " + s);
+    static void logHeaders(String s, Object... s1) {
+        if (headers())
+            logger.log(Level.INFO, "HEADERS: " + s, s1);
+    }
+// START HTTP2
+    static boolean loggingFrame(Class<? extends Http2Frame> clazz) {
+        if (frametypes == ALL) {
+            return true;
+        }
+        if (clazz == DataFrame.class) {
+            return (frametypes & DATA) != 0;
+        } else if (clazz == WindowUpdateFrame.class) {
+            return (frametypes & WINDOW_UPDATES) != 0;
+        } else {
+            return (frametypes & CONTROL) != 0;
+        }
     }
 
-    static void logResponse(String s) {
-        if (requests())
-            logger.log(Level.INFO, "RESPONSE: " + s);
-    }
-
-    static void logHeaders(String s) {
-        if (headers())
-            logger.log(Level.INFO, "HEADERS: " + s);
+    static void logFrames(Http2Frame f, String direction) {
+        if (frames() && loggingFrame(f.getClass())) {
+            logger.log(Level.INFO, "FRAME: " + direction + ": " + f.toString());
+        }
     }
 
     // not instantiable
--- a/jdk/src/java.httpclient/share/classes/java/net/http/MultiExchange.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/MultiExchange.java	Tue May 03 12:25:20 2016 -0700
@@ -54,7 +54,7 @@
 
     final static int DEFAULT_MAX_ATTEMPTS = 5;
     final static int max_attempts = Utils.getIntegerNetProperty(
-            "sun.net.httpclient.redirects.retrylimit", DEFAULT_MAX_ATTEMPTS
+            "java.net.httpclient.redirects.retrylimit", DEFAULT_MAX_ATTEMPTS
     );
 
     private final List<HeaderFilter> filters;
@@ -187,8 +187,7 @@
     public CompletableFuture<HttpResponseImpl> responseAsync(Void v) {
         CompletableFuture<HttpResponseImpl> cf;
         if (++attempts > max_attempts) {
-            cf = new CompletableFuture<>();
-            cf.completeExceptionally(new IOException("Too many retries"));
+            cf = CompletableFuture.failedFuture(new IOException("Too many retries"));
         } else {
             if (currentreq.timeval() != 0) {
                 // set timer
@@ -241,7 +240,6 @@
      * completed exceptionally.
      */
     private CompletableFuture<HttpResponseImpl> getExceptionalCF(Throwable t) {
-        CompletableFuture<HttpResponseImpl> error = new CompletableFuture<>();
         if ((t instanceof CompletionException) || (t instanceof ExecutionException)) {
             if (t.getCause() != null) {
                 t = t.getCause();
@@ -250,8 +248,7 @@
         if (cancelled && t instanceof IOException) {
             t = new HttpTimeoutException("request timed out");
         }
-        error.completeExceptionally(t);
-        return error;
+        return CompletableFuture.failedFuture(t);
     }
 
     <T> T responseBody(HttpResponse.BodyProcessor<T> processor) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/OutgoingHeaders.java	Tue May 03 12:25:20 2016 -0700
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ */
+
+package java.net.http;
+
+import java.io.IOException;
+
+/**
+ * Contains all parameters for outgoing headers. Is converted to
+ * HeadersFrame and ContinuationFrames by Http2Connection.
+ */
+class OutgoingHeaders extends Http2Frame {
+
+    int streamDependency;
+    int weight;
+    boolean exclusive;
+    Stream stream;
+
+    public static final int PRIORITY = 0x20;
+
+    HttpHeaders user, system;
+
+    OutgoingHeaders(HttpHeaders hdrs1, HttpHeaders hdrs2, Stream stream) {
+        this.user = hdrs2;
+        this.system = hdrs1;
+        this.stream = stream;
+    }
+
+    public void setPriority(int streamDependency, boolean exclusive, int weight) {
+        this.streamDependency = streamDependency;
+        this.exclusive = exclusive;
+        this.weight = weight;
+        this.flags |= PRIORITY;
+    }
+
+    public int getStreamDependency() {
+        return streamDependency;
+    }
+
+    public int getWeight() {
+        return weight;
+    }
+
+    public boolean getExclusive() {
+        return exclusive;
+    }
+
+    public Stream getStream() {
+        return stream;
+    }
+
+    public HttpHeaders getUserHeaders() {
+        return user;
+    }
+
+    public HttpHeaders getSystemHeaders() {
+        return system;
+    }
+
+    @Override
+    void readIncomingImpl(ByteBufferConsumer bc) throws IOException {
+        throw new UnsupportedOperationException("Not supported.");
+    }
+
+    @Override
+    void computeLength() {
+        //To change body of generated methods, choose Tools | Templates.
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+}
--- a/jdk/src/java.httpclient/share/classes/java/net/http/Pair.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/Pair.java	Tue May 03 12:25:20 2016 -0700
@@ -43,4 +43,9 @@
     static <T, U> Pair<T, U> pair(T first, U second) {
         return new Pair<>(first, second);
     }
+
+    @Override
+    public String toString() {
+        return "(" + first + ", " + second + ")";
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/PingFrame.java	Tue May 03 12:25:20 2016 -0700
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ */
+
+package java.net.http;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+class PingFrame extends Http2Frame {
+
+    PingFrame() {
+        type = TYPE;
+    }
+
+    byte[] data;
+
+    public final static int TYPE = 0x6;
+
+    // Flags
+    public static final int ACK = 0x1;
+
+    @Override
+    String flagAsString(int flag) {
+        switch (flag) {
+        case ACK:
+            return "ACK";
+        }
+        return super.flagAsString(flag);
+    }
+
+    public void setData(byte[] data) {
+        if (data.length != 8) {
+            throw new IllegalArgumentException("Ping data not 8 bytes");
+        }
+        this.data = data;
+    }
+
+    public byte[] getData() {
+        return data;
+    }
+
+    @Override
+    void readIncomingImpl(ByteBufferConsumer bc) throws IOException {
+        if (length != 8) {
+            throw new IOException("Invalid Ping frame");
+        }
+        data = bc.getBytes(8);
+    }
+
+    @Override
+    void writeOutgoing(ByteBufferGenerator bg) {
+        if (data == null) {
+            data = new byte[] {0, 0, 0, 0, 0 ,0, 0, 0};
+        }
+        super.writeOutgoing(bg);
+        ByteBuffer buf = bg.getBuffer(8);
+        buf.put(data);
+    }
+
+    @Override
+    void computeLength() {
+        length = 8;
+    }
+}
--- a/jdk/src/java.httpclient/share/classes/java/net/http/PlainHttpConnection.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/PlainHttpConnection.java	Tue May 03 12:25:20 2016 -0700
@@ -31,20 +31,43 @@
 import java.nio.channels.SelectionKey;
 import java.nio.channels.SocketChannel;
 import java.util.concurrent.CompletableFuture;
+import java.util.function.Consumer;
 
 /**
- * Plain raw TCP connection direct to destination
+ * Plain raw TCP connection direct to destination. 2 modes
+ * 1) Blocking used by http/1. In this case the connect is actually non
+ *    blocking but the request is sent blocking. The first byte of a response
+ *    is received non-blocking and the remainder of the response is received
+ *    blocking
+ * 2) Non-blocking. In this case (for http/2) the connection is actually opened
+ *    blocking but all reads and writes are done non-blocking under the
+ *    control of a Http2Connection object.
  */
-class PlainHttpConnection extends HttpConnection {
+class PlainHttpConnection extends HttpConnection implements AsyncConnection {
 
     protected SocketChannel chan;
     private volatile boolean connected;
     private boolean closed;
+    Consumer<ByteBuffer> asyncReceiver;
+    Consumer<Throwable> errorReceiver;
+    Queue<ByteBuffer> asyncOutputQ;
+    final Object reading = new Object();
+    final Object writing = new Object();
 
-    class ConnectEvent extends AsyncEvent implements AsyncEvent.Blocking {
+    @Override
+    public void startReading() {
+        try {
+            client.registerEvent(new ReadEvent());
+        } catch (IOException e) {
+            shutdown();
+        }
+    }
+
+    class ConnectEvent extends AsyncEvent {
         CompletableFuture<Void> cf;
 
         ConnectEvent(CompletableFuture<Void> cf) {
+            super(AsyncEvent.BLOCKING);
             this.cf = cf;
         }
 
@@ -112,14 +135,62 @@
 
     @Override
     long write(ByteBuffer[] buffers, int start, int number) throws IOException {
-        //debugPrint("Send", buffers, start, number);
-        return chan.write(buffers, start, number);
+        if (mode != Mode.ASYNC)
+            return chan.write(buffers, start, number);
+        // async
+        synchronized(writing) {
+            int qlen = asyncOutputQ.size();
+            ByteBuffer[] bufs = Utils.reduce(buffers, start, number);
+            long n = Utils.remaining(bufs);
+            asyncOutputQ.putAll(bufs);
+            if (qlen == 0)
+                asyncOutput();
+            return n;
+        }
+    }
+
+    ByteBuffer asyncBuffer = null;
+
+    void asyncOutput() {
+        synchronized (writing) {
+            try {
+                while (true) {
+                    if (asyncBuffer == null) {
+                        asyncBuffer = asyncOutputQ.poll();
+                        if (asyncBuffer == null) {
+                            return;
+                        }
+                    }
+                    if (!asyncBuffer.hasRemaining()) {
+                        asyncBuffer = null;
+                        continue;
+                    }
+                    int n = chan.write(asyncBuffer);
+                    //System.err.printf("Written %d bytes to chan\n", n);
+                    if (n == 0) {
+                        client.registerEvent(new WriteEvent());
+                        return;
+                    }
+                }
+            } catch (IOException e) {
+                shutdown();
+            }
+        }
     }
 
     @Override
     long write(ByteBuffer buffer) throws IOException {
-        //debugPrint("Send", buffer);
-        return chan.write(buffer);
+        if (mode != Mode.ASYNC)
+            return chan.write(buffer);
+        // async
+        synchronized(writing) {
+            int qlen = asyncOutputQ.size();
+            long n = buffer.remaining();
+            asyncOutputQ.put(buffer);
+            if (qlen == 0)
+                asyncOutput();
+            return n;
+        }
     }
 
     @Override
@@ -131,7 +202,7 @@
      * Close this connection
      */
     @Override
-    synchronized void close() {
+    public synchronized void close() {
         if (closed)
             return;
         closed = true;
@@ -155,14 +226,49 @@
         return buf;
     }
 
+    void shutdown() {
+        close();
+        errorReceiver.accept(new IOException("Connection aborted"));
+    }
+
+    void asyncRead() {
+        synchronized (reading) {
+            try {
+                while (true) {
+                    ByteBuffer buf = getBuffer();
+                    int n = chan.read(buf);
+                    //System.err.printf("Read %d bytes from chan\n", n);
+                    if (n == -1) {
+                        throw new IOException();
+                    }
+                    if (n == 0) {
+                        returnBuffer(buf);
+                        return;
+                    }
+                    buf.flip();
+                    asyncReceiver.accept(buf);
+                }
+            } catch (IOException e) {
+                shutdown();
+            }
+        }
+    }
+
     @Override
     protected int readImpl(ByteBuffer buf) throws IOException {
         int mark = buf.position();
-        int n = chan.read(buf);
+        int n;
+        // FIXME: this hack works in conjunction with the corresponding change
+        // in java.net.http.RawChannel.registerEvent
+        if ((n = buffer.remaining()) != 0) {
+            buf.put(buffer);
+        } else {
+            n = chan.read(buf);
+        }
         if (n == -1) {
             return -1;
         }
-        Utils.flipToMark(buffer, mark);
+        Utils.flipToMark(buf, mark);
         String s = "Receive (" + n + " bytes) ";
         //debugPrint(s, buf);
         return n;
@@ -178,10 +284,67 @@
         return connected;
     }
 
-    class ReceiveResponseEvent extends AsyncEvent implements AsyncEvent.Blocking {
+    // used for all output in HTTP/2
+    class WriteEvent extends AsyncEvent {
+        WriteEvent() {
+            super(0);
+        }
+
+        @Override
+        public SelectableChannel channel() {
+            return chan;
+        }
+
+        @Override
+        public int interestOps() {
+            return SelectionKey.OP_WRITE;
+        }
+
+        @Override
+        public void handle() {
+            asyncOutput();
+        }
+
+        @Override
+        public void abort() {
+            shutdown();
+        }
+    }
+
+    // used for all input in HTTP/2
+    class ReadEvent extends AsyncEvent {
+        ReadEvent() {
+            super(AsyncEvent.REPEATING); // && !BLOCKING
+        }
+
+        @Override
+        public SelectableChannel channel() {
+            return chan;
+        }
+
+        @Override
+        public int interestOps() {
+            return SelectionKey.OP_READ;
+        }
+
+        @Override
+        public void handle() {
+            asyncRead();
+        }
+
+        @Override
+        public void abort() {
+            shutdown();
+        }
+
+    }
+
+    // used in blocking channels only
+    class ReceiveResponseEvent extends AsyncEvent {
         CompletableFuture<Void> cf;
 
         ReceiveResponseEvent(CompletableFuture<Void> cf) {
+            super(AsyncEvent.BLOCKING);
             this.cf = cf;
         }
         @Override
@@ -216,6 +379,15 @@
     }
 
     @Override
+    public synchronized void setAsyncCallbacks(Consumer<ByteBuffer> asyncReceiver,
+            Consumer<Throwable> errorReceiver) {
+        this.asyncReceiver = asyncReceiver;
+        this.errorReceiver = errorReceiver;
+        asyncOutputQ = new Queue<>();
+        asyncOutputQ.registerPutCallback(this::asyncOutput);
+    }
+
+    @Override
     CompletableFuture<Void> whenReceivingResponse() {
         CompletableFuture<Void> cf = new CompletableFuture<>();
         try {
--- a/jdk/src/java.httpclient/share/classes/java/net/http/PlainTunnelingConnection.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/PlainTunnelingConnection.java	Tue May 03 12:25:20 2016 -0700
@@ -111,7 +111,7 @@
     }
 
     @Override
-    void close() {
+    public void close() {
         delegate.close();
         connected = false;
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/PriorityFrame.java	Tue May 03 12:25:20 2016 -0700
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ */
+
+package java.net.http;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+class PriorityFrame extends Http2Frame {
+
+    int streamDependency;
+    int weight;
+    boolean exclusive;
+
+    public final static int TYPE = 0x2;
+
+    PriorityFrame() {
+        type = TYPE;
+    }
+
+    public PriorityFrame(int streamDependency, boolean exclusive, int weight) {
+        this.streamDependency = streamDependency;
+        this.exclusive = exclusive;
+        this.weight = weight;
+        this.type = TYPE;
+    }
+
+    int streamDependency() {
+        return streamDependency;
+    }
+
+    int weight() {
+        return weight;
+    }
+
+    boolean exclusive() {
+        return exclusive;
+    }
+
+    @Override
+    void readIncomingImpl(ByteBufferConsumer bc) throws IOException {
+        int x = bc.getInt();
+        exclusive = (x & 0x80000000) != 0;
+        streamDependency = x & 0x7fffffff;
+        weight = bc.getByte();
+    }
+
+    @Override
+    void writeOutgoing(ByteBufferGenerator bg) {
+        super.writeOutgoing(bg);
+        ByteBuffer buf = bg.getBuffer(5);
+        int x = exclusive ? (1 << 31) + streamDependency : streamDependency;
+        buf.putInt(x);
+        buf.put((byte)weight);
+    }
+
+    @Override
+    void computeLength() {
+        length = 5;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/PushPromiseFrame.java	Tue May 03 12:25:20 2016 -0700
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ */
+
+package java.net.http;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+class PushPromiseFrame extends HeaderFrame {
+
+    int padLength;
+    int promisedStream;
+
+    PushPromiseFrame() {
+        type = TYPE;
+    }
+
+    public static final int TYPE = 0x5;
+
+    // Flags
+    public static final int END_HEADERS = 0x4;
+    public static final int PADDED = 0x8;
+
+    @Override
+    public String toString() {
+        return super.toString() + " promisedStreamid: " + promisedStream
+                + " headerLength: " + headerLength;
+    }
+
+    @Override
+    String flagAsString(int flag) {
+        switch (flag) {
+        case PADDED:
+            return "PADDED";
+        case END_HEADERS:
+            return "END_HEADERS";
+        }
+        return super.flagAsString(flag);
+    }
+
+    public void setPadLength(int padLength) {
+        this.padLength = padLength;
+        flags |= PADDED;
+    }
+
+    public void setPromisedStream(int stream) {
+        this.promisedStream = stream;
+    }
+
+    public int getPromisedStream() {
+        return promisedStream;
+    }
+
+    /**
+     */
+    @Override
+    void readIncomingImpl(ByteBufferConsumer bc) throws IOException {
+        if ((flags & PADDED) != 0) {
+            padLength = bc.getByte();
+            headerLength = length - (padLength + 5);
+        } else
+            headerLength = length - 4;
+
+        promisedStream = bc.getInt() & 0x7fffffff;
+        headerBlocks = bc.getBuffers(headerLength);
+    }
+
+    @Override
+    void computeLength() {
+        int len = 0;
+        if ((flags & PADDED) != 0) {
+            len += (1 + padLength);
+        }
+        len += (4 + headerLength);
+        this.length = len;
+    }
+
+    @Override
+    void writeOutgoing(ByteBufferGenerator bg) {
+        super.writeOutgoing(bg);
+        ByteBuffer buf = bg.getBuffer(length);
+        if ((flags & PADDED) != 0) {
+            buf.put((byte)padLength);
+        }
+        buf.putInt(promisedStream);
+        for (int i=0; i<headerBlocks.length; i++) {
+            bg.addByteBuffer(headerBlocks[i]);
+        }
+        if ((flags & PADDED) != 0) {
+            bg.addPadding(padLength);
+        }
+    }
+
+    @Override
+    public boolean endHeaders() {
+        return getFlag(END_HEADERS);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/Queue.java	Tue May 03 12:25:20 2016 -0700
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ */
+
+package java.net.http;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.util.LinkedList;
+
+// Each stream has one of these for input. Each Http2Connection has one
+// for output. Can be used blocking or asynchronously.
+
+class Queue<T> implements Closeable {
+
+    private final LinkedList<T> q = new LinkedList<>();
+    private volatile boolean closed = false;
+    private Runnable callback;
+    private boolean forceCallback;
+    private int waiters; // true if someone waiting
+
+    synchronized void putAll(T[] objs) throws IOException {
+        if (closed) {
+            throw new IOException("stream closed");
+        }
+        boolean wasEmpty = q.isEmpty();
+
+        for (T obj : objs) {
+            q.add(obj);
+        }
+
+        if (waiters > 0)
+            notifyAll();
+
+        if (wasEmpty || forceCallback) {
+            forceCallback = false;
+            if (callback != null) {
+                callback.run();
+            }
+        }
+    }
+
+    synchronized int size() {
+        return q.size();
+    }
+
+    synchronized void put(T obj) throws IOException {
+        if (closed) {
+            throw new IOException("stream closed");
+        }
+
+        q.add(obj);
+        if (waiters > 0)
+            notifyAll();
+
+        if (q.size() == 1 || forceCallback) {
+            forceCallback = false;
+            if (callback != null) {
+                callback.run();
+            }
+        }
+    }
+
+    /**
+     * callback is invoked any time put is called where
+     * the Queue was empty.
+     */
+    synchronized void registerPutCallback(Runnable callback) {
+        this.callback = callback;
+        if (callback != null && q.size() > 0)
+            callback.run();
+    }
+
+    @Override
+    public synchronized void close() {
+        closed = true;
+        notifyAll();
+    }
+
+    synchronized T take() throws IOException {
+        if (closed) {
+            throw new IOException("stream closed");
+        }
+        try {
+            while (q.size() == 0) {
+                waiters++;
+                wait();
+                waiters--;
+            }
+            return q.removeFirst();
+        } catch (InterruptedException ex) {
+            throw new IOException(ex);
+        }
+    }
+
+    public synchronized T poll() throws IOException {
+        if (closed)
+            throw new IOException("stream closed");
+
+        if (q.isEmpty())
+            return null;
+        T res = q.removeFirst();
+        return res;
+    }
+
+    public synchronized T[] pollAll(T[] type) throws IOException {
+        T[] ret = q.toArray(type);
+        q.clear();
+        return ret;
+    }
+
+    public synchronized void pushback(T v) {
+        forceCallback = true;
+        q.addFirst(v);
+    }
+
+    public synchronized void pushbackAll(T[] v) {
+        forceCallback = true;
+        for (int i=v.length-1; i>=0; i--) {
+            q.addFirst(v[i]);
+        }
+    }
+}
--- a/jdk/src/java.httpclient/share/classes/java/net/http/RawChannel.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/RawChannel.java	Tue May 03 12:25:20 2016 -0700
@@ -28,18 +28,18 @@
 import java.nio.channels.ByteChannel;
 import java.nio.channels.GatheringByteChannel;
 import java.nio.channels.SelectableChannel;
+import java.nio.channels.SelectionKey;
 
-/**
- * Used to implement WebSocket. Each RawChannel corresponds to
- * a TCP connection (SocketChannel) but is connected to a Selector
- * and an ExecutorService for invoking the send and receive callbacks
- * Also includes SSL processing.
- */
-class RawChannel implements ByteChannel, GatheringByteChannel {
+//
+// Used to implement WebSocket. Each RawChannel corresponds to a TCP connection
+// (SocketChannel) but is connected to a Selector and an ExecutorService for
+// invoking the send and receive callbacks. Also includes SSL processing.
+//
+final class RawChannel implements ByteChannel, GatheringByteChannel {
 
     private final HttpClientImpl client;
     private final HttpConnection connection;
-    private boolean closed;
+    private volatile boolean closed;
 
     private interface RawEvent {
 
@@ -50,8 +50,6 @@
         void handle();
     }
 
-    interface BlockingEvent extends RawEvent { }
-
     interface NonBlockingEvent extends RawEvent { }
 
     RawChannel(HttpClientImpl client, HttpConnection connection) {
@@ -64,39 +62,40 @@
         private final RawEvent re;
 
         RawAsyncEvent(RawEvent re) {
+            super(AsyncEvent.BLOCKING); // BLOCKING & !REPEATING
             this.re = re;
         }
 
+        RawAsyncEvent(RawEvent re, int flags) {
+            super(flags);
+            this.re = re;
+        }
+
+        @Override
         public SelectableChannel channel() {
             return connection.channel();
         }
 
         // must return the selector interest op flags OR'd
+        @Override
         public int interestOps() {
             return re.interestOps();
         }
 
         // called when event occurs
+        @Override
         public void handle() {
             re.handle();
         }
 
-        public void abort() {}
+        @Override
+        public void abort() { }
     }
 
-    private class BlockingRawAsyncEvent extends RawAsyncEvent
-            implements AsyncEvent.Blocking {
-
-        BlockingRawAsyncEvent(RawEvent re) {
-            super(re);
-        }
-    }
-
-    private class NonBlockingRawAsyncEvent extends RawAsyncEvent
-            implements AsyncEvent.NonBlocking {
+    private class NonBlockingRawAsyncEvent extends RawAsyncEvent {
 
         NonBlockingRawAsyncEvent(RawEvent re) {
-            super(re);
+            super(re, 0); // !BLOCKING & !REPEATING
         }
     }
 
@@ -105,17 +104,24 @@
      * (i.e. register new event for each callback)
      */
     public void registerEvent(RawEvent event) throws IOException {
-        if (event instanceof BlockingEvent) {
-            client.registerEvent(new BlockingRawAsyncEvent(event));
-        } else if (event instanceof NonBlockingEvent) {
+        if (!(event instanceof NonBlockingEvent)) {
+            throw new InternalError();
+        }
+        if ((event.interestOps() & SelectionKey.OP_READ) != 0
+                && connection.buffer.hasRemaining()) {
+            // FIXME: a hack to deal with leftovers from previous reads into an
+            // internal buffer (works in conjunction with change in
+            // java.net.http.PlainHttpConnection.readImpl(java.nio.ByteBuffer)
+            connection.channel().configureBlocking(false);
+            event.handle();
+        } else {
             client.registerEvent(new NonBlockingRawAsyncEvent(event));
-        } else {
-            throw new InternalError();
         }
     }
 
     @Override
     public int read(ByteBuffer dst) throws IOException {
+        assert !connection.channel().isBlocking();
         return connection.read(dst);
     }
 
--- a/jdk/src/java.httpclient/share/classes/java/net/http/RedirectFilter.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/RedirectFilter.java	Tue May 03 12:25:20 2016 -0700
@@ -33,17 +33,19 @@
     HttpRequestImpl requestImpl;
     HttpRequest request;
     HttpClientImpl client;
+    HttpClient.Redirect policy;
     String method;
     final static int DEFAULT_MAX_REDIRECTS = 5;
     URI uri;
 
     final static int max_redirects = Utils.getIntegerNetProperty(
-            "sun.net.httpclient.redirects.retrylimit", DEFAULT_MAX_REDIRECTS
+            "java.net.httpclient.redirects.retrylimit", DEFAULT_MAX_REDIRECTS
     );
 
     @Override
     public void request(HttpRequestImpl r) throws IOException {
         this.request = r;
+        this.policy = request.followRedirects();
         this.client = r.getClient();
         this.method = r.method();
         this.requestImpl = r;
@@ -61,7 +63,7 @@
      */
     private HttpRequestImpl handleResponse(HttpResponseImpl r) {
         int rcode = r.statusCode();
-        if (rcode == 200) {
+        if (rcode == 200 || policy == HttpClient.Redirect.NEVER) {
             return null;
         }
         if (rcode >= 300 && rcode <= 399) {
@@ -79,6 +81,7 @@
 
     private URI getRedirectedURI(HttpHeaders headers) {
         URI redirectedURI;
+        String ss = headers.firstValue("Location").orElse("Not present");
         redirectedURI = headers.firstValue("Location")
                 .map((s) -> URI.create(s))
                 .orElseThrow(() -> new UncheckedIOException(
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/ResetFrame.java	Tue May 03 12:25:20 2016 -0700
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ */
+
+package java.net.http;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+class ResetFrame extends ErrorFrame {
+
+    public final static int TYPE = 0x3;
+
+    // See ErrorFrame for error values
+
+    ResetFrame() {
+        type = TYPE;
+    }
+
+    public ResetFrame(int errorCode) {
+        this.errorCode = errorCode;
+        this.type = TYPE;
+    }
+
+    @Override
+    void readIncomingImpl(ByteBufferConsumer bc) throws IOException {
+        errorCode = bc.getInt();
+    }
+
+    @Override
+    void writeOutgoing(ByteBufferGenerator bg) {
+        super.writeOutgoing(bg);
+        ByteBuffer buf = bg.getBuffer(4);
+        buf.putInt(errorCode);
+    }
+
+    @Override
+    void computeLength() {
+        length = 4;
+    }
+}
--- a/jdk/src/java.httpclient/share/classes/java/net/http/ResponseHeaders.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/ResponseHeaders.java	Tue May 03 12:25:20 2016 -0700
@@ -48,7 +48,7 @@
  *
  * This class is not thread-safe
  */
-class ResponseHeaders implements HttpHeaders1 {
+class ResponseHeaders implements HttpHeaders {
 
     static final int DATA_SIZE = 16 * 1024;  // initial space for headers
     static final int NUM_HEADERS = 50; // initial expected max number of headers
@@ -368,10 +368,6 @@
         return Collections.unmodifiableList(l);
     }
 
-    @Override
-    public void makeUnmodifiable() {
-    }
-
     // Delegates map to HashMap but converts keys to lower case
 
     static class HeaderMap implements Map<String,List<String>> {
--- a/jdk/src/java.httpclient/share/classes/java/net/http/SSLConnection.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/SSLConnection.java	Tue May 03 12:25:20 2016 -0700
@@ -121,13 +121,8 @@
     }
 
     @Override
-    void close() {
-        try {
-            //System.err.println ("Closing: " + this);
-            delegate.channel().close(); // TODO: proper close
-        } catch (IOException ex) {
-            Log.logError(ex.toString());
-        }
+    public void close() {
+        Utils.close(delegate.channel());
     }
 
     @Override
--- a/jdk/src/java.httpclient/share/classes/java/net/http/SSLDelegate.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/SSLDelegate.java	Tue May 03 12:25:20 2016 -0700
@@ -29,13 +29,9 @@
 import java.util.Arrays;
 import java.util.concurrent.locks.Lock;
 import java.util.concurrent.locks.ReentrantLock;
-import javax.net.ssl.SSLContext;
-import javax.net.ssl.SSLEngine;
-import javax.net.ssl.SSLEngineResult;
 import javax.net.ssl.SSLEngineResult.HandshakeStatus;
 import javax.net.ssl.SSLEngineResult.Status;
-import javax.net.ssl.SSLParameters;
-import javax.net.ssl.SSLSession;
+import javax.net.ssl.*;
 import static javax.net.ssl.SSLEngineResult.HandshakeStatus.*;
 
 /**
@@ -60,16 +56,18 @@
         engine.setUseClientMode(true);
         SSLParameters sslp = client.sslParameters().orElse(null);
         if (sslp == null) {
-            sslp = context.getDefaultSSLParameters();
+            sslp = context.getSupportedSSLParameters();
         }
         sslParameters = Utils.copySSLParameters(sslp);
         if (alpn != null) {
             sslParameters.setApplicationProtocols(alpn);
             Log.logSSL("Setting application protocols: " + Arrays.toString(alpn));
         } else {
-            Log.logSSL("Warning no application protocols proposed!");
+            Log.logSSL("No application protocols proposed");
         }
         engine.setSSLParameters(sslParameters);
+        engine.setEnabledCipherSuites(sslp.getCipherSuites());
+        engine.setEnabledProtocols(sslp.getProtocols());
         wrapper = new EngineWrapper(chan, engine);
         this.chan = chan;
         this.client = client;
@@ -268,7 +266,7 @@
                 do {
                     if (needData) {
                         do {
-                        x = chan.read (unwrap_src);
+                            x = chan.read (unwrap_src);
                         } while (x == 0);
                         if (x == -1) {
                             throw new IOException ("connection closed for reading");
@@ -440,6 +438,27 @@
         }
     }
 
+    static void printParams(SSLParameters p) {
+        System.out.println("SSLParameters:");
+        if (p == null) {
+            System.out.println("Null params");
+            return;
+        }
+        for (String cipher : p.getCipherSuites()) {
+                System.out.printf("cipher: %s\n", cipher);
+        }
+        for (String approto : p.getApplicationProtocols()) {
+                System.out.printf("application protocol: %s\n", approto);
+        }
+        for (String protocol : p.getProtocols()) {
+                System.out.printf("protocol: %s\n", protocol);
+        }
+        if (p.getServerNames() != null)
+        for (SNIServerName sname : p.getServerNames()) {
+                System.out.printf("server name: %s\n", sname.toString());
+        }
+    }
+
     String getSessionInfo() {
         StringBuilder sb = new StringBuilder();
         String application = engine.getApplicationProtocol();
--- a/jdk/src/java.httpclient/share/classes/java/net/http/SSLTunnelConnection.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/SSLTunnelConnection.java	Tue May 03 12:25:20 2016 -0700
@@ -130,12 +130,8 @@
     }
 
     @Override
-    void close() {
-        try {
-            //System.err.println ("Closing: " + this);
-            delegate.channel().close(); // TODO: proper close
-        } catch (IOException ex) {
-        }
+    public void close() {
+        Utils.close(delegate.channel());
     }
 
     @Override
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/SettingsFrame.java	Tue May 03 12:25:20 2016 -0700
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ */
+
+package java.net.http;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+class SettingsFrame extends Http2Frame {
+
+    int[] parameters;
+
+    public static final int TYPE = 0x4;
+
+    // Flags
+    public static final int ACK = 0x1;
+
+    @Override
+    String flagAsString(int flag) {
+        switch (flag) {
+        case ACK:
+            return "ACK";
+        }
+        return super.flagAsString(flag);
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append(super.toString())
+          .append(" Settings: ");
+
+        for (int i = 0; i < MAX_PARAM; i++) {
+            if (parameters[i] != -1) {
+                sb.append(name(i))
+                  .append("=")
+                  .append(Integer.toString(parameters[i]))
+                  .append(' ');
+            }
+        }
+        return sb.toString();
+    }
+
+    // Parameters
+    public static final int HEADER_TABLE_SIZE = 0x1;
+    public static final int ENABLE_PUSH = 0x2;
+    public static final int MAX_CONCURRENT_STREAMS = 0x3;
+    public static final int INITIAL_WINDOW_SIZE = 0x4;
+    public static final int MAX_FRAME_SIZE = 0x5;
+    public static final int MAX_HEADER_LIST_SIZE = 0x6;
+
+    private String name(int i) {
+        switch (i+1) {
+        case HEADER_TABLE_SIZE:
+            return "HEADER_TABLE_SIZE";
+        case ENABLE_PUSH:
+            return "ENABLE_PUSH";
+        case MAX_CONCURRENT_STREAMS:
+            return "MAX_CONCURRENT_STREAMS";
+        case INITIAL_WINDOW_SIZE:
+            return "INITIAL_WINDOW_SIZE";
+        case MAX_FRAME_SIZE:
+            return "MAX_FRAME_SIZE";
+        case MAX_HEADER_LIST_SIZE:
+            return "MAX_HEADER_LIST_SIZE";
+        }
+        return "unknown parameter";
+    }
+    public static final int MAX_PARAM = 0x6;
+
+    public SettingsFrame() {
+        type = TYPE;
+        parameters = new int [MAX_PARAM];
+        for (int i=0; i < parameters.length; i++) {
+            parameters[i] = -1;
+        }
+    }
+
+    public int getParameter(int paramID) {
+        if (paramID > MAX_PARAM) {
+            throw new IllegalArgumentException("illegal parameter");
+        }
+        return parameters[paramID-1];
+    }
+
+    public SettingsFrame setParameter(int paramID, int value) {
+        if (paramID > MAX_PARAM) {
+            throw new IllegalArgumentException("illegal parameter");
+        }
+        parameters[paramID-1] = value;
+        return this;
+    }
+
+    @Override
+    void readIncomingImpl(ByteBufferConsumer bc) throws IOException {
+        if (length % 6 != 0) {
+            throw new IOException("Protocol error: invalid settings frame");
+        }
+        int n = length / 6;
+        for (int i=0; i<n; i++) {
+            int id = bc.getShort();
+            int val = bc.getInt();
+            if (id > 0 || id <= MAX_PARAM) {
+                // a known parameter. Ignore otherwise
+                parameters[id-1] = val;
+            }
+        }
+    }
+
+    @Override
+    void computeLength() {
+        length = 0;
+        for (int i : parameters) {
+            if (i != -1) {
+                length += 6;
+            }
+        }
+    }
+
+    @Override
+    void writeOutgoing(ByteBufferGenerator bg) {
+        super.writeOutgoing(bg);
+        ByteBuffer buf = bg.getBuffer(length);
+        for (int i = 0; i < MAX_PARAM; i++) {
+            if (parameters[i] != -1) {
+                buf.putShort((short)(i+1));
+                buf.putInt(parameters[i]);
+            }
+        }
+    }
+
+    private static final int K = 1024;
+
+    public static SettingsFrame getDefaultSettings() {
+        SettingsFrame f = new SettingsFrame();
+        // TODO: check these values
+        f.setParameter(ENABLE_PUSH, 1);
+        f.setParameter(HEADER_TABLE_SIZE, 4 * K);
+        f.setParameter(MAX_CONCURRENT_STREAMS, 35);
+        f.setParameter(INITIAL_WINDOW_SIZE, 16 * K);
+        f.setParameter(MAX_FRAME_SIZE, 16 * K);
+        return f;
+    }
+}
--- a/jdk/src/java.httpclient/share/classes/java/net/http/Stream.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/Stream.java	Tue May 03 12:25:20 2016 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -24,78 +24,819 @@
 
 package java.net.http;
 
+import sun.net.httpclient.hpack.DecodingCallback;
+
 import java.io.IOException;
-import java.io.UncheckedIOException;
 import java.net.URI;
 import java.nio.ByteBuffer;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.CompletionException;
+import java.util.function.BiFunction;
 import java.util.function.LongConsumer;
 
 /**
- * Http/2 Stream
+ * Http/2 Stream handling.
+ *
+ * REQUESTS
+ *
+ * sendHeadersOnly() -- assembles HEADERS frame and puts on connection outbound Q
+ *
+ * sendRequest() -- sendHeadersOnly() + sendBody()
+ *
+ * sendBody() -- in calling thread: obeys all flow control (so may block)
+ *               obtains data from request body processor and places on connection
+ *               outbound Q.
+ *
+ * sendBodyAsync() -- calls sendBody() in an executor thread.
+ *
+ * sendHeadersAsync() -- calls sendHeadersOnly() which does not block
+ *
+ * sendRequestAsync() -- calls sendRequest() in an executor thread
+ *
+ * RESPONSES
+ *
+ * Multiple responses can be received per request. Responses are queued up on
+ * a LinkedList of CF<HttpResponse> and the the first one on the list is completed
+ * with the next response
+ *
+ * getResponseAsync() -- queries list of response CFs and returns first one
+ *               if one exists. Otherwise, creates one and adds it to list
+ *               and returns it. Completion is achieved through the
+ *               incoming() upcall from connection reader thread.
+ *
+ * getResponse() -- calls getResponseAsync() and waits for CF to complete
+ *
+ * responseBody() -- in calling thread: blocks for incoming DATA frames on
+ *               stream inputQ. Obeys remote and local flow control so may block.
+ *               Calls user response body processor with data buffers.
+ *
+ * responseBodyAsync() -- calls responseBody() in an executor thread.
+ *
+ * incoming() -- entry point called from connection reader thread. Frames are
+ *               either handled immediately without blocking or for data frames
+ *               placed on the stream's inputQ which is consumed by the stream's
+ *               reader thread.
+ *
+ * PushedStream sub class
+ * ======================
+ * Sending side methods are not used because the request comes from a PUSH_PROMISE
+ * frame sent by the server. When a PUSH_PROMISE is received the PushedStream
+ * is created. PushedStream does not use responseCF list as there can be only
+ * one response. The CF is created when the object created and when the response
+ * HEADERS frame is received the object is completed.
  */
 class Stream extends ExchangeImpl {
 
-    void debugPrint() {
-    }
+    final Queue<Http2Frame> inputQ;
+
+    volatile int streamid;
+
+    long responseContentLen = -1;
+    long responseBytesProcessed = 0;
+    long requestContentLen;
+
+    Http2Connection connection;
+    HttpClientImpl client;
+    final HttpRequestImpl request;
+    final DecodingCallback rspHeadersConsumer;
+    HttpHeadersImpl responseHeaders;
+    final HttpHeadersImpl requestHeaders;
+    final HttpHeadersImpl requestPseudoHeaders;
+    HttpResponse.BodyProcessor<?> responseProcessor;
+    final HttpRequest.BodyProcessor requestProcessor;
+    HttpResponse response;
+
+    // state flags
+    boolean requestSent, responseReceived;
+
+    final FlowController userRequestFlowController =
+            new FlowController();
+    final FlowController remoteRequestFlowController =
+            new FlowController();
+    final FlowController responseFlowController =
+            new FlowController();
+
+    final ExecutorWrapper executor;
 
     @Override
     @SuppressWarnings("unchecked")
     <T> CompletableFuture<T> responseBodyAsync(HttpResponse.BodyProcessor<T> processor) {
-            return null;
+        this.responseProcessor = processor;
+        CompletableFuture<T> cf;
+        try {
+            T body = processor.onResponseBodyStart(
+                    responseContentLen, responseHeaders,
+                    responseFlowController); // TODO: filter headers
+            if (body != null) {
+                cf = CompletableFuture.completedFuture(body);
+                receiveDataAsync(processor);
+            } else
+                cf = receiveDataAsync(processor);
+        } catch (IOException e) {
+            cf = CompletableFuture.failedFuture(e);
+        }
+        PushGroup<?> pg = request.pushGroup();
+        if (pg != null) {
+            // if an error occurs make sure it is recorded in the PushGroup
+            cf = cf.whenComplete((t,e) -> pg.pushError(e));
+        }
+        return cf;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append("streamid: ")
+                .append(streamid);
+        return sb.toString();
+    }
+
+    // pushes entire response body into response processor
+    // blocking when required by local or remote flow control
+    void receiveData() throws IOException {
+        Http2Frame frame;
+        DataFrame df = null;
+        try {
+            do {
+                frame = inputQ.take();
+                if (!(frame instanceof DataFrame)) {
+                    assert false;
+                    continue;
+                }
+                df = (DataFrame) frame;
+                int len = df.getDataLength();
+                ByteBuffer[] buffers = df.getData();
+                for (ByteBuffer b : buffers) {
+                    responseFlowController.take();
+                    responseProcessor.onResponseBodyChunk(b);
+                }
+                sendWindowUpdate(len);
+            } while (!df.getFlag(DataFrame.END_STREAM));
+        } catch (InterruptedException e) {
+            throw new IOException(e);
+        }
+    }
+
+    private <T> CompletableFuture<T> receiveDataAsync(HttpResponse.BodyProcessor<T> processor) {
+        CompletableFuture<T> cf = new CompletableFuture<>();
+        executor.execute(() -> {
+            try {
+                receiveData();
+                T body = processor.onResponseComplete();
+                cf.complete(body);
+                responseReceived();
+            } catch (Throwable t) {
+                cf.completeExceptionally(t);
+            }
+        }, null);
+        return cf;
+    }
+
+    private void sendWindowUpdate(int increment)
+            throws IOException, InterruptedException {
+        if (increment == 0)
+            return;
+        LinkedList<Http2Frame> list = new LinkedList<>();
+        WindowUpdateFrame frame = new WindowUpdateFrame();
+        frame.streamid(streamid);
+        frame.setUpdate(increment);
+        list.add(frame);
+        frame = new WindowUpdateFrame();
+        frame.streamid(0);
+        frame.setUpdate(increment);
+        list.add(frame);
+        connection.sendFrames(list);
+    }
+
+    @Override
+    CompletableFuture<Void> sendBodyAsync() {
+        final CompletableFuture<Void> cf = new CompletableFuture<>();
+        executor.execute(() -> {
+            try {
+                sendBodyImpl();
+                cf.complete(null);
+            } catch (IOException | InterruptedException e) {
+                cf.completeExceptionally(e);
+            }
+        }, null);
+        return cf;
+    }
+
+    @SuppressWarnings("unchecked")
+    Stream(HttpClientImpl client, Http2Connection connection, Exchange e) {
+        super(e);
+        this.client = client;
+        this.connection = connection;
+        this.request = e.request();
+        this.requestProcessor = request.requestProcessor();
+        responseHeaders = new HttpHeadersImpl();
+        requestHeaders = new HttpHeadersImpl();
+        rspHeadersConsumer = (name, value) -> {
+            responseHeaders.addHeader(name.toString(), value.toString());
+        };
+        this.executor = client.executorWrapper();
+        //this.response_cf = new CompletableFuture<HttpResponseImpl>();
+        this.requestPseudoHeaders = new HttpHeadersImpl();
+        // NEW
+        this.inputQ = new Queue<>();
+    }
+
+    @SuppressWarnings("unchecked")
+    Stream(HttpClientImpl client, Http2Connection connection, HttpRequestImpl req) {
+        super(null);
+        this.client = client;
+        this.connection = connection;
+        this.request = req;
+        this.requestProcessor = null;
+        responseHeaders = new HttpHeadersImpl();
+        requestHeaders = new HttpHeadersImpl();
+        rspHeadersConsumer = (name, value) -> {
+            responseHeaders.addHeader(name.toString(), value.toString());
+        };
+        this.executor = client.executorWrapper();
+        //this.response_cf = new CompletableFuture<HttpResponseImpl>();
+        this.requestPseudoHeaders = new HttpHeadersImpl();
+        // NEW
+        this.inputQ = new Queue<>();
     }
 
-    Stream(HttpClientImpl client, Http2Connection connection, Exchange e) {
-        super(e);
+    /**
+     * Entry point from Http2Connection reader thread.
+     *
+     * Data frames will be removed by response body thread.
+     *
+     * @param frame
+     * @throws IOException
+     */
+    void incoming(Http2Frame frame) throws IOException, InterruptedException {
+        if ((frame instanceof HeaderFrame) && ((HeaderFrame)frame).endHeaders()) {
+            // Complete headers accumulated. handle response.
+            // It's okay if there are multiple HeaderFrames.
+            handleResponse();
+        } else if (frame instanceof DataFrame) {
+            inputQ.put(frame);
+        } else {
+            otherFrame(frame);
+        }
+    }
+
+    void otherFrame(Http2Frame frame) throws IOException {
+        switch (frame.type()) {
+            case WindowUpdateFrame.TYPE:
+                incoming_windowUpdate((WindowUpdateFrame) frame);
+                break;
+            case ResetFrame.TYPE:
+                incoming_reset((ResetFrame) frame);
+                break;
+            case PriorityFrame.TYPE:
+                incoming_priority((PriorityFrame) frame);
+                break;
+            default:
+                String msg = "Unexpected frame: " + frame.toString();
+                throw new IOException(msg);
+        }
+    }
+
+    // The Hpack decoder decodes into one of these consumers of name,value pairs
+
+    DecodingCallback rspHeadersConsumer() {
+        return rspHeadersConsumer;
+    }
+
+    // create and return the HttpResponseImpl
+    protected void handleResponse() throws IOException {
+        HttpConnection c = connection.connection; // TODO: improve
+        long statusCode = responseHeaders
+                .firstValueAsLong(":status")
+                .orElseThrow(() -> new IOException("no statuscode in response"));
+
+        this.response = new HttpResponseImpl((int)statusCode, exchange, responseHeaders, null,
+                c.sslParameters(), HttpClient.Version.HTTP_2, c);
+        this.responseContentLen = responseHeaders
+                .firstValueAsLong("content-length")
+                .orElse(-1L);
+        // different implementations for normal streams and pushed streams
+        completeResponse(response);
+    }
+
+    void incoming_reset(ResetFrame frame) {
+        // TODO: implement reset
+        int error = frame.getErrorCode();
+        IOException e = new IOException(ErrorFrame.stringForCode(error));
+        completeResponseExceptionally(e);
+        throw new UnsupportedOperationException("Not implemented");
+    }
+
+    void incoming_priority(PriorityFrame frame) {
+        // TODO: implement priority
+        throw new UnsupportedOperationException("Not implemented");
+    }
+
+    void incoming_windowUpdate(WindowUpdateFrame frame) {
+        int amount = frame.getUpdate();
+        if (amount > 0)
+            remoteRequestFlowController.accept(amount);
+    }
+
+    void incoming_pushPromise(HttpRequestImpl pushReq, PushedStream pushStream) throws IOException {
+        if (Log.requests()) {
+            Log.logRequest("PUSH_PROMISE: " + pushReq.toString());
+        }
+        PushGroup<?> pushGroup = request.pushGroup();
+        if (pushGroup == null) {
+            cancelImpl(new IllegalStateException("unexpected push promise"));
+        }
+        // get the handler and call it.
+        BiFunction<HttpRequest,CompletableFuture<HttpResponse>,Boolean> ph =
+            pushGroup.pushHandler();
+
+        CompletableFuture<HttpResponse> pushCF = pushStream
+                .getResponseAsync(null)
+                .thenApply(r -> (HttpResponse)r);
+        boolean accept = ph.apply(pushReq, pushCF);
+        if (!accept) {
+            IOException ex = new IOException("Stream cancelled by user");
+            cancelImpl(ex);
+            pushCF.completeExceptionally(ex);
+        } else {
+            pushStream.requestSent();
+            pushGroup.addPush();
+        }
+    }
+
+    private OutgoingHeaders headerFrame(long contentLength) {
+        HttpHeadersImpl h = request.getSystemHeaders();
+        if (contentLength > 0) {
+            h.setHeader("content-length", Long.toString(contentLength));
+        }
+        setPseudoHeaderFields();
+        OutgoingHeaders f = new OutgoingHeaders(h, request.getUserHeaders(), this);
+        if (contentLength == 0) {
+            f.setFlag(HeadersFrame.END_STREAM);
+        }
+        return f;
+    }
+
+    private void setPseudoHeaderFields() {
+        HttpHeadersImpl hdrs = requestPseudoHeaders;
+        String method = request.method();
+        hdrs.setHeader(":method", method);
+        URI uri = request.uri();
+        hdrs.setHeader(":scheme", uri.getScheme());
+        // TODO: userinfo deprecated. Needs to be removed
+        hdrs.setHeader(":authority", uri.getAuthority());
+        // TODO: ensure header names beginning with : not in user headers
+        String query = uri.getQuery();
+        String path = uri.getPath();
+        if (path == null) {
+            if (method.equalsIgnoreCase("OPTIONS")) {
+                path = "*";
+            } else {
+                path = "/";
+            }
+        }
+        if (query != null) {
+            path += "?" + query;
+        }
+        hdrs.setHeader(":path", path);
+    }
+
+    HttpHeadersImpl getRequestPseudoHeaders() {
+        return requestPseudoHeaders;
     }
 
     @Override
     HttpResponseImpl getResponse() throws IOException {
-        return null;
+        try {
+            return getResponseAsync(null).join();
+        } catch (Throwable e) {
+            Throwable t = e.getCause();
+            if (t instanceof IOException) {
+                throw (IOException)t;
+            }
+            throw e;
+        }
     }
 
     @Override
     void sendRequest() throws IOException, InterruptedException {
+        sendHeadersOnly();
+        sendBody();
+    }
+
+    /**
+     * A simple general purpose blocking flow controller
+     */
+    class FlowController implements LongConsumer {
+        int permits;
+
+        FlowController() {
+            this.permits = 0;
+        }
+
+        @Override
+        public synchronized void accept(long n) {
+            if (n < 1) {
+                throw new InternalError("FlowController.accept called with " + n);
+            }
+            if (permits == 0) {
+                permits += n;
+                notifyAll();
+            } else {
+                permits += n;
+            }
+        }
+
+        public synchronized void take() throws InterruptedException {
+            take(1);
+        }
+
+        public synchronized void take(int amount) throws InterruptedException {
+            assert permits >= 0;
+            while (permits < amount) {
+                int n = Math.min(amount, permits);
+                permits -= n;
+                amount -= n;
+                if (amount > 0)
+                    wait();
+            }
+        }
     }
 
     @Override
     void sendHeadersOnly() throws IOException, InterruptedException {
+        if (Log.requests() && request != null) {
+            Log.logRequest(request.toString());
+        }
+        requestContentLen = requestProcessor.onRequestStart(request, userRequestFlowController);
+        OutgoingHeaders f = headerFrame(requestContentLen);
+        connection.sendFrame(f);
     }
 
     @Override
     void sendBody() throws IOException, InterruptedException {
+        sendBodyImpl();
     }
 
+    void registerStream(int id) {
+        this.streamid = id;
+        connection.putStream(this, streamid);
+    }
+
+    DataFrame getDataFrame() throws IOException, InterruptedException {
+        userRequestFlowController.take();
+        int maxpayloadLen = connection.getMaxSendFrameSize() - 9;
+        ByteBuffer buffer = connection.getBuffer();
+        buffer.limit(maxpayloadLen);
+        boolean complete = requestProcessor.onRequestBodyChunk(buffer);
+        buffer.flip();
+        int amount = buffer.remaining();
+        // wait for flow control if necessary. Following method will block
+        // until after headers frame is sent, so correct streamid is set.
+        remoteRequestFlowController.take(amount);
+        connection.obtainSendWindow(amount);
+
+        DataFrame df = new DataFrame();
+        df.streamid(streamid);
+        if (complete) {
+            df.setFlag(DataFrame.END_STREAM);
+        }
+        df.setData(buffer);
+        df.computeLength();
+        return df;
+    }
+
+
     @Override
     CompletableFuture<Void> sendHeadersAsync() {
-        return null;
+        try {
+            sendHeadersOnly();
+            return CompletableFuture.completedFuture(null);
+        } catch (IOException | InterruptedException ex) {
+            return CompletableFuture.failedFuture(ex);
+        }
     }
 
+    /**
+     * A List of responses relating to this stream. Normally there is only
+     * one response, but intermediate responses like 100 are allowed
+     * and must be passed up to higher level before continuing. Deals with races
+     * such as if responses are returned before the CFs get created by
+     * getResponseAsync()
+     */
+
+    final List<CompletableFuture<HttpResponseImpl>> response_cfs = new LinkedList<>();
+
     @Override
     CompletableFuture<HttpResponseImpl> getResponseAsync(Void v) {
-        return null;
+        CompletableFuture<HttpResponseImpl> cf;
+        synchronized (response_cfs) {
+            if (!response_cfs.isEmpty()) {
+                cf = response_cfs.remove(0);
+            } else {
+                cf = new CompletableFuture<>();
+                response_cfs.add(cf);
+            }
+        }
+        PushGroup<?> pg = request.pushGroup();
+        if (pg != null) {
+            // if an error occurs make sure it is recorded in the PushGroup
+            cf = cf.whenComplete((t,e) -> pg.pushError(e));
+        }
+        return cf;
+    }
+
+    /**
+     * Completes the first uncompleted CF on list, and removes it. If there is no
+     * uncompleted CF then creates one (completes it) and adds to list
+     */
+    void completeResponse(HttpResponse r) {
+        HttpResponseImpl resp = (HttpResponseImpl)r;
+        synchronized (response_cfs) {
+            for (CompletableFuture<HttpResponseImpl> cf : response_cfs) {
+                if (!cf.isDone()) {
+                    cf.complete(resp);
+                    response_cfs.remove(cf);
+                    //responseHeaders = new HttpHeadersImpl(); // for any following header blocks
+                    return;
+                } else
+                    System.err.println("Stream: " + this + " ALREADY DONE");
+            }
+            response_cfs.add(CompletableFuture.completedFuture(resp));
+            //responseHeaders = new HttpHeadersImpl(); // for any following header blocks
+        }
     }
 
-    @Override
-    CompletableFuture<Void> sendBodyAsync() {
-        return null;
+    // methods to update state and remove stream when finished
+
+    synchronized void requestSent() {
+        requestSent = true;
+        if (responseReceived)
+            connection.deleteStream(this);
+    }
+
+    synchronized void responseReceived() {
+        responseReceived = true;
+        if (requestSent)
+            connection.deleteStream(this);
+        PushGroup<?> pg = request.pushGroup();
+        if (pg != null)
+            pg.noMorePushes();
+    }
+
+    /**
+     * same as above but for errors
+     *
+     * @param t
+     */
+    void completeResponseExceptionally(Throwable t) {
+        synchronized (response_cfs) {
+            for (CompletableFuture<HttpResponseImpl> cf : response_cfs) {
+                if (!cf.isDone()) {
+                    cf.completeExceptionally(t);
+                    response_cfs.remove(cf);
+                    return;
+                }
+            }
+            response_cfs.add(CompletableFuture.failedFuture(t));
+        }
+    }
+
+    void sendBodyImpl() throws IOException, InterruptedException {
+        if (requestContentLen == 0) {
+            // no body
+            return;
+        }
+        DataFrame df;
+        do {
+            df = getDataFrame();
+            // TODO: check accumulated content length (if not checked below)
+            connection.sendFrame(df);
+        } while (!df.getFlag(DataFrame.END_STREAM));
+        requestSent();
     }
 
     @Override
     void cancel() {
+        cancelImpl(new Exception("Cancelled"));
     }
 
 
+    void cancelImpl(Throwable e) {
+        Log.logTrace("cancelling stream: {0}\n", e.toString());
+        inputQ.close();
+        try {
+            connection.resetStream(streamid, ResetFrame.CANCEL);
+        } catch (IOException | InterruptedException ex) {
+            Log.logError(ex);
+        }
+    }
+
     @Override
     CompletableFuture<Void> sendRequestAsync() {
-        return null;
+        CompletableFuture<Void> cf = new CompletableFuture<>();
+        executor.execute(() -> {
+           try {
+               sendRequest();
+               cf.complete(null);
+           } catch (IOException |InterruptedException e) {
+               cf.completeExceptionally(e);
+           }
+        }, null);
+        return cf;
     }
 
     @Override
     <T> T responseBody(HttpResponse.BodyProcessor<T> processor) throws IOException {
-        return null;
+        this.responseProcessor = processor;
+        T body = processor.onResponseBodyStart(
+                    responseContentLen, responseHeaders,
+                    responseFlowController); // TODO: filter headers
+        if (body == null) {
+            receiveData();
+            return processor.onResponseComplete();
+        } else
+            receiveDataAsync(processor);
+        responseReceived();
+        return body;
+    }
+
+    // called from Http2Connection reader thread
+    synchronized void updateOutgoingWindow(int update) {
+        remoteRequestFlowController.accept(update);
+    }
+
+    void close(String msg) {
+        cancel();
+    }
+
+    static class PushedStream extends Stream {
+        final PushGroup<?> pushGroup;
+        final private Stream parent;      // used by server push streams
+        // push streams need the response CF allocated up front as it is
+        // given directly to user via the multi handler callback function.
+        final CompletableFuture<HttpResponseImpl> pushCF;
+        final HttpRequestImpl pushReq;
+
+        PushedStream(PushGroup<?> pushGroup, HttpClientImpl client,
+                Http2Connection connection, Stream parent,
+                HttpRequestImpl pushReq) {
+            super(client, connection, pushReq);
+            this.pushGroup = pushGroup;
+            this.pushReq = pushReq;
+            this.pushCF = new CompletableFuture<>();
+            this.parent = parent;
+        }
+
+        // Following methods call the super class but in case of
+        // error record it in the PushGroup. The error method is called
+        // with a null value when no error occurred (is a no-op)
+        @Override
+        CompletableFuture<Void> sendBodyAsync() {
+            return super.sendBodyAsync()
+                        .whenComplete((v, t) -> pushGroup.pushError(t));
+        }
+
+        @Override
+        CompletableFuture<Void> sendHeadersAsync() {
+            return super.sendHeadersAsync()
+                        .whenComplete((v, t) -> pushGroup.pushError(t));
+        }
+
+        @Override
+        CompletableFuture<Void> sendRequestAsync() {
+            return super.sendRequestAsync()
+                        .whenComplete((v, t) -> pushGroup.pushError(t));
+        }
+
+        @Override
+        CompletableFuture<HttpResponseImpl> getResponseAsync(Void vo) {
+            return pushCF.whenComplete((v, t) -> pushGroup.pushError(t));
+        }
+
+        @Override
+        <T> CompletableFuture<T> responseBodyAsync(HttpResponse.BodyProcessor<T> processor) {
+            return super.responseBodyAsync(processor)
+                        .whenComplete((v, t) -> pushGroup.pushError(t));
+        }
+
+        @Override
+        void completeResponse(HttpResponse r) {
+            HttpResponseImpl resp = (HttpResponseImpl)r;
+            Utils.logResponse(resp);
+            pushCF.complete(resp);
+        }
+
+        @Override
+        void completeResponseExceptionally(Throwable t) {
+            pushCF.completeExceptionally(t);
+        }
+
+        @Override
+        synchronized void responseReceived() {
+            super.responseReceived();
+            pushGroup.pushCompleted();
+        }
+
+        // create and return the PushResponseImpl
+        @Override
+        protected void handleResponse() {
+            HttpConnection c = connection.connection; // TODO: improve
+            long statusCode = responseHeaders
+                .firstValueAsLong(":status")
+                .orElse(-1L);
+
+            if (statusCode == -1L)
+                completeResponseExceptionally(new IOException("No status code"));
+            ImmutableHeaders h = new ImmutableHeaders(responseHeaders, Utils.ALL_HEADERS);
+            this.response = new HttpResponseImpl((int)statusCode, pushReq, h, this,
+                c.sslParameters());
+            this.responseContentLen = responseHeaders
+                .firstValueAsLong("content-length")
+                .orElse(-1L);
+            // different implementations for normal streams and pushed streams
+            completeResponse(response);
+        }
+    }
+
+    /**
+     * One PushGroup object is associated with the parent Stream of
+     * the pushed Streams. This keeps track of all common state associated
+     * with the pushes.
+     */
+    static class PushGroup<T> {
+        // the overall completion object, completed when all pushes are done.
+        final CompletableFuture<T> resultCF;
+        Throwable error; // any exception that occured during pushes
+
+        // CF for main response
+        final CompletableFuture<HttpResponse> mainResponse;
+
+        // user's processor object
+        final HttpResponse.MultiProcessor<T> multiProcessor;
+
+        // per push handler function provided by processor
+        final private BiFunction<HttpRequest,
+                           CompletableFuture<HttpResponse>,
+                           Boolean> pushHandler;
+        int numberOfPushes;
+        int remainingPushes;
+        boolean noMorePushes = false;
+
+        PushGroup(HttpResponse.MultiProcessor<T> multiProcessor, HttpRequestImpl req) {
+            this.resultCF = new CompletableFuture<>();
+            this.mainResponse = new CompletableFuture<>();
+            this.multiProcessor = multiProcessor;
+            this.pushHandler = multiProcessor.onStart(req, mainResponse);
+        }
+
+        CompletableFuture<T> groupResult() {
+            return resultCF;
+        }
+
+        CompletableFuture<HttpResponse> mainResponse() {
+            return mainResponse;
+        }
+
+        private BiFunction<HttpRequest,
+            CompletableFuture<HttpResponse>, Boolean> pushHandler()
+        {
+                return pushHandler;
+        }
+
+        synchronized void addPush() {
+            numberOfPushes++;
+            remainingPushes++;
+        }
+
+        synchronized int numberOfPushes() {
+            return numberOfPushes;
+        }
+        // This is called when the main body response completes because it means
+        // no more PUSH_PROMISEs are possible
+        synchronized void noMorePushes() {
+            noMorePushes = true;
+            checkIfCompleted();
+        }
+
+        synchronized void pushCompleted() {
+            remainingPushes--;
+            checkIfCompleted();
+        }
+
+        synchronized void checkIfCompleted() {
+            if (remainingPushes == 0 && error == null && noMorePushes) {
+                T overallResult = multiProcessor.onComplete();
+                resultCF.complete(overallResult);
+            }
+        }
+
+        synchronized void pushError(Throwable t) {
+            if (t == null)
+                return;
+            this.error = t;
+            resultCF.completeExceptionally(t);
+        }
     }
 }
--- a/jdk/src/java.httpclient/share/classes/java/net/http/Utils.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/Utils.java	Tue May 03 12:25:20 2016 -0700
@@ -21,28 +21,37 @@
  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  * or visit www.oracle.com if you need additional information or have any
  */
-
 package java.net.http;
 
+import sun.net.NetProperties;
+
+import javax.net.ssl.SSLParameters;
 import java.io.ByteArrayOutputStream;
+import java.io.Closeable;
+import java.io.IOException;
 import java.io.PrintStream;
 import java.io.UnsupportedEncodingException;
+import java.net.InetSocketAddress;
 import java.net.NetPermission;
 import java.net.URI;
 import java.net.URLPermission;
+import java.nio.Buffer;
 import java.nio.ByteBuffer;
+import java.nio.charset.StandardCharsets;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
+import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
-import javax.net.ssl.SSLParameters;
-import sun.net.NetProperties;
+import java.util.concurrent.CompletableFuture;
+import java.util.function.LongBinaryOperator;
+import java.util.function.Predicate;
 
 /**
  * Miscellaneous utilities
  */
-class Utils {
+final class Utils {
 
     /**
      * Allocated buffer size. Must never be higher than 16K. But can be lower
@@ -51,7 +60,59 @@
      */
     public static final int BUFSIZE = 16 * 1024;
 
-    /** Validates a RFC7230 token */
+    private static final Set<String> DISALLOWED_HEADERS_SET = Set.of(
+            "authorization", "connection", "cookie", "content-length",
+            "date", "expect", "from", "host", "origin", "proxy-authorization",
+            "referer", "user-agent", "upgrade", "via", "warning");
+
+    static final Predicate<String>
+        ALLOWED_HEADERS = header -> !Utils.DISALLOWED_HEADERS_SET.contains(header);
+
+    static final Predicate<String>
+        ALL_HEADERS = header -> true;
+
+    static InetSocketAddress getAddress(HttpRequestImpl req) {
+        URI uri = req.uri();
+        if (uri == null) {
+            return req.authority();
+        }
+        int port = uri.getPort();
+        if (port == -1) {
+            if (uri.getScheme().equalsIgnoreCase("https")) {
+                port = 443;
+            } else {
+                port = 80;
+            }
+        }
+        String host = uri.getHost();
+        if (req.proxy() == null) {
+            return new InetSocketAddress(host, port);
+        } else {
+            return InetSocketAddress.createUnresolved(host, port);
+        }
+    }
+
+    /**
+     * Puts position to limit and limit to capacity so we can resume reading
+     * into this buffer, but if required > 0 then limit may be reduced so that
+     * no more than required bytes are read next time.
+     */
+    static void resumeChannelRead(ByteBuffer buf, int required) {
+        int limit = buf.limit();
+        buf.position(limit);
+        int capacity = buf.capacity() - limit;
+        if (required > 0 && required < capacity) {
+            buf.limit(limit + required);
+        } else {
+            buf.limit(buf.capacity());
+        }
+    }
+
+    private Utils() { }
+
+    /**
+     * Validates a RFC7230 token
+     */
     static void validateToken(String token, String errormsg) {
         int length = token.length();
         for (int i = 0; i < length; i++) {
@@ -69,7 +130,7 @@
     }
 
     /**
-     * Return sthe security permission required for the given details.
+     * Returns the security permission required for the given details.
      * If method is CONNECT, then uri must be of form "scheme://host:port"
      */
     static URLPermission getPermission(URI uri,
@@ -117,13 +178,13 @@
     }
 
     static int getIntegerNetProperty(String name, int defaultValue) {
-        return AccessController.doPrivileged((PrivilegedAction<Integer>)() ->
-            NetProperties.getInteger(name, defaultValue) );
+        return AccessController.doPrivileged((PrivilegedAction<Integer>) () ->
+                NetProperties.getInteger(name, defaultValue));
     }
 
     static String getNetProperty(String name) {
-        return AccessController.doPrivileged((PrivilegedAction<String>)() ->
-            NetProperties.get(name) );
+        return AccessController.doPrivileged((PrivilegedAction<String>) () ->
+                NetProperties.get(name));
     }
 
     static SSLParameters copySSLParameters(SSLParameters p) {
@@ -134,7 +195,9 @@
         p1.setEndpointIdentificationAlgorithm(p.getEndpointIdentificationAlgorithm());
         p1.setMaximumPacketSize(p.getMaximumPacketSize());
         p1.setNeedClientAuth(p.getNeedClientAuth());
-        p1.setProtocols(p.getProtocols().clone());
+        String[] protocols = p.getProtocols();
+        if (protocols != null)
+            p1.setProtocols(protocols.clone());
         p1.setSNIMatchers(p.getSNIMatchers());
         p1.setServerNames(p.getServerNames());
         p1.setUseCipherSuitesOrder(p.getUseCipherSuitesOrder());
@@ -142,33 +205,14 @@
         return p1;
     }
 
-
-    /** Resumes reading into the given buffer. */
-    static void unflip(ByteBuffer buf) {
-        buf.position(buf.limit());
-        buf.limit(buf.capacity());
-    }
-
     /**
      * Set limit to position, and position to mark.
-     *
-     *
-     * @param buffer
-     * @param mark
      */
     static void flipToMark(ByteBuffer buffer, int mark) {
         buffer.limit(buffer.position());
         buffer.position(mark);
     }
 
-    /** Compact and leave ready for reading. */
-    static void compact(List<ByteBuffer> buffers) {
-        for (ByteBuffer b : buffers) {
-            b.compact();
-            b.flip();
-        }
-    }
-
     static String stackTrace(Throwable t) {
         ByteArrayOutputStream bos = new ByteArrayOutputStream();
         String s = null;
@@ -182,8 +226,10 @@
         return s;
     }
 
-    /** Copies as much of src to dst as possible. */
-    static void copy (ByteBuffer src, ByteBuffer dst) {
+    /**
+     * Copies as much of src to dst as possible.
+     */
+    static void copy(ByteBuffer src, ByteBuffer dst) {
         int srcLen = src.remaining();
         int dstLen = dst.remaining();
         if (srcLen > dstLen) {
@@ -204,18 +250,101 @@
         return dst;
     }
 
-    static String combine(String[] s) {
+    //
+    // Helps to trim long names (packages, nested/inner types) in logs/toString
+    //
+    static String toStringSimple(Object o) {
+        return o.getClass().getSimpleName() + "@" +
+                Integer.toHexString(System.identityHashCode(o));
+    }
+
+    //
+    // 1. It adds a number of remaining bytes;
+    // 2. Standard Buffer-type toString for CharBuffer (since it adheres to the
+    // contract of java.lang.CharSequence.toString() which is both not too
+    // useful and not too private)
+    //
+    static String toString(Buffer b) {
+        return toStringSimple(b)
+                + "[pos=" + b.position()
+                + " lim=" + b.limit()
+                + " cap=" + b.capacity()
+                + " rem=" + b.remaining() + "]";
+    }
+
+    static String toString(CharSequence s) {
+        return s == null
+                ? "null"
+                : toStringSimple(s) + "[len=" + s.length() + "]";
+    }
+
+    static String dump(Object... objects) {
+        return Arrays.toString(objects);
+    }
+
+    static final System.Logger logger = System.getLogger("java.net.http.WebSocket");
+
+    static final ByteBuffer EMPTY_BYTE_BUFFER = ByteBuffer.allocate(0);
+
+    static String webSocketSpecViolation(String section, String detail) {
+        return "RFC 6455 " + section + " " + detail;
+    }
+
+    static void logResponse(HttpResponseImpl r) {
+        if (!Log.requests()) {
+            return;
+        }
         StringBuilder sb = new StringBuilder();
-        sb.append('[');
-        boolean first = true;
-        for (String s1 : s) {
-            if (!first) {
-                sb.append(", ");
-                first = false;
+        String method = r.request().method();
+        URI uri = r.uri();
+        String uristring = uri == null ? "" : uri.toString();
+        sb.append('(').append(method).append(" ").append(uristring).append(") ").append(Integer.toString(r.statusCode()));
+        Log.logResponse(sb.toString());
+    }
+
+    static int remaining(ByteBuffer[] bufs) {
+        int remain = 0;
+        for (ByteBuffer buf : bufs)
+            remain += buf.remaining();
+        return remain;
+    }
+
+    // assumes buffer was written into starting at position zero
+    static void unflip(ByteBuffer buf) {
+        buf.position(buf.limit());
+        buf.limit(buf.capacity());
+    }
+
+    static void close(Closeable... chans) {
+        for (Closeable chan : chans) {
+            System.err.println("Closing " + chan);
+            try {
+                chan.close();
+            } catch (IOException e) {
             }
-            sb.append(s1);
         }
-        sb.append(']');
-        return sb.toString();
+    }
+
+    static ByteBuffer[] reduce(ByteBuffer[] bufs, int start, int number) {
+        if (start == 0 && number == bufs.length)
+            return bufs;
+        ByteBuffer[] nbufs = new ByteBuffer[number];
+        int j = 0;
+        for (int i=start; i<start+number; i++)
+            nbufs[j++] = bufs[i];
+        return nbufs;
     }
+
+    static String asString(ByteBuffer buf) {
+        byte[] b = new byte[buf.remaining()];
+        buf.get(b);
+        return new String(b, StandardCharsets.US_ASCII);
+    }
+
+    // Put all these static 'empty' singletons here
+    @SuppressWarnings("rawtypes")
+    static CompletableFuture[] EMPTY_CFARRAY = new CompletableFuture[0];
+
+    static ByteBuffer EMPTY_BYTEBUFFER = ByteBuffer.allocate(0);
+    static ByteBuffer[] EMPTY_BB_ARRAY = new ByteBuffer[0];
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/WindowUpdateFrame.java	Tue May 03 12:25:20 2016 -0700
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ */
+
+package java.net.http;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+class WindowUpdateFrame extends Http2Frame {
+
+    int windowUpdate;
+
+    WindowUpdateFrame() {
+        type = TYPE;
+    }
+
+    public final static int TYPE = 0x8;
+
+    public void setUpdate(int windowUpdate) {
+        this.windowUpdate = windowUpdate;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append(super.toString())
+          .append(" WindowUpdate: ")
+          .append(windowUpdate);
+        return sb.toString();
+    }
+
+    public int getUpdate() {
+        return this.windowUpdate;
+    }
+
+    /**
+     */
+    @Override
+    void readIncomingImpl(ByteBufferConsumer bc) throws IOException {
+        if (length != 4) {
+            throw new IOException("Invalid WindowUpdate frame");
+        }
+        windowUpdate = bc.getInt() & 0x7fffffff;
+    }
+
+    @Override
+    void computeLength() {
+        length = 4;
+    }
+
+    @Override
+    void writeOutgoing(ByteBufferGenerator bg) {
+        super.writeOutgoing(bg);
+        ByteBuffer buf = bg.getBuffer(4);
+        buf.putInt(windowUpdate);
+    }
+}
--- a/jdk/src/java.httpclient/share/classes/java/net/http/package-info.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.httpclient/share/classes/java/net/http/package-info.java	Tue May 03 12:25:20 2016 -0700
@@ -24,11 +24,11 @@
  */
 
 /**
- * <h2>High level HTTP API</h2>
- * This provides a high-level client interface to HTTP (versions 1.1 and 2).
- * Synchronous and asynchronous (via
- * {@link java.util.concurrent.CompletableFuture}) modes are provided. The main
- * classes defined are:
+ * <h2>High level HTTP and WebSocket API</h2>
+ * This provides a high-level client interfaces to HTTP (versions 1.1 and 2)
+ * and WebSocket. Synchronous and asynchronous (via {@link
+ * java.util.concurrent.CompletableFuture}) modes are provided for HTTP.
+ * WebSocket works in asynchronous mode only. The main types defined are:
  * <ul>
  *    <li>{@link java.net.http.HttpClient}</li>
  *    <li>{@link java.net.http.HttpRequest}</li>
--- a/jdk/src/java.logging/share/classes/java/util/logging/LogManager.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.logging/share/classes/java/util/logging/LogManager.java	Tue May 03 12:25:20 2016 -0700
@@ -231,13 +231,15 @@
                     cname = System.getProperty("java.util.logging.manager");
                     if (cname != null) {
                         try {
-                            Class<?> clz = ClassLoader.getSystemClassLoader()
-                                    .loadClass(cname);
-                            mgr = (LogManager) clz.newInstance();
+                            @SuppressWarnings("deprecation")
+                            Object tmp = ClassLoader.getSystemClassLoader()
+                                .loadClass(cname).newInstance();
+                            mgr = (LogManager) tmp;
                         } catch (ClassNotFoundException ex) {
-                            Class<?> clz = Thread.currentThread()
-                                    .getContextClassLoader().loadClass(cname);
-                            mgr = (LogManager) clz.newInstance();
+                            @SuppressWarnings("deprecation")
+                            Object tmp = Thread.currentThread()
+                                .getContextClassLoader().loadClass(cname).newInstance();
+                            mgr = (LogManager) tmp;
                         }
                     }
                 } catch (Exception ex) {
@@ -991,8 +993,9 @@
         List<Handler> handlers = new ArrayList<>(names.length);
         for (String type : names) {
             try {
-                Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(type);
-                Handler hdl = (Handler) clz.newInstance();
+                @SuppressWarnings("deprecation")
+                Object o = ClassLoader.getSystemClassLoader().loadClass(type).newInstance();
+                Handler hdl = (Handler) o;
                 // Check if there is a property defining the
                 // this handler's level.
                 String levs = getProperty(type + ".level");
@@ -1330,11 +1333,13 @@
                 // calling readConfiguration(InputStream) with a suitable stream.
                 try {
                     Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(cname);
-                    clz.newInstance();
+                    @SuppressWarnings("deprecation")
+                    Object witness = clz.newInstance();
                     return;
                 } catch (ClassNotFoundException ex) {
                     Class<?> clz = Thread.currentThread().getContextClassLoader().loadClass(cname);
-                    clz.newInstance();
+                    @SuppressWarnings("deprecation")
+                    Object witness = clz.newInstance();
                     return;
                 }
             } catch (Exception ex) {
@@ -1561,7 +1566,8 @@
                 for (String word : names) {
                     try {
                         Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(word);
-                        clz.newInstance();
+                        @SuppressWarnings("deprecation")
+                        Object witness = clz.newInstance();
                     } catch (Exception ex) {
                         System.err.println("Can't load config class \"" + word + "\"");
                         System.err.println("" + ex);
@@ -2307,8 +2313,9 @@
         String val = getProperty(name);
         try {
             if (val != null) {
-                Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(val);
-                return (Filter) clz.newInstance();
+                @SuppressWarnings("deprecation")
+                Object o = ClassLoader.getSystemClassLoader().loadClass(val).newInstance();
+                return (Filter) o;
             }
         } catch (Exception ex) {
             // We got one of a variety of exceptions in creating the
@@ -2328,8 +2335,9 @@
         String val = getProperty(name);
         try {
             if (val != null) {
-                Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(val);
-                return (Formatter) clz.newInstance();
+                @SuppressWarnings("deprecation")
+                Object o = ClassLoader.getSystemClassLoader().loadClass(val).newInstance();
+                return (Formatter) o;
             }
         } catch (Exception ex) {
             // We got one of a variety of exceptions in creating the
--- a/jdk/src/java.logging/share/classes/java/util/logging/MemoryHandler.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.logging/share/classes/java/util/logging/MemoryHandler.java	Tue May 03 12:25:20 2016 -0700
@@ -117,7 +117,9 @@
         Class<?> clz;
         try {
             clz = ClassLoader.getSystemClassLoader().loadClass(targetName);
-            target = (Handler) clz.newInstance();
+            @SuppressWarnings("deprecation")
+            Object o = clz.newInstance();
+            target = (Handler) o;
         } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
             throw new RuntimeException("MemoryHandler can't load handler target \"" + targetName + "\"" , e);
         }
--- a/jdk/src/java.management/share/classes/com/sun/jmx/mbeanserver/DefaultMXBeanMappingFactory.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.management/share/classes/com/sun/jmx/mbeanserver/DefaultMXBeanMappingFactory.java	Tue May 03 12:25:20 2016 -0700
@@ -655,7 +655,9 @@
             final Object[] openArray = (Object[]) openValue;
             final Collection<Object> valueCollection;
             try {
-                valueCollection = cast(collectionClass.newInstance());
+                @SuppressWarnings("deprecation")
+                Collection<?> tmp = collectionClass.newInstance();
+                valueCollection = cast(tmp);
             } catch (Exception e) {
                 throw invalidObjectException("Cannot create collection", e);
             }
@@ -1114,7 +1116,9 @@
             try {
                 final Class<?> targetClass = getTargetClass();
                 ReflectUtil.checkPackageAccess(targetClass);
-                o = targetClass.newInstance();
+                @SuppressWarnings("deprecation")
+                Object tmp = targetClass.newInstance();
+                o = tmp;
                 for (int i = 0; i < itemNames.length; i++) {
                     if (cd.containsKey(itemNames[i])) {
                         Object openItem = cd.get(itemNames[i]);
--- a/jdk/src/java.management/share/classes/javax/management/MBeanServerFactory.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.management/share/classes/javax/management/MBeanServerFactory.java	Tue May 03 12:25:20 2016 -0700
@@ -458,6 +458,7 @@
      **/
     private static MBeanServerBuilder newBuilder(Class<?> builderClass) {
         try {
+            @SuppressWarnings("deprecation")
             final Object abuilder = builderClass.newInstance();
             return (MBeanServerBuilder)abuilder;
         } catch (RuntimeException x) {
--- a/jdk/src/java.management/share/classes/javax/management/remote/JMXConnectorFactory.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.management/share/classes/javax/management/remote/JMXConnectorFactory.java	Tue May 03 12:25:20 2016 -0700
@@ -531,7 +531,9 @@
             // We have just proved that this cast is correct
             Class<? extends T> providerClassT = Util.cast(providerClass);
             try {
-                return providerClassT.newInstance();
+                @SuppressWarnings("deprecation")
+                T result = providerClassT.newInstance();
+                return result;
             } catch (Exception e) {
                 final String msg =
                     "Exception when instantiating provider [" + className +
--- a/jdk/src/java.naming/share/classes/com/sun/naming/internal/FactoryEnumeration.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.naming/share/classes/com/sun/naming/internal/FactoryEnumeration.java	Tue May 03 12:25:20 2016 -0700
@@ -86,7 +86,9 @@
                     answer = cls;
                 }
                 // Instantiate Class to get factory
-                answer = ((Class) answer).newInstance();
+                @SuppressWarnings("deprecation")
+                Object tmp = ((Class) answer).newInstance();
+                answer = tmp;
                 ref = new NamedWeakReference<>(answer, className);
                 factories.set(posn-1, ref);  // replace Class object or null
                 return answer;
--- a/jdk/src/java.naming/share/classes/com/sun/naming/internal/ResourceManager.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.naming/share/classes/com/sun/naming/internal/ResourceManager.java	Tue May 03 12:25:20 2016 -0700
@@ -399,7 +399,9 @@
                 className = parser.nextToken() + classSuffix;
                 try {
                     // System.out.println("loading " + className);
-                    factory = helper.loadClass(className, loader).newInstance();
+                    @SuppressWarnings("deprecation") // Class.newInstance
+                    Object tmp = helper.loadClass(className, loader).newInstance();
+                    factory = tmp;
                 } catch (InstantiationException e) {
                     NamingException ne =
                         new NamingException("Cannot instantiate " + className);
--- a/jdk/src/java.naming/share/classes/javax/naming/ldap/StartTlsRequest.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.naming/share/classes/javax/naming/ldap/StartTlsRequest.java	Tue May 03 12:25:20 2016 -0700
@@ -192,18 +192,12 @@
         }
         try {
             VersionHelper helper = VersionHelper.getVersionHelper();
-            Class<?> clas = helper.loadClass(
-                "com.sun.jndi.ldap.ext.StartTlsResponseImpl");
-
-            resp = (StartTlsResponse) clas.newInstance();
+            @SuppressWarnings("deprecation")
+            Object o = helper.loadClass(
+                "com.sun.jndi.ldap.ext.StartTlsResponseImpl").newInstance();
+            resp = (StartTlsResponse) o;
 
-        } catch (IllegalAccessException e) {
-            throw wrapException(e);
-
-        } catch (InstantiationException e) {
-            throw wrapException(e);
-
-        } catch (ClassNotFoundException e) {
+        } catch (IllegalAccessException | InstantiationException | ClassNotFoundException e) {
             throw wrapException(e);
         }
 
--- a/jdk/src/java.naming/share/classes/javax/naming/spi/NamingManager.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.naming/share/classes/javax/naming/spi/NamingManager.java	Tue May 03 12:25:20 2016 -0700
@@ -159,7 +159,9 @@
             }
         }
 
-        return (clas != null) ? (ObjectFactory) clas.newInstance() : null;
+        @SuppressWarnings("deprecation") // Class.newInstance
+        ObjectFactory result = (clas != null) ? (ObjectFactory) clas.newInstance() : null;
+        return result;
     }
 
 
@@ -710,8 +712,9 @@
 
             if (factory == null) {
                 try {
-                    factory = (InitialContextFactory)
-                            helper.loadClass(className).newInstance();
+                    @SuppressWarnings("deprecation")
+                    Object o = helper.loadClass(className).newInstance();
+                    factory = (InitialContextFactory) o;
                 } catch (Exception e) {
                     NoInitialContextException ne =
                             new NoInitialContextException(
--- a/jdk/src/java.prefs/share/classes/java/util/prefs/Preferences.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.prefs/share/classes/java/util/prefs/Preferences.java	Tue May 03 12:25:20 2016 -0700
@@ -238,10 +238,11 @@
             // dependent on the invoking thread.
             // Checking AllPermission also seems wrong.
             try {
-                return (PreferencesFactory)
-                    Class.forName(factoryName, false,
-                                  ClassLoader.getSystemClassLoader())
+                @SuppressWarnings("deprecation")
+                Object result =Class.forName(factoryName, false,
+                                             ClassLoader.getSystemClassLoader())
                     .newInstance();
+                return (PreferencesFactory)result;
             } catch (Exception ex) {
                 try {
                     // workaround for javaws, plugin,
@@ -250,11 +251,12 @@
                     if (sm != null) {
                         sm.checkPermission(new java.security.AllPermission());
                     }
-                    return (PreferencesFactory)
-                        Class.forName(factoryName, false,
-                                      Thread.currentThread()
-                                      .getContextClassLoader())
+                    @SuppressWarnings("deprecation")
+                    Object result = Class.forName(factoryName, false,
+                                                  Thread.currentThread()
+                                                  .getContextClassLoader())
                         .newInstance();
+                    return (PreferencesFactory) result;
                 } catch (Exception e) {
                     throw new InternalError(
                         "Can't instantiate Preferences factory "
@@ -299,9 +301,10 @@
             platformFactory = "java.util.prefs.FileSystemPreferencesFactory";
         }
         try {
-            return (PreferencesFactory)
-                Class.forName(platformFactory, false,
-                              Preferences.class.getClassLoader()).newInstance();
+            @SuppressWarnings("deprecation")
+            Object result = Class.forName(platformFactory, false,
+                                          Preferences.class.getClassLoader()).newInstance();
+            return (PreferencesFactory) result;
         } catch (Exception e) {
             throw new InternalError(
                 "Can't instantiate platform default Preferences factory "
--- a/jdk/src/java.rmi/share/classes/java/rmi/activation/ActivationID.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.rmi/share/classes/java/rmi/activation/ActivationID.java	Tue May 03 12:25:20 2016 -0700
@@ -272,6 +272,7 @@
             Class<? extends RemoteRef> refClass =
                 Class.forName(RemoteRef.packagePrefix + "." + in.readUTF())
                 .asSubclass(RemoteRef.class);
+            @SuppressWarnings("deprecation")
             RemoteRef ref = refClass.newInstance();
             ref.readExternal(in);
             activator = (Activator)
--- a/jdk/src/java.rmi/share/classes/java/rmi/server/RMIClassLoader.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.rmi/share/classes/java/rmi/server/RMIClassLoader.java	Tue May 03 12:25:20 2016 -0700
@@ -681,7 +681,9 @@
                     Class.forName(providerClassName, false,
                                   ClassLoader.getSystemClassLoader())
                     .asSubclass(RMIClassLoaderSpi.class);
-                return providerClass.newInstance();
+                @SuppressWarnings("deprecation")
+                RMIClassLoaderSpi result = providerClass.newInstance();
+                return result;
 
             } catch (ClassNotFoundException e) {
                 throw new NoClassDefFoundError(e.getMessage());
--- a/jdk/src/java.rmi/share/classes/java/rmi/server/RemoteObject.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.rmi/share/classes/java/rmi/server/RemoteObject.java	Tue May 03 12:25:20 2016 -0700
@@ -439,18 +439,16 @@
                 RemoteRef.packagePrefix + "." + refClassName;
             Class<?> refClass = Class.forName(internalRefClassName);
             try {
-                ref = (RemoteRef) refClass.newInstance();
+                @SuppressWarnings("deprecation")
+                Object tmp = refClass.newInstance();
+                ref = (RemoteRef) tmp;
 
                 /*
                  * If this step fails, assume we found an internal
                  * class that is not meant to be a serializable ref
                  * type.
                  */
-            } catch (InstantiationException e) {
-                throw new ClassNotFoundException(internalRefClassName, e);
-            } catch (IllegalAccessException e) {
-                throw new ClassNotFoundException(internalRefClassName, e);
-            } catch (ClassCastException e) {
+            } catch (InstantiationException | IllegalAccessException | ClassCastException e) {
                 throw new ClassNotFoundException(internalRefClassName, e);
             }
             ref.readExternal(in);
--- a/jdk/src/java.rmi/share/classes/sun/rmi/server/Activation.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.rmi/share/classes/sun/rmi/server/Activation.java	Tue May 03 12:25:20 2016 -0700
@@ -2066,7 +2066,9 @@
 
                 try {
                     Class<?> execPolicyClass = getRMIClass(execPolicyClassName);
-                    execPolicy = execPolicyClass.newInstance();
+                    @SuppressWarnings("deprecation")
+                    Object tmp = execPolicyClass.newInstance();
+                    execPolicy = tmp;
                     execPolicyMethod =
                         execPolicyClass.getMethod("checkExecCommand",
                                                   ActivationGroupDesc.class,
--- a/jdk/src/java.smartcardio/share/classes/javax/smartcardio/TerminalFactory.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.smartcardio/share/classes/javax/smartcardio/TerminalFactory.java	Tue May 03 12:25:20 2016 -0700
@@ -111,8 +111,9 @@
                 type = "PC/SC";
                 Provider sun = Security.getProvider("SunPCSC");
                 if (sun == null) {
-                    Class<?> clazz = Class.forName("sun.security.smartcardio.SunPCSC");
-                    sun = (Provider)clazz.newInstance();
+                    @SuppressWarnings("deprecation")
+                    Object o = Class.forName("sun.security.smartcardio.SunPCSC").newInstance();
+                    sun = (Provider)o;
                 }
                 factory = TerminalFactory.getInstance(type, null, sun);
             } catch (Exception e) {
--- a/jdk/src/java.sql.rowset/share/classes/com/sun/rowset/CachedRowSetImpl.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.sql.rowset/share/classes/com/sun/rowset/CachedRowSetImpl.java	Tue May 03 12:25:20 2016 -0700
@@ -2962,7 +2962,9 @@
                 SQLData obj = null;
                 try {
                     ReflectUtil.checkPackageAccess(c);
-                    obj = (SQLData) c.newInstance();
+                    @SuppressWarnings("deprecation")
+                    Object tmp = c.newInstance();
+                    obj = (SQLData) tmp;
                 } catch(Exception ex) {
                     throw new SQLException("Unable to Instantiate: ", ex);
                 }
@@ -5710,7 +5712,9 @@
                 SQLData obj = null;
                 try {
                     ReflectUtil.checkPackageAccess(c);
-                    obj = (SQLData) c.newInstance();
+                    @SuppressWarnings("deprecation")
+                    Object tmp = c.newInstance();
+                    obj = (SQLData) tmp;
                 } catch(Exception ex) {
                     throw new SQLException("Unable to Instantiate: ", ex);
                 }
--- a/jdk/src/java.sql.rowset/share/classes/com/sun/rowset/internal/CachedRowSetWriter.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.sql.rowset/share/classes/com/sun/rowset/internal/CachedRowSetWriter.java	Tue May 03 12:25:20 2016 -0700
@@ -574,7 +574,9 @@
                         SQLData obj = null;
                         try {
                             ReflectUtil.checkPackageAccess(c);
-                            obj = (SQLData)c.newInstance();
+                            @SuppressWarnings("deprecation")
+                            Object tmp = c.newInstance();
+                            obj = (SQLData)tmp;
                         } catch (Exception ex) {
                             throw new SQLException("Unable to Instantiate: ", ex);
                         }
--- a/jdk/src/java.sql.rowset/share/classes/javax/sql/rowset/RowSetProvider.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.sql.rowset/share/classes/javax/sql/rowset/RowSetProvider.java	Tue May 03 12:25:20 2016 -0700
@@ -136,8 +136,9 @@
                 }
                 // getFactoryClass takes care of adding the read edge if
                 // necessary
-                Class<?> c = getFactoryClass(factoryClassName, null, false);
-                factory = (RowSetFactory) c.newInstance();
+                @SuppressWarnings("deprecation")
+                Object o = getFactoryClass(factoryClassName, null, false).newInstance();
+                factory = (RowSetFactory) o;
             }
         } catch (Exception e) {
             throw new SQLException( "RowSetFactory: " + factoryClassName +
@@ -202,6 +203,7 @@
             // getFactoryClass takes care of adding the read edge if
             // necessary
             Class<?> providerClass = getFactoryClass(factoryClassName, cl, false);
+            @SuppressWarnings("deprecation")
             RowSetFactory instance = (RowSetFactory) providerClass.newInstance();
             if (debug) {
                 trace("Created new instance of " + providerClass +
--- a/jdk/src/java.sql.rowset/share/classes/javax/sql/rowset/serial/SQLInputImpl.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.sql.rowset/share/classes/javax/sql/rowset/serial/SQLInputImpl.java	Tue May 03 12:25:20 2016 -0700
@@ -478,7 +478,9 @@
                 SQLData obj = null;
                 try {
                     ReflectUtil.checkPackageAccess(c);
-                    obj = (SQLData)c.newInstance();
+                    @SuppressWarnings("deprecation")
+                    Object tmp = c.newInstance();
+                    obj = (SQLData)tmp;
                 } catch (Exception ex) {
                     throw new SQLException("Unable to Instantiate: ", ex);
                 }
--- a/jdk/src/java.sql.rowset/share/classes/javax/sql/rowset/spi/SyncFactory.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.sql.rowset/share/classes/javax/sql/rowset/spi/SyncFactory.java	Tue May 03 12:25:20 2016 -0700
@@ -582,14 +582,12 @@
              * there.
              **/
             c = Class.forName(providerID, true, cl);
-            return (SyncProvider) c.newInstance();
+            @SuppressWarnings("deprecation")
+            Object result =  c.newInstance();
+            return (SyncProvider)result;
 
-        } catch (IllegalAccessException e) {
+        } catch (IllegalAccessException | InstantiationException | ClassNotFoundException e) {
             throw new SyncFactoryException("IllegalAccessException: " + e.getMessage());
-        } catch (InstantiationException e) {
-            throw new SyncFactoryException("InstantiationException: " + e.getMessage());
-        } catch (ClassNotFoundException e) {
-            throw new SyncFactoryException("ClassNotFoundException: " + e.getMessage());
         }
     }
 
--- a/jdk/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/algorithms/SignatureAlgorithm.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/algorithms/SignatureAlgorithm.java	Tue May 03 12:25:20 2016 -0700
@@ -152,7 +152,9 @@
                 log.log(java.util.logging.Level.FINE, "Create URI \"" + algorithmURI + "\" class \""
                    + implementingClass + "\"");
             }
-            return implementingClass.newInstance();
+            @SuppressWarnings("deprecation")
+            SignatureAlgorithmSpi result = implementingClass.newInstance();
+            return result;
         }  catch (IllegalAccessException ex) {
             Object exArgs[] = { algorithmURI, ex.getMessage() };
             throw new XMLSignatureException("algorithms.NoSuchAlgorithm", exArgs, ex);
--- a/jdk/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/c14n/Canonicalizer.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/c14n/Canonicalizer.java	Tue May 03 12:25:20 2016 -0700
@@ -115,7 +115,9 @@
             Class<? extends CanonicalizerSpi> implementingClass =
                 canonicalizerHash.get(algorithmURI);
 
-            canonicalizerSpi = implementingClass.newInstance();
+            @SuppressWarnings("deprecation")
+            CanonicalizerSpi tmp = implementingClass.newInstance();
+            canonicalizerSpi = tmp;
             canonicalizerSpi.reset = true;
         } catch (Exception e) {
             Object exArgs[] = { algorithmURI };
--- a/jdk/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/KeyResolver.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/KeyResolver.java	Tue May 03 12:25:20 2016 -0700
@@ -182,6 +182,7 @@
     public static void register(String className, boolean globalResolver)
         throws ClassNotFoundException, IllegalAccessException, InstantiationException {
         JavaUtils.checkRegisterPermission();
+        @SuppressWarnings("deprecation")
         KeyResolverSpi keyResolverSpi =
             (KeyResolverSpi) Class.forName(className).newInstance();
         keyResolverSpi.setGlobalResolver(globalResolver);
@@ -207,7 +208,9 @@
         KeyResolverSpi keyResolverSpi = null;
         Exception ex = null;
         try {
-            keyResolverSpi = (KeyResolverSpi) Class.forName(className).newInstance();
+            @SuppressWarnings("deprecation")
+            Object tmp = Class.forName(className).newInstance();
+            keyResolverSpi = (KeyResolverSpi) tmp;
         } catch (ClassNotFoundException e) {
             ex = e;
         } catch (IllegalAccessException e) {
@@ -272,6 +275,7 @@
         JavaUtils.checkRegisterPermission();
         List<KeyResolver> keyResolverList = new ArrayList<KeyResolver>(classNames.size());
         for (String className : classNames) {
+            @SuppressWarnings("deprecation")
             KeyResolverSpi keyResolverSpi =
                 (KeyResolverSpi) Class.forName(className).newInstance();
             keyResolverSpi.setGlobalResolver(false);
--- a/jdk/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/KeyResolverSpi.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/keys/keyresolver/KeyResolverSpi.java	Tue May 03 12:25:20 2016 -0700
@@ -110,7 +110,9 @@
         KeyResolverSpi tmp = this;
         if (globalResolver) {
             try {
-                tmp = getClass().newInstance();
+                @SuppressWarnings("deprecation")
+                KeyResolverSpi krs = getClass().newInstance();
+                tmp = krs;
             } catch (InstantiationException e) {
                 throw new KeyResolverException("", e);
             } catch (IllegalAccessException e) {
--- a/jdk/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/transforms/Transform.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/transforms/Transform.java	Tue May 03 12:25:20 2016 -0700
@@ -160,7 +160,9 @@
             throw new InvalidTransformException("signature.Transform.UnknownTransform", exArgs);
         }
         try {
-            transformSpi = transformSpiClass.newInstance();
+            @SuppressWarnings("deprecation")
+            TransformSpi tmp = transformSpiClass.newInstance();
+            transformSpi = tmp;
         } catch (InstantiationException ex) {
             Object exArgs[] = { algorithmURI };
             throw new InvalidTransformException(
@@ -345,7 +347,9 @@
         }
         TransformSpi newTransformSpi = null;
         try {
-            newTransformSpi = transformSpiClass.newInstance();
+            @SuppressWarnings("deprecation")
+            TransformSpi tmp = transformSpiClass.newInstance();
+            newTransformSpi = tmp;
         } catch (InstantiationException ex) {
             Object exArgs[] = { algorithmURI };
             throw new InvalidTransformException(
--- a/jdk/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/utils/resolver/ResourceResolver.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/java.xml.crypto/share/classes/com/sun/org/apache/xml/internal/security/utils/resolver/ResourceResolver.java	Tue May 03 12:25:20 2016 -0700
@@ -99,8 +99,10 @@
                 ResourceResolver resolverTmp = resolver;
                 if (!resolver.resolverSpi.engineIsThreadSafe()) {
                     try {
-                        resolverTmp =
-                            new ResourceResolver(resolver.resolverSpi.getClass().newInstance());
+                        @SuppressWarnings("deprecation")
+                        ResourceResolver tmp = new ResourceResolver(resolver.resolverSpi.getClass().newInstance());
+                        resolverTmp = tmp;
+                            ;
                     } catch (InstantiationException e) {
                         throw new ResourceResolverException("", e, context.attr, context.baseUri);
                     } catch (IllegalAccessException e) {
@@ -246,6 +248,7 @@
     public static void register(Class<? extends ResourceResolverSpi> className, boolean start) {
         JavaUtils.checkRegisterPermission();
         try {
+            @SuppressWarnings("deprecation")
             ResourceResolverSpi resourceResolverSpi = className.newInstance();
             register(resourceResolverSpi, start);
         } catch (IllegalAccessException e) {
--- a/jdk/src/jdk.accessibility/share/classes/com/sun/java/accessibility/util/Translator.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/jdk.accessibility/share/classes/com/sun/java/accessibility/util/Translator.java	Tue May 03 12:25:20 2016 -0700
@@ -121,6 +121,7 @@
             Class<?> translatorClass = getTranslatorClass(o.getClass());
             if (translatorClass != null) {
                 try {
+                    @SuppressWarnings("deprecation")
                     Translator t = (Translator)translatorClass.newInstance();
                     t.setSource(o);
                     a = t;
--- a/jdk/src/jdk.charsets/share/classes/sun/nio/cs/ext/AbstractCharsetProvider.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/jdk.charsets/share/classes/sun/nio/cs/ext/AbstractCharsetProvider.java	Tue May 03 12:25:20 2016 -0700
@@ -148,6 +148,7 @@
                                        true,
                                        this.getClass().getClassLoader());
 
+            @SuppressWarnings("deprecation")
             Charset cs = (Charset)c.newInstance();
             cache.put(csn, new SoftReference<Charset>(cs));
             return cs;
--- a/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/P11Util.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/P11Util.java	Tue May 03 12:25:20 2016 -0700
@@ -88,8 +88,9 @@
         p = Security.getProvider(providerName);
         if (p == null) {
             try {
-                Class<?> clazz = Class.forName(className);
-                p = (Provider)clazz.newInstance();
+                @SuppressWarnings("deprecation")
+                Object o = Class.forName(className).newInstance();
+                p = (Provider)o;
             } catch (Exception e) {
                 throw new ProviderException
                         ("Could not find provider " + providerName, e);
--- a/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/SunPKCS11.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/jdk.crypto.pkcs11/share/classes/sun/security/pkcs11/SunPKCS11.java	Tue May 03 12:25:20 2016 -0700
@@ -1446,7 +1446,9 @@
                             }
                             return null;
                         }
-                        return (CallbackHandler)c.newInstance();
+                        @SuppressWarnings("deprecation")
+                        Object result = c.newInstance();
+                        return (CallbackHandler)result;
                     }
                 });
                 // save it
--- a/jdk/src/jdk.httpserver/share/classes/com/sun/net/httpserver/spi/HttpServerProvider.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/jdk.httpserver/share/classes/com/sun/net/httpserver/spi/HttpServerProvider.java	Tue May 03 12:25:20 2016 -0700
@@ -89,9 +89,10 @@
         if (cn == null)
             return false;
         try {
-            Class<?> c = Class.forName(cn, true,
-                                       ClassLoader.getSystemClassLoader());
-            provider = (HttpServerProvider)c.newInstance();
+            @SuppressWarnings("deprecation")
+            Object o = Class.forName(cn, true,
+                                     ClassLoader.getSystemClassLoader()).newInstance();
+            provider = (HttpServerProvider)o;
             return true;
         } catch (ClassNotFoundException |
                  IllegalAccessException |
--- a/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/TerminalFactory.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/TerminalFactory.java	Tue May 03 12:25:20 2016 -0700
@@ -82,7 +82,9 @@
                 }
                 else {
                     try {
-                        t = (Terminal) Thread.currentThread().getContextClassLoader().loadClass(type).newInstance();
+                        @SuppressWarnings("deprecation")
+                        Object o = Thread.currentThread().getContextClassLoader().loadClass(type).newInstance();
+                        t = (Terminal) o;
                     }
                     catch (Exception e) {
                         throw new IllegalArgumentException(MessageFormat.format("Invalid terminal type: {0}", type), e);
--- a/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/internal/ConsoleRunner.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/jdk.internal.le/share/classes/jdk/internal/jline/console/internal/ConsoleRunner.java	Tue May 03 12:25:20 2016 -0700
@@ -61,6 +61,7 @@
         List<Completer> completorList = new ArrayList<Completer>();
 
         for (StringTokenizer tok = new StringTokenizer(completors, ","); tok.hasMoreTokens();) {
+            @SuppressWarnings("deprecation")
             Object obj = Class.forName(tok.nextToken()).newInstance();
             completorList.add((Completer) obj);
         }
--- a/jdk/src/jdk.jartool/share/classes/sun/tools/jar/GNUStyleOptions.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/jdk.jartool/share/classes/sun/tools/jar/GNUStyleOptions.java	Tue May 03 12:25:20 2016 -0700
@@ -136,10 +136,10 @@
                     jartool.moduleVersion = Version.parse(arg);
                 }
             },
-            new Option(true, OptionType.CREATE_UPDATE, "--hash-dependencies") {
+            new Option(true, OptionType.CREATE_UPDATE, "--hash-modules") {
                 void process(Main jartool, String opt, String arg) throws BadArgs {
                     try {
-                        jartool.dependenciesToHash = Pattern.compile(arg);
+                        jartool.modulesToHash = Pattern.compile(arg);
                     } catch (PatternSyntaxException e) {
                         throw new BadArgs("err.badpattern", arg).showUsage(true);
                     }
--- a/jdk/src/jdk.jartool/share/classes/sun/tools/jar/Main.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/jdk.jartool/share/classes/sun/tools/jar/Main.java	Tue May 03 12:25:20 2016 -0700
@@ -26,21 +26,25 @@
 package sun.tools.jar;
 
 import java.io.*;
+import java.lang.module.Configuration;
 import java.lang.module.ModuleDescriptor;
 import java.lang.module.ModuleDescriptor.Exports;
 import java.lang.module.ModuleDescriptor.Provides;
 import java.lang.module.ModuleDescriptor.Requires;
 import java.lang.module.ModuleDescriptor.Version;
 import java.lang.module.ModuleFinder;
+import java.lang.module.ModuleReader;
 import java.lang.module.ModuleReference;
-import java.lang.reflect.Method;
+import java.lang.module.ResolutionException;
+import java.lang.module.ResolvedModule;
 import java.net.URI;
 import java.nio.file.Path;
 import java.nio.file.Files;
 import java.nio.file.Paths;
 import java.util.*;
 import java.util.function.Consumer;
-import java.util.regex.Matcher;
+import java.util.function.Function;
+import java.util.function.Supplier;
 import java.util.regex.Pattern;
 import java.util.stream.Collectors;
 import java.util.zip.*;
@@ -49,9 +53,12 @@
 import java.util.jar.Manifest;
 import java.text.MessageFormat;
 
-import jdk.internal.module.Hasher;
+import jdk.internal.misc.JavaLangModuleAccess;
+import jdk.internal.misc.SharedSecrets;
+import jdk.internal.module.ModuleHashes;
 import jdk.internal.module.ModuleInfoExtender;
 import jdk.internal.util.jar.JarIndex;
+
 import static jdk.internal.util.jar.JarIndex.INDEX_NAME;
 import static java.util.jar.JarFile.MANIFEST_NAME;
 import static java.util.stream.Collectors.joining;
@@ -117,7 +124,7 @@
     /* Modular jar related options */
     boolean printModuleDescriptor;
     Version moduleVersion;
-    Pattern dependenciesToHash;
+    Pattern modulesToHash;
     ModuleFinder moduleFinder = ModuleFinder.empty();
 
     private static final String MODULE_INFO = "module-info.class";
@@ -241,7 +248,7 @@
                 if (isModularJar()) {
                     moduleInfoBytes = addExtendedModuleAttributes(
                             readModuleInfo(moduleInfo));
-                } else if (moduleVersion != null || dependenciesToHash != null) {
+                } else if (moduleVersion != null || modulesToHash != null) {
                     error(getMsg("error.module.options.without.info"));
                     return false;
                 }
@@ -801,7 +808,7 @@
                 }
             } else if (isModuleInfoEntry
                        && ((newModuleInfoBytes != null) || (ename != null)
-                           || moduleVersion != null || dependenciesToHash != null)) {
+                           || moduleVersion != null || modulesToHash != null)) {
                 if (newModuleInfoBytes == null) {
                     // Update existing module-info.class
                     newModuleInfoBytes = readModuleInfo(zis);
@@ -861,7 +868,7 @@
             if (!updateModuleInfo(newModuleInfoBytes, zos)) {
                 updateOk = false;
             }
-        } else if (moduleVersion != null || dependenciesToHash != null) {
+        } else if (moduleVersion != null || modulesToHash != null) {
             error(getMsg("error.module.options.without.info"));
             updateOk = false;
         }
@@ -1642,70 +1649,60 @@
         return false;
     }
 
-    @SuppressWarnings("unchecked")
+    static <T> String toString(Set<T> set) {
+        if (set.isEmpty()) { return ""; }
+        return set.stream().map(e -> e.toString().toLowerCase(Locale.ROOT))
+                  .collect(joining(" "));
+    }
+
+    private static final JavaLangModuleAccess JLMA = SharedSecrets.getJavaLangModuleAccess();
+
     private void printModuleDescriptor(InputStream entryInputStream)
         throws IOException
     {
         ModuleDescriptor md = ModuleDescriptor.read(entryInputStream);
         StringBuilder sb = new StringBuilder();
-        sb.append("\nName:\n  " + md.toNameAndVersion());
-
-        Set<Requires> requires = md.requires();
-        if (!requires.isEmpty()) {
-            sb.append("\nRequires:");
-            requires.forEach(r ->
-                    sb.append("\n  ").append(r.name())
-                            .append(toString(r.modifiers(), " [ ", " ]")));
-        }
+        sb.append("\n").append(md.toNameAndVersion());
 
-        Set<String> s = md.uses();
-        if (!s.isEmpty()) {
-            sb.append("\nUses: ");
-            s.forEach(sv -> sb.append("\n  ").append(sv));
-        }
+        md.requires().stream()
+            .sorted(Comparator.comparing(Requires::name))
+            .forEach(r -> {
+                sb.append("\n  requires ");
+                if (!r.modifiers().isEmpty())
+                    sb.append(toString(r.modifiers())).append(" ");
+                sb.append(r.name());
+            });
 
-        Set<Exports> exports = md.exports();
-        if (!exports.isEmpty()) {
-            sb.append("\nExports:");
-            exports.forEach(sv -> sb.append("\n  ").append(sv));
-        }
+        md.uses().stream().sorted()
+            .forEach(p -> sb.append("\n  uses ").append(p));
+
+        md.exports().stream()
+            .sorted(Comparator.comparing(Exports::source))
+            .forEach(p -> sb.append("\n  exports ").append(p));
+
+        md.conceals().stream().sorted()
+            .forEach(p -> sb.append("\n  conceals ").append(p));
 
-        Map<String,Provides> provides = md.provides();
-        if (!provides.isEmpty()) {
-            sb.append("\nProvides: ");
-            provides.values().forEach(p ->
-                    sb.append("\n  ").append(p.service())
-                      .append(" with ")
-                      .append(toString(p.providers(), "", "")));
-        }
+        md.provides().values().stream()
+            .sorted(Comparator.comparing(Provides::service))
+            .forEach(p -> sb.append("\n  provides ").append(p.service())
+                            .append(" with ")
+                            .append(toString(p.providers())));
 
-        Optional<String> mc = md.mainClass();
-        if (mc.isPresent())
-            sb.append("\nMain class:\n  " + mc.get());
+        md.mainClass().ifPresent(v -> sb.append("\n  main-class " + v));
+
+        md.osName().ifPresent(v -> sb.append("\n  operating-system-name " + v));
 
-        s = md.conceals();
-        if (!s.isEmpty()) {
-            sb.append("\nConceals:");
-            s.forEach(p -> sb.append("\n  ").append(p));
-        }
+        md.osArch().ifPresent(v -> sb.append("\n  operating-system-architecture " + v));
 
-        try {
-            Method m = ModuleDescriptor.class.getDeclaredMethod("hashes");
-            m.setAccessible(true);
-            Optional<Hasher.DependencyHashes> optHashes =
-                    (Optional<Hasher.DependencyHashes>) m.invoke(md);
+        md.osVersion().ifPresent(v -> sb.append("\n  operating-system-version " + v));
 
-            if (optHashes.isPresent()) {
-                Hasher.DependencyHashes hashes = optHashes.get();
-                sb.append("\nHashes:");
-                sb.append("\n  Algorithm: " + hashes.algorithm());
-                hashes.names().stream().forEach(mod ->
-                        sb.append("\n  ").append(mod)
-                          .append(": ").append(hashes.hashFor(mod)));
-            }
-        } catch (ReflectiveOperationException x) {
-            throw new InternalError(x);
-        }
+        JLMA.hashes(md).ifPresent(hashes ->
+                hashes.names().stream().sorted().forEach(
+                    mod -> sb.append("\n  hashes ").append(mod).append(" ")
+                             .append(hashes.algorithm()).append(" ")
+                             .append(hashes.hashFor(mod))));
+
         output(sb.toString());
     }
 
@@ -1751,7 +1748,6 @@
             md = ModuleDescriptor.read(in);
         }
         String name = md.name();
-        Set<ModuleDescriptor.Requires> dependences = md.requires();
         Set<String> exported = md.exports()
                                  .stream()
                                  .map(ModuleDescriptor.Exports::source)
@@ -1778,9 +1774,17 @@
             if (moduleVersion != null)
                 extender.version(moduleVersion);
 
-            // --hash-dependencies
-            if (dependenciesToHash != null)
-                extender.hashes(hashDependences(name, dependences));
+            // --hash-modules
+            if (modulesToHash != null) {
+                Hasher hasher = new Hasher(md, fname);
+                ModuleHashes moduleHashes = hasher.computeHashes(name);
+                if (moduleHashes != null) {
+                    extender.hashes(moduleHashes);
+                } else {
+                    // should it issue warning or silent?
+                    System.out.println("warning: no module is recorded in hash in " + name);
+                }
+            }
 
             extender.write(baos);
             return baos.toByteArray();
@@ -1788,36 +1792,156 @@
     }
 
     /**
-     * Examines the module dependences of the given module and computes the
-     * hash of any module that matches the pattern {@code dependenciesToHash}.
+     * Compute and record hashes
      */
-    private Hasher.DependencyHashes
-    hashDependences(String name,
-                    Set<ModuleDescriptor.Requires> moduleDependences)
-        throws IOException
-    {
-        Map<String, Path> map = new HashMap<>();
-        Matcher matcher = dependenciesToHash.matcher("");
-        for (ModuleDescriptor.Requires md: moduleDependences) {
-            String dn = md.name();
-            if (matcher.reset(dn).find()) {
-                Optional<ModuleReference> omref = moduleFinder.find(dn);
-                if (!omref.isPresent()) {
-                    throw new IOException(formatMsg2("error.hash.dep", name , dn));
-                }
-                map.put(dn, modRefToPath(omref.get()));
+    private class Hasher {
+        final ModuleFinder finder;
+        final Map<String, Path> moduleNameToPath;
+        final Set<String> modules;
+        final Configuration configuration;
+        Hasher(ModuleDescriptor descriptor, String fname) throws IOException {
+            // Create a module finder that finds the modular JAR
+            // being created/updated
+            URI uri = Paths.get(fname).toUri();
+            ModuleReference mref = new ModuleReference(descriptor, uri,
+                new Supplier<>() {
+                    @Override
+                    public ModuleReader get() {
+                        throw new UnsupportedOperationException("should not reach here");
+                    }
+                });
+
+            // Compose a module finder with the module path and
+            // the modular JAR being created or updated
+            this.finder = ModuleFinder.compose(moduleFinder,
+                new ModuleFinder() {
+                    @Override
+                    public Optional<ModuleReference> find(String name) {
+                        if (descriptor.name().equals(name))
+                            return Optional.of(mref);
+                        else
+                            return Optional.empty();
+                    }
+
+                    @Override
+                    public Set<ModuleReference> findAll() {
+                        return Collections.singleton(mref);
+                    }
+                });
+
+            // Determine the modules that matches the modulesToHash pattern
+            this.modules = moduleFinder.findAll().stream()
+                .map(moduleReference -> moduleReference.descriptor().name())
+                .filter(mn -> modulesToHash.matcher(mn).find())
+                .collect(Collectors.toSet());
+
+            // a map from a module name to Path of the modular JAR
+            this.moduleNameToPath = moduleFinder.findAll().stream()
+                .map(ModuleReference::descriptor)
+                .map(ModuleDescriptor::name)
+                .collect(Collectors.toMap(Function.identity(), mn -> moduleToPath(mn)));
+
+            Configuration config = null;
+            try {
+                config = Configuration.empty()
+                    .resolveRequires(ModuleFinder.ofSystem(), finder, modules);
+            } catch (ResolutionException e) {
+                // should it throw an error?  or emit a warning
+                System.out.println("warning: " + e.getMessage());
             }
+            this.configuration = config;
         }
 
-        if (map.size() == 0) {
-            return null;
-        } else {
-            return Hasher.generate(map, "SHA-256");
+        /**
+         * Compute hashes of the modules that depend upon the specified
+         * module directly or indirectly.
+         */
+        ModuleHashes computeHashes(String name) {
+            // the transposed graph includes all modules in the resolved graph
+            Map<String, Set<String>> graph = transpose();
+
+            // find the modules that transitively depend upon the specified name
+            Deque<String> deque = new ArrayDeque<>();
+            deque.add(name);
+            Set<String> mods = visitNodes(graph, deque);
+
+            // filter modules matching the pattern specified --hash-modules
+            // as well as itself as the jmod file is being generated
+            Map<String, Path> modulesForHash = mods.stream()
+                .filter(mn -> !mn.equals(name) && modules.contains(mn))
+                .collect(Collectors.toMap(Function.identity(), moduleNameToPath::get));
+
+            if (modulesForHash.isEmpty())
+                return null;
+
+            return ModuleHashes.generate(modulesForHash, "SHA-256");
+        }
+
+        /**
+         * Returns all nodes traversed from the given roots.
+         */
+        private Set<String> visitNodes(Map<String, Set<String>> graph,
+                                       Deque<String> roots) {
+            Set<String> visited = new HashSet<>();
+            while (!roots.isEmpty()) {
+                String mn = roots.pop();
+                if (!visited.contains(mn)) {
+                    visited.add(mn);
+
+                    // the given roots may not be part of the graph
+                    if (graph.containsKey(mn)) {
+                        for (String dm : graph.get(mn)) {
+                            if (!visited.contains(dm))
+                                roots.push(dm);
+                        }
+                    }
+                }
+            }
+            return visited;
+        }
+
+        /**
+         * Returns a transposed graph from the resolved module graph.
+         */
+        private Map<String, Set<String>> transpose() {
+            Map<String, Set<String>> transposedGraph = new HashMap<>();
+            Deque<String> deque = new ArrayDeque<>(modules);
+
+            Set<String> visited = new HashSet<>();
+            while (!deque.isEmpty()) {
+                String mn = deque.pop();
+                if (!visited.contains(mn)) {
+                    visited.add(mn);
+
+                    // add an empty set
+                    transposedGraph.computeIfAbsent(mn, _k -> new HashSet<>());
+
+                    ResolvedModule resolvedModule = configuration.findModule(mn).get();
+                    for (ResolvedModule dm : resolvedModule.reads()) {
+                        String name = dm.name();
+                        if (!visited.contains(name)) {
+                            deque.push(name);
+                        }
+                        // reverse edge
+                        transposedGraph.computeIfAbsent(name, _k -> new HashSet<>())
+                                       .add(mn);
+                    }
+                }
+            }
+            return transposedGraph;
+        }
+
+        private Path moduleToPath(String name) {
+            ModuleReference mref = moduleFinder.find(name).orElseThrow(
+                () -> new InternalError(formatMsg2("error.hash.dep",name , name)));
+
+            URI uri = mref.location().get();
+            Path path = Paths.get(uri);
+            String fn = path.getFileName().toString();
+            if (!fn.endsWith(".jar")) {
+                throw new UnsupportedOperationException(path + " is not a modular JAR");
+            }
+            return path;
         }
     }
-
-    private static Path modRefToPath(ModuleReference mref) {
-        URI location = mref.location().get();
-        return Paths.get(location);
-    }
 }
--- a/jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar.properties	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/jdk.jartool/share/classes/sun/tools/jar/resources/jar.properties	Tue May 03 12:25:20 2016 -0700
@@ -57,7 +57,7 @@
 error.hash.dep=\
         Hashing module {0} dependences, unable to find module {1} on module path
 error.module.options.without.info=\
-        One of --module-version or --hash-dependencies without module-info.class
+        One of --module-version or --hash-modules without module-info.class
 error.unexpected.module-info=\
         Unexpected module descriptor {0}
 error.module.descriptor.not.found=\
@@ -178,11 +178,11 @@
 main.help.opt.create.update.module-version=\
 \      --module-version=VERSION    The module version, when creating a modular\n\
 \                             jar, or updating a non-modular jar
-main.help.opt.create.update.hash-dependencies=\
-\      --hash-dependencies=PATTERN  Compute and record the hashes of module\n\
-\                             dependencies matched by the given pattern, when\n\
-\                             creating a modular jar, or updating a non-modular\n\
-\                             jar
+main.help.opt.create.update.hash-modules=\
+\      --hash-modules=PATTERN Compute and record the hashes of modules \n\
+\                             matched by the given pattern and that depend upon\n\
+\                             directly or indirectly on a modular jar being\n\
+\                             created or a non-modular jar being updated
 main.help.opt.create.update.modulepath=\
 \      --modulepath           Location of module dependence for generating
 \                             the hash
@@ -201,7 +201,7 @@
 \ located in the root of the given directories, or the root of the jar archive\n\
 \ itself. The following operations are only valid when creating a modular jar,\n\
 \ or updating an existing non-modular jar: '--module-version',\n\
-\ '--hash-dependencies', and '--modulepath'.\n\
+\ '--hash-modules', and '--modulepath'.\n\
 \n\
 \ Mandatory or optional arguments to long options are also mandatory or optional\n\
 \ for any corresponding short options.
\ No newline at end of file
--- a/jdk/src/jdk.jdi/share/classes/com/sun/tools/jdi/ProcessAttachingConnector.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/jdk.jdi/share/classes/com/sun/tools/jdi/ProcessAttachingConnector.java	Tue May 03 12:25:20 2016 -0700
@@ -128,7 +128,9 @@
             if (lib.equals("dt_shmem")) {
                 try {
                     Class<?> c = Class.forName("com.sun.tools.jdi.SharedMemoryTransportService");
-                    ts = (TransportService)c.newInstance();
+                    @SuppressWarnings("deprecation")
+                    Object tmp = c.newInstance();
+                    ts = (TransportService)tmp;
                 } catch (Exception x) { }
             }
         }
--- a/jdk/src/jdk.jdi/share/classes/com/sun/tools/jdi/RawCommandLineLauncher.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/jdk.jdi/share/classes/com/sun/tools/jdi/RawCommandLineLauncher.java	Tue May 03 12:25:20 2016 -0700
@@ -53,17 +53,19 @@
         super();
 
         try {
-            Class<?> c = Class.forName("com.sun.tools.jdi.SharedMemoryTransportService");
-            transportService = (TransportService)c.newInstance();
+            @SuppressWarnings("deprecation")
+            Object o =
+                Class.forName("com.sun.tools.jdi.SharedMemoryTransportService").newInstance();
+            transportService = (TransportService)o;
             transport = new Transport() {
                 public String name() {
                     return "dt_shmem";
                 }
             };
-        } catch (ClassNotFoundException x) {
-        } catch (UnsatisfiedLinkError x) {
-        } catch (InstantiationException x) {
-        } catch (IllegalAccessException x) {
+        } catch (ClassNotFoundException |
+                 UnsatisfiedLinkError |
+                 InstantiationException |
+                 IllegalAccessException x) {
         };
 
         if (transportService == null) {
--- a/jdk/src/jdk.jdi/share/classes/com/sun/tools/jdi/SunCommandLineLauncher.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/jdk.jdi/share/classes/com/sun/tools/jdi/SunCommandLineLauncher.java	Tue May 03 12:25:20 2016 -0700
@@ -64,18 +64,20 @@
          * transport or the socket transport
          */
         try {
-            Class<?> c = Class.forName("com.sun.tools.jdi.SharedMemoryTransportService");
-            transportService = (TransportService)c.newInstance();
+            @SuppressWarnings("deprecation")
+            Object o =
+                Class.forName("com.sun.tools.jdi.SharedMemoryTransportService").newInstance();
+            transportService = (TransportService)o;
             transport = new Transport() {
                 public String name() {
                     return "dt_shmem";
                 }
             };
             usingSharedMemory = true;
-        } catch (ClassNotFoundException x) {
-        } catch (UnsatisfiedLinkError x) {
-        } catch (InstantiationException x) {
-        } catch (IllegalAccessException x) {
+        } catch (ClassNotFoundException |
+                 UnsatisfiedLinkError |
+                 InstantiationException |
+                 IllegalAccessException x) {
         };
         if (transportService == null) {
             transportService = new SocketTransportService();
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/builder/DefaultImageBuilder.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/builder/DefaultImageBuilder.java	Tue May 03 12:25:20 2016 -0700
@@ -95,27 +95,23 @@
 
     private final Path root;
     private final Path mdir;
-    private final boolean genBom;
     private final Set<String> modules = new HashSet<>();
 
     /**
      * Default image builder constructor.
      *
-     * @param genBom true, generates a bom file.
      * @param root The image root directory.
      * @throws IOException
      */
-    public DefaultImageBuilder(boolean genBom, Path root) throws IOException {
+    public DefaultImageBuilder(Path root) throws IOException {
         Objects.requireNonNull(root);
 
-        this.genBom = genBom;
-
         this.root = root;
         this.mdir = root.resolve("lib");
         Files.createDirectories(mdir);
     }
 
-    private void storeFiles(Set<String> modules, String bom, Properties release) throws IOException {
+    private void storeFiles(Set<String> modules, Properties release) throws IOException {
         if (release != null) {
             addModules(release, modules);
             File r = new File(root.toFile(), "release");
@@ -123,11 +119,6 @@
                 release.store(fo, null);
             }
         }
-        // Generate bom
-        if (genBom) {
-            File bomFile = new File(root.toFile(), "bom");
-            createUtf8File(bomFile, bom);
-        }
     }
 
     private void addModules(Properties release, Set<String> modules) throws IOException {
@@ -144,7 +135,7 @@
     }
 
     @Override
-    public void storeFiles(Pool files, String bom, Properties release) {
+    public void storeFiles(Pool files, Properties release) {
         try {
             for (ModuleData f : files.getContent()) {
                if (!f.getType().equals(Pool.ModuleDataType.CLASS_OR_RESOURCE)) {
@@ -161,7 +152,7 @@
                     modules.add(m.getName());
                 }
             }
-            storeFiles(modules, bom, release);
+            storeFiles(modules, release);
 
             if (Files.getFileStore(root).supportsFileAttributeView(PosixFileAttributeView.class)) {
                 // launchers in the bin directory need execute permission
@@ -190,8 +181,8 @@
     }
 
     @Override
-    public void storeFiles(Pool files, String bom) {
-        storeFiles(files, bom, new Properties());
+    public void storeFiles(Pool files) {
+        storeFiles(files, new Properties());
     }
 
     /**
@@ -213,28 +204,48 @@
             mainClass = ModuleDescriptor.read(stream).mainClass();
             if (mainClass.isPresent()) {
                 Path cmd = root.resolve("bin").resolve(module);
-                if (!Files.exists(cmd)) {
-                    StringBuilder sb = new StringBuilder();
-                    sb.append("#!/bin/sh")
-                            .append("\n");
-                    sb.append("JLINK_VM_OPTIONS=")
-                            .append("\n");
-                    sb.append("DIR=`dirname $0`")
-                            .append("\n");
-                    sb.append("$DIR/java $JLINK_VM_OPTIONS -m ")
+                // generate shell script for Unix platforms
+                StringBuilder sb = new StringBuilder();
+                sb.append("#!/bin/sh")
+                        .append("\n");
+                sb.append("JLINK_VM_OPTIONS=")
+                        .append("\n");
+                sb.append("DIR=`dirname $0`")
+                        .append("\n");
+                sb.append("$DIR/java $JLINK_VM_OPTIONS -m ")
+                        .append(module).append('/')
+                        .append(mainClass.get())
+                        .append(" $@\n");
+
+                try (BufferedWriter writer = Files.newBufferedWriter(cmd,
+                        StandardCharsets.ISO_8859_1,
+                        StandardOpenOption.CREATE_NEW)) {
+                    writer.write(sb.toString());
+                }
+                if (Files.getFileStore(root.resolve("bin"))
+                        .supportsFileAttributeView(PosixFileAttributeView.class)) {
+                    setExecutable(cmd);
+                }
+                // generate .bat file for Windows
+                if (isWindows()) {
+                    Path bat = root.resolve("bin").resolve(module + ".bat");
+                    sb = new StringBuilder();
+                    sb.append("@echo off")
+                            .append("\r\n");
+                    sb.append("set JLINK_VM_OPTIONS=")
+                            .append("\r\n");
+                    sb.append("set DIR=%~dp0")
+                            .append("\r\n");
+                    sb.append("\"%DIR%\\java\" %JLINK_VM_OPTIONS% -m ")
                             .append(module).append('/')
                             .append(mainClass.get())
-                            .append(" $@\n");
+                            .append(" %*\r\n");
 
-                    try (BufferedWriter writer = Files.newBufferedWriter(cmd,
+                    try (BufferedWriter writer = Files.newBufferedWriter(bat,
                             StandardCharsets.ISO_8859_1,
                             StandardOpenOption.CREATE_NEW)) {
                         writer.write(sb.toString());
                     }
-                    if (Files.getFileStore(root.resolve("bin"))
-                            .supportsFileAttributeView(PosixFileAttributeView.class)) {
-                        setExecutable(cmd);
-                    }
                 }
             }
         }
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/builder/ImageBuilder.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/builder/ImageBuilder.java	Tue May 03 12:25:20 2016 -0700
@@ -42,22 +42,20 @@
      * Store the external files.
      *
      * @param content Pool of module content.
-     * @param bom The options used to build the image file.
      * @param release the release properties
      * @throws PluginException
      */
-    public default void storeFiles(Pool content, String bom, Properties release) {
-        storeFiles(content, bom);
+    public default void storeFiles(Pool content, Properties release) {
+        storeFiles(content);
     }
 
     /**
      * Store the external files.
      *
      * @param content Pool of module content.
-     * @param bom The options used to build the image file.
      * @throws PluginException
      */
-    public default void storeFiles(Pool content, String bom) {
+    public default void storeFiles(Pool content) {
         throw new UnsupportedOperationException("storeFiles");
     }
 
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ImageFileCreator.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ImageFileCreator.java	Tue May 03 12:25:20 2016 -0700
@@ -88,7 +88,7 @@
             ByteOrder byteOrder)
             throws IOException {
         return ImageFileCreator.create(archives, byteOrder,
-                new ImagePluginStack(null));
+                new ImagePluginStack());
     }
 
     public static ExecutableImage create(Set<Archive> archives,
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ImagePluginConfiguration.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ImagePluginConfiguration.java	Tue May 03 12:25:20 2016 -0700
@@ -68,20 +68,13 @@
     private ImagePluginConfiguration() {
     }
 
-    public static ImagePluginStack parseConfiguration(Jlink.PluginsConfiguration plugins)
-            throws Exception {
-        return parseConfiguration(plugins, null);
-    }
-
     /*
      * Create a stack of plugins from a a configuration.
-     *
      */
-    public static ImagePluginStack parseConfiguration(Jlink.PluginsConfiguration pluginsConfiguration,
-            String bom)
+    public static ImagePluginStack parseConfiguration(Jlink.PluginsConfiguration pluginsConfiguration)
             throws Exception {
         if (pluginsConfiguration == null) {
-            return new ImagePluginStack(bom);
+            return new ImagePluginStack();
         }
         Map<Plugin.CATEGORY, List<Plugin>> plugins = new LinkedHashMap<>();
         for (Plugin.CATEGORY cat : CATEGORIES_ORDER) {
@@ -150,7 +143,7 @@
                 }
 
                 @Override
-                public void storeFiles(Pool files, String bom) {
+                public void storeFiles(Pool files) {
                     throw new PluginException("No directory setup to store files");
                 }
             };
@@ -158,6 +151,6 @@
 
         PluginContext ctxt = pluginsConfiguration.getPluginContext();
         return new ImagePluginStack(builder, transformerPlugins,
-                lastSorter, postProcessingPlugins, ctxt, bom);
+                lastSorter, postProcessingPlugins, ctxt);
     }
 }
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ImagePluginStack.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/ImagePluginStack.java	Tue May 03 12:25:20 2016 -0700
@@ -167,28 +167,25 @@
 
     private final ImageBuilder imageBuilder;
     private final Properties release;
-    private final String bom;
+
+    public ImagePluginStack() {
+        this(null, Collections.emptyList(), null,
+                Collections.emptyList(), null);
+    }
 
-    public ImagePluginStack(String bom) {
-        this(null, Collections.emptyList(), null,
-                Collections.emptyList(), null, bom);
+    public ImagePluginStack(ImageBuilder imageBuilder,
+            List<TransformerPlugin> contentPlugins,
+            Plugin lastSorter,
+            List<PostProcessorPlugin> postprocessingPlugins) {
+        this(imageBuilder, contentPlugins, lastSorter,
+            postprocessingPlugins, null);
     }
 
     public ImagePluginStack(ImageBuilder imageBuilder,
             List<TransformerPlugin> contentPlugins,
             Plugin lastSorter,
             List<PostProcessorPlugin> postprocessingPlugins,
-            String bom) {
-        this(imageBuilder, contentPlugins, lastSorter,
-            postprocessingPlugins, null, bom);
-    }
-
-    public ImagePluginStack(ImageBuilder imageBuilder,
-            List<TransformerPlugin> contentPlugins,
-            Plugin lastSorter,
-            List<PostProcessorPlugin> postprocessingPlugins,
-            PluginContext ctxt,
-            String bom) {
+            PluginContext ctxt) {
         Objects.requireNonNull(contentPlugins);
         this.lastSorter = lastSorter;
         for (TransformerPlugin p : contentPlugins) {
@@ -204,7 +201,6 @@
         }
         this.imageBuilder = imageBuilder;
         this.release = ctxt != null? ctxt.getReleaseProperties() : new Properties();
-        this.bom = bom;
     }
 
     public void operate(ImageProvider provider) throws Exception {
@@ -479,7 +475,7 @@
         } catch (Exception ignored) {
         }
 
-        imageBuilder.storeFiles(new LastPool(transformed), bom, release);
+        imageBuilder.storeFiles(new LastPool(transformed), release);
     }
 
     public ExecutableImage getExecutableImage() throws IOException {
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/JlinkTask.java	Tue May 03 12:25:20 2016 -0700
@@ -70,6 +70,7 @@
  * ## Should use jdk.joptsimple some day.
  */
 public class JlinkTask {
+    private static final boolean DEBUG = Boolean.getBoolean("jlink.debug");
 
     private static <T extends Throwable> void fail(Class<T> type,
             String format,
@@ -142,9 +143,6 @@
             }
             task.options.packagedModulesPath = path;
         }, true, "--keep-packaged-modules"),
-        new Option<JlinkTask>(false, (task, opt, arg) -> {
-            task.options.genbom = true;
-        }, true, "--genbom"),
         new Option<JlinkTask>(true, (task, opt, arg) -> {
             task.options.saveoptsfile = arg;
         }, "--saveopts"),
@@ -175,7 +173,6 @@
 
     static class OptionsValues {
         boolean help;
-        boolean genbom;
         String  saveoptsfile;
         boolean version;
         boolean fullVersion;
@@ -219,18 +216,24 @@
             }
 
             return EXIT_OK;
-        } catch (UncheckedIOException | PluginException | IOException | ResolutionException e) {
+        } catch (UncheckedIOException | PluginException | IllegalArgumentException |
+                 IOException | ResolutionException e) {
             log.println(taskHelper.getMessage("error.prefix") + " " + e.getMessage());
-            log.println(taskHelper.getMessage("main.usage.summary", PROGNAME));
+            if (DEBUG) {
+                e.printStackTrace(log);
+            }
             return EXIT_ERROR;
         } catch (BadArgs e) {
             taskHelper.reportError(e.key, e.args);
             if (e.showUsage) {
                 log.println(taskHelper.getMessage("main.usage.summary", PROGNAME));
             }
+            if (DEBUG) {
+                e.printStackTrace(log);
+            }
             return EXIT_CMDERR;
         } catch (Throwable x) {
-            log.println(taskHelper.getMessage("main.msg.bug"));
+            log.println(taskHelper.getMessage("error.prefix") + " " + x.getMessage());
             x.printStackTrace(log);
             return EXIT_ABNORMAL;
         } finally {
@@ -238,16 +241,6 @@
         }
     }
 
-    private static Map<String, Path> modulesToPath(Configuration cf) {
-        Map<String, Path> modPaths = new HashMap<>();
-        for (ResolvedModule resolvedModule : cf.modules()) {
-            ModuleReference mref = resolvedModule.reference();
-            URI uri = mref.location().get();
-            modPaths.put(mref.descriptor().name(), Paths.get(uri));
-        }
-        return modPaths;
-    }
-
     /*
      * Jlink API entry point.
      */
@@ -275,8 +268,7 @@
                                       null);
 
         // Then create the Plugin Stack
-        ImagePluginStack stack = ImagePluginConfiguration.parseConfiguration(plugins,
-                genBOMContent(config, plugins));
+        ImagePluginStack stack = ImagePluginConfiguration.parseConfiguration(plugins);
 
         //Ask the stack to proceed;
         stack.operate(imageProvider);
@@ -297,7 +289,7 @@
     }
 
     private void postProcessOnly(Path existingImage) throws Exception {
-        PluginsConfiguration config = taskHelper.getPluginsConfig(null, false);
+        PluginsConfiguration config = taskHelper.getPluginsConfig(null);
         ExecutableImage img = DefaultImageBuilder.getExecutableImage(existingImage);
         if (img == null) {
             throw taskHelper.newBadArgs("err.existing.image.invalid");
@@ -327,8 +319,7 @@
 
         // Then create the Plugin Stack
         ImagePluginStack stack = ImagePluginConfiguration.
-                parseConfiguration(taskHelper.getPluginsConfig(options.output, options.genbom),
-                        genBOMContent());
+                parseConfiguration(taskHelper.getPluginsConfig(options.output));
 
         //Ask the stack to proceed
         stack.operate(imageProvider);
@@ -358,6 +349,15 @@
         return finder;
     }
 
+
+    private static Path toPathLocation(ResolvedModule m) {
+        Optional<URI> ouri = m.reference().location();
+        if (!ouri.isPresent())
+            throw new InternalError(m + " does not have a location");
+        URI uri = ouri.get();
+        return Paths.get(uri);
+    }
+
     private static ImageProvider createImageProvider(ModuleFinder finder,
                                                      Set<String> addMods,
                                                      Set<String> limitMods,
@@ -374,7 +374,8 @@
                                  ModuleFinder.empty(),
                                  addMods);
 
-        Map<String, Path> mods = modulesToPath(cf);
+        Map<String, Path> mods = cf.modules().stream()
+            .collect(Collectors.toMap(ResolvedModule::name, JlinkTask::toPathLocation));
         return new ImageHelper(cf, mods, order, retainModulesPath);
     }
 
@@ -399,21 +400,15 @@
             map.put(mref.descriptor().name(), mref);
         });
 
+        // add the other modules
+        otherMods.stream()
+            .map(finder::find)
+            .flatMap(Optional::stream)
+            .forEach(mref -> map.putIfAbsent(mref.descriptor().name(), mref));
+
         // set of modules that are observable
         Set<ModuleReference> mrefs = new HashSet<>(map.values());
 
-        // add the other modules
-        for (String mod : otherMods) {
-            Optional<ModuleReference> omref = finder.find(mod);
-            if (omref.isPresent()) {
-                ModuleReference mref = omref.get();
-                map.putIfAbsent(mod, mref);
-                mrefs.add(mref);
-            } else {
-                // no need to fail
-            }
-        }
-
         return new ModuleFinder() {
             @Override
             public Optional<ModuleReference> find(String name) {
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/TaskHelper.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/TaskHelper.java	Tue May 03 12:25:20 2016 -0700
@@ -337,8 +337,8 @@
             return null;
         }
 
-        private PluginsConfiguration getPluginsConfig(Path output,
-                boolean genbom) throws IOException, BadArgs {
+        private PluginsConfiguration getPluginsConfig(Path output
+                    ) throws IOException, BadArgs {
             if (output != null) {
                 if (Files.exists(output)) {
                     throw new PluginException(PluginsResourceBundle.
@@ -367,7 +367,7 @@
             // recreate or postprocessing don't require an output directory.
             ImageBuilder builder = null;
             if (output != null) {
-                builder = new DefaultImageBuilder(genbom, output);
+                builder = new DefaultImageBuilder(output);
 
             }
             return new Jlink.PluginsConfiguration(pluginsList,
@@ -676,9 +676,9 @@
                 + bundleHelper.getMessage(key, args));
     }
 
-    public PluginsConfiguration getPluginsConfig(Path output, boolean genbom)
+    public PluginsConfiguration getPluginsConfig(Path output)
             throws IOException, BadArgs {
-        return pluginOptions.getPluginsConfig(output, genbom);
+        return pluginOptions.getPluginsConfig(output);
     }
 
     public Path getExistingImage() {
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/packager/AppRuntimeImageBuilder.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/packager/AppRuntimeImageBuilder.java	Tue May 03 12:25:20 2016 -0700
@@ -139,7 +139,7 @@
 
         // build the image
         Jlink.PluginsConfiguration pluginConfig = new Jlink.PluginsConfiguration(
-            plugins, new DefaultImageBuilder(true, outputDir), null);
+            plugins, new DefaultImageBuilder(outputDir), null);
         Jlink jlink = new Jlink();
         jlink.build(jlinkConfig, pluginConfig);
     }
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/DefaultCompressPlugin.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/DefaultCompressPlugin.java	Tue May 03 12:25:20 2016 -0700
@@ -125,7 +125,7 @@
                         zip = new ZipPlugin(resFilter);
                         break;
                     default:
-                        throw new PluginException("Invalid level " + level);
+                        throw new IllegalArgumentException("Invalid compression level " + level);
                 }
             } else {
                 ss = new StringSharingPlugin(resFilter);
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/ExcludeVMPlugin.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/ExcludeVMPlugin.java	Tue May 03 12:25:20 2016 -0700
@@ -208,7 +208,7 @@
                     break;
                 }
                 default: {
-                    throw new PluginException("Unknown option " + value);
+                    throw new IllegalArgumentException("Unknown exclude VM option: " + value);
                 }
             }
             predicate = new ResourceFilter(Utils.listParser.apply(exclude), true);
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/IncludeLocalesPlugin.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/IncludeLocalesPlugin.java	Tue May 03 12:25:20 2016 -0700
@@ -164,7 +164,7 @@
                 try {
                     return new Locale.LanguageRange(s);
                 } catch (IllegalArgumentException iae) {
-                    throw new PluginException(String.format(
+                    throw new IllegalArgumentException(String.format(
                         PluginsResourceBundle.getMessage(NAME + ".invalidtag"), s));
                 }
             })
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/OptimizationPlugin.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/OptimizationPlugin.java	Tue May 03 12:25:20 2016 -0700
@@ -273,7 +273,7 @@
             } else if (s.equals(FORNAME_REMOVAL)) {
                 optimizers.add(new ForNameFolding());
             } else {
-                throw new PluginException("Unknown optimization");
+                throw new IllegalArgumentException("Unknown optimization: " + s);
             }
         }
         String f = config.get(LOG);
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/SystemModuleDescriptorPlugin.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/SystemModuleDescriptorPlugin.java	Tue May 03 12:25:20 2016 -0700
@@ -39,6 +39,8 @@
 import java.util.Set;
 import java.util.stream.Collectors;
 
+import jdk.internal.misc.JavaLangModuleAccess;
+import jdk.internal.misc.SharedSecrets;
 import jdk.internal.module.Checks;
 import jdk.internal.module.ModuleInfoExtender;
 import jdk.internal.module.SystemModules;
@@ -50,6 +52,7 @@
 import jdk.tools.jlink.plugin.PluginException;
 import jdk.tools.jlink.plugin.Pool;
 import jdk.tools.jlink.plugin.TransformerPlugin;
+import jdk.tools.jlink.internal.plugins.SystemModuleDescriptorPlugin.Builder.*;
 
 /**
  * Jlink plugin to reconstitute module descriptors for installed modules.
@@ -63,6 +66,8 @@
  * @see SystemModules
  */
 public final class SystemModuleDescriptorPlugin implements TransformerPlugin {
+    private static final JavaLangModuleAccess JLMA = SharedSecrets.getJavaLangModuleAccess();
+
     // TODO: packager has the dependency on the plugin name
     // Keep it as "--installed-modules" until packager removes such
     // dependency (should not need to specify this plugin since it
@@ -118,7 +123,8 @@
             Pool.ModuleData data = module.get("module-info.class");
             if (data == null) {
                 // automatic module not supported yet
-                throw new PluginException("module-info.class not found for " + module.getName() + " module");
+                throw new PluginException("module-info.class not found for " +
+                                          module.getName() + " module");
             }
             assert module.getName().equals(data.getModule());
             try {
@@ -126,15 +132,20 @@
                 ModuleDescriptor md = ModuleDescriptor.read(bain);
                 validateNames(md);
 
-                Builder.ModuleDescriptorBuilder mbuilder = builder.module(md, module.getAllPackages());
+                ModuleDescriptorBuilder mbuilder = builder.module(md, module.getAllPackages());
+                int packages = md.exports().size() + md.conceals().size();
                 if (md.conceals().isEmpty() &&
-                        (md.exports().size() + md.conceals().size()) != module.getAllPackages().size()) {
+                        packages != module.getAllPackages().size()) {
                     // add ConcealedPackages attribute if not exist
                     bain.reset();
-                    ModuleInfoRewriter minfoWriter = new ModuleInfoRewriter(bain, mbuilder.conceals());
+                    ModuleInfoRewriter minfoWriter =
+                        new ModuleInfoRewriter(bain, mbuilder.conceals());
                     // replace with the overridden version
-                    data = new Pool.ModuleData(data.getModule(), data.getPath(), data.getType(),
-                                               minfoWriter.stream(), minfoWriter.size());
+                    data = new Pool.ModuleData(data.getModule(),
+                                               data.getPath(),
+                                               data.getType(),
+                                               minfoWriter.stream(),
+                                               minfoWriter.size());
                 }
                 out.add(data);
             } catch (IOException e) {
@@ -151,8 +162,12 @@
 
             if (builder.isOverriddenClass(data.getPath())) {
                 byte[] bytes = cwriter.toByteArray();
-                Pool.ModuleData ndata = new Pool.ModuleData(data.getModule(), data.getPath(), data.getType(),
-                                                            new ByteArrayInputStream(bytes), bytes.length);
+                Pool.ModuleData ndata =
+                    new Pool.ModuleData(data.getModule(),
+                                        data.getPath(),
+                                        data.getType(),
+                                        new ByteArrayInputStream(bytes),
+                                        bytes.length);
                 out.add(ndata);
             } else {
                 out.add(data);
@@ -230,6 +245,7 @@
 
         // static variables in SystemModules class
         private static final String MODULE_NAMES = "MODULE_NAMES";
+        private static final String MODULES_TO_HASH = "MODULES_TO_HASH";
         private static final String PACKAGE_COUNT = "PACKAGES_IN_BOOT_LAYER";
 
         private static final int BUILDER_VAR    = 0;
@@ -246,6 +262,9 @@
         // list of all ModuleDescriptorBuilders, invoked in turn when building.
         private final List<ModuleDescriptorBuilder> builders = new ArrayList<>();
 
+        // module name to hash
+        private final Map<String, String> modulesToHash = new HashMap<>();
+
         // map Set<String> to a specialized builder to allow them to be
         // deduplicated as they are requested
         private final Map<Set<String>, StringSetBuilder> stringSets = new HashMap<>();
@@ -268,6 +287,11 @@
                     "[Ljava/lang/String;", null, null)
                     .visitEnd();
 
+            // public static String[] MODULES_TO_HASH = new String[] {....};
+            cw.visitField(ACC_PUBLIC+ACC_FINAL+ACC_STATIC, MODULES_TO_HASH,
+                "[Ljava/lang/String;", null, null)
+                .visitEnd();
+
             // public static int PACKAGES_IN_BOOT_LAYER;
             cw.visitField(ACC_PUBLIC+ACC_FINAL+ACC_STATIC, PACKAGE_COUNT,
                     "I", null, numPackages)
@@ -283,15 +307,35 @@
 
             int index = 0;
             for (ModuleDescriptorBuilder builder : builders) {
-                mv.visitInsn(DUP);       // arrayref
+                mv.visitInsn(DUP);                  // arrayref
                 pushInt(index++);
-                mv.visitLdcInsn(builder.md.name());      // value
+                mv.visitLdcInsn(builder.md.name()); // value
                 mv.visitInsn(AASTORE);
             }
 
             mv.visitFieldInsn(PUTSTATIC, CLASSNAME, MODULE_NAMES,
                     "[Ljava/lang/String;");
 
+            // create the MODULES_TO_HASH array
+            pushInt(numModules);
+            mv.visitTypeInsn(ANEWARRAY, "java/lang/String");
+
+            index = 0;
+            for (ModuleDescriptorBuilder builder : builders) {
+                String mn = builder.md.name();
+                String recordedHash = modulesToHash.get(mn);
+                if (recordedHash != null) {
+                    mv.visitInsn(DUP);              // arrayref
+                    pushInt(index);
+                    mv.visitLdcInsn(recordedHash);  // value
+                    mv.visitInsn(AASTORE);
+                }
+                index++;
+            }
+
+            mv.visitFieldInsn(PUTSTATIC, CLASSNAME, MODULES_TO_HASH,
+                    "[Ljava/lang/String;");
+
             mv.visitInsn(RETURN);
             mv.visitMaxs(0, 0);
             mv.visitEnd();
@@ -315,15 +359,19 @@
                 }
             }
 
-            // provides
+            // provides (preserve iteration order)
             for (ModuleDescriptor.Provides p : md.provides().values()) {
-                stringSets.computeIfAbsent(p.providers(), s -> new StringSetBuilder(s))
+                stringSets.computeIfAbsent(p.providers(), s -> new StringSetBuilder(s, true))
                           .increment();
             }
 
             // uses
             stringSets.computeIfAbsent(md.uses(), s -> new StringSetBuilder(s))
                       .increment();
+
+            // hashes
+            JLMA.hashes(md).ifPresent(mh -> modulesToHash.putAll(mh.hashes()));
+
             return builder;
         }
 
@@ -484,13 +532,17 @@
                     conceals(pn);
                 }
 
-                if (md.version().isPresent()) {
-                    version(md.version().get());
-                }
+                // version
+                md.version().ifPresent(this::version);
+
+                // main class
+                md.mainClass().ifPresent(this::mainClass);
 
-                if (md.mainClass().isPresent()) {
-                    mainClass(md.mainClass().get());
-                }
+                // hashes
+                JLMA.hashes(md).ifPresent(mh -> {
+                    algorithm(mh.algorithm());
+                    mh.names().forEach(mn -> moduleHash(mn, mh.hashFor(mn)));
+                });
 
                 putModuleDescriptor();
             }
@@ -603,7 +655,7 @@
             /*
              * Invoke Builder.provides(String service, Set<String> providers)
              *
-             * Set<String> providers = new HashSet<>();
+             * Set<String> providers = new LinkedHashSet<>();
              * providers.add(impl);
              * :
              * :
@@ -652,6 +704,22 @@
                 mv.visitInsn(POP);
             }
 
+            void algorithm(String alg) {
+                mv.visitVarInsn(ALOAD, BUILDER_VAR);
+                mv.visitLdcInsn(alg);
+                mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
+                    "algorithm", STRING_SIG, false);
+                mv.visitInsn(POP);
+            }
+
+            void moduleHash(String name, String hashString) {
+                mv.visitVarInsn(ALOAD, BUILDER_VAR);
+                mv.visitLdcInsn(name);
+                mv.visitLdcInsn(hashString);
+                mv.visitMethodInsn(INVOKEVIRTUAL, MODULE_DESCRIPTOR_BUILDER,
+                    "moduleHash", STRING_STRING_SIG, false);
+                mv.visitInsn(POP);
+            }
         }
 
         /*
@@ -663,10 +731,17 @@
          */
         class StringSetBuilder {
             final Set<String> names;
+            final boolean linked;
             int refCount;
             int localVarIndex;
+
+            StringSetBuilder(Set<String> names, boolean linked) {
+                this.names = names;
+                this.linked = linked;
+            }
+
             StringSetBuilder(Set<String> names) {
-                this.names = names;
+                this(names, false);
             }
 
             void increment() {
@@ -704,11 +779,11 @@
                                 "singleton", "(Ljava/lang/Object;)Ljava/util/Set;", false);
                         mv.visitVarInsn(ASTORE, index);
                     } else {
-                        mv.visitTypeInsn(NEW, "java/util/HashSet");
+                        String cn = linked ? "java/util/LinkedHashSet" : "java/util/HashSet";
+                        mv.visitTypeInsn(NEW, cn);
                         mv.visitInsn(DUP);
                         pushInt(initialCapacity(names.size()));
-                        mv.visitMethodInsn(INVOKESPECIAL, "java/util/HashSet",
-                                "<init>", "(I)V", false);
+                        mv.visitMethodInsn(INVOKESPECIAL, cn, "<init>", "(I)V", false);
 
                         mv.visitVarInsn(ASTORE, index);
                         for (String t : names) {
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/plugin/Plugin.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/plugin/Plugin.java	Tue May 03 12:25:20 2016 -0700
@@ -201,6 +201,8 @@
      * This method is called prior to invoke the plugin.
      *
      * @param config The plugin configuration.
+     * @throws IllegalArgumentException if a mandatory argument is missing or
+     * if an argument has invalid value.
      */
     public default void configure(Map<String, String> config) {
     }
@@ -211,6 +213,9 @@
      *
      * @param config The plugin configuration.
      * @param ctx The plugin context
+     * @throws IllegalArgumentException if a mandatory argument is missing or
+     * if an argument has invalid value.
+     *
      */
     public default void configure(Map<String, String> config, PluginContext ctx) {
         configure(config);
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/jlink.properties	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jlink/resources/jlink.properties	Tue May 03 12:25:20 2016 -0700
@@ -33,9 +33,6 @@
 main.opt.endian=\
 \  --endian <little|big>             Byte order of generated jimage (default:native)
 
-main.opt.genbom=\
-\  --genbom                          Generate a bom file containing jlink info
-
 main.opt.saveopts=\
 \  --saveopts <filename>             Save jlink options in the given file
 
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jmod/JmodTask.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jmod/JmodTask.java	Tue May 03 12:25:20 2016 -0700
@@ -26,6 +26,7 @@
 package jdk.tools.jmod;
 
 import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.File;
@@ -34,14 +35,17 @@
 import java.io.OutputStream;
 import java.io.PrintStream;
 import java.io.UncheckedIOException;
-import java.lang.module.FindException;
+import java.lang.module.Configuration;
+import java.lang.module.ModuleReader;
 import java.lang.module.ModuleReference;
 import java.lang.module.ModuleFinder;
+import java.lang.module.ModuleDescriptor;
+import java.lang.module.ModuleDescriptor.Exports;
+import java.lang.module.ModuleDescriptor.Provides;
 import java.lang.module.ModuleDescriptor.Requires;
-import java.lang.module.ModuleDescriptor;
 import java.lang.module.ModuleDescriptor.Version;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
+import java.lang.module.ResolutionException;
+import java.lang.module.ResolvedModule;
 import java.net.URI;
 import java.nio.file.FileSystems;
 import java.nio.file.FileVisitResult;
@@ -51,13 +55,16 @@
 import java.nio.file.PathMatcher;
 import java.nio.file.Paths;
 import java.nio.file.SimpleFileVisitor;
+import java.nio.file.StandardCopyOption;
 import java.nio.file.attribute.BasicFileAttributes;
 import java.text.MessageFormat;
+import java.util.ArrayDeque;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
-import java.util.Formatter;
+import java.util.Comparator;
+import java.util.Deque;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
@@ -68,6 +75,7 @@
 import java.util.ResourceBundle;
 import java.util.Set;
 import java.util.function.Consumer;
+import java.util.function.Function;
 import java.util.function.Predicate;
 import java.util.function.Supplier;
 import java.util.jar.JarEntry;
@@ -89,16 +97,14 @@
 import jdk.internal.joptsimple.OptionSet;
 import jdk.internal.joptsimple.OptionSpec;
 import jdk.internal.joptsimple.ValueConverter;
+import jdk.internal.misc.JavaLangModuleAccess;
+import jdk.internal.misc.SharedSecrets;
 import jdk.internal.module.ConfigurableModuleFinder;
 import jdk.internal.module.ConfigurableModuleFinder.Phase;
-import jdk.internal.module.Hasher;
-import jdk.internal.module.Hasher.DependencyHashes;
+import jdk.internal.module.ModuleHashes;
 import jdk.internal.module.ModuleInfoExtender;
 
-import static java.util.function.Function.identity;
 import static java.util.stream.Collectors.joining;
-import static java.util.stream.Collectors.toList;
-import static java.util.stream.Collectors.toMap;
 
 /**
  * Implementation for the jmod tool.
@@ -127,21 +133,6 @@
         }
     }
 
-    static <T extends Throwable> void fail(Class<T> type,
-                                           String format,
-                                           Object... args) throws T {
-        String msg = new Formatter().format(format, args).toString();
-        try {
-            T t = type.getConstructor(String.class).newInstance(msg);
-            throw t;
-        } catch (InstantiationException |
-                 InvocationTargetException |
-                 NoSuchMethodException |
-                 IllegalAccessException e) {
-            throw new InternalError("Unable to create an instance of " + type, e);
-        }
-    }
-
     private static final String PROGNAME = "jmod";
     private static final String MODULE_INFO = "module-info.class";
 
@@ -161,7 +152,8 @@
     enum Mode {
         CREATE,
         LIST,
-        DESCRIBE
+        DESCRIBE,
+        HASH
     };
 
     static class Options {
@@ -179,7 +171,8 @@
         String osName;
         String osArch;
         String osVersion;
-        Pattern dependenciesToHash;
+        Pattern modulesToHash;
+        boolean dryrun;
         List<PathMatcher> excludes;
     }
 
@@ -211,6 +204,9 @@
                 case DESCRIBE:
                     ok = describe();
                     break;
+                case HASH:
+                    ok = hashModules();
+                    break;
                 default:
                     throw new AssertionError("Unknown mode: " + options.mode.name());
             }
@@ -248,26 +244,8 @@
         }
     }
 
-    private Map<String, Path> modulesToPath(Set<ModuleDescriptor> modules) {
-        ModuleFinder finder = options.moduleFinder;
-
-        Map<String,Path> modPaths = new HashMap<>();
-        for (ModuleDescriptor m : modules) {
-            String name = m.name();
-
-            Optional<ModuleReference> omref = finder.find(name);
-            if (!omref.isPresent()) {
-                // this should not happen, module path bug?
-                fail(InternalError.class,
-                     "Selected module %s not on module path",
-                     name);
-            }
-
-            URI uri = omref.get().location().get();
-            modPaths.put(name, Paths.get(uri));
-
-        }
-        return modPaths;
+    private boolean hashModules() {
+        return new Hasher(options.moduleFinder).run();
     }
 
     private boolean describe() throws IOException {
@@ -297,6 +275,8 @@
                   .collect(joining(" "));
     }
 
+    private static final JavaLangModuleAccess JLMA = SharedSecrets.getJavaLangModuleAccess();
+
     private boolean printModuleDescriptor(InputStream in)
         throws IOException
     {
@@ -311,74 +291,45 @@
                     StringBuilder sb = new StringBuilder();
                     sb.append("\n").append(md.toNameAndVersion());
 
-                    List<Requires> requires = md.requires().stream().sorted().collect(toList());
-                    if (!requires.isEmpty()) {
-                        requires.forEach(r -> {
-                                sb.append("\n  requires ");
-                                if (!r.modifiers().isEmpty())
-                                  sb.append(toString(r.modifiers())).append(" ");
-                                sb.append(r.name());
-                            });
-                    }
-
-                    List<String> l = md.uses().stream().sorted().collect(toList());
-                    if (!l.isEmpty()) {
-                        l.forEach(sv -> sb.append("\n  uses ").append(sv));
-                    }
+                    md.requires().stream()
+                        .sorted(Comparator.comparing(Requires::name))
+                        .forEach(r -> {
+                            sb.append("\n  requires ");
+                            if (!r.modifiers().isEmpty())
+                                sb.append(toString(r.modifiers())).append(" ");
+                            sb.append(r.name());
+                        });
 
-                    List<ModuleDescriptor.Exports> exports = sortExports(md.exports());
-                    if (!exports.isEmpty()) {
-                        exports.forEach(ex -> sb.append("\n  exports ").append(ex));
-                    }
+                    md.uses().stream().sorted()
+                        .forEach(s -> sb.append("\n  uses ").append(s));
 
-                    l = md.conceals().stream().sorted().collect(toList());
-                    if (!l.isEmpty()) {
-                        l.forEach(p -> sb.append("\n  conceals ").append(p));
-                    }
+                    md.exports().stream()
+                        .sorted(Comparator.comparing(Exports::source))
+                        .forEach(p -> sb.append("\n  exports ").append(p));
 
-                    Map<String, ModuleDescriptor.Provides> provides = md.provides();
-                    if (!provides.isEmpty()) {
-                        provides.values().forEach(p ->
-                                sb.append("\n  provides ").append(p.service())
-                                  .append(" with ")
-                                  .append(toString(p.providers())));
-                    }
+                    md.conceals().stream().sorted()
+                        .forEach(p -> sb.append("\n  conceals ").append(p));
 
-                    Optional<String> mc = md.mainClass();
-                    if (mc.isPresent())
-                        sb.append("\n  main-class " + mc.get());
-
-
+                    md.provides().values().stream()
+                        .sorted(Comparator.comparing(Provides::service))
+                        .forEach(p -> sb.append("\n  provides ").append(p.service())
+                                        .append(" with ")
+                                        .append(toString(p.providers())));
 
-                    Optional<String> osname = md.osName();
-                    if (osname.isPresent())
-                        sb.append("\n  operating-system-name " + osname.get());
+                    md.mainClass().ifPresent(v -> sb.append("\n  main-class " + v));
 
-                    Optional<String> osarch = md.osArch();
-                    if (osarch.isPresent())
-                        sb.append("\n  operating-system-architecture " + osarch.get());
-
-                    Optional<String> osversion = md.osVersion();
-                    if (osversion.isPresent())
-                        sb.append("\n  operating-system-version " + osversion.get());
+                    md.osName().ifPresent(v -> sb.append("\n  operating-system-name " + v));
 
-                    try {
-                        Method m = ModuleDescriptor.class.getDeclaredMethod("hashes");
-                        m.setAccessible(true);
-                        @SuppressWarnings("unchecked")
-                        Optional<Hasher.DependencyHashes> optHashes =
-                                (Optional<Hasher.DependencyHashes>) m.invoke(md);
+                    md.osArch().ifPresent(v -> sb.append("\n  operating-system-architecture " + v));
+
+                    md.osVersion().ifPresent(v -> sb.append("\n  operating-system-version " + v));
 
-                        if (optHashes.isPresent()) {
-                            Hasher.DependencyHashes hashes = optHashes.get();
-                            hashes.names().stream().forEach(mod ->
-                                    sb.append("\n  hashes ").append(mod).append(" ")
-                                      .append(hashes.algorithm()).append(" ")
-                                      .append(hashes.hashFor(mod)));
-                        }
-                    } catch (ReflectiveOperationException x) {
-                        throw new InternalError(x);
-                    }
+                    JLMA.hashes(md).ifPresent(
+                            hashes -> hashes.names().stream().sorted().forEach(
+                                    mod -> sb.append("\n  hashes ").append(mod).append(" ")
+                                             .append(hashes.algorithm()).append(" ")
+                                             .append(hashes.hashFor(mod))));
+
                     out.println(sb.toString());
                     return true;
                 }
@@ -387,21 +338,6 @@
         return false;
     }
 
-    static List<ModuleDescriptor.Exports> sortExports(Set<ModuleDescriptor.Exports> exports) {
-        Map<String,ModuleDescriptor.Exports> map =
-                exports.stream()
-                       .collect(toMap(ModuleDescriptor.Exports::source,
-                                      identity()));
-        List<String> sources = exports.stream()
-                                      .map(ModuleDescriptor.Exports::source)
-                                      .sorted()
-                                      .collect(toList());
-
-        List<ModuleDescriptor.Exports> l = new ArrayList<>();
-        sources.forEach(e -> l.add(map.get(e)));
-        return l;
-    }
-
     private boolean create() throws IOException {
         JmodFileWriter jmod = new JmodFileWriter();
 
@@ -410,8 +346,9 @@
         Path target = options.jmodFile;
         Path tempTarget = target.resolveSibling(target.getFileName() + ".tmp");
         try {
-            try (OutputStream out = Files.newOutputStream(tempTarget)) {
-                jmod.write(out);
+            try (OutputStream out = Files.newOutputStream(tempTarget);
+                 BufferedOutputStream bos = new BufferedOutputStream(out)) {
+                jmod.write(bos);
             }
             Files.move(tempTarget, target);
         } catch (Exception e) {
@@ -428,7 +365,6 @@
     }
 
     private class JmodFileWriter {
-        final ModuleFinder moduleFinder = options.moduleFinder;
         final List<Path> cmds = options.cmds;
         final List<Path> libs = options.libs;
         final List<Path> configs = options.configs;
@@ -438,8 +374,8 @@
         final String osName = options.osName;
         final String osArch = options.osArch;
         final String osVersion = options.osVersion;
-        final Pattern dependenciesToHash = options.dependenciesToHash;
         final List<PathMatcher> excludes = options.excludes;
+        final Hasher hasher = hasher();
 
         JmodFileWriter() { }
 
@@ -545,11 +481,13 @@
                 if (moduleVersion != null)
                     extender.version(moduleVersion);
 
-                // --hash-dependencies
-                if (dependenciesToHash != null) {
-                    String name = descriptor.name();
-                    Set<Requires> dependences = descriptor.requires();
-                    extender.hashes(hashDependences(name, dependences));
+                if (hasher != null) {
+                    ModuleHashes moduleHashes = hasher.computeHashes(descriptor.name());
+                    if (moduleHashes != null) {
+                        extender.hashes(moduleHashes);
+                    } else {
+                        warning("warn.no.module.hashes", descriptor.name());
+                    }
                 }
 
                 // write the (possibly extended or modified) module-info.class
@@ -561,38 +499,56 @@
             }
         }
 
-        /**
-         * Examines the module dependences of the given module
-         * and computes the hash of any module that matches the
-         * pattern {@code dependenciesToHash}.
+        /*
+         * Hasher resolves a module graph using the --hash-modules PATTERN
+         * as the roots.
+         *
+         * The jmod file is being created and does not exist in the
+         * given modulepath.
          */
-        DependencyHashes hashDependences(String name, Set<Requires> moduleDependences)
-            throws IOException
-        {
-            Set<ModuleDescriptor> descriptors = new HashSet<>();
-            for (Requires md: moduleDependences) {
-                String dn = md.name();
-                if (dependenciesToHash.matcher(dn).find()) {
-                    try {
-                        Optional<ModuleReference> omref = moduleFinder.find(dn);
-                        if (!omref.isPresent()) {
-                            throw new RuntimeException("Hashing module " + name
-                                + " dependencies, unable to find module " + dn
-                                + " on module path");
+        private Hasher hasher() {
+            if (options.modulesToHash == null)
+                return null;
+
+            try {
+                Supplier<InputStream> miSupplier = newModuleInfoSupplier();
+                if (miSupplier == null) {
+                    throw new IOException(MODULE_INFO + " not found");
+                }
+
+                ModuleDescriptor descriptor;
+                try (InputStream in = miSupplier.get()) {
+                    descriptor = ModuleDescriptor.read(in);
+                }
+
+                URI uri = options.jmodFile.toUri();
+                ModuleReference mref = new ModuleReference(descriptor, uri, new Supplier<>() {
+                    @Override
+                    public ModuleReader get() {
+                        throw new UnsupportedOperationException();
+                    }
+                });
+
+                // compose a module finder with the module path and also
+                // a module finder that can find the jmod file being created
+                ModuleFinder finder = ModuleFinder.compose(options.moduleFinder,
+                    new ModuleFinder() {
+                        @Override
+                        public Optional<ModuleReference> find(String name) {
+                            if (descriptor.name().equals(name))
+                                return Optional.of(mref);
+                            else return Optional.empty();
                         }
-                        descriptors.add(omref.get().descriptor());
-                    } catch (FindException x) {
-                        throw new IOException("error reading module path", x);
-                    }
-                }
-            }
 
-            Map<String, Path> map = modulesToPath(descriptors);
-            if (map.size() == 0) {
-                return null;
-            } else {
-                // use SHA-256 for now, easy to make this configurable if needed
-                return Hasher.generate(map, "SHA-256");
+                        @Override
+                        public Set<ModuleReference> findAll() {
+                            return Collections.singleton(mref);
+                        }
+                    });
+
+                return new Hasher(finder);
+            } catch (IOException e) {
+                throw new UncheckedIOException(e);
             }
         }
 
@@ -765,6 +721,273 @@
         }
     }
 
+    /**
+     * Compute and record hashes
+     */
+    private class Hasher {
+        final ModuleFinder moduleFinder;
+        final Map<String, Path> moduleNameToPath;
+        final Set<String> modules;
+        final Configuration configuration;
+        final boolean dryrun = options.dryrun;
+        Hasher(ModuleFinder finder) {
+            this.moduleFinder = finder;
+            // Determine the modules that matches the pattern {@code modulesToHash}
+            this.modules = moduleFinder.findAll().stream()
+                .map(mref -> mref.descriptor().name())
+                .filter(mn -> options.modulesToHash.matcher(mn).find())
+                .collect(Collectors.toSet());
+
+            // a map from a module name to Path of the packaged module
+            this.moduleNameToPath = moduleFinder.findAll().stream()
+                .map(mref -> mref.descriptor().name())
+                .collect(Collectors.toMap(Function.identity(), mn -> moduleToPath(mn)));
+
+            // get a resolved module graph
+            Configuration config = null;
+            try {
+                config = Configuration.empty()
+                    .resolveRequires(ModuleFinder.ofSystem(), moduleFinder, modules);
+            } catch (ResolutionException e) {
+                warning("warn.module.resolution.fail", e.getMessage());
+            }
+            this.configuration = config;
+        }
+
+        /**
+         * This method is for jmod hash command.
+         *
+         * Identify the base modules in the module graph, i.e. no outgoing edge
+         * to any of the modules to be hashed.
+         *
+         * For each base module M, compute the hashes of all modules that depend
+         * upon M directly or indirectly.  Then update M's module-info.class
+         * to record the hashes.
+         */
+        boolean run() {
+            if (configuration == null)
+                return false;
+
+            // transposed graph containing the the packaged modules and
+            // its transitive dependences matching --hash-modules
+            Map<String, Set<String>> graph = new HashMap<>();
+            for (String root : modules) {
+                Deque<String> deque = new ArrayDeque<>();
+                deque.add(root);
+                Set<String> visited = new HashSet<>();
+                while (!deque.isEmpty()) {
+                    String mn = deque.pop();
+                    if (!visited.contains(mn)) {
+                        visited.add(mn);
+
+                        if (modules.contains(mn))
+                            graph.computeIfAbsent(mn, _k -> new HashSet<>());
+
+                        ResolvedModule resolvedModule = configuration.findModule(mn).get();
+                        for (ResolvedModule dm : resolvedModule.reads()) {
+                            String name = dm.name();
+                            if (!visited.contains(name)) {
+                                deque.push(name);
+                            }
+
+                            // reverse edge
+                            if (modules.contains(name) && modules.contains(mn)) {
+                                graph.computeIfAbsent(name, _k -> new HashSet<>()).add(mn);
+                            }
+                        }
+                    }
+                }
+            }
+
+            if (dryrun)
+                out.println("Dry run:");
+
+            // each node in a transposed graph is a matching packaged module
+            // in which the hash of the modules that depend upon it is recorded
+            graph.entrySet().stream()
+                .filter(e -> !e.getValue().isEmpty())
+                .forEach(e -> {
+                    String mn = e.getKey();
+                    Map<String, Path> modulesForHash = e.getValue().stream()
+                            .collect(Collectors.toMap(Function.identity(),
+                                                      moduleNameToPath::get));
+                    ModuleHashes hashes = ModuleHashes.generate(modulesForHash, "SHA-256");
+                    if (dryrun) {
+                        out.format("%s%n", mn);
+                        hashes.names().stream()
+                              .sorted()
+                              .forEach(name -> out.format("  hashes %s %s %s%n",
+                                  name, hashes.algorithm(), hashes.hashFor(name)));
+                    } else {
+                        try {
+                            updateModuleInfo(mn, hashes);
+                        } catch (IOException ex) {
+                            throw new UncheckedIOException(ex);
+                        }
+                    }
+                });
+            return true;
+        }
+
+        /**
+         * Compute hashes of the specified module.
+         *
+         * It records the hashing modules that depend upon the specified
+         * module directly or indirectly.
+         */
+        ModuleHashes computeHashes(String name) {
+            if (configuration == null)
+                return null;
+
+            // the transposed graph includes all modules in the resolved graph
+            Map<String, Set<String>> graph = transpose();
+
+            // find the modules that transitively depend upon the specified name
+            Deque<String> deque = new ArrayDeque<>();
+            deque.add(name);
+            Set<String> mods = visitNodes(graph, deque);
+
+            // filter modules matching the pattern specified --hash-modules
+            // as well as itself as the jmod file is being generated
+            Map<String, Path> modulesForHash = mods.stream()
+                .filter(mn -> !mn.equals(name) && modules.contains(mn))
+                .collect(Collectors.toMap(Function.identity(), moduleNameToPath::get));
+
+            if (modulesForHash.isEmpty())
+                return null;
+
+           return ModuleHashes.generate(modulesForHash, "SHA-256");
+        }
+
+        /**
+         * Returns all nodes traversed from the given roots.
+         */
+        private Set<String> visitNodes(Map<String, Set<String>> graph,
+                                       Deque<String> roots) {
+            Set<String> visited = new HashSet<>();
+            while (!roots.isEmpty()) {
+                String mn = roots.pop();
+                if (!visited.contains(mn)) {
+                    visited.add(mn);
+                    // the given roots may not be part of the graph
+                    if (graph.containsKey(mn)) {
+                        for (String dm : graph.get(mn)) {
+                            if (!visited.contains(dm)) {
+                                roots.push(dm);
+                            }
+                        }
+                    }
+                }
+            }
+            return visited;
+        }
+
+        /**
+         * Returns a transposed graph from the resolved module graph.
+         */
+        private Map<String, Set<String>> transpose() {
+            Map<String, Set<String>> transposedGraph = new HashMap<>();
+            Deque<String> deque = new ArrayDeque<>(modules);
+
+            Set<String> visited = new HashSet<>();
+            while (!deque.isEmpty()) {
+                String mn = deque.pop();
+                if (!visited.contains(mn)) {
+                    visited.add(mn);
+
+                    transposedGraph.computeIfAbsent(mn, _k -> new HashSet<>());
+
+                    ResolvedModule resolvedModule = configuration.findModule(mn).get();
+                    for (ResolvedModule dm : resolvedModule.reads()) {
+                        String name = dm.name();
+                        if (!visited.contains(name)) {
+                            deque.push(name);
+                        }
+
+                        // reverse edge
+                        transposedGraph.computeIfAbsent(name, _k -> new HashSet<>())
+                                .add(mn);
+                    }
+                }
+            }
+            return transposedGraph;
+        }
+
+        /**
+         * Reads the given input stream of module-info.class and write
+         * the extended module-info.class with the given ModuleHashes
+         *
+         * @param in       InputStream of module-info.class
+         * @param out      OutputStream to write the extended module-info.class
+         * @param hashes   ModuleHashes
+         */
+        private void recordHashes(InputStream in, OutputStream out, ModuleHashes hashes)
+            throws IOException
+        {
+            ModuleInfoExtender extender = ModuleInfoExtender.newExtender(in);
+            extender.hashes(hashes);
+            extender.write(out);
+        }
+
+        private void updateModuleInfo(String name, ModuleHashes moduleHashes)
+            throws IOException
+        {
+            Path target = moduleNameToPath.get(name);
+            Path tempTarget = target.resolveSibling(target.getFileName() + ".tmp");
+            ZipFile zip = new ZipFile(target.toFile());
+            try {
+                try (OutputStream out = Files.newOutputStream(tempTarget);
+                     ZipOutputStream zos = new ZipOutputStream(out)) {
+                    zip.stream().forEach(e -> {
+                        try {
+                            InputStream in = zip.getInputStream(e);
+                            if (e.getName().equals(MODULE_INFO) ||
+                                e.getName().equals(Section.CLASSES.jmodDir() + "/" + MODULE_INFO)) {
+                                ZipEntry ze = new ZipEntry(e.getName());
+                                ze.setTime(System.currentTimeMillis());
+                                zos.putNextEntry(ze);
+                                recordHashes(in, zos, moduleHashes);
+                                zos.closeEntry();
+                            } else {
+                                zos.putNextEntry(e);
+                                zos.write(in.readAllBytes());
+                                zos.closeEntry();
+                            }
+                        } catch (IOException x) {
+                            throw new UncheckedIOException(x);
+                        }
+                    });
+                }
+            } catch (IOException|RuntimeException e) {
+                if (Files.exists(tempTarget)) {
+                    try {
+                        Files.delete(tempTarget);
+                    } catch (IOException ioe) {
+                        e.addSuppressed(ioe);
+                    }
+                }
+                throw e;
+            } finally {
+                zip.close();
+            }
+            out.println(getMessage("module.hashes.recorded", name));
+            Files.move(tempTarget, target, StandardCopyOption.REPLACE_EXISTING);
+        }
+
+        private Path moduleToPath(String name) {
+            ModuleReference mref = moduleFinder.find(name).orElseThrow(
+                () -> new InternalError("Selected module " + name + " not on module path"));
+
+            URI uri = mref.location().get();
+            Path path = Paths.get(uri);
+            String fn = path.getFileName().toString();
+            if (!fn.endsWith(".jar") && !fn.endsWith(".jmod")) {
+                throw new InternalError(path + " is not a modular JAR or jmod file");
+            }
+            return path;
+        }
+    }
+
     enum Section {
         NATIVE_LIBS("native"),
         NATIVE_CMDS("bin"),
@@ -921,7 +1144,8 @@
             builder.append("\n").append(" Main operation modes:\n  ");
             builder.append(getMessage("main.opt.mode.create")).append("\n  ");
             builder.append(getMessage("main.opt.mode.list")).append("\n  ");
-            builder.append(getMessage("main.opt.mode.describe")).append("\n\n");
+            builder.append(getMessage("main.opt.mode.describe")).append("\n  ");
+            builder.append(getMessage("main.opt.mode.hash")).append("\n\n");
 
             String cmdfile = null;
             String[] lines = content.split("\n");
@@ -964,13 +1188,16 @@
                         .withValuesSeparatedBy(File.pathSeparatorChar)
                         .withValuesConvertedBy(DirPathConverter.INSTANCE);
 
+        OptionSpec<Void> dryrun
+            = parser.accepts("dry-run", getMessage("main.opt.dry-run"));
+
         OptionSpec<PathMatcher> excludes
                 = parser.accepts("exclude", getMessage("main.opt.exclude"))
                         .withRequiredArg()
                         .withValuesConvertedBy(new GlobConverter());
 
-        OptionSpec<Pattern> hashDependencies
-                = parser.accepts("hash-dependencies", getMessage("main.opt.hash-dependencies"))
+        OptionSpec<Pattern> hashModules
+                = parser.accepts("hash-modules", getMessage("main.opt.hash-modules"))
                         .withRequiredArg()
                         .withValuesConvertedBy(new PatternConverter());
 
@@ -1049,6 +1276,8 @@
                 options.cmds = opts.valuesOf(cmds);
             if (opts.has(config))
                 options.configs = opts.valuesOf(config);
+            if (opts.has(dryrun))
+                options.dryrun = true;
             if (opts.has(excludes))
                 options.excludes = opts.valuesOf(excludes);
             if (opts.has(libs))
@@ -1069,27 +1298,39 @@
                 options.osArch = opts.valueOf(osArch);
             if (opts.has(osVersion))
                 options.osVersion = opts.valueOf(osVersion);
-            if (opts.has(hashDependencies)) {
-                options.dependenciesToHash = opts.valueOf(hashDependencies);
-                // if storing hashes of dependencies then the module path is required
+            if (opts.has(hashModules)) {
+                options.modulesToHash = opts.valueOf(hashModules);
+                // if storing hashes then the module path is required
                 if (options.moduleFinder == null)
-                    throw new CommandException("err.modulepath.must.be.specified").showUsage(true);
+                    throw new CommandException("err.modulepath.must.be.specified")
+                            .showUsage(true);
             }
 
-            if (words.size() <= 1)
-                throw new CommandException("err.jmod.must.be.specified").showUsage(true);
-            Path path = Paths.get(words.get(1));
-            if (options.mode.equals(Mode.CREATE) && Files.exists(path))
-                throw new CommandException("err.file.already.exists", path);
-            else if ((options.mode.equals(Mode.LIST) ||
-                          options.mode.equals(Mode.DESCRIBE))
-                      && Files.notExists(path))
-                throw new CommandException("err.jmod.not.found", path);
-            options.jmodFile = path;
+            if (options.mode.equals(Mode.HASH)) {
+                if (options.moduleFinder == null || options.modulesToHash == null)
+                    throw new CommandException("err.modulepath.must.be.specified")
+                            .showUsage(true);
+            } else {
+                if (words.size() <= 1)
+                    throw new CommandException("err.jmod.must.be.specified").showUsage(true);
+                Path path = Paths.get(words.get(1));
 
-            if (words.size() > 2)
-                throw new CommandException("err.unknown.option",
-                        words.subList(2, words.size())).showUsage(true);
+                if (options.mode.equals(Mode.CREATE) && Files.exists(path))
+                    throw new CommandException("err.file.already.exists", path);
+                else if ((options.mode.equals(Mode.LIST) ||
+                            options.mode.equals(Mode.DESCRIBE))
+                         && Files.notExists(path))
+                    throw new CommandException("err.jmod.not.found", path);
+
+                if (options.dryrun) {
+                    throw new CommandException("err.invalid.dryrun.option");
+                }
+                options.jmodFile = path;
+
+                if (words.size() > 2)
+                    throw new CommandException("err.unknown.option",
+                            words.subList(2, words.size())).showUsage(true);
+            }
 
             if (options.mode.equals(Mode.CREATE) && options.classpath == null)
                 throw new CommandException("err.classpath.must.be.specified").showUsage(true);
--- a/jdk/src/jdk.jlink/share/classes/jdk/tools/jmod/resources/jmod.properties	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/jdk.jlink/share/classes/jdk/tools/jmod/resources/jmod.properties	Tue May 03 12:25:20 2016 -0700
@@ -1,9 +1,9 @@
 main.usage.summary=\
-Usage: {0} (create|list|describe) <OPTIONS> <jmod-file>\n\
+Usage: {0} (create|list|describe|hash) <OPTIONS> <jmod-file>\n\
 use --help for a list of possible options
 
 main.usage=\
-Usage: {0} (create|list|describe) <OPTIONS> <jmod-file>
+Usage: {0} (create|list|describe|hash) <OPTIONS> <jmod-file>
 
 error.prefix=Error:
 warn.prefix=Warning:
@@ -14,6 +14,8 @@
 \list      - Prints the names of all the entries
 main.opt.mode.describe=\
 \describe  - Prints the module details
+main.opt.mode.hash=\
+\hash      - Records hashes of tied modules.
 
 main.opt.help=Print this usage message
 main.opt.version=Version information
@@ -21,9 +23,9 @@
 main.opt.libs=Location of native libraries
 main.opt.cmds=Location of native commands
 main.opt.config=Location of user-editable config files
+main.opt.dry-run=Dry run of hash mode
 main.opt.exclude=Exclude files, given as a PATTERN
 main.opt.module-version= Module version
-main.opt.modulepath=Module path
 main.opt.main-class=Main class
 main.opt.main-class.arg=class-name
 main.opt.os-name=Operating system name
@@ -32,18 +34,25 @@
 main.opt.os-arch.arg=os-arch
 main.opt.os-version=Operating system version
 main.opt.os-version.arg=os-version
-main.opt.hash-dependencies=Compute and record hashes of dependencies matched by the pattern
+main.opt.modulepath=Module path
+main.opt.hash-modules=Compute and record hashes to tie a packaged module\
+\ with modules matching the given pattern and depending upon it directly\
+\ or indirectly. The hashes are recorded in the JMOD file being created, or\
+\ a JMOD file or modular JAR on the module path specified the jmod hash command.
+
 main.opt.cmdfile=Read options from the specified file
 
-err.missing.mode=one of create, list, or describe must be specified
-err.invalid.mode=mode must be one of create, list, or describe: {0}
+module.hashes.recorded=Hashes are recorded in module {0}
+
+err.missing.mode=one of create, list, describe, or hash must be specified
+err.invalid.mode=mode must be one of create, list, describe, or hash: {0}
 err.classpath.must.be.specified=--class-path must be specified
 err.jmod.must.be.specified=jmod-file must be specified
 err.invalid.version=invalid module version {0}
-err.output.must.be.specified:--output must be specified
-err.mods.must.be.specified:--mods must be specified
-err.modulepath.must.be.specified:--module-path must be specified when hashing dependencies
-err.invalid.main-class:invalid main-class name: {0}
+err.output.must.be.specified=--output must be specified
+err.mods.must.be.specified=--mods must be specified
+err.modulepath.must.be.specified=--module-path must be specified when hashing modules
+err.invalid.main-class=invalid main-class name: {0}
 err.path.not.found=path not found: {0}
 err.path.not.valid=invalid path: {0}
 err.path.not.a.dir=path must be a directory: {0}
@@ -54,5 +63,9 @@
 err.unknown.option=unknown option(s): {0}
 err.missing.arg=no value given for {0}
 err.internal.error=internal error: {0} {1} {2}
+err.invalid.dryrun.option=--dry-run can only be used with hash mode
 err.module.descriptor.not.found=Module descriptor not found
 warn.invalid.arg=Invalid classname or pathname not exist: {0}
+warn.no.module.hashes=No hashes recorded: no module specified for hashing depends on {0}
+warn.module.resolution.fail=No hashes recorded: {0}
+
--- a/jdk/src/jdk.localedata/share/classes/sun/util/resources/provider/LocaleDataProvider.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/src/jdk.localedata/share/classes/sun/util/resources/provider/LocaleDataProvider.java	Tue May 03 12:25:20 2016 -0700
@@ -46,7 +46,7 @@
         Class<?> c = Class.forName(LocaleDataProvider.class.getModule(), bundleName);
         if (c != null && ResourceBundle.class.isAssignableFrom(c)) {
             try {
-                @SuppressWarnings("unchecked")
+                @SuppressWarnings({"unchecked", "deprecation"})
                 ResourceBundle rb = ((Class<ResourceBundle>) c).newInstance();
                 return rb;
             } catch (InstantiationException | IllegalAccessException e) {
--- a/jdk/test/ProblemList.txt	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/test/ProblemList.txt	Tue May 03 12:25:20 2016 -0700
@@ -319,6 +319,8 @@
 
 tools/launcher/FXLauncherTest.java                              8068049 linux-all,macosx-all
 
+tools/pack200/Pack200Props.java                                 8155857 generic-all
+
 ############################################################################
 
 # jdk_jdi
--- a/jdk/test/TEST.ROOT	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/test/TEST.ROOT	Tue May 03 12:25:20 2016 -0700
@@ -26,9 +26,12 @@
 # Allow querying of sun.arch.data.model in @requires clauses
 requires.properties=sun.arch.data.model 
 
-# Tests using jtreg 4.2 b01 features
-requiredVersion=4.2 b01
+# Tests using jtreg 4.2 b02 features
+requiredVersion=4.2 b02
 
 # Path to libraries in the topmost test directory. This is needed so @library
 # does not need ../../ notation to reach them
 external.lib.roots = ../../
+
+# Use new form of -Xpatch
+useNewXpatch=true
--- a/jdk/test/com/sun/corba/5036554/TestCorbaBug.sh	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/test/com/sun/corba/5036554/TestCorbaBug.sh	Tue May 03 12:25:20 2016 -0700
@@ -81,9 +81,9 @@
 
 chmod -fR 777 bug
 
-${COMPILEJAVA}${FS}bin${FS}javac -d . bug${FS}*.java
+${COMPILEJAVA}${FS}bin${FS}javac -addmods java.corba -d . bug${FS}*.java
 
-${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} -cp . bug/JavaBug > test.out 2>&1 
+${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} -addmods java.corba -cp . bug/JavaBug > test.out 2>&1 
 
 grep "NullPointerException" test.out
 
--- a/jdk/test/com/sun/corba/7130985/CorbaExceptionsCompileTest.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/test/com/sun/corba/7130985/CorbaExceptionsCompileTest.java	Tue May 03 12:25:20 2016 -0700
@@ -27,7 +27,8 @@
  * @summary Four helper classes missing in Sun JDK
  * @library /lib/testlibrary
  * @build jdk.testlibrary.*
- * @run main CorbaExceptionsCompileTest
+ * @compile -addmods java.corba CorbaExceptionsCompileTest.java
+ * @run main/othervm -addmods java.corba CorbaExceptionsCompileTest
  */
 
 import java.io.*;
--- a/jdk/test/com/sun/corba/se/impl/io/HookPutFieldsTest.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/test/com/sun/corba/se/impl/io/HookPutFieldsTest.java	Tue May 03 12:25:20 2016 -0700
@@ -25,6 +25,8 @@
  * @test
  * @bug 7095856
  * @summary OutputStreamHook doesn't handle null values
+ * @compile -addmods java.corba HookPutFieldsTest.java
+ * @run main/othervm -addmods java.corba HookPutFieldsTest
  */
 
 import java.net.InetAddress;
--- a/jdk/test/com/sun/corba/se/impl/orb/SetDefaultORBTest.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/test/com/sun/corba/se/impl/orb/SetDefaultORBTest.java	Tue May 03 12:25:20 2016 -0700
@@ -25,7 +25,8 @@
  * @test
  * @bug 8028215
  * @summary SetDefaultORBTest setting ORB impl via properties test
- * @run main/othervm SetDefaultORBTest
+ * @compile -addmods java.corba SetDefaultORBTest.java
+ * @run main/othervm -addmods java.corba SetDefaultORBTest
  *
  */
 
--- a/jdk/test/com/sun/net/httpserver/bugs/B6373555.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/test/com/sun/net/httpserver/bugs/B6373555.java	Tue May 03 12:25:20 2016 -0700
@@ -29,7 +29,6 @@
 
 import java.net.*;
 import java.io.*;
-import javax.xml.soap.*;
 import java.util.*;
 import com.sun.net.httpserver.*;
 import java.util.concurrent.*;
--- a/jdk/test/java/lang/invoke/VarHandles/VarHandleBaseTest.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/test/java/lang/invoke/VarHandles/VarHandleBaseTest.java	Tue May 03 12:25:20 2016 -0700
@@ -148,6 +148,7 @@
         COMPARE_AND_EXCHANGE_ACQUIRE(TestAccessType.COMPARE_AND_EXCHANGE),
         COMPARE_AND_EXCHANGE_RELEASE(TestAccessType.COMPARE_AND_EXCHANGE),
         WEAK_COMPARE_AND_SET(TestAccessType.COMPARE_AND_SET),
+        WEAK_COMPARE_AND_SET_VOLATILE(TestAccessType.COMPARE_AND_SET),
         WEAK_COMPARE_AND_SET_ACQUIRE(TestAccessType.COMPARE_AND_SET),
         WEAK_COMPARE_AND_SET_RELEASE(TestAccessType.COMPARE_AND_SET),
         GET_AND_SET(TestAccessType.GET_AND_SET),
--- a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestAccessBoolean.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestAccessBoolean.java	Tue May 03 12:25:20 2016 -0700
@@ -104,6 +104,7 @@
         assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.COMPARE_AND_EXCHANGE_ACQUIRE));
         assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.COMPARE_AND_EXCHANGE_RELEASE));
         assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET));
+        assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_VOLATILE));
         assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE));
         assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE));
         assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_SET));
@@ -280,6 +281,10 @@
         });
 
         checkUOE(() -> {
+            boolean r = vh.weakCompareAndSetVolatile(recv, true, false);
+        });
+
+        checkUOE(() -> {
             boolean r = vh.weakCompareAndSetAcquire(recv, true, false);
         });
 
@@ -362,6 +367,10 @@
         });
 
         checkUOE(() -> {
+            boolean r = vh.weakCompareAndSetVolatile(true, false);
+        });
+
+        checkUOE(() -> {
             boolean r = vh.weakCompareAndSetAcquire(true, false);
         });
 
@@ -434,6 +443,10 @@
         });
 
         checkUOE(() -> {
+            boolean r = vh.weakCompareAndSetVolatile(recv, true, false);
+        });
+
+        checkUOE(() -> {
             boolean r = vh.weakCompareAndSetAcquire(recv, true, false);
         });
 
@@ -506,6 +519,10 @@
         });
 
         checkUOE(() -> {
+            boolean r = vh.weakCompareAndSetVolatile(true, false);
+        });
+
+        checkUOE(() -> {
             boolean r = vh.weakCompareAndSetAcquire(true, false);
         });
 
@@ -585,6 +602,10 @@
         });
 
         checkUOE(() -> {
+            boolean r = vh.weakCompareAndSetVolatile(array, i, true, false);
+        });
+
+        checkUOE(() -> {
             boolean r = vh.weakCompareAndSetAcquire(array, i, true, false);
         });
 
--- a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestAccessByte.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestAccessByte.java	Tue May 03 12:25:20 2016 -0700
@@ -104,6 +104,7 @@
         assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.COMPARE_AND_EXCHANGE_ACQUIRE));
         assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.COMPARE_AND_EXCHANGE_RELEASE));
         assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET));
+        assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_VOLATILE));
         assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE));
         assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE));
         assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_SET));
@@ -280,6 +281,10 @@
         });
 
         checkUOE(() -> {
+            boolean r = vh.weakCompareAndSetVolatile(recv, (byte)1, (byte)2);
+        });
+
+        checkUOE(() -> {
             boolean r = vh.weakCompareAndSetAcquire(recv, (byte)1, (byte)2);
         });
 
@@ -362,6 +367,10 @@
         });
 
         checkUOE(() -> {
+            boolean r = vh.weakCompareAndSetVolatile((byte)1, (byte)2);
+        });
+
+        checkUOE(() -> {
             boolean r = vh.weakCompareAndSetAcquire((byte)1, (byte)2);
         });
 
@@ -434,6 +443,10 @@
         });
 
         checkUOE(() -> {
+            boolean r = vh.weakCompareAndSetVolatile(recv, (byte)1, (byte)2);
+        });
+
+        checkUOE(() -> {
             boolean r = vh.weakCompareAndSetAcquire(recv, (byte)1, (byte)2);
         });
 
@@ -506,6 +519,10 @@
         });
 
         checkUOE(() -> {
+            boolean r = vh.weakCompareAndSetVolatile((byte)1, (byte)2);
+        });
+
+        checkUOE(() -> {
             boolean r = vh.weakCompareAndSetAcquire((byte)1, (byte)2);
         });
 
@@ -585,6 +602,10 @@
         });
 
         checkUOE(() -> {
+            boolean r = vh.weakCompareAndSetVolatile(array, i, (byte)1, (byte)2);
+        });
+
+        checkUOE(() -> {
             boolean r = vh.weakCompareAndSetAcquire(array, i, (byte)1, (byte)2);
         });
 
--- a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestAccessChar.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestAccessChar.java	Tue May 03 12:25:20 2016 -0700
@@ -104,6 +104,7 @@
         assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.COMPARE_AND_EXCHANGE_ACQUIRE));
         assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.COMPARE_AND_EXCHANGE_RELEASE));
         assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET));
+        assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_VOLATILE));
         assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE));
         assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE));
         assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_SET));
@@ -280,6 +281,10 @@
         });
 
         checkUOE(() -> {
+            boolean r = vh.weakCompareAndSetVolatile(recv, 'a', 'b');
+        });
+
+        checkUOE(() -> {
             boolean r = vh.weakCompareAndSetAcquire(recv, 'a', 'b');
         });
 
@@ -362,6 +367,10 @@
         });
 
         checkUOE(() -> {
+            boolean r = vh.weakCompareAndSetVolatile('a', 'b');
+        });
+
+        checkUOE(() -> {
             boolean r = vh.weakCompareAndSetAcquire('a', 'b');
         });
 
@@ -434,6 +443,10 @@
         });
 
         checkUOE(() -> {
+            boolean r = vh.weakCompareAndSetVolatile(recv, 'a', 'b');
+        });
+
+        checkUOE(() -> {
             boolean r = vh.weakCompareAndSetAcquire(recv, 'a', 'b');
         });
 
@@ -506,6 +519,10 @@
         });
 
         checkUOE(() -> {
+            boolean r = vh.weakCompareAndSetVolatile('a', 'b');
+        });
+
+        checkUOE(() -> {
             boolean r = vh.weakCompareAndSetAcquire('a', 'b');
         });
 
@@ -585,6 +602,10 @@
         });
 
         checkUOE(() -> {
+            boolean r = vh.weakCompareAndSetVolatile(array, i, 'a', 'b');
+        });
+
+        checkUOE(() -> {
             boolean r = vh.weakCompareAndSetAcquire(array, i, 'a', 'b');
         });
 
--- a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestAccessDouble.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestAccessDouble.java	Tue May 03 12:25:20 2016 -0700
@@ -104,6 +104,7 @@
         assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.COMPARE_AND_EXCHANGE_ACQUIRE));
         assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.COMPARE_AND_EXCHANGE_RELEASE));
         assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET));
+        assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_VOLATILE));
         assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE));
         assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE));
         assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_SET));
@@ -280,6 +281,10 @@
         });
 
         checkUOE(() -> {
+            boolean r = vh.weakCompareAndSetVolatile(recv, 1.0d, 2.0d);
+        });
+
+        checkUOE(() -> {
             boolean r = vh.weakCompareAndSetAcquire(recv, 1.0d, 2.0d);
         });
 
@@ -362,6 +367,10 @@
         });
 
         checkUOE(() -> {
+            boolean r = vh.weakCompareAndSetVolatile(1.0d, 2.0d);
+        });
+
+        checkUOE(() -> {
             boolean r = vh.weakCompareAndSetAcquire(1.0d, 2.0d);
         });
 
@@ -434,6 +443,10 @@
         });
 
         checkUOE(() -> {
+            boolean r = vh.weakCompareAndSetVolatile(recv, 1.0d, 2.0d);
+        });
+
+        checkUOE(() -> {
             boolean r = vh.weakCompareAndSetAcquire(recv, 1.0d, 2.0d);
         });
 
@@ -506,6 +519,10 @@
         });
 
         checkUOE(() -> {
+            boolean r = vh.weakCompareAndSetVolatile(1.0d, 2.0d);
+        });
+
+        checkUOE(() -> {
             boolean r = vh.weakCompareAndSetAcquire(1.0d, 2.0d);
         });
 
@@ -585,6 +602,10 @@
         });
 
         checkUOE(() -> {
+            boolean r = vh.weakCompareAndSetVolatile(array, i, 1.0d, 2.0d);
+        });
+
+        checkUOE(() -> {
             boolean r = vh.weakCompareAndSetAcquire(array, i, 1.0d, 2.0d);
         });
 
--- a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestAccessFloat.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestAccessFloat.java	Tue May 03 12:25:20 2016 -0700
@@ -104,6 +104,7 @@
         assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.COMPARE_AND_EXCHANGE_ACQUIRE));
         assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.COMPARE_AND_EXCHANGE_RELEASE));
         assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET));
+        assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_VOLATILE));
         assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE));
         assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE));
         assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_SET));
@@ -280,6 +281,10 @@
         });
 
         checkUOE(() -> {
+            boolean r = vh.weakCompareAndSetVolatile(recv, 1.0f, 2.0f);
+        });
+
+        checkUOE(() -> {
             boolean r = vh.weakCompareAndSetAcquire(recv, 1.0f, 2.0f);
         });
 
@@ -362,6 +367,10 @@
         });
 
         checkUOE(() -> {
+            boolean r = vh.weakCompareAndSetVolatile(1.0f, 2.0f);
+        });
+
+        checkUOE(() -> {
             boolean r = vh.weakCompareAndSetAcquire(1.0f, 2.0f);
         });
 
@@ -434,6 +443,10 @@
         });
 
         checkUOE(() -> {
+            boolean r = vh.weakCompareAndSetVolatile(recv, 1.0f, 2.0f);
+        });
+
+        checkUOE(() -> {
             boolean r = vh.weakCompareAndSetAcquire(recv, 1.0f, 2.0f);
         });
 
@@ -506,6 +519,10 @@
         });
 
         checkUOE(() -> {
+            boolean r = vh.weakCompareAndSetVolatile(1.0f, 2.0f);
+        });
+
+        checkUOE(() -> {
             boolean r = vh.weakCompareAndSetAcquire(1.0f, 2.0f);
         });
 
@@ -585,6 +602,10 @@
         });
 
         checkUOE(() -> {
+            boolean r = vh.weakCompareAndSetVolatile(array, i, 1.0f, 2.0f);
+        });
+
+        checkUOE(() -> {
             boolean r = vh.weakCompareAndSetAcquire(array, i, 1.0f, 2.0f);
         });
 
--- a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestAccessInt.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestAccessInt.java	Tue May 03 12:25:20 2016 -0700
@@ -104,6 +104,7 @@
         assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.COMPARE_AND_EXCHANGE_ACQUIRE));
         assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.COMPARE_AND_EXCHANGE_RELEASE));
         assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET));
+        assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_VOLATILE));
         assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE));
         assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE));
         assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_SET));
@@ -421,12 +422,19 @@
             assertEquals(x, 2, "weakCompareAndSetRelease int");
         }
 
+        {
+            boolean r = vh.weakCompareAndSetVolatile(recv, 2, 1);
+            assertEquals(r, true, "weakCompareAndSetVolatile int");
+            int x = (int) vh.get(recv);
+            assertEquals(x, 1, "weakCompareAndSetVolatile int value");
+        }
+
         // Compare set and get
         {
-            int o = (int) vh.getAndSet(recv, 1);
-            assertEquals(o, 2, "getAndSet int");
+            int o = (int) vh.getAndSet(recv, 2);
+            assertEquals(o, 1, "getAndSet int");
             int x = (int) vh.get(recv);
-            assertEquals(x, 1, "getAndSet int value");
+            assertEquals(x, 2, "getAndSet int value");
         }
 
         vh.set(recv, 1);
@@ -549,18 +557,25 @@
         }
 
         {
-            boolean r = (boolean) vh.weakCompareAndSetRelease( 1, 2);
+            boolean r = (boolean) vh.weakCompareAndSetRelease(1, 2);
             assertEquals(r, true, "weakCompareAndSetRelease int");
             int x = (int) vh.get();
             assertEquals(x, 2, "weakCompareAndSetRelease int");
         }
 
+        {
+            boolean r = (boolean) vh.weakCompareAndSetVolatile(2, 1);
+            assertEquals(r, true, "weakCompareAndSetVolatile int");
+            int x = (int) vh.get();
+            assertEquals(x, 1, "weakCompareAndSetVolatile int value");
+        }
+
         // Compare set and get
         {
-            int o = (int) vh.getAndSet( 1);
-            assertEquals(o, 2, "getAndSet int");
+            int o = (int) vh.getAndSet( 2);
+            assertEquals(o, 1, "getAndSet int");
             int x = (int) vh.get();
-            assertEquals(x, 1, "getAndSet int value");
+            assertEquals(x, 2, "getAndSet int value");
         }
 
         vh.set(1);
@@ -692,12 +707,19 @@
                 assertEquals(x, 2, "weakCompareAndSetRelease int");
             }
 
+            {
+                boolean r = vh.weakCompareAndSetVolatile(array, i, 2, 1);
+                assertEquals(r, true, "weakCompareAndSetVolatile int");
+                int x = (int) vh.get(array, i);
+                assertEquals(x, 1, "weakCompareAndSetVolatile int value");
+            }
+
             // Compare set and get
             {
-                int o = (int) vh.getAndSet(array, i, 1);
-                assertEquals(o, 2, "getAndSet int");
+                int o = (int) vh.getAndSet(array, i, 2);
+                assertEquals(o, 1, "getAndSet int");
                 int x = (int) vh.get(array, i);
-                assertEquals(x, 1, "getAndSet int value");
+                assertEquals(x, 2, "getAndSet int value");
             }
 
             vh.set(array, i, 1);
@@ -778,6 +800,10 @@
             });
 
             checkIOOBE(() -> {
+                boolean r = vh.weakCompareAndSetVolatile(array, ci, 1, 2);
+            });
+
+            checkIOOBE(() -> {
                 boolean r = vh.weakCompareAndSetAcquire(array, ci, 1, 2);
             });
 
--- a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestAccessLong.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestAccessLong.java	Tue May 03 12:25:20 2016 -0700
@@ -104,6 +104,7 @@
         assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.COMPARE_AND_EXCHANGE_ACQUIRE));
         assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.COMPARE_AND_EXCHANGE_RELEASE));
         assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET));
+        assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_VOLATILE));
         assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE));
         assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE));
         assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_SET));
@@ -421,12 +422,19 @@
             assertEquals(x, 2L, "weakCompareAndSetRelease long");
         }
 
+        {
+            boolean r = vh.weakCompareAndSetVolatile(recv, 2L, 1L);
+            assertEquals(r, true, "weakCompareAndSetVolatile long");
+            long x = (long) vh.get(recv);
+            assertEquals(x, 1L, "weakCompareAndSetVolatile long value");
+        }
+
         // Compare set and get
         {
-            long o = (long) vh.getAndSet(recv, 1L);
-            assertEquals(o, 2L, "getAndSet long");
+            long o = (long) vh.getAndSet(recv, 2L);
+            assertEquals(o, 1L, "getAndSet long");
             long x = (long) vh.get(recv);
-            assertEquals(x, 1L, "getAndSet long value");
+            assertEquals(x, 2L, "getAndSet long value");
         }
 
         vh.set(recv, 1L);
@@ -549,18 +557,25 @@
         }
 
         {
-            boolean r = (boolean) vh.weakCompareAndSetRelease( 1L, 2L);
+            boolean r = (boolean) vh.weakCompareAndSetRelease(1L, 2L);
             assertEquals(r, true, "weakCompareAndSetRelease long");
             long x = (long) vh.get();
             assertEquals(x, 2L, "weakCompareAndSetRelease long");
         }
 
+        {
+            boolean r = (boolean) vh.weakCompareAndSetVolatile(2L, 1L);
+            assertEquals(r, true, "weakCompareAndSetVolatile long");
+            long x = (long) vh.get();
+            assertEquals(x, 1L, "weakCompareAndSetVolatile long value");
+        }
+
         // Compare set and get
         {
-            long o = (long) vh.getAndSet( 1L);
-            assertEquals(o, 2L, "getAndSet long");
+            long o = (long) vh.getAndSet( 2L);
+            assertEquals(o, 1L, "getAndSet long");
             long x = (long) vh.get();
-            assertEquals(x, 1L, "getAndSet long value");
+            assertEquals(x, 2L, "getAndSet long value");
         }
 
         vh.set(1L);
@@ -692,12 +707,19 @@
                 assertEquals(x, 2L, "weakCompareAndSetRelease long");
             }
 
+            {
+                boolean r = vh.weakCompareAndSetVolatile(array, i, 2L, 1L);
+                assertEquals(r, true, "weakCompareAndSetVolatile long");
+                long x = (long) vh.get(array, i);
+                assertEquals(x, 1L, "weakCompareAndSetVolatile long value");
+            }
+
             // Compare set and get
             {
-                long o = (long) vh.getAndSet(array, i, 1L);
-                assertEquals(o, 2L, "getAndSet long");
+                long o = (long) vh.getAndSet(array, i, 2L);
+                assertEquals(o, 1L, "getAndSet long");
                 long x = (long) vh.get(array, i);
-                assertEquals(x, 1L, "getAndSet long value");
+                assertEquals(x, 2L, "getAndSet long value");
             }
 
             vh.set(array, i, 1L);
@@ -778,6 +800,10 @@
             });
 
             checkIOOBE(() -> {
+                boolean r = vh.weakCompareAndSetVolatile(array, ci, 1L, 2L);
+            });
+
+            checkIOOBE(() -> {
                 boolean r = vh.weakCompareAndSetAcquire(array, ci, 1L, 2L);
             });
 
--- a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestAccessShort.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestAccessShort.java	Tue May 03 12:25:20 2016 -0700
@@ -104,6 +104,7 @@
         assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.COMPARE_AND_EXCHANGE_ACQUIRE));
         assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.COMPARE_AND_EXCHANGE_RELEASE));
         assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET));
+        assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_VOLATILE));
         assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE));
         assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE));
         assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_SET));
@@ -280,6 +281,10 @@
         });
 
         checkUOE(() -> {
+            boolean r = vh.weakCompareAndSetVolatile(recv, (short)1, (short)2);
+        });
+
+        checkUOE(() -> {
             boolean r = vh.weakCompareAndSetAcquire(recv, (short)1, (short)2);
         });
 
@@ -362,6 +367,10 @@
         });
 
         checkUOE(() -> {
+            boolean r = vh.weakCompareAndSetVolatile((short)1, (short)2);
+        });
+
+        checkUOE(() -> {
             boolean r = vh.weakCompareAndSetAcquire((short)1, (short)2);
         });
 
@@ -434,6 +443,10 @@
         });
 
         checkUOE(() -> {
+            boolean r = vh.weakCompareAndSetVolatile(recv, (short)1, (short)2);
+        });
+
+        checkUOE(() -> {
             boolean r = vh.weakCompareAndSetAcquire(recv, (short)1, (short)2);
         });
 
@@ -506,6 +519,10 @@
         });
 
         checkUOE(() -> {
+            boolean r = vh.weakCompareAndSetVolatile((short)1, (short)2);
+        });
+
+        checkUOE(() -> {
             boolean r = vh.weakCompareAndSetAcquire((short)1, (short)2);
         });
 
@@ -585,6 +602,10 @@
         });
 
         checkUOE(() -> {
+            boolean r = vh.weakCompareAndSetVolatile(array, i, (short)1, (short)2);
+        });
+
+        checkUOE(() -> {
             boolean r = vh.weakCompareAndSetAcquire(array, i, (short)1, (short)2);
         });
 
--- a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestAccessString.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestAccessString.java	Tue May 03 12:25:20 2016 -0700
@@ -104,6 +104,7 @@
         assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.COMPARE_AND_EXCHANGE_ACQUIRE));
         assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.COMPARE_AND_EXCHANGE_RELEASE));
         assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET));
+        assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_VOLATILE));
         assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE));
         assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE));
         assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_SET));
@@ -435,12 +436,19 @@
             assertEquals(x, "bar", "weakCompareAndSetRelease String");
         }
 
+        {
+            boolean r = vh.weakCompareAndSetVolatile(recv, "bar", "foo");
+            assertEquals(r, true, "weakCompareAndSetVolatile String");
+            String x = (String) vh.get(recv);
+            assertEquals(x, "foo", "weakCompareAndSetVolatile String value");
+        }
+
         // Compare set and get
         {
-            String o = (String) vh.getAndSet(recv, "foo");
-            assertEquals(o, "bar", "getAndSet String");
+            String o = (String) vh.getAndSet(recv, "bar");
+            assertEquals(o, "foo", "getAndSet String");
             String x = (String) vh.get(recv);
-            assertEquals(x, "foo", "getAndSet String value");
+            assertEquals(x, "bar", "getAndSet String value");
         }
 
     }
@@ -561,18 +569,25 @@
         }
 
         {
-            boolean r = (boolean) vh.weakCompareAndSetRelease( "foo", "bar");
+            boolean r = (boolean) vh.weakCompareAndSetRelease("foo", "bar");
             assertEquals(r, true, "weakCompareAndSetRelease String");
             String x = (String) vh.get();
             assertEquals(x, "bar", "weakCompareAndSetRelease String");
         }
 
+        {
+            boolean r = (boolean) vh.weakCompareAndSetVolatile("bar", "foo");
+            assertEquals(r, true, "weakCompareAndSetVolatile String");
+            String x = (String) vh.get();
+            assertEquals(x, "foo", "weakCompareAndSetVolatile String value");
+        }
+
         // Compare set and get
         {
-            String o = (String) vh.getAndSet( "foo");
-            assertEquals(o, "bar", "getAndSet String");
+            String o = (String) vh.getAndSet( "bar");
+            assertEquals(o, "foo", "getAndSet String");
             String x = (String) vh.get();
-            assertEquals(x, "foo", "getAndSet String value");
+            assertEquals(x, "bar", "getAndSet String value");
         }
 
     }
@@ -702,12 +717,19 @@
                 assertEquals(x, "bar", "weakCompareAndSetRelease String");
             }
 
+            {
+                boolean r = vh.weakCompareAndSetVolatile(array, i, "bar", "foo");
+                assertEquals(r, true, "weakCompareAndSetVolatile String");
+                String x = (String) vh.get(array, i);
+                assertEquals(x, "foo", "weakCompareAndSetVolatile String value");
+            }
+
             // Compare set and get
             {
-                String o = (String) vh.getAndSet(array, i, "foo");
-                assertEquals(o, "bar", "getAndSet String");
+                String o = (String) vh.getAndSet(array, i, "bar");
+                assertEquals(o, "foo", "getAndSet String");
                 String x = (String) vh.get(array, i);
-                assertEquals(x, "foo", "getAndSet String value");
+                assertEquals(x, "bar", "getAndSet String value");
             }
 
         }
@@ -786,6 +808,10 @@
             });
 
             checkIOOBE(() -> {
+                boolean r = vh.weakCompareAndSetVolatile(array, ci, "foo", "bar");
+            });
+
+            checkIOOBE(() -> {
                 boolean r = vh.weakCompareAndSetAcquire(array, ci, "foo", "bar");
             });
 
--- a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsChar.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsChar.java	Tue May 03 12:25:20 2016 -0700
@@ -93,6 +93,7 @@
         assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.COMPARE_AND_EXCHANGE_ACQUIRE));
         assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.COMPARE_AND_EXCHANGE_RELEASE));
         assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET));
+        assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_VOLATILE));
         assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE));
         assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE));
         assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_SET));
@@ -204,6 +205,10 @@
         });
 
         checkUOE(() -> {
+            boolean r = vh.weakCompareAndSetVolatile(array, ci, VALUE_1, VALUE_2);
+        });
+
+        checkUOE(() -> {
             boolean r = vh.weakCompareAndSetAcquire(array, ci, VALUE_1, VALUE_2);
         });
 
@@ -265,6 +270,10 @@
             });
 
             checkUOE(() -> {
+                boolean r = vh.weakCompareAndSetVolatile(array, ci, VALUE_1, VALUE_2);
+            });
+
+            checkUOE(() -> {
                 boolean r = vh.weakCompareAndSetAcquire(array, ci, VALUE_1, VALUE_2);
             });
 
@@ -306,6 +315,10 @@
             });
 
             checkUOE(() -> {
+                boolean r = vh.weakCompareAndSetVolatile(array, ci, VALUE_1, VALUE_2);
+            });
+
+            checkUOE(() -> {
                 boolean r = vh.weakCompareAndSetAcquire(array, ci, VALUE_1, VALUE_2);
             });
 
--- a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsDouble.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsDouble.java	Tue May 03 12:25:20 2016 -0700
@@ -93,6 +93,7 @@
         assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.COMPARE_AND_EXCHANGE_ACQUIRE));
         assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.COMPARE_AND_EXCHANGE_RELEASE));
         assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET));
+        assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_VOLATILE));
         assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE));
         assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE));
         assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_SET));
@@ -239,6 +240,10 @@
             });
 
             checkROBE(() -> {
+                boolean r = vh.weakCompareAndSetVolatile(array, ci, VALUE_1, VALUE_2);
+            });
+
+            checkROBE(() -> {
                 boolean r = vh.weakCompareAndSetAcquire(array, ci, VALUE_1, VALUE_2);
             });
 
@@ -334,6 +339,10 @@
             });
 
             checkIOOBE(() -> {
+                boolean r = vh.weakCompareAndSetVolatile(array, ci, VALUE_1, VALUE_2);
+            });
+
+            checkIOOBE(() -> {
                 boolean r = vh.weakCompareAndSetAcquire(array, ci, VALUE_1, VALUE_2);
             });
 
@@ -415,6 +424,10 @@
                 });
 
                 checkIOOBE(() -> {
+                    boolean r = vh.weakCompareAndSetVolatile(array, ci, VALUE_1, VALUE_2);
+                });
+
+                checkIOOBE(() -> {
                     boolean r = vh.weakCompareAndSetAcquire(array, ci, VALUE_1, VALUE_2);
                 });
 
@@ -487,6 +500,10 @@
                 });
 
                 checkISE(() -> {
+                    boolean r = vh.weakCompareAndSetVolatile(array, ci, VALUE_1, VALUE_2);
+                });
+
+                checkISE(() -> {
                     boolean r = vh.weakCompareAndSetAcquire(array, ci, VALUE_1, VALUE_2);
                 });
 
@@ -562,6 +579,10 @@
                     });
 
                     checkISE(() -> {
+                        boolean r = vh.weakCompareAndSetVolatile(array, ci, VALUE_1, VALUE_2);
+                    });
+
+                    checkISE(() -> {
                         boolean r = vh.weakCompareAndSetAcquire(array, ci, VALUE_1, VALUE_2);
                     });
 
@@ -699,12 +720,19 @@
                     assertEquals(x, VALUE_2, "weakCompareAndSetRelease double");
                 }
 
+                {
+                    boolean r = vh.weakCompareAndSetVolatile(array, i, VALUE_2, VALUE_1);
+                    assertEquals(r, true, "weakCompareAndSetVolatile double");
+                    double x = (double) vh.get(array, i);
+                    assertEquals(x, VALUE_1, "weakCompareAndSetVolatile double value");
+                }
+
                 // Compare set and get
                 {
-                    double o = (double) vh.getAndSet(array, i, VALUE_1);
-                    assertEquals(o, VALUE_2, "getAndSet double");
+                    double o = (double) vh.getAndSet(array, i, VALUE_2);
+                    assertEquals(o, VALUE_1, "getAndSet double");
                     double x = (double) vh.get(array, i);
-                    assertEquals(x, VALUE_1, "getAndSet double value");
+                    assertEquals(x, VALUE_2, "getAndSet double value");
                 }
 
             }
@@ -832,12 +860,19 @@
                     assertEquals(x, VALUE_2, "weakCompareAndSetRelease double");
                 }
 
+                {
+                    boolean r = vh.weakCompareAndSetVolatile(array, i, VALUE_2, VALUE_1);
+                    assertEquals(r, true, "weakCompareAndSetVolatile double");
+                    double x = (double) vh.get(array, i);
+                    assertEquals(x, VALUE_1, "weakCompareAndSetVolatile double value");
+                }
+
                 // Compare set and get
                 {
-                    double o = (double) vh.getAndSet(array, i, VALUE_1);
-                    assertEquals(o, VALUE_2, "getAndSet double");
+                    double o = (double) vh.getAndSet(array, i, VALUE_2);
+                    assertEquals(o, VALUE_1, "getAndSet double");
                     double x = (double) vh.get(array, i);
-                    assertEquals(x, VALUE_1, "getAndSet double value");
+                    assertEquals(x, VALUE_2, "getAndSet double value");
                 }
 
             }
--- a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsFloat.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsFloat.java	Tue May 03 12:25:20 2016 -0700
@@ -93,6 +93,7 @@
         assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.COMPARE_AND_EXCHANGE_ACQUIRE));
         assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.COMPARE_AND_EXCHANGE_RELEASE));
         assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET));
+        assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_VOLATILE));
         assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE));
         assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE));
         assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_SET));
@@ -239,6 +240,10 @@
             });
 
             checkROBE(() -> {
+                boolean r = vh.weakCompareAndSetVolatile(array, ci, VALUE_1, VALUE_2);
+            });
+
+            checkROBE(() -> {
                 boolean r = vh.weakCompareAndSetAcquire(array, ci, VALUE_1, VALUE_2);
             });
 
@@ -334,6 +339,10 @@
             });
 
             checkIOOBE(() -> {
+                boolean r = vh.weakCompareAndSetVolatile(array, ci, VALUE_1, VALUE_2);
+            });
+
+            checkIOOBE(() -> {
                 boolean r = vh.weakCompareAndSetAcquire(array, ci, VALUE_1, VALUE_2);
             });
 
@@ -415,6 +424,10 @@
                 });
 
                 checkIOOBE(() -> {
+                    boolean r = vh.weakCompareAndSetVolatile(array, ci, VALUE_1, VALUE_2);
+                });
+
+                checkIOOBE(() -> {
                     boolean r = vh.weakCompareAndSetAcquire(array, ci, VALUE_1, VALUE_2);
                 });
 
@@ -487,6 +500,10 @@
                 });
 
                 checkISE(() -> {
+                    boolean r = vh.weakCompareAndSetVolatile(array, ci, VALUE_1, VALUE_2);
+                });
+
+                checkISE(() -> {
                     boolean r = vh.weakCompareAndSetAcquire(array, ci, VALUE_1, VALUE_2);
                 });
 
@@ -562,6 +579,10 @@
                     });
 
                     checkISE(() -> {
+                        boolean r = vh.weakCompareAndSetVolatile(array, ci, VALUE_1, VALUE_2);
+                    });
+
+                    checkISE(() -> {
                         boolean r = vh.weakCompareAndSetAcquire(array, ci, VALUE_1, VALUE_2);
                     });
 
@@ -699,12 +720,19 @@
                     assertEquals(x, VALUE_2, "weakCompareAndSetRelease float");
                 }
 
+                {
+                    boolean r = vh.weakCompareAndSetVolatile(array, i, VALUE_2, VALUE_1);
+                    assertEquals(r, true, "weakCompareAndSetVolatile float");
+                    float x = (float) vh.get(array, i);
+                    assertEquals(x, VALUE_1, "weakCompareAndSetVolatile float value");
+                }
+
                 // Compare set and get
                 {
-                    float o = (float) vh.getAndSet(array, i, VALUE_1);
-                    assertEquals(o, VALUE_2, "getAndSet float");
+                    float o = (float) vh.getAndSet(array, i, VALUE_2);
+                    assertEquals(o, VALUE_1, "getAndSet float");
                     float x = (float) vh.get(array, i);
-                    assertEquals(x, VALUE_1, "getAndSet float value");
+                    assertEquals(x, VALUE_2, "getAndSet float value");
                 }
 
             }
@@ -832,12 +860,19 @@
                     assertEquals(x, VALUE_2, "weakCompareAndSetRelease float");
                 }
 
+                {
+                    boolean r = vh.weakCompareAndSetVolatile(array, i, VALUE_2, VALUE_1);
+                    assertEquals(r, true, "weakCompareAndSetVolatile float");
+                    float x = (float) vh.get(array, i);
+                    assertEquals(x, VALUE_1, "weakCompareAndSetVolatile float value");
+                }
+
                 // Compare set and get
                 {
-                    float o = (float) vh.getAndSet(array, i, VALUE_1);
-                    assertEquals(o, VALUE_2, "getAndSet float");
+                    float o = (float) vh.getAndSet(array, i, VALUE_2);
+                    assertEquals(o, VALUE_1, "getAndSet float");
                     float x = (float) vh.get(array, i);
-                    assertEquals(x, VALUE_1, "getAndSet float value");
+                    assertEquals(x, VALUE_2, "getAndSet float value");
                 }
 
             }
--- a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsInt.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsInt.java	Tue May 03 12:25:20 2016 -0700
@@ -38,10 +38,10 @@
 import java.nio.ByteOrder;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.EnumSet;
 import java.util.List;
 
-import static org.testng.Assert.assertEquals;
-import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.*;
 
 public class VarHandleTestByteArrayAsInt extends VarHandleBaseByteArrayTest {
     static final int SIZE = Integer.BYTES;
@@ -93,6 +93,7 @@
         assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.COMPARE_AND_EXCHANGE_ACQUIRE));
         assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.COMPARE_AND_EXCHANGE_RELEASE));
         assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET));
+        assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_VOLATILE));
         assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE));
         assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE));
         assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_SET));
@@ -232,6 +233,10 @@
             });
 
             checkROBE(() -> {
+                boolean r = vh.weakCompareAndSetVolatile(array, ci, VALUE_1, VALUE_2);
+            });
+
+            checkROBE(() -> {
                 boolean r = vh.weakCompareAndSetAcquire(array, ci, VALUE_1, VALUE_2);
             });
 
@@ -320,6 +325,10 @@
             });
 
             checkIOOBE(() -> {
+                boolean r = vh.weakCompareAndSetVolatile(array, ci, VALUE_1, VALUE_2);
+            });
+
+            checkIOOBE(() -> {
                 boolean r = vh.weakCompareAndSetAcquire(array, ci, VALUE_1, VALUE_2);
             });
 
@@ -408,6 +417,10 @@
                 });
 
                 checkIOOBE(() -> {
+                    boolean r = vh.weakCompareAndSetVolatile(array, ci, VALUE_1, VALUE_2);
+                });
+
+                checkIOOBE(() -> {
                     boolean r = vh.weakCompareAndSetAcquire(array, ci, VALUE_1, VALUE_2);
                 });
 
@@ -487,6 +500,10 @@
                 });
 
                 checkISE(() -> {
+                    boolean r = vh.weakCompareAndSetVolatile(array, ci, VALUE_1, VALUE_2);
+                });
+
+                checkISE(() -> {
                     boolean r = vh.weakCompareAndSetAcquire(array, ci, VALUE_1, VALUE_2);
                 });
 
@@ -569,6 +586,10 @@
                     });
 
                     checkISE(() -> {
+                        boolean r = vh.weakCompareAndSetVolatile(array, ci, VALUE_1, VALUE_2);
+                    });
+
+                    checkISE(() -> {
                         boolean r = vh.weakCompareAndSetAcquire(array, ci, VALUE_1, VALUE_2);
                     });
 
@@ -713,12 +734,19 @@
                     assertEquals(x, VALUE_2, "weakCompareAndSetRelease int");
                 }
 
+                {
+                    boolean r = vh.weakCompareAndSetVolatile(array, i, VALUE_2, VALUE_1);
+                    assertEquals(r, true, "weakCompareAndSetVolatile int");
+                    int x = (int) vh.get(array, i);
+                    assertEquals(x, VALUE_1, "weakCompareAndSetVolatile int value");
+                }
+
                 // Compare set and get
                 {
-                    int o = (int) vh.getAndSet(array, i, VALUE_1);
-                    assertEquals(o, VALUE_2, "getAndSet int");
+                    int o = (int) vh.getAndSet(array, i, VALUE_2);
+                    assertEquals(o, VALUE_1, "getAndSet int");
                     int x = (int) vh.get(array, i);
-                    assertEquals(x, VALUE_1, "getAndSet int value");
+                    assertEquals(x, VALUE_2, "getAndSet int value");
                 }
 
                 vh.set(array, i, VALUE_1);
@@ -855,12 +883,19 @@
                     assertEquals(x, VALUE_2, "weakCompareAndSetRelease int");
                 }
 
+                {
+                    boolean r = vh.weakCompareAndSetVolatile(array, i, VALUE_2, VALUE_1);
+                    assertEquals(r, true, "weakCompareAndSetVolatile int");
+                    int x = (int) vh.get(array, i);
+                    assertEquals(x, VALUE_1, "weakCompareAndSetVolatile int value");
+                }
+
                 // Compare set and get
                 {
-                    int o = (int) vh.getAndSet(array, i, VALUE_1);
-                    assertEquals(o, VALUE_2, "getAndSet int");
+                    int o = (int) vh.getAndSet(array, i, VALUE_2);
+                    assertEquals(o, VALUE_1, "getAndSet int");
                     int x = (int) vh.get(array, i);
-                    assertEquals(x, VALUE_1, "getAndSet int value");
+                    assertEquals(x, VALUE_2, "getAndSet int value");
                 }
 
                 vh.set(array, i, VALUE_1);
--- a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsLong.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsLong.java	Tue May 03 12:25:20 2016 -0700
@@ -93,6 +93,7 @@
         assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.COMPARE_AND_EXCHANGE_ACQUIRE));
         assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.COMPARE_AND_EXCHANGE_RELEASE));
         assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET));
+        assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_VOLATILE));
         assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE));
         assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE));
         assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_SET));
@@ -232,6 +233,10 @@
             });
 
             checkROBE(() -> {
+                boolean r = vh.weakCompareAndSetVolatile(array, ci, VALUE_1, VALUE_2);
+            });
+
+            checkROBE(() -> {
                 boolean r = vh.weakCompareAndSetAcquire(array, ci, VALUE_1, VALUE_2);
             });
 
@@ -320,6 +325,10 @@
             });
 
             checkIOOBE(() -> {
+                boolean r = vh.weakCompareAndSetVolatile(array, ci, VALUE_1, VALUE_2);
+            });
+
+            checkIOOBE(() -> {
                 boolean r = vh.weakCompareAndSetAcquire(array, ci, VALUE_1, VALUE_2);
             });
 
@@ -408,6 +417,10 @@
                 });
 
                 checkIOOBE(() -> {
+                    boolean r = vh.weakCompareAndSetVolatile(array, ci, VALUE_1, VALUE_2);
+                });
+
+                checkIOOBE(() -> {
                     boolean r = vh.weakCompareAndSetAcquire(array, ci, VALUE_1, VALUE_2);
                 });
 
@@ -487,6 +500,10 @@
                 });
 
                 checkISE(() -> {
+                    boolean r = vh.weakCompareAndSetVolatile(array, ci, VALUE_1, VALUE_2);
+                });
+
+                checkISE(() -> {
                     boolean r = vh.weakCompareAndSetAcquire(array, ci, VALUE_1, VALUE_2);
                 });
 
@@ -569,6 +586,10 @@
                     });
 
                     checkISE(() -> {
+                        boolean r = vh.weakCompareAndSetVolatile(array, ci, VALUE_1, VALUE_2);
+                    });
+
+                    checkISE(() -> {
                         boolean r = vh.weakCompareAndSetAcquire(array, ci, VALUE_1, VALUE_2);
                     });
 
@@ -713,12 +734,19 @@
                     assertEquals(x, VALUE_2, "weakCompareAndSetRelease long");
                 }
 
+                {
+                    boolean r = vh.weakCompareAndSetVolatile(array, i, VALUE_2, VALUE_1);
+                    assertEquals(r, true, "weakCompareAndSetVolatile long");
+                    long x = (long) vh.get(array, i);
+                    assertEquals(x, VALUE_1, "weakCompareAndSetVolatile long value");
+                }
+
                 // Compare set and get
                 {
-                    long o = (long) vh.getAndSet(array, i, VALUE_1);
-                    assertEquals(o, VALUE_2, "getAndSet long");
+                    long o = (long) vh.getAndSet(array, i, VALUE_2);
+                    assertEquals(o, VALUE_1, "getAndSet long");
                     long x = (long) vh.get(array, i);
-                    assertEquals(x, VALUE_1, "getAndSet long value");
+                    assertEquals(x, VALUE_2, "getAndSet long value");
                 }
 
                 vh.set(array, i, VALUE_1);
@@ -855,12 +883,19 @@
                     assertEquals(x, VALUE_2, "weakCompareAndSetRelease long");
                 }
 
+                {
+                    boolean r = vh.weakCompareAndSetVolatile(array, i, VALUE_2, VALUE_1);
+                    assertEquals(r, true, "weakCompareAndSetVolatile long");
+                    long x = (long) vh.get(array, i);
+                    assertEquals(x, VALUE_1, "weakCompareAndSetVolatile long value");
+                }
+
                 // Compare set and get
                 {
-                    long o = (long) vh.getAndSet(array, i, VALUE_1);
-                    assertEquals(o, VALUE_2, "getAndSet long");
+                    long o = (long) vh.getAndSet(array, i, VALUE_2);
+                    assertEquals(o, VALUE_1, "getAndSet long");
                     long x = (long) vh.get(array, i);
-                    assertEquals(x, VALUE_1, "getAndSet long value");
+                    assertEquals(x, VALUE_2, "getAndSet long value");
                 }
 
                 vh.set(array, i, VALUE_1);
--- a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsShort.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsShort.java	Tue May 03 12:25:20 2016 -0700
@@ -93,6 +93,7 @@
         assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.COMPARE_AND_EXCHANGE_ACQUIRE));
         assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.COMPARE_AND_EXCHANGE_RELEASE));
         assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET));
+        assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_VOLATILE));
         assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE));
         assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE));
         assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_SET));
@@ -204,6 +205,10 @@
         });
 
         checkUOE(() -> {
+            boolean r = vh.weakCompareAndSetVolatile(array, ci, VALUE_1, VALUE_2);
+        });
+
+        checkUOE(() -> {
             boolean r = vh.weakCompareAndSetAcquire(array, ci, VALUE_1, VALUE_2);
         });
 
@@ -265,6 +270,10 @@
             });
 
             checkUOE(() -> {
+                boolean r = vh.weakCompareAndSetVolatile(array, ci, VALUE_1, VALUE_2);
+            });
+
+            checkUOE(() -> {
                 boolean r = vh.weakCompareAndSetAcquire(array, ci, VALUE_1, VALUE_2);
             });
 
@@ -306,6 +315,10 @@
             });
 
             checkUOE(() -> {
+                boolean r = vh.weakCompareAndSetVolatile(array, ci, VALUE_1, VALUE_2);
+            });
+
+            checkUOE(() -> {
                 boolean r = vh.weakCompareAndSetAcquire(array, ci, VALUE_1, VALUE_2);
             });
 
--- a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessInt.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessInt.java	Tue May 03 12:25:20 2016 -0700
@@ -228,12 +228,19 @@
             assertEquals(x, 2, "weakCompareAndSetRelease int");
         }
 
+        {
+            boolean r = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_VOLATILE).invokeExact(recv, 2, 1);
+            assertEquals(r, true, "weakCompareAndSetVolatile int");
+            int x = (int) hs.get(TestAccessMode.GET).invokeExact(recv);
+            assertEquals(x, 1, "weakCompareAndSetVolatile int value");
+        }
+
         // Compare set and get
         {
-            int o = (int) hs.get(TestAccessMode.GET_AND_SET).invokeExact(recv, 1);
-            assertEquals(o, 2, "getAndSet int");
+            int o = (int) hs.get(TestAccessMode.GET_AND_SET).invokeExact(recv, 2);
+            assertEquals(o, 1, "getAndSet int");
             int x = (int) hs.get(TestAccessMode.GET).invokeExact(recv);
-            assertEquals(x, 1, "getAndSet int value");
+            assertEquals(x, 2, "getAndSet int value");
         }
 
         hs.get(TestAccessMode.SET).invokeExact(recv, 1);
@@ -356,18 +363,25 @@
         }
 
         {
-            boolean r = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE).invokeExact( 1, 2);
+            boolean r = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE).invokeExact(1, 2);
             assertEquals(r, true, "weakCompareAndSetRelease int");
             int x = (int) hs.get(TestAccessMode.GET).invokeExact();
             assertEquals(x, 2, "weakCompareAndSetRelease int");
         }
 
+        {
+            boolean r = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_VOLATILE).invokeExact(2, 1);
+            assertEquals(r, true, "weakCompareAndSetVolatile int");
+            int x = (int) hs.get(TestAccessMode.GET).invokeExact();
+            assertEquals(x, 1, "weakCompareAndSetVolatile int value");
+        }
+
         // Compare set and get
         {
-            int o = (int) hs.get(TestAccessMode.GET_AND_SET).invokeExact( 1);
-            assertEquals(o, 2, "getAndSet int");
+            int o = (int) hs.get(TestAccessMode.GET_AND_SET).invokeExact(2);
+            assertEquals(o, 1, "getAndSet int");
             int x = (int) hs.get(TestAccessMode.GET).invokeExact();
-            assertEquals(x, 1, "getAndSet int value");
+            assertEquals(x, 2, "getAndSet int value");
         }
 
         hs.get(TestAccessMode.SET).invokeExact(1);
@@ -499,12 +513,19 @@
                 assertEquals(x, 2, "weakCompareAndSetRelease int");
             }
 
+            {
+                boolean r = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_VOLATILE).invokeExact(array, i, 2, 1);
+                assertEquals(r, true, "weakCompareAndSetVolatile int");
+                int x = (int) hs.get(TestAccessMode.GET).invokeExact(array, i);
+                assertEquals(x, 1, "weakCompareAndSetVolatile int value");
+            }
+
             // Compare set and get
             {
-                int o = (int) hs.get(TestAccessMode.GET_AND_SET).invokeExact(array, i, 1);
-                assertEquals(o, 2, "getAndSet int");
+                int o = (int) hs.get(TestAccessMode.GET_AND_SET).invokeExact(array, i, 2);
+                assertEquals(o, 1, "getAndSet int");
                 int x = (int) hs.get(TestAccessMode.GET).invokeExact(array, i);
-                assertEquals(x, 1, "getAndSet int value");
+                assertEquals(x, 2, "getAndSet int value");
             }
 
             hs.get(TestAccessMode.SET).invokeExact(array, i, 1);
--- a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessLong.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessLong.java	Tue May 03 12:25:20 2016 -0700
@@ -228,12 +228,19 @@
             assertEquals(x, 2L, "weakCompareAndSetRelease long");
         }
 
+        {
+            boolean r = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_VOLATILE).invokeExact(recv, 2L, 1L);
+            assertEquals(r, true, "weakCompareAndSetVolatile long");
+            long x = (long) hs.get(TestAccessMode.GET).invokeExact(recv);
+            assertEquals(x, 1L, "weakCompareAndSetVolatile long value");
+        }
+
         // Compare set and get
         {
-            long o = (long) hs.get(TestAccessMode.GET_AND_SET).invokeExact(recv, 1L);
-            assertEquals(o, 2L, "getAndSet long");
+            long o = (long) hs.get(TestAccessMode.GET_AND_SET).invokeExact(recv, 2L);
+            assertEquals(o, 1L, "getAndSet long");
             long x = (long) hs.get(TestAccessMode.GET).invokeExact(recv);
-            assertEquals(x, 1L, "getAndSet long value");
+            assertEquals(x, 2L, "getAndSet long value");
         }
 
         hs.get(TestAccessMode.SET).invokeExact(recv, 1L);
@@ -356,18 +363,25 @@
         }
 
         {
-            boolean r = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE).invokeExact( 1L, 2L);
+            boolean r = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE).invokeExact(1L, 2L);
             assertEquals(r, true, "weakCompareAndSetRelease long");
             long x = (long) hs.get(TestAccessMode.GET).invokeExact();
             assertEquals(x, 2L, "weakCompareAndSetRelease long");
         }
 
+        {
+            boolean r = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_VOLATILE).invokeExact(2L, 1L);
+            assertEquals(r, true, "weakCompareAndSetVolatile long");
+            long x = (long) hs.get(TestAccessMode.GET).invokeExact();
+            assertEquals(x, 1L, "weakCompareAndSetVolatile long value");
+        }
+
         // Compare set and get
         {
-            long o = (long) hs.get(TestAccessMode.GET_AND_SET).invokeExact( 1L);
-            assertEquals(o, 2L, "getAndSet long");
+            long o = (long) hs.get(TestAccessMode.GET_AND_SET).invokeExact(2L);
+            assertEquals(o, 1L, "getAndSet long");
             long x = (long) hs.get(TestAccessMode.GET).invokeExact();
-            assertEquals(x, 1L, "getAndSet long value");
+            assertEquals(x, 2L, "getAndSet long value");
         }
 
         hs.get(TestAccessMode.SET).invokeExact(1L);
@@ -499,12 +513,19 @@
                 assertEquals(x, 2L, "weakCompareAndSetRelease long");
             }
 
+            {
+                boolean r = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_VOLATILE).invokeExact(array, i, 2L, 1L);
+                assertEquals(r, true, "weakCompareAndSetVolatile long");
+                long x = (long) hs.get(TestAccessMode.GET).invokeExact(array, i);
+                assertEquals(x, 1L, "weakCompareAndSetVolatile long value");
+            }
+
             // Compare set and get
             {
-                long o = (long) hs.get(TestAccessMode.GET_AND_SET).invokeExact(array, i, 1L);
-                assertEquals(o, 2L, "getAndSet long");
+                long o = (long) hs.get(TestAccessMode.GET_AND_SET).invokeExact(array, i, 2L);
+                assertEquals(o, 1L, "getAndSet long");
                 long x = (long) hs.get(TestAccessMode.GET).invokeExact(array, i);
-                assertEquals(x, 1L, "getAndSet long value");
+                assertEquals(x, 2L, "getAndSet long value");
             }
 
             hs.get(TestAccessMode.SET).invokeExact(array, i, 1L);
--- a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessString.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessString.java	Tue May 03 12:25:20 2016 -0700
@@ -228,12 +228,19 @@
             assertEquals(x, "bar", "weakCompareAndSetRelease String");
         }
 
+        {
+            boolean r = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_VOLATILE).invokeExact(recv, "bar", "foo");
+            assertEquals(r, true, "weakCompareAndSetVolatile String");
+            String x = (String) hs.get(TestAccessMode.GET).invokeExact(recv);
+            assertEquals(x, "foo", "weakCompareAndSetVolatile String value");
+        }
+
         // Compare set and get
         {
-            String o = (String) hs.get(TestAccessMode.GET_AND_SET).invokeExact(recv, "foo");
-            assertEquals(o, "bar", "getAndSet String");
+            String o = (String) hs.get(TestAccessMode.GET_AND_SET).invokeExact(recv, "bar");
+            assertEquals(o, "foo", "getAndSet String");
             String x = (String) hs.get(TestAccessMode.GET).invokeExact(recv);
-            assertEquals(x, "foo", "getAndSet String value");
+            assertEquals(x, "bar", "getAndSet String value");
         }
 
     }
@@ -352,18 +359,25 @@
         }
 
         {
-            boolean r = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE).invokeExact( "foo", "bar");
+            boolean r = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE).invokeExact("foo", "bar");
             assertEquals(r, true, "weakCompareAndSetRelease String");
             String x = (String) hs.get(TestAccessMode.GET).invokeExact();
             assertEquals(x, "bar", "weakCompareAndSetRelease String");
         }
 
+        {
+            boolean r = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_VOLATILE).invokeExact("bar", "foo");
+            assertEquals(r, true, "weakCompareAndSetVolatile String");
+            String x = (String) hs.get(TestAccessMode.GET).invokeExact();
+            assertEquals(x, "foo", "weakCompareAndSetVolatile String value");
+        }
+
         // Compare set and get
         {
-            String o = (String) hs.get(TestAccessMode.GET_AND_SET).invokeExact( "foo");
-            assertEquals(o, "bar", "getAndSet String");
+            String o = (String) hs.get(TestAccessMode.GET_AND_SET).invokeExact("bar");
+            assertEquals(o, "foo", "getAndSet String");
             String x = (String) hs.get(TestAccessMode.GET).invokeExact();
-            assertEquals(x, "foo", "getAndSet String value");
+            assertEquals(x, "bar", "getAndSet String value");
         }
 
     }
@@ -491,12 +505,19 @@
                 assertEquals(x, "bar", "weakCompareAndSetRelease String");
             }
 
+            {
+                boolean r = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_VOLATILE).invokeExact(array, i, "bar", "foo");
+                assertEquals(r, true, "weakCompareAndSetVolatile String");
+                String x = (String) hs.get(TestAccessMode.GET).invokeExact(array, i);
+                assertEquals(x, "foo", "weakCompareAndSetVolatile String value");
+            }
+
             // Compare set and get
             {
-                String o = (String) hs.get(TestAccessMode.GET_AND_SET).invokeExact(array, i, "foo");
-                assertEquals(o, "bar", "getAndSet String");
+                String o = (String) hs.get(TestAccessMode.GET_AND_SET).invokeExact(array, i, "bar");
+                assertEquals(o, "foo", "getAndSet String");
                 String x = (String) hs.get(TestAccessMode.GET).invokeExact(array, i);
-                assertEquals(x, "foo", "getAndSet String value");
+                assertEquals(x, "bar", "getAndSet String value");
             }
 
         }
--- a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestMethodTypeInt.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestMethodTypeInt.java	Tue May 03 12:25:20 2016 -0700
@@ -374,6 +374,32 @@
         });
 
 
+        // WeakCompareAndSetVolatile
+        // Incorrect argument types
+        checkNPE(() -> { // null receiver
+            boolean r = vh.weakCompareAndSetVolatile(null, 1, 1);
+        });
+        checkCCE(() -> { // receiver reference class
+            boolean r = vh.weakCompareAndSetVolatile(Void.class, 1, 1);
+        });
+        checkWMTE(() -> { // expected reference class
+            boolean r = vh.weakCompareAndSetVolatile(recv, Void.class, 1);
+        });
+        checkWMTE(() -> { // actual reference class
+            boolean r = vh.weakCompareAndSetVolatile(recv, 1, Void.class);
+        });
+        checkWMTE(() -> { // receiver primitive class
+            boolean r = vh.weakCompareAndSetVolatile(0, 1, 1);
+        });
+        // Incorrect arity
+        checkWMTE(() -> { // 0
+            boolean r = vh.weakCompareAndSetVolatile();
+        });
+        checkWMTE(() -> { // >
+            boolean r = vh.weakCompareAndSetVolatile(recv, 1, 1, Void.class);
+        });
+
+
         // WeakCompareAndSetAcquire
         // Incorrect argument types
         checkNPE(() -> { // null receiver
@@ -972,6 +998,23 @@
         });
 
 
+        // WeakCompareAndSetVolatile
+        // Incorrect argument types
+        checkWMTE(() -> { // expected reference class
+            boolean r = vh.weakCompareAndSetVolatile(Void.class, 1);
+        });
+        checkWMTE(() -> { // actual reference class
+            boolean r = vh.weakCompareAndSetVolatile(1, Void.class);
+        });
+        // Incorrect arity
+        checkWMTE(() -> { // 0
+            boolean r = vh.weakCompareAndSetVolatile();
+        });
+        checkWMTE(() -> { // >
+            boolean r = vh.weakCompareAndSetVolatile(1, 1, Void.class);
+        });
+
+
         // WeakCompareAndSetAcquire
         // Incorrect argument types
         checkWMTE(() -> { // expected reference class
@@ -1566,6 +1609,35 @@
         });
 
 
+        // WeakCompareAndSetVolatile
+        // Incorrect argument types
+        checkNPE(() -> { // null receiver
+            boolean r = vh.weakCompareAndSetVolatile(null, 0, 1, 1);
+        });
+        checkCCE(() -> { // receiver reference class
+            boolean r = vh.weakCompareAndSetVolatile(Void.class, 0, 1, 1);
+        });
+        checkWMTE(() -> { // expected reference class
+            boolean r = vh.weakCompareAndSetVolatile(array, 0, Void.class, 1);
+        });
+        checkWMTE(() -> { // actual reference class
+            boolean r = vh.weakCompareAndSetVolatile(array, 0, 1, Void.class);
+        });
+        checkWMTE(() -> { // receiver primitive class
+            boolean r = vh.weakCompareAndSetVolatile(0, 0, 1, 1);
+        });
+        checkWMTE(() -> { // index reference class
+            boolean r = vh.weakCompareAndSetVolatile(array, Void.class, 1, 1);
+        });
+        // Incorrect arity
+        checkWMTE(() -> { // 0
+            boolean r = vh.weakCompareAndSetVolatile();
+        });
+        checkWMTE(() -> { // >
+            boolean r = vh.weakCompareAndSetVolatile(array, 0, 1, 1, Void.class);
+        });
+
+
         // WeakCompareAndSetAcquire
         // Incorrect argument types
         checkNPE(() -> { // null receiver
--- a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestMethodTypeLong.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestMethodTypeLong.java	Tue May 03 12:25:20 2016 -0700
@@ -374,6 +374,32 @@
         });
 
 
+        // WeakCompareAndSetVolatile
+        // Incorrect argument types
+        checkNPE(() -> { // null receiver
+            boolean r = vh.weakCompareAndSetVolatile(null, 1L, 1L);
+        });
+        checkCCE(() -> { // receiver reference class
+            boolean r = vh.weakCompareAndSetVolatile(Void.class, 1L, 1L);
+        });
+        checkWMTE(() -> { // expected reference class
+            boolean r = vh.weakCompareAndSetVolatile(recv, Void.class, 1L);
+        });
+        checkWMTE(() -> { // actual reference class
+            boolean r = vh.weakCompareAndSetVolatile(recv, 1L, Void.class);
+        });
+        checkWMTE(() -> { // receiver primitive class
+            boolean r = vh.weakCompareAndSetVolatile(0, 1L, 1L);
+        });
+        // Incorrect arity
+        checkWMTE(() -> { // 0
+            boolean r = vh.weakCompareAndSetVolatile();
+        });
+        checkWMTE(() -> { // >
+            boolean r = vh.weakCompareAndSetVolatile(recv, 1L, 1L, Void.class);
+        });
+
+
         // WeakCompareAndSetAcquire
         // Incorrect argument types
         checkNPE(() -> { // null receiver
@@ -972,6 +998,23 @@
         });
 
 
+        // WeakCompareAndSetVolatile
+        // Incorrect argument types
+        checkWMTE(() -> { // expected reference class
+            boolean r = vh.weakCompareAndSetVolatile(Void.class, 1L);
+        });
+        checkWMTE(() -> { // actual reference class
+            boolean r = vh.weakCompareAndSetVolatile(1L, Void.class);
+        });
+        // Incorrect arity
+        checkWMTE(() -> { // 0
+            boolean r = vh.weakCompareAndSetVolatile();
+        });
+        checkWMTE(() -> { // >
+            boolean r = vh.weakCompareAndSetVolatile(1L, 1L, Void.class);
+        });
+
+
         // WeakCompareAndSetAcquire
         // Incorrect argument types
         checkWMTE(() -> { // expected reference class
@@ -1566,6 +1609,35 @@
         });
 
 
+        // WeakCompareAndSetVolatile
+        // Incorrect argument types
+        checkNPE(() -> { // null receiver
+            boolean r = vh.weakCompareAndSetVolatile(null, 0, 1L, 1L);
+        });
+        checkCCE(() -> { // receiver reference class
+            boolean r = vh.weakCompareAndSetVolatile(Void.class, 0, 1L, 1L);
+        });
+        checkWMTE(() -> { // expected reference class
+            boolean r = vh.weakCompareAndSetVolatile(array, 0, Void.class, 1L);
+        });
+        checkWMTE(() -> { // actual reference class
+            boolean r = vh.weakCompareAndSetVolatile(array, 0, 1L, Void.class);
+        });
+        checkWMTE(() -> { // receiver primitive class
+            boolean r = vh.weakCompareAndSetVolatile(0, 0, 1L, 1L);
+        });
+        checkWMTE(() -> { // index reference class
+            boolean r = vh.weakCompareAndSetVolatile(array, Void.class, 1L, 1L);
+        });
+        // Incorrect arity
+        checkWMTE(() -> { // 0
+            boolean r = vh.weakCompareAndSetVolatile();
+        });
+        checkWMTE(() -> { // >
+            boolean r = vh.weakCompareAndSetVolatile(array, 0, 1L, 1L, Void.class);
+        });
+
+
         // WeakCompareAndSetAcquire
         // Incorrect argument types
         checkNPE(() -> { // null receiver
--- a/jdk/test/java/lang/invoke/VarHandles/VarHandleTestMethodTypeString.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/test/java/lang/invoke/VarHandles/VarHandleTestMethodTypeString.java	Tue May 03 12:25:20 2016 -0700
@@ -374,6 +374,32 @@
         });
 
 
+        // WeakCompareAndSetVolatile
+        // Incorrect argument types
+        checkNPE(() -> { // null receiver
+            boolean r = vh.weakCompareAndSetVolatile(null, "foo", "foo");
+        });
+        checkCCE(() -> { // receiver reference class
+            boolean r = vh.weakCompareAndSetVolatile(Void.class, "foo", "foo");
+        });
+        checkCCE(() -> { // expected reference class
+            boolean r = vh.weakCompareAndSetVolatile(recv, Void.class, "foo");
+        });
+        checkCCE(() -> { // actual reference class
+            boolean r = vh.weakCompareAndSetVolatile(recv, "foo", Void.class);
+        });
+        checkWMTE(() -> { // receiver primitive class
+            boolean r = vh.weakCompareAndSetVolatile(0, "foo", "foo");
+        });
+        // Incorrect arity
+        checkWMTE(() -> { // 0
+            boolean r = vh.weakCompareAndSetVolatile();
+        });
+        checkWMTE(() -> { // >
+            boolean r = vh.weakCompareAndSetVolatile(recv, "foo", "foo", Void.class);
+        });
+
+
         // WeakCompareAndSetAcquire
         // Incorrect argument types
         checkNPE(() -> { // null receiver
@@ -878,6 +904,23 @@
         });
 
 
+        // WeakCompareAndSetVolatile
+        // Incorrect argument types
+        checkCCE(() -> { // expected reference class
+            boolean r = vh.weakCompareAndSetVolatile(Void.class, "foo");
+        });
+        checkCCE(() -> { // actual reference class
+            boolean r = vh.weakCompareAndSetVolatile("foo", Void.class);
+        });
+        // Incorrect arity
+        checkWMTE(() -> { // 0
+            boolean r = vh.weakCompareAndSetVolatile();
+        });
+        checkWMTE(() -> { // >
+            boolean r = vh.weakCompareAndSetVolatile("foo", "foo", Void.class);
+        });
+
+
         // WeakCompareAndSetAcquire
         // Incorrect argument types
         checkCCE(() -> { // expected reference class
@@ -1407,6 +1450,35 @@
         });
 
 
+        // WeakCompareAndSetVolatile
+        // Incorrect argument types
+        checkNPE(() -> { // null receiver
+            boolean r = vh.weakCompareAndSetVolatile(null, 0, "foo", "foo");
+        });
+        checkCCE(() -> { // receiver reference class
+            boolean r = vh.weakCompareAndSetVolatile(Void.class, 0, "foo", "foo");
+        });
+        checkCCE(() -> { // expected reference class
+            boolean r = vh.weakCompareAndSetVolatile(array, 0, Void.class, "foo");
+        });
+        checkCCE(() -> { // actual reference class
+            boolean r = vh.weakCompareAndSetVolatile(array, 0, "foo", Void.class);
+        });
+        checkWMTE(() -> { // receiver primitive class
+            boolean r = vh.weakCompareAndSetVolatile(0, 0, "foo", "foo");
+        });
+        checkWMTE(() -> { // index reference class
+            boolean r = vh.weakCompareAndSetVolatile(array, Void.class, "foo", "foo");
+        });
+        // Incorrect arity
+        checkWMTE(() -> { // 0
+            boolean r = vh.weakCompareAndSetVolatile();
+        });
+        checkWMTE(() -> { // >
+            boolean r = vh.weakCompareAndSetVolatile(array, 0, "foo", "foo", Void.class);
+        });
+
+
         // WeakCompareAndSetAcquire
         // Incorrect argument types
         checkNPE(() -> { // null receiver
--- a/jdk/test/java/lang/invoke/VarHandles/X-VarHandleTestAccess.java.template	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/test/java/lang/invoke/VarHandles/X-VarHandleTestAccess.java.template	Tue May 03 12:25:20 2016 -0700
@@ -105,6 +105,7 @@
         assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.COMPARE_AND_EXCHANGE_ACQUIRE));
         assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.COMPARE_AND_EXCHANGE_RELEASE));
         assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET));
+        assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_VOLATILE));
         assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE));
         assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE));
         assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_SET));
@@ -114,6 +115,7 @@
         assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.COMPARE_AND_EXCHANGE_ACQUIRE));
         assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.COMPARE_AND_EXCHANGE_RELEASE));
         assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET));
+        assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_VOLATILE));
         assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE));
         assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE));
         assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_SET));
@@ -297,6 +299,10 @@
         });
 
         checkUOE(() -> {
+            boolean r = vh.weakCompareAndSetVolatile(recv, $value1$, $value2$);
+        });
+
+        checkUOE(() -> {
             boolean r = vh.weakCompareAndSetAcquire(recv, $value1$, $value2$);
         });
 
@@ -383,6 +389,10 @@
         });
 
         checkUOE(() -> {
+            boolean r = vh.weakCompareAndSetVolatile($value1$, $value2$);
+        });
+
+        checkUOE(() -> {
             boolean r = vh.weakCompareAndSetAcquire($value1$, $value2$);
         });
 
@@ -514,12 +524,19 @@
             assertEquals(x, $value2$, "weakCompareAndSetRelease $type$");
         }
 
+        {
+            boolean r = vh.weakCompareAndSetVolatile(recv, $value2$, $value1$);
+            assertEquals(r, true, "weakCompareAndSetVolatile $type$");
+            $type$ x = ($type$) vh.get(recv);
+            assertEquals(x, $value1$, "weakCompareAndSetVolatile $type$ value");
+        }
+
         // Compare set and get
         {
-            $type$ o = ($type$) vh.getAndSet(recv, $value1$);
-            assertEquals(o, $value2$, "getAndSet $type$");
+            $type$ o = ($type$) vh.getAndSet(recv, $value2$);
+            assertEquals(o, $value1$, "getAndSet $type$");
             $type$ x = ($type$) vh.get(recv);
-            assertEquals(x, $value1$, "getAndSet $type$ value");
+            assertEquals(x, $value2$, "getAndSet $type$ value");
         }
 #end[CAS]
 
@@ -559,6 +576,10 @@
         });
 
         checkUOE(() -> {
+            boolean r = vh.weakCompareAndSetVolatile(recv, $value1$, $value2$);
+        });
+
+        checkUOE(() -> {
             boolean r = vh.weakCompareAndSetAcquire(recv, $value1$, $value2$);
         });
 
@@ -684,18 +705,25 @@
         }
 
         {
-            boolean r = (boolean) vh.weakCompareAndSetRelease( $value1$, $value2$);
+            boolean r = (boolean) vh.weakCompareAndSetRelease($value1$, $value2$);
             assertEquals(r, true, "weakCompareAndSetRelease $type$");
             $type$ x = ($type$) vh.get();
             assertEquals(x, $value2$, "weakCompareAndSetRelease $type$");
         }
 
+        {
+            boolean r = (boolean) vh.weakCompareAndSetVolatile($value2$, $value1$);
+            assertEquals(r, true, "weakCompareAndSetVolatile $type$");
+            $type$ x = ($type$) vh.get();
+            assertEquals(x, $value1$, "weakCompareAndSetVolatile $type$ value");
+        }
+
         // Compare set and get
         {
-            $type$ o = ($type$) vh.getAndSet( $value1$);
-            assertEquals(o, $value2$, "getAndSet $type$");
+            $type$ o = ($type$) vh.getAndSet( $value2$);
+            assertEquals(o, $value1$, "getAndSet $type$");
             $type$ x = ($type$) vh.get();
-            assertEquals(x, $value1$, "getAndSet $type$ value");
+            assertEquals(x, $value2$, "getAndSet $type$ value");
         }
 #end[CAS]
 
@@ -735,6 +763,10 @@
         });
 
         checkUOE(() -> {
+            boolean r = vh.weakCompareAndSetVolatile($value1$, $value2$);
+        });
+
+        checkUOE(() -> {
             boolean r = vh.weakCompareAndSetAcquire($value1$, $value2$);
         });
 
@@ -869,12 +901,19 @@
                 assertEquals(x, $value2$, "weakCompareAndSetRelease $type$");
             }
 
+            {
+                boolean r = vh.weakCompareAndSetVolatile(array, i, $value2$, $value1$);
+                assertEquals(r, true, "weakCompareAndSetVolatile $type$");
+                $type$ x = ($type$) vh.get(array, i);
+                assertEquals(x, $value1$, "weakCompareAndSetVolatile $type$ value");
+            }
+
             // Compare set and get
             {
-                $type$ o = ($type$) vh.getAndSet(array, i, $value1$);
-                assertEquals(o, $value2$, "getAndSet $type$");
+                $type$ o = ($type$) vh.getAndSet(array, i, $value2$);
+                assertEquals(o, $value1$, "getAndSet $type$");
                 $type$ x = ($type$) vh.get(array, i);
-                assertEquals(x, $value1$, "getAndSet $type$ value");
+                assertEquals(x, $value2$, "getAndSet $type$ value");
             }
 #end[CAS]
 
@@ -918,6 +957,10 @@
         });
 
         checkUOE(() -> {
+            boolean r = vh.weakCompareAndSetVolatile(array, i, $value1$, $value2$);
+        });
+
+        checkUOE(() -> {
             boolean r = vh.weakCompareAndSetAcquire(array, i, $value1$, $value2$);
         });
 
@@ -997,6 +1040,10 @@
             });
 
             checkIOOBE(() -> {
+                boolean r = vh.weakCompareAndSetVolatile(array, ci, $value1$, $value2$);
+            });
+
+            checkIOOBE(() -> {
                 boolean r = vh.weakCompareAndSetAcquire(array, ci, $value1$, $value2$);
             });
 
--- a/jdk/test/java/lang/invoke/VarHandles/X-VarHandleTestByteArrayView.java.template	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/test/java/lang/invoke/VarHandles/X-VarHandleTestByteArrayView.java.template	Tue May 03 12:25:20 2016 -0700
@@ -94,6 +94,7 @@
         assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.COMPARE_AND_EXCHANGE_ACQUIRE));
         assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.COMPARE_AND_EXCHANGE_RELEASE));
         assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET));
+        assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_VOLATILE));
         assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE));
         assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE));
         assertTrue(vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_SET));
@@ -103,6 +104,7 @@
         assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.COMPARE_AND_EXCHANGE_ACQUIRE));
         assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.COMPARE_AND_EXCHANGE_RELEASE));
         assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET));
+        assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_VOLATILE));
         assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_ACQUIRE));
         assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.WEAK_COMPARE_AND_SET_RELEASE));
         assertFalse(vh.isAccessModeSupported(VarHandle.AccessMode.GET_AND_SET));
@@ -221,6 +223,10 @@
         });
 
         checkUOE(() -> {
+            boolean r = vh.weakCompareAndSetVolatile(array, ci, VALUE_1, VALUE_2);
+        });
+
+        checkUOE(() -> {
             boolean r = vh.weakCompareAndSetAcquire(array, ci, VALUE_1, VALUE_2);
         });
 
@@ -291,6 +297,10 @@
             });
 
             checkROBE(() -> {
+                boolean r = vh.weakCompareAndSetVolatile(array, ci, VALUE_1, VALUE_2);
+            });
+
+            checkROBE(() -> {
                 boolean r = vh.weakCompareAndSetAcquire(array, ci, VALUE_1, VALUE_2);
             });
 
@@ -322,6 +332,10 @@
             });
 
             checkUOE(() -> {
+                boolean r = vh.weakCompareAndSetVolatile(array, ci, VALUE_1, VALUE_2);
+            });
+
+            checkUOE(() -> {
                 boolean r = vh.weakCompareAndSetAcquire(array, ci, VALUE_1, VALUE_2);
             });
 
@@ -375,6 +389,10 @@
             });
 
             checkUOE(() -> {
+                boolean r = vh.weakCompareAndSetVolatile(array, ci, VALUE_1, VALUE_2);
+            });
+
+            checkUOE(() -> {
                 boolean r = vh.weakCompareAndSetAcquire(array, ci, VALUE_1, VALUE_2);
             });
 
@@ -461,6 +479,10 @@
             });
 
             checkIOOBE(() -> {
+                boolean r = vh.weakCompareAndSetVolatile(array, ci, VALUE_1, VALUE_2);
+            });
+
+            checkIOOBE(() -> {
                 boolean r = vh.weakCompareAndSetAcquire(array, ci, VALUE_1, VALUE_2);
             });
 
@@ -553,6 +575,10 @@
                 });
 
                 checkIOOBE(() -> {
+                    boolean r = vh.weakCompareAndSetVolatile(array, ci, VALUE_1, VALUE_2);
+                });
+
+                checkIOOBE(() -> {
                     boolean r = vh.weakCompareAndSetAcquire(array, ci, VALUE_1, VALUE_2);
                 });
 
@@ -636,6 +662,10 @@
                 });
 
                 checkISE(() -> {
+                    boolean r = vh.weakCompareAndSetVolatile(array, ci, VALUE_1, VALUE_2);
+                });
+
+                checkISE(() -> {
                     boolean r = vh.weakCompareAndSetAcquire(array, ci, VALUE_1, VALUE_2);
                 });
 
@@ -722,6 +752,10 @@
                     });
 
                     checkISE(() -> {
+                        boolean r = vh.weakCompareAndSetVolatile(array, ci, VALUE_1, VALUE_2);
+                    });
+
+                    checkISE(() -> {
                         boolean r = vh.weakCompareAndSetAcquire(array, ci, VALUE_1, VALUE_2);
                     });
 
@@ -870,12 +904,19 @@
                     assertEquals(x, VALUE_2, "weakCompareAndSetRelease $type$");
                 }
 
+                {
+                    boolean r = vh.weakCompareAndSetVolatile(array, i, VALUE_2, VALUE_1);
+                    assertEquals(r, true, "weakCompareAndSetVolatile $type$");
+                    $type$ x = ($type$) vh.get(array, i);
+                    assertEquals(x, VALUE_1, "weakCompareAndSetVolatile $type$ value");
+                }
+
                 // Compare set and get
                 {
-                    $type$ o = ($type$) vh.getAndSet(array, i, VALUE_1);
-                    assertEquals(o, VALUE_2, "getAndSet $type$");
+                    $type$ o = ($type$) vh.getAndSet(array, i, VALUE_2);
+                    assertEquals(o, VALUE_1, "getAndSet $type$");
                     $type$ x = ($type$) vh.get(array, i);
-                    assertEquals(x, VALUE_1, "getAndSet $type$ value");
+                    assertEquals(x, VALUE_2, "getAndSet $type$ value");
                 }
 #end[CAS]
 
@@ -1016,12 +1057,19 @@
                     assertEquals(x, VALUE_2, "weakCompareAndSetRelease $type$");
                 }
 
+                {
+                    boolean r = vh.weakCompareAndSetVolatile(array, i, VALUE_2, VALUE_1);
+                    assertEquals(r, true, "weakCompareAndSetVolatile $type$");
+                    $type$ x = ($type$) vh.get(array, i);
+                    assertEquals(x, VALUE_1, "weakCompareAndSetVolatile $type$ value");
+                }
+
                 // Compare set and get
                 {
-                    $type$ o = ($type$) vh.getAndSet(array, i, VALUE_1);
-                    assertEquals(o, VALUE_2, "getAndSet $type$");
+                    $type$ o = ($type$) vh.getAndSet(array, i, VALUE_2);
+                    assertEquals(o, VALUE_1, "getAndSet $type$");
                     $type$ x = ($type$) vh.get(array, i);
-                    assertEquals(x, VALUE_1, "getAndSet $type$ value");
+                    assertEquals(x, VALUE_2, "getAndSet $type$ value");
                 }
 #end[CAS]
 
--- a/jdk/test/java/lang/invoke/VarHandles/X-VarHandleTestMethodHandleAccess.java.template	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/test/java/lang/invoke/VarHandles/X-VarHandleTestMethodHandleAccess.java.template	Tue May 03 12:25:20 2016 -0700
@@ -229,12 +229,19 @@
             assertEquals(x, $value2$, "weakCompareAndSetRelease $type$");
         }
 
+        {
+            boolean r = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_VOLATILE).invokeExact(recv, $value2$, $value1$);
+            assertEquals(r, true, "weakCompareAndSetVolatile $type$");
+            $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(recv);
+            assertEquals(x, $value1$, "weakCompareAndSetVolatile $type$ value");
+        }
+
         // Compare set and get
         {
-            $type$ o = ($type$) hs.get(TestAccessMode.GET_AND_SET).invokeExact(recv, $value1$);
-            assertEquals(o, $value2$, "getAndSet $type$");
+            $type$ o = ($type$) hs.get(TestAccessMode.GET_AND_SET).invokeExact(recv, $value2$);
+            assertEquals(o, $value1$, "getAndSet $type$");
             $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(recv);
-            assertEquals(x, $value1$, "getAndSet $type$ value");
+            assertEquals(x, $value2$, "getAndSet $type$ value");
         }
 #end[CAS]
 
@@ -387,18 +394,25 @@
         }
 
         {
-            boolean r = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE).invokeExact( $value1$, $value2$);
+            boolean r = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE).invokeExact($value1$, $value2$);
             assertEquals(r, true, "weakCompareAndSetRelease $type$");
             $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact();
             assertEquals(x, $value2$, "weakCompareAndSetRelease $type$");
         }
 
+        {
+            boolean r = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_VOLATILE).invokeExact($value2$, $value1$);
+            assertEquals(r, true, "weakCompareAndSetVolatile $type$");
+            $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact();
+            assertEquals(x, $value1$, "weakCompareAndSetVolatile $type$ value");
+        }
+
         // Compare set and get
         {
-            $type$ o = ($type$) hs.get(TestAccessMode.GET_AND_SET).invokeExact( $value1$);
-            assertEquals(o, $value2$, "getAndSet $type$");
+            $type$ o = ($type$) hs.get(TestAccessMode.GET_AND_SET).invokeExact($value2$);
+            assertEquals(o, $value1$, "getAndSet $type$");
             $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact();
-            assertEquals(x, $value1$, "getAndSet $type$ value");
+            assertEquals(x, $value2$, "getAndSet $type$ value");
         }
 #end[CAS]
 
@@ -560,12 +574,19 @@
                 assertEquals(x, $value2$, "weakCompareAndSetRelease $type$");
             }
 
+            {
+                boolean r = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_VOLATILE).invokeExact(array, i, $value2$, $value1$);
+                assertEquals(r, true, "weakCompareAndSetVolatile $type$");
+                $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(array, i);
+                assertEquals(x, $value1$, "weakCompareAndSetVolatile $type$ value");
+            }
+
             // Compare set and get
             {
-                $type$ o = ($type$) hs.get(TestAccessMode.GET_AND_SET).invokeExact(array, i, $value1$);
-                assertEquals(o, $value2$, "getAndSet $type$");
+                $type$ o = ($type$) hs.get(TestAccessMode.GET_AND_SET).invokeExact(array, i, $value2$);
+                assertEquals(o, $value1$, "getAndSet $type$");
                 $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(array, i);
-                assertEquals(x, $value1$, "getAndSet $type$ value");
+                assertEquals(x, $value2$, "getAndSet $type$ value");
             }
 #end[CAS]
 
--- a/jdk/test/java/lang/invoke/VarHandles/X-VarHandleTestMethodType.java.template	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/test/java/lang/invoke/VarHandles/X-VarHandleTestMethodType.java.template	Tue May 03 12:25:20 2016 -0700
@@ -375,6 +375,32 @@
         });
 
 
+        // WeakCompareAndSetVolatile
+        // Incorrect argument types
+        checkNPE(() -> { // null receiver
+            boolean r = vh.weakCompareAndSetVolatile(null, $value1$, $value1$);
+        });
+        checkCCE(() -> { // receiver reference class
+            boolean r = vh.weakCompareAndSetVolatile(Void.class, $value1$, $value1$);
+        });
+        check{#if[String]?CCE:WMTE}(() -> { // expected reference class
+            boolean r = vh.weakCompareAndSetVolatile(recv, Void.class, $value1$);
+        });
+        check{#if[String]?CCE:WMTE}(() -> { // actual reference class
+            boolean r = vh.weakCompareAndSetVolatile(recv, $value1$, Void.class);
+        });
+        checkWMTE(() -> { // receiver primitive class
+            boolean r = vh.weakCompareAndSetVolatile(0, $value1$, $value1$);
+        });
+        // Incorrect arity
+        checkWMTE(() -> { // 0
+            boolean r = vh.weakCompareAndSetVolatile();
+        });
+        checkWMTE(() -> { // >
+            boolean r = vh.weakCompareAndSetVolatile(recv, $value1$, $value1$, Void.class);
+        });
+
+
         // WeakCompareAndSetAcquire
         // Incorrect argument types
         checkNPE(() -> { // null receiver
@@ -981,6 +1007,23 @@
         });
 
 
+        // WeakCompareAndSetVolatile
+        // Incorrect argument types
+        check{#if[String]?CCE:WMTE}(() -> { // expected reference class
+            boolean r = vh.weakCompareAndSetVolatile(Void.class, $value1$);
+        });
+        check{#if[String]?CCE:WMTE}(() -> { // actual reference class
+            boolean r = vh.weakCompareAndSetVolatile($value1$, Void.class);
+        });
+        // Incorrect arity
+        checkWMTE(() -> { // 0
+            boolean r = vh.weakCompareAndSetVolatile();
+        });
+        checkWMTE(() -> { // >
+            boolean r = vh.weakCompareAndSetVolatile($value1$, $value1$, Void.class);
+        });
+
+
         // WeakCompareAndSetAcquire
         // Incorrect argument types
         check{#if[String]?CCE:WMTE}(() -> { // expected reference class
@@ -1583,6 +1626,35 @@
         });
 
 
+        // WeakCompareAndSetVolatile
+        // Incorrect argument types
+        checkNPE(() -> { // null receiver
+            boolean r = vh.weakCompareAndSetVolatile(null, 0, $value1$, $value1$);
+        });
+        checkCCE(() -> { // receiver reference class
+            boolean r = vh.weakCompareAndSetVolatile(Void.class, 0, $value1$, $value1$);
+        });
+        check{#if[String]?CCE:WMTE}(() -> { // expected reference class
+            boolean r = vh.weakCompareAndSetVolatile(array, 0, Void.class, $value1$);
+        });
+        check{#if[String]?CCE:WMTE}(() -> { // actual reference class
+            boolean r = vh.weakCompareAndSetVolatile(array, 0, $value1$, Void.class);
+        });
+        checkWMTE(() -> { // receiver primitive class
+            boolean r = vh.weakCompareAndSetVolatile(0, 0, $value1$, $value1$);
+        });
+        checkWMTE(() -> { // index reference class
+            boolean r = vh.weakCompareAndSetVolatile(array, Void.class, $value1$, $value1$);
+        });
+        // Incorrect arity
+        checkWMTE(() -> { // 0
+            boolean r = vh.weakCompareAndSetVolatile();
+        });
+        checkWMTE(() -> { // >
+            boolean r = vh.weakCompareAndSetVolatile(array, 0, $value1$, $value1$, Void.class);
+        });
+
+
         // WeakCompareAndSetAcquire
         // Incorrect argument types
         checkNPE(() -> { // null receiver
--- a/jdk/test/java/lang/invoke/VarargsArrayTest.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/test/java/lang/invoke/VarargsArrayTest.java	Tue May 03 12:25:20 2016 -0700
@@ -37,7 +37,7 @@
  * @library /lib/testlibrary /lib/testlibrary/jsr292
  * @compile/module=java.base java/lang/invoke/MethodHandleHelper.java
  * @run main/bootclasspath VarargsArrayTest
- * @run main/bootclasspath -DVarargsArrayTest.MAX_ARITY=255 -DVarargsArrayTest.START_ARITY=250
+ * @run main/bootclasspath/othervm -DVarargsArrayTest.MAX_ARITY=255 -DVarargsArrayTest.START_ARITY=250
  *                         VarargsArrayTest
  */
 
--- a/jdk/test/java/lang/module/ModuleFinderTest.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/test/java/lang/module/ModuleFinderTest.java	Tue May 03 12:25:20 2016 -0700
@@ -340,7 +340,7 @@
      */
     public void testOfWithUnrecognizedEntry() throws Exception {
         Path dir = Files.createTempDirectory(USER_DIR, "mods");
-        Path mod = Files.createTempFile(dir, "m", "mod");
+        Path mod = Files.createTempFile(dir, "m", ".junk");
 
         ModuleFinder finder = ModuleFinder.of(mod);
         try {
@@ -361,6 +361,48 @@
 
 
     /**
+     * Test ModuleFinder.of with a file path to a directory containing a file
+     * that will not be recognized as a module.
+     */
+    public void testOfWithUnrecognizedEntryInDirectory() throws Exception {
+        Path dir = Files.createTempDirectory(USER_DIR, "mods");
+        Files.createTempFile(dir, "m", ".junk");
+
+        ModuleFinder finder = ModuleFinder.of(dir);
+        try {
+            finder.find("java.rhubarb");
+            assertTrue(false);
+        } catch (FindException e) {
+            // expected
+        }
+
+        finder = ModuleFinder.of(dir);
+        try {
+            finder.findAll();
+            assertTrue(false);
+        } catch (FindException e) {
+            // expected
+        }
+    }
+
+
+    /**
+     * Test ModuleFinder.of with a file path to a directory containing a file
+     * starting with ".", the file should be ignored.
+     */
+    public void testOfWithHiddenEntryInDirectory() throws Exception {
+        Path dir = Files.createTempDirectory(USER_DIR, "mods");
+        Files.createTempFile(dir, ".marker", "");
+
+        ModuleFinder finder = ModuleFinder.of(dir);
+        assertFalse(finder.find("java.rhubarb").isPresent());
+
+        finder = ModuleFinder.of(dir);
+        assertTrue(finder.findAll().isEmpty());
+    }
+
+
+    /**
      * Test ModuleFinder.of with a directory that contains two
      * versions of the same module
      */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/reflect/WeakPairMap/Driver.java	Tue May 03 12:25:20 2016 -0700
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @bug 8888888
+ * @summary Functional test for WeakPairMap
+ * @build java.base/java.lang.reflect.WeakPairMapTest
+ * @run main Driver
+ */
+public class Driver {
+    public static void main(String[] args) {
+        java.lang.reflect.WeakPairMapTest.main(args);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/reflect/WeakPairMap/java.base/java/lang/reflect/WeakPairMapTest.java	Tue May 03 12:25:20 2016 -0700
@@ -0,0 +1,175 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.reflect;
+
+import java.lang.ref.Reference;
+import java.util.Objects;
+
+/**
+ * Functional test for WeakPairMap
+ *
+ * @author Peter Levart
+ */
+public class WeakPairMapTest {
+    public static void main(String[] args) {
+        WeakPairMap<Object, Object, String> pm = new WeakPairMap<>();
+        Object key1 = new Object();
+        Object key2 = new Object();
+
+        // check for emptiness
+        assertEquals(pm.containsKeyPair(key1, key2), false);
+        assertEquals(pm.get(key1, key2), null);
+
+        // check for NPE(s)
+        for (Object k1 : new Object[]{null, key1}) {
+            for (Object k2 : new Object[]{null, key2}) {
+                for (String v : new String[]{null, "abc"}) {
+
+                    if (k1 != null && k2 != null && v != null) {
+                        // skip non-null args
+                        continue;
+                    }
+
+                    try {
+                        pm.put(k1, k2, v);
+                        throw new AssertionError("Unexpected code path, k1=" +
+                                                 k1 + ", k2=" + k2 + ", v=" + v);
+                    } catch (NullPointerException e) {
+                        // expected
+                    }
+
+                    try {
+                        pm.putIfAbsent(k1, k2, v);
+                        throw new AssertionError("Unexpected code path, k1=" +
+                                                 k1 + ", k2=" + k2 + ", v=" + v);
+                    } catch (NullPointerException e) {
+                        // expected
+                    }
+
+                    if (k1 != null && k2 != null) {
+                        // skip non-null args
+                        continue;
+                    }
+
+                    try {
+                        pm.computeIfAbsent(k1, k2, (_k1, _k2) -> v);
+                        throw new AssertionError("Unexpected code path, k1=" +
+                                                 k1 + ", k2=" + k2 + ", v=" + v);
+                    } catch (NullPointerException e) {
+                        // expected
+                    }
+
+                    try {
+                        pm.containsKeyPair(k1, k2);
+                        throw new AssertionError("Unexpected code path, k1=" +
+                                                 k1 + ", k2=" + k2);
+                    } catch (NullPointerException e) {
+                        // expected
+                    }
+
+                    try {
+                        pm.get(k1, k2);
+                        throw new AssertionError("Unexpected code path, k1=" +
+                                                 k1 + ", k2=" + k2);
+                    } catch (NullPointerException e) {
+                        // expected
+                    }
+                }
+            }
+        }
+
+        // how much to wait when it is expected for entry to be retained
+        final long retentionTimeout = 500L;
+        // how much to wait when it is expected for entry to be removed
+        final long cleanupTimeout = 30_000L;
+
+        // check insertion
+        assertEquals(pm.putIfAbsent(key1, key2, "abc"), null);
+        assertEquals(pm.get(key1, key2), "abc");
+
+        // check retention while both keys are still reachable
+        assertEquals(gcAndWaitRemoved(pm, "abc", retentionTimeout), false);
+        assertEquals(pm.get(key1, key2), "abc");
+
+        // check cleanup when both keys are unreachable
+        key1 = null;
+        key2 = null;
+        assertEquals(gcAndWaitRemoved(pm, "abc", cleanupTimeout), true);
+
+        // new insertion
+        key1 = new Object();
+        key2 = new Object();
+        assertEquals(pm.putIfAbsent(key1, key2, "abc"), null);
+        assertEquals(pm.get(key1, key2), "abc");
+
+        // check retention while both keys are still reachable
+        assertEquals(gcAndWaitRemoved(pm, "abc", retentionTimeout), false);
+        assertEquals(pm.get(key1, key2), "abc");
+
+        // check cleanup when 1st key is unreachable
+        key1 = null;
+        assertEquals(gcAndWaitRemoved(pm, "abc", cleanupTimeout), true);
+        Reference.reachabilityFence(key2);
+
+        // new insertion
+        key1 = new Object();
+        key2 = new Object();
+        assertEquals(pm.putIfAbsent(key1, key2, "abc"), null);
+        assertEquals(pm.get(key1, key2), "abc");
+
+        // check retention while both keys are still reachable
+        assertEquals(gcAndWaitRemoved(pm, "abc", retentionTimeout), false);
+        assertEquals(pm.get(key1, key2), "abc");
+
+        // check cleanup when 2nd key is unreachable
+        key2 = null;
+        assertEquals(gcAndWaitRemoved(pm, "abc", cleanupTimeout), true);
+        Reference.reachabilityFence(key1);
+    }
+
+    /**
+     * Trigger GC and wait for at most {@code millis} ms for given value to
+     * be removed from given WeakPairMap.
+     *
+     * @return true if element has been removed or false if not
+     */
+    static <V> boolean gcAndWaitRemoved(WeakPairMap<?, ?, V> pm, V value,
+                                        long millis) {
+        System.gc();
+        for (int i = 0; i < (millis + 99) / 100 && pm.values().contains(value); i++) {
+            try {
+                Thread.sleep(100L);
+            } catch (InterruptedException e) {
+                throw new AssertionError("Interrupted");
+            }
+        }
+        return !pm.values().contains(value);
+    }
+
+    static void assertEquals(Object actual, Object expected) {
+        if (!Objects.equals(actual, expected)) {
+            throw new AssertionError("Expected: " + expected + ", actual: " + actual);
+        }
+    }
+}
--- a/jdk/test/java/net/httpclient/APIErrors.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/test/java/net/httpclient/APIErrors.java	Tue May 03 12:25:20 2016 -0700
@@ -26,6 +26,7 @@
  * @bug 8087112
  * @library /lib/testlibrary/
  * @build jdk.testlibrary.SimpleSSLContext ProxyServer
+ * @build TestKit
  * @compile ../../../com/sun/net/httpserver/LogFilter.java
  * @compile ../../../com/sun/net/httpserver/FileServerHandler.java
  * @run main/othervm APIErrors
@@ -73,26 +74,6 @@
         }
     }
 
-    static void reject(Runnable r, Class<? extends Exception> extype) {
-        try {
-            r.run();
-            throw new RuntimeException("Expected: " + extype);
-        } catch (Throwable t) {
-            if (!extype.isAssignableFrom(t.getClass())) {
-                throw new RuntimeException("Wrong exception type: " + extype + " / "
-                    +t.getClass());
-            }
-        }
-    }
-
-    static void accept(Runnable r) {
-        try {
-            r.run();
-        } catch (Throwable t) {
-            throw new RuntimeException("Unexpected exception: " + t);
-        }
-    }
-
     static void checkNonNull(Supplier<?> r) {
         if (r.get() == null)
             throw new RuntimeException("Unexpected null return:");
@@ -108,12 +89,14 @@
         System.out.println("Test 1");
         HttpClient.Builder cb = HttpClient.create();
         InetSocketAddress addr = new InetSocketAddress("127.0.0.1", 5000);
-        reject(() -> { cb.priority(-1);}, IllegalArgumentException.class);
-        reject(() -> { cb.priority(500);}, IllegalArgumentException.class);
-        accept(() -> { cb.priority(1);});
-        accept(() -> { cb.priority(255);});
-
-        accept(() -> {clients.add(cb.build()); clients.add(cb.build());});
+        TestKit.assertThrows(IllegalArgumentException.class, () -> cb.priority(-1));
+        TestKit.assertThrows(IllegalArgumentException.class, () -> cb.priority(500));
+        TestKit.assertNotThrows(() -> cb.priority(1));
+        TestKit.assertNotThrows(() -> cb.priority(255));
+        TestKit.assertNotThrows(() -> {
+            clients.add(cb.build());
+            clients.add(cb.build());
+        });
     }
 
     static void test2() throws Exception {
@@ -139,7 +122,7 @@
 
     static void test3() throws Exception {
         System.out.println("Test 3");
-        reject(()-> {
+        TestKit.assertThrows(IllegalStateException.class, ()-> {
             try {
                 HttpRequest r1 = request();
                 HttpResponse resp = r1.response();
@@ -147,9 +130,9 @@
             } catch (IOException |InterruptedException e) {
                 throw new RuntimeException(e);
             }
-        }, IllegalStateException.class);
+        });
 
-        reject(()-> {
+        TestKit.assertThrows(IllegalStateException.class, ()-> {
             try {
                 HttpRequest r1 = request();
                 HttpResponse resp = r1.response();
@@ -157,8 +140,8 @@
             } catch (IOException |InterruptedException | ExecutionException e) {
                 throw new RuntimeException(e);
             }
-        }, IllegalStateException.class);
-        reject(()-> {
+        });
+        TestKit.assertThrows(IllegalStateException.class, ()-> {
             try {
                 HttpRequest r1 = request();
                 HttpResponse resp1 = r1.responseAsync().get();
@@ -166,7 +149,7 @@
             } catch (IOException |InterruptedException | ExecutionException e) {
                 throw new RuntimeException(e);
             }
-        }, IllegalStateException.class);
+        });
     }
 
     static class Auth extends java.net.Authenticator {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/httpclient/EchoHandler.java	Tue May 03 12:25:20 2016 -0700
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import com.sun.net.httpserver.*;
+import java.net.*;
+import java.net.http.*;
+import java.io.*;
+import java.util.concurrent.*;
+import javax.net.ssl.*;
+import java.nio.file.*;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Random;
+import jdk.testlibrary.SimpleSSLContext;
+import static java.net.http.HttpRequest.*;
+import static java.net.http.HttpResponse.*;
+import java.util.logging.ConsoleHandler;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+public class EchoHandler implements HttpHandler {
+    public EchoHandler() {}
+
+    @Override
+    public void handle(HttpExchange t)
+            throws IOException {
+        try {
+            System.err.println("EchoHandler received request to " + t.getRequestURI());
+            InputStream is = t.getRequestBody();
+            Headers map = t.getRequestHeaders();
+            Headers map1 = t.getResponseHeaders();
+            map1.add("X-Hello", "world");
+            map1.add("X-Bye", "universe");
+            String fixedrequest = map.getFirst("XFixed");
+            File outfile = File.createTempFile("foo", "bar");
+            FileOutputStream fos = new FileOutputStream(outfile);
+            int count = (int) is.transferTo(fos);
+            is.close();
+            fos.close();
+            InputStream is1 = new FileInputStream(outfile);
+            OutputStream os = null;
+            // return the number of bytes received (no echo)
+            String summary = map.getFirst("XSummary");
+            if (fixedrequest != null && summary == null) {
+                t.sendResponseHeaders(200, count);
+                os = t.getResponseBody();
+                is1.transferTo(os);
+            } else {
+                t.sendResponseHeaders(200, 0);
+                os = t.getResponseBody();
+                is1.transferTo(os);
+
+                if (summary != null) {
+                    String s = Integer.toString(count);
+                    os.write(s.getBytes());
+                }
+            }
+            outfile.delete();
+            os.close();
+            is1.close();
+        } catch (Throwable e) {
+            e.printStackTrace();
+            throw new IOException(e);
+        }
+    }
+}
--- a/jdk/test/java/net/httpclient/LightWeightHttpServer.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/test/java/net/httpclient/LightWeightHttpServer.java	Tue May 03 12:25:20 2016 -0700
@@ -22,10 +22,10 @@
  */
 
 /**
- * @library /lib/testlibrary/
- * @build jdk.testlibrary.SimpleSSLContext ProxyServer
- * @compile ../../../com/sun/net/httpserver/LogFilter.java
- * @compile ../../../com/sun/net/httpserver/FileServerHandler.java
+ * library /lib/testlibrary/ /
+ * build jdk.testlibrary.SimpleSSLContext ProxyServer EchoHandler
+ * compile ../../../com/sun/net/httpserver/LogFilter.java
+ * compile ../../../com/sun/net/httpserver/FileServerHandler.java
  */
 import com.sun.net.httpserver.Headers;
 import com.sun.net.httpserver.HttpContext;
--- a/jdk/test/java/net/httpclient/ManyRequests.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/test/java/net/httpclient/ManyRequests.java	Tue May 03 12:25:20 2016 -0700
@@ -24,18 +24,17 @@
 /**
  * @test
  * @bug 8087112
- * @library /lib/testlibrary/
- * @build jdk.testlibrary.SimpleSSLContext
+ * @library /lib/testlibrary/ /
+ * @build jdk.testlibrary.SimpleSSLContext EchoHandler
  * @compile ../../../com/sun/net/httpserver/LogFilter.java
  * @compile ../../../com/sun/net/httpserver/FileServerHandler.java
- * @run main/othervm ManyRequests
+ * @run main/othervm/timeout=40 -Djava.net.http.HttpClient.log=ssl ManyRequests
  * @summary Send a large number of requests asynchronously
  */
 
 //package javaapplication16;
 
-import com.sun.net.httpserver.HttpsConfigurator;
-import com.sun.net.httpserver.HttpsServer;
+import com.sun.net.httpserver.*;
 import java.io.IOException;
 import java.io.UncheckedIOException;
 import java.net.http.HttpClient;
@@ -47,18 +46,25 @@
 import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.Random;
+import java.util.logging.*;
 import java.util.concurrent.CompletableFuture;
-import javax.net.ssl.SSLContext;
+import javax.net.ssl.*;
 import jdk.testlibrary.SimpleSSLContext;
 
 public class ManyRequests {
 
+    volatile static int counter = 0;
+
     public static void main(String[] args) throws Exception {
+        Logger logger = Logger.getLogger("com.sun.net.httpserver");
+        logger.setLevel(Level.ALL);
+        logger.info("TEST");
+
         SSLContext ctx = new SimpleSSLContext().get();
 
         InetSocketAddress addr = new InetSocketAddress(0);
         HttpsServer server = HttpsServer.create(addr, 0);
-        server.setHttpsConfigurator(new HttpsConfigurator(ctx));
+        server.setHttpsConfigurator(new Configurator(ctx));
 
         HttpClient client = HttpClient.create()
                                       .sslContext(ctx)
@@ -72,7 +78,8 @@
         }
     }
 
-    static final int REQUESTS = 1000;
+    //static final int REQUESTS = 1000;
+    static final int REQUESTS = 20;
 
     static void test(HttpsServer server, HttpClient client) throws Exception {
         int port = server.getAddress().getPort();
@@ -102,6 +109,9 @@
                                resp.bodyAsync(HttpResponse.ignoreBody());
                                String s = "Expected 200, got: " + resp.statusCode();
                                return completedWithIOException(s);
+                           } else {
+                               counter++;
+                               System.out.println("Result from " + counter);
                            }
                            return resp.bodyAsync(HttpResponse.asByteArray())
                                       .thenApply((b) -> new Pair<>(resp, b));
@@ -114,14 +124,18 @@
 
                       });
         }
+
         // wait for them all to complete and throw exception in case of error
-        CompletableFuture.allOf(results).join();
+        //try {
+            CompletableFuture.allOf(results).join();
+        //} catch (Exception  e) {
+            //e.printStackTrace();
+            //throw e;
+        //}
     }
 
     static <T> CompletableFuture<T> completedWithIOException(String message) {
-        CompletableFuture<T> cf = new CompletableFuture<>();
-        cf.completeExceptionally(new IOException(message));
-        return cf;
+        return CompletableFuture.failedFuture(new IOException(message));
     }
 
     static final class Pair<T,U> {
@@ -192,3 +206,14 @@
         throw new RuntimeException(sb.toString());
     }
 }
+
+class Configurator extends HttpsConfigurator {
+    public Configurator(SSLContext ctx) {
+        super(ctx);
+    }
+
+    public void configure (HttpsParameters params) {
+        params.setSSLParameters (getSSLContext().getSupportedSSLParameters());
+    }
+}
+
--- a/jdk/test/java/net/httpclient/RequestBodyTest.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/test/java/net/httpclient/RequestBodyTest.java	Tue May 03 12:25:20 2016 -0700
@@ -23,10 +23,11 @@
 
 /**
  * @test @bug 8087112
- * @library /lib/testlibrary/
- * @build jdk.testlibrary.SimpleSSLContext ProxyServer
+ * @library /lib/testlibrary/ /
  * @compile ../../../com/sun/net/httpserver/LogFilter.java
  * @compile ../../../com/sun/net/httpserver/FileServerHandler.java
+ * @build LightWeightHttpServer
+ * @build jdk.testlibrary.SimpleSSLContext ProxyServer
  * @run main/othervm RequestBodyTest
  */
 
--- a/jdk/test/java/net/httpclient/SmokeTest.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/test/java/net/httpclient/SmokeTest.java	Tue May 03 12:25:20 2016 -0700
@@ -24,15 +24,13 @@
 /**
  * @test
  * @bug 8087112
- * @library /lib/testlibrary/
- * @build jdk.testlibrary.SimpleSSLContext ProxyServer
+ * @library /lib/testlibrary/ /
+ * @build jdk.testlibrary.SimpleSSLContext ProxyServer EchoHandler
  * @compile ../../../com/sun/net/httpserver/LogFilter.java
  * @compile ../../../com/sun/net/httpserver/FileServerHandler.java
  * @run main/othervm SmokeTest
  */
 
-//package javaapplication16;
-
 import com.sun.net.httpserver.*;
 import java.net.*;
 import java.net.http.*;
@@ -69,6 +67,7 @@
  */
 public class SmokeTest {
     static SSLContext ctx;
+    static SSLParameters sslparams;
     static HttpServer s1 ;
     static HttpsServer s2;
     static ExecutorService executor;
@@ -107,6 +106,7 @@
 
         client = HttpClient.create()
                            .sslContext(ctx)
+                           .sslParameters(sslparams)
                            .followRedirects(HttpClient.Redirect.ALWAYS)
                            .executorService(Executors.newCachedThreadPool())
                            .build();
@@ -285,6 +285,7 @@
         HttpClient cl = HttpClient.create()
                                   .proxy(ProxySelector.of(proxyAddr))
                                   .sslContext(ctx)
+                                  .sslParameters(sslparams)
                                   .build();
 
         CompletableFuture<String> fut = cl.request(uri)
@@ -672,7 +673,8 @@
         s1.setExecutor(executor);
         s2.setExecutor(executor);
         ctx = new SimpleSSLContext().get();
-        s2.setHttpsConfigurator(new HttpsConfigurator(ctx));
+        sslparams = ctx.getSupportedSSLParameters();
+        s2.setHttpsConfigurator(new Configurator(ctx));
         s1.start();
         s2.start();
 
@@ -689,6 +691,16 @@
     }
 }
 
+class Configurator extends HttpsConfigurator {
+    public Configurator(SSLContext ctx) {
+        super(ctx);
+    }
+
+    public void configure (HttpsParameters params) {
+        params.setSSLParameters (getSSLContext().getSupportedSSLParameters());
+    }
+}
+
 class UploadServer extends Thread {
     int statusCode;
     ServerSocket ss;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/httpclient/TestKit.java	Tue May 03 12:25:20 2016 -0700
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.util.regex.Pattern;
+
+import static java.util.Objects.requireNonNull;
+
+//
+// A set of testing utility functions
+//
+public final class TestKit {
+
+    private TestKit() { }
+
+    public static void assertNotThrows(ThrowingProcedure code) {
+        requireNonNull(code, "code");
+        assertNotThrows(() -> {
+            code.run();
+            return null;
+        });
+    }
+
+    public static <V> V assertNotThrows(ThrowingFunction<V> code) {
+        requireNonNull(code, "code");
+        try {
+            return code.run();
+        } catch (Throwable t) {
+            throw new RuntimeException("Expected to run normally, but threw "
+                    + t.getClass().getCanonicalName(), t);
+        }
+    }
+
+    public static <T extends Throwable> T assertThrows(Class<? extends T> clazz,
+                                                       ThrowingProcedure code) {
+        requireNonNull(clazz, "clazz");
+        requireNonNull(code, "code");
+        try {
+            code.run();
+        } catch (Throwable t) {
+            if (clazz.isInstance(t)) {
+                return clazz.cast(t);
+            }
+            throw new RuntimeException("Expected to catch an exception of type "
+                    + clazz.getCanonicalName() + ", but caught "
+                    + t.getClass().getCanonicalName(), t);
+
+        }
+        throw new RuntimeException("Expected to catch an exception of type "
+                + clazz.getCanonicalName() + ", but caught nothing");
+    }
+
+    public interface ThrowingProcedure {
+        void run() throws Throwable;
+    }
+
+    public interface ThrowingFunction<V> {
+        V run() throws Throwable;
+    }
+
+    // The rationale behind asking for a regex is to not pollute variable names
+    // space in the scope of assertion: if it's something as simple as checking
+    // a message, we can do it inside
+    public static <T extends Throwable> T assertThrows(Class<? extends T> clazz,
+                                                       String messageRegex,
+                                                       ThrowingProcedure code) {
+        requireNonNull(messageRegex, "messagePattern");
+        T t = assertThrows(clazz, code);
+        String m = t.getMessage();
+        if (m == null) {
+            throw new RuntimeException(String.format(
+                    "Expected exception message to match the regex '%s', " +
+                            "but the message was null", messageRegex), t);
+        }
+        if (!Pattern.matches(messageRegex, m)) {
+            throw new RuntimeException(String.format(
+                    "Expected exception message to match the regex '%s', " +
+                            "actual message: %s", messageRegex, m), t);
+        }
+        return t;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/httpclient/TestKitTest.java	Tue May 03 12:25:20 2016 -0700
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.io.IOException;
+import java.util.IllegalFormatException;
+import java.util.Set;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.assertTrue;
+
+/*
+ * @test
+ * @compile TestKit.java
+ * @run testng TestKitTest
+ */
+public final class TestKitTest {
+
+    public static void main(String[] args) {
+        testAssertNotThrows();
+        testAssertThrows();
+    }
+
+    private static void testAssertNotThrows() {
+        Integer integer = TestKit.assertNotThrows(
+                () -> TestKit.assertNotThrows(() -> 1)
+        );
+        assertEquals(integer, Integer.valueOf(1));
+
+        RuntimeException re = TestKit.assertThrows(
+                RuntimeException.class,
+                () -> TestKit.assertNotThrows(() -> { throw new IOException(); })
+        );
+        assertEquals(re.getMessage(),
+                "Expected to run normally, but threw "
+                        + "java.io.IOException");
+
+        TestKit.assertNotThrows(
+                () -> TestKit.assertNotThrows(() -> { })
+        );
+
+        re = TestKit.assertThrows(
+                RuntimeException.class,
+                () ->  TestKit.assertNotThrows((TestKit.ThrowingProcedure) () -> { throw new IOException(); })
+        );
+        assertEquals(re.getMessage(),
+                "Expected to run normally, but threw "
+                        + "java.io.IOException");
+    }
+
+    private static void testAssertThrows() {
+        NullPointerException npe = TestKit.assertThrows(
+                NullPointerException.class,
+                () -> TestKit.assertThrows(null, null)
+        );
+        assertNotNull(npe);
+        assertTrue(Set.of("clazz", "code").contains(npe.getMessage()), npe.getMessage());
+
+        npe = TestKit.assertThrows(
+                NullPointerException.class,
+                () -> TestKit.assertThrows(IOException.class, null)
+        );
+        assertNotNull(npe);
+        assertEquals(npe.getMessage(), "code");
+
+        npe = TestKit.assertThrows(
+                NullPointerException.class,
+                () -> TestKit.assertThrows(null, () -> { })
+        );
+        assertEquals(npe.getMessage(), "clazz");
+
+        npe = TestKit.assertThrows(
+                NullPointerException.class,
+                () -> { throw new NullPointerException(); }
+        );
+        assertNotNull(npe);
+        assertNull(npe.getMessage());
+        assertEquals(npe.getClass(), NullPointerException.class);
+
+        RuntimeException re = TestKit.assertThrows(
+                RuntimeException.class,
+                () -> TestKit.assertThrows(NullPointerException.class, () -> { })
+        );
+        assertEquals(re.getClass(), RuntimeException.class);
+        assertEquals(re.getMessage(),
+                "Expected to catch an exception of type "
+                        + "java.lang.NullPointerException, but caught nothing");
+
+        re = TestKit.assertThrows(
+                RuntimeException.class,
+                () -> { throw new NullPointerException(); }
+        );
+        assertNotNull(re);
+        assertNull(re.getMessage());
+        assertEquals(re.getClass(), NullPointerException.class);
+
+        re = TestKit.assertThrows(
+                RuntimeException.class,
+                () -> TestKit.assertThrows(
+                        IllegalFormatException.class,
+                        () -> { throw new IndexOutOfBoundsException(); }
+                ));
+        assertNotNull(re);
+        assertEquals(re.getClass(), RuntimeException.class);
+        assertEquals(re.getMessage(),
+                "Expected to catch an exception of type java.util.IllegalFormatException"
+                        + ", but caught java.lang.IndexOutOfBoundsException");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/httpclient/http2/BasicTest.java	Tue May 03 12:25:20 2016 -0700
@@ -0,0 +1,222 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8087112
+ * @library /lib/testlibrary
+ * @build jdk.testlibrary.SimpleSSLContext
+ * @modules java.httpclient
+ * @compile/module=java.httpclient java/net/http/BodyOutputStream.java
+ * @compile/module=java.httpclient java/net/http/BodyInputStream.java
+ * @compile/module=java.httpclient java/net/http/EchoHandler.java
+ * @compile/module=java.httpclient java/net/http/Http2Handler.java
+ * @compile/module=java.httpclient java/net/http/Http2TestExchange.java
+ * @compile/module=java.httpclient java/net/http/Http2TestServerConnection.java
+ * @compile/module=java.httpclient java/net/http/Http2TestServer.java
+ * @compile/module=java.httpclient java/net/http/OutgoingPushPromise.java
+ * @compile/module=java.httpclient java/net/http/TestUtil.java
+ * @run testng/othervm -Djava.net.http.HttpClient.log=ssl,requests,responses,errors BasicTest
+ */
+
+import java.io.*;
+import java.net.*;
+import java.net.http.*;
+import static java.net.http.HttpClient.Version.HTTP_2;
+import javax.net.ssl.*;
+import java.nio.file.*;
+import java.util.concurrent.*;
+import jdk.testlibrary.SimpleSSLContext;
+
+
+import org.testng.annotations.Test;
+import org.testng.annotations.Parameters;
+
+@Test
+public class BasicTest {
+    static int httpPort, httpsPort;
+    static Http2TestServer httpServer, httpsServer;
+    static HttpClient client = null;
+    static ExecutorService exec;
+    static SSLContext sslContext;
+
+    static String httpURIString, httpsURIString;
+
+    static void initialize() throws Exception {
+        try {
+            SimpleSSLContext sslct = new SimpleSSLContext();
+            sslContext = sslct.get();
+            client = getClient();
+            exec = client.executorService();
+            httpServer = new Http2TestServer(false, 0, new EchoHandler(),
+                    exec, sslContext);
+            httpPort = httpServer.getAddress().getPort();
+
+            httpsServer = new Http2TestServer(true, 0, new EchoHandler(),
+                    exec, sslContext);
+
+            httpsPort = httpsServer.getAddress().getPort();
+            httpURIString = "http://127.0.0.1:" + Integer.toString(httpPort) +
+                    "/foo/";
+            httpsURIString = "https://127.0.0.1:" + Integer.toString(httpsPort) +
+                    "/bar/";
+
+            httpServer.start();
+            httpsServer.start();
+        } catch (Throwable e) {
+            System.err.println("Throwing now");
+            e.printStackTrace();
+            throw e;
+        }
+    }
+
+    @Test(timeOut=30000)
+    public static void test() throws Exception {
+        try {
+            initialize();
+            simpleTest(false);
+            simpleTest(true);
+            streamTest(false);
+            streamTest(true);
+            Thread.sleep(1000 * 4);
+        } finally {
+            httpServer.stop();
+            httpsServer.stop();
+            exec.shutdownNow();
+        }
+    }
+
+    static HttpClient getClient() {
+        if (client == null) {
+            client = HttpClient.create()
+                .sslContext(sslContext)
+                .version(HTTP_2)
+                .build();
+        }
+        return client;
+    }
+
+    static URI getURI(boolean secure) {
+        if (secure)
+            return URI.create(httpsURIString);
+        else
+            return URI.create(httpURIString);
+    }
+
+    static void checkStatus(int expected, int found) throws Exception {
+        if (expected != found) {
+            System.err.printf ("Test failed: wrong status code %d/%d\n",
+                expected, found);
+            throw new RuntimeException("Test failed");
+        }
+    }
+
+    static void checkStrings(String expected, String found) throws Exception {
+        if (!expected.equals(found)) {
+            System.err.printf ("Test failed: wrong string %s/%s\n",
+                expected, found);
+            throw new RuntimeException("Test failed");
+        }
+    }
+
+    static Void compareFiles(Path path1, Path path2) {
+        return java.net.http.TestUtil.compareFiles(path1, path2);
+    }
+
+    static Path tempFile() {
+        return java.net.http.TestUtil.tempFile();
+    }
+
+    static final String SIMPLE_STRING = "Hello world Goodbye world";
+
+    static final int LOOPS = 13;
+    static final int FILESIZE = 64 * 1024;
+
+    static void streamTest(boolean secure) throws Exception {
+        URI uri = getURI(secure);
+        System.err.printf("streamTest %b to %s\n" , secure, uri);
+
+        HttpClient client = getClient();
+        Path src = java.net.http.TestUtil.getAFile(FILESIZE * 4);
+        HttpRequest req = client.request(uri)
+                .body(HttpRequest.fromFile(src))
+                .POST();
+
+        CompletableFuture<InputStream> response = req.responseAsync()
+                .thenCompose(resp -> {
+                    if (resp.statusCode() != 200)
+                        throw new RuntimeException();
+                    return resp.bodyAsync(HttpResponse.asInputStream());
+                });
+        InputStream is = response.join();
+        File dest = File.createTempFile("foo","bar");
+        dest.deleteOnExit();
+        FileOutputStream os = new FileOutputStream(dest);
+        is.transferTo(os);
+        is.close();
+        os.close();
+        int count = 0;
+        compareFiles(src, dest.toPath());
+        System.err.println("DONE");
+    }
+
+
+    static void simpleTest(boolean secure) throws Exception {
+        URI uri = getURI(secure);
+        System.err.println("Request to " + uri);
+
+        // Do a simple warmup request
+
+        HttpClient client = getClient();
+        HttpRequest req = client.request(uri)
+                .body(HttpRequest.fromString(SIMPLE_STRING))
+                .POST();
+        HttpResponse response = req.response();
+        HttpHeaders h = response.headers();
+
+        checkStatus(200, response.statusCode());
+
+        String responseBody = response.body(HttpResponse.asString());
+        checkStrings(SIMPLE_STRING, responseBody);
+
+        checkStrings(h.firstValue("x-hello").get(), "world");
+        checkStrings(h.firstValue("x-bye").get(), "universe");
+
+        // Do loops asynchronously
+
+        CompletableFuture[] responses = new CompletableFuture[LOOPS];
+        final Path source = java.net.http.TestUtil.getAFile(FILESIZE);
+        for (int i = 0; i < LOOPS; i++) {
+            responses[i] = client.request(uri)
+                .body(HttpRequest.fromFile(source))
+                .version(HTTP_2)
+                .POST()
+                .responseAsync()
+                .thenCompose(r -> r.bodyAsync(HttpResponse.asFile(tempFile())))
+                .thenApply(path -> compareFiles(path, source));
+            Thread.sleep(100);
+        }
+        CompletableFuture.allOf(responses).join();
+        System.err.println("DONE");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/httpclient/http2/ServerPush.java	Tue May 03 12:25:20 2016 -0700
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8087112
+ * @library /lib/testlibrary
+ * @build jdk.testlibrary.SimpleSSLContext
+ * @modules java.httpclient
+ * @compile/module=java.httpclient java/net/http/BodyOutputStream.java
+ * @compile/module=java.httpclient java/net/http/BodyInputStream.java
+ * @compile/module=java.httpclient java/net/http/PushHandler.java
+ * @compile/module=java.httpclient java/net/http/Http2Handler.java
+ * @compile/module=java.httpclient java/net/http/Http2TestExchange.java
+ * @compile/module=java.httpclient java/net/http/Http2TestServerConnection.java
+ * @compile/module=java.httpclient java/net/http/Http2TestServer.java
+ * @compile/module=java.httpclient java/net/http/OutgoingPushPromise.java
+ * @compile/module=java.httpclient java/net/http/TestUtil.java
+ * @run testng/othervm -Djava.net.http.HttpClient.log=requests,responses ServerPush
+ */
+
+import java.io.*;
+import java.net.*;
+import java.nio.file.*;
+import java.nio.file.attribute.*;
+import java.net.http.*;
+import java.util.*;
+import java.util.concurrent.*;
+import org.testng.annotations.Test;
+
+public class ServerPush {
+
+    static ExecutorService e = Executors.newCachedThreadPool();
+
+    static final int LOOPS = 13;
+    static final int FILE_SIZE = 32 * 1024;
+
+    static Path tempFile;
+
+    @Test(timeOut=30000)
+    public static void test() throws Exception {
+        Http2TestServer server = null;
+        Path dir = null;
+        try {
+            server = new Http2TestServer(false, 0,
+                                         new PushHandler(FILE_SIZE, LOOPS));
+            tempFile = TestUtil.getAFile(FILE_SIZE);
+
+            System.err.println("Server listening on port " + server.getAddress().getPort());
+            server.start();
+            int port = server.getAddress().getPort();
+            dir = Files.createTempDirectory("serverPush");
+
+            URI uri = new URI("http://127.0.0.1:" + Integer.toString(port) + "/foo");
+            HttpRequest request = HttpRequest.create(uri)
+                    .version(HttpClient.Version.HTTP_2)
+                    .GET();
+
+            CompletableFuture<Map<URI,Path>> cf =
+            request.multiResponseAsync(HttpResponse.multiFile(dir));
+            Map<URI,Path> results = cf.get();
+
+            //HttpResponse resp = request.response();
+            System.err.println(results.size());
+            Set<URI> uris = results.keySet();
+            for (URI u : uris) {
+                Path result = results.get(u);
+                System.err.printf("%s -> %s\n", u.toString(), result.toString());
+                TestUtil.compareFiles(result, tempFile);
+            }
+            System.out.println("TEST OK");
+        } finally {
+            e.shutdownNow();
+            server.stop();
+            Files.walkFileTree(dir, new SimpleFileVisitor<Path>() {
+                public FileVisitResult postVisitDirectory(Path dir, IOException exc) {
+                    dir.toFile().delete();
+                    return FileVisitResult.CONTINUE;
+                }
+                public FileVisitResult visitFile(Path path, BasicFileAttributes attrs) {
+                    path.toFile().delete();
+                    return FileVisitResult.CONTINUE;
+                }
+            });
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/httpclient/http2/TEST.properties	Tue May 03 12:25:20 2016 -0700
@@ -0,0 +1,1 @@
+bootclasspath.dirs = /java/net/httpclient
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/httpclient/http2/java.httpclient/java/net/http/BodyInputStream.java	Tue May 03 12:25:20 2016 -0700
@@ -0,0 +1,107 @@
+package java.net.http;
+
+import java.io.*;
+import java.nio.ByteBuffer;
+
+/**
+ * InputStream reads frames off stream q and supplies read demand from any
+ * DataFrames it finds. Window updates are sent back on the connections send
+ * q.
+ */
+class BodyInputStream extends InputStream {
+
+    final Queue<Http2Frame> q;
+    final int streamid;
+    boolean closed;
+    boolean eof;
+    final Http2TestServerConnection conn;
+
+    @SuppressWarnings({"rawtypes","unchecked"})
+    BodyInputStream(Queue q, int streamid, Http2TestServerConnection conn) {
+        this.q = q;
+        this.streamid = streamid;
+        this.conn = conn;
+    }
+
+    DataFrame df;
+    ByteBuffer[] buffers;
+    ByteBuffer buffer;
+    int nextIndex = -1;
+
+    private DataFrame getData() throws IOException {
+        if (eof) {
+            return null;
+        }
+        Http2Frame frame;
+        do {
+            frame = q.take();
+            if (frame.type() == ResetFrame.TYPE) {
+                conn.handleStreamReset((ResetFrame) frame); // throws IOException
+            }
+            // ignoring others for now Wupdates handled elsewhere
+            if (frame.type() != DataFrame.TYPE) {
+                System.out.println("Ignoring " + frame.toString() + " CHECK THIS");
+            }
+        } while (frame.type() != DataFrame.TYPE);
+        df = (DataFrame) frame;
+        int len = df.getDataLength();
+        eof = frame.getFlag(DataFrame.END_STREAM);
+        // acknowledge
+        conn.sendWindowUpdates(len, streamid);
+        return (DataFrame) frame;
+    }
+
+    // null return means EOF
+    private ByteBuffer getBuffer() throws IOException {
+        if (buffer == null || !buffer.hasRemaining()) {
+            if (nextIndex == -1 || nextIndex == buffers.length) {
+                DataFrame df = getData();
+                if (df == null) {
+                    return null;
+                }
+                int len = df.getDataLength();
+                if ((len == 0) && eof) {
+                    return null;
+                }
+                buffers = df.getData();
+                nextIndex = 0;
+            }
+            buffer = buffers[nextIndex++];
+        }
+        return buffer;
+    }
+
+    @Override
+    public int read(byte[] buf, int offset, int length) throws IOException {
+        if (closed) {
+            throw new IOException("closed");
+        }
+        ByteBuffer b = getBuffer();
+        if (b == null) {
+            return -1;
+        }
+        int remaining = b.remaining();
+        if (remaining < length) {
+            length = remaining;
+        }
+        b.get(buf, offset, length);
+        return length;
+    }
+
+    byte[] one = new byte[1];
+
+    @Override
+    public int read() throws IOException {
+        int c = read(one, 0, 1);
+        if (c == -1) {
+            return -1;
+        }
+        return one[0];
+    }
+
+    @Override
+    public void close() {
+        // TODO reset this stream
+        closed = true;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/httpclient/http2/java.httpclient/java/net/http/BodyOutputStream.java	Tue May 03 12:25:20 2016 -0700
@@ -0,0 +1,106 @@
+package java.net.http;
+
+import java.io.*;
+import java.nio.ByteBuffer;
+
+/**
+ * OutputStream. Incoming window updates handled by the main connection
+ * reader thread.
+ */
+@SuppressWarnings({"rawtypes","unchecked"})
+class BodyOutputStream extends OutputStream {
+    final static byte[] EMPTY_BARRAY = new byte[0];
+
+    final int streamid;
+    int window;
+    boolean closed;
+    boolean goodToGo = false; // not allowed to send until headers sent
+    final Http2TestServerConnection conn;
+    final Queue outputQ;
+
+    BodyOutputStream(int streamid, int initialWindow, Http2TestServerConnection conn) {
+        this.window = initialWindow;
+        this.streamid = streamid;
+        this.conn = conn;
+        this.outputQ = conn.outputQ;
+        conn.registerStreamWindowUpdater(streamid, this::updateWindow);
+    }
+
+    // called from connection reader thread as all incoming window
+    // updates are handled there.
+    synchronized void updateWindow(int update) {
+        window += update;
+        notifyAll();
+    }
+
+    void waitForWindow(int demand) throws InterruptedException {
+        // first wait for the connection window
+        conn.obtainConnectionWindow(demand);
+        // now wait for the stream window
+        synchronized (this) {
+            while (demand > 0) {
+                int n = Math.min(demand, window);
+                demand -= n;
+                window -= n;
+                if (demand > 0) {
+                    wait();
+                }
+            }
+        }
+    }
+
+    void goodToGo() {
+        goodToGo = true;
+    }
+
+    @Override
+    public void write(byte[] buf, int offset, int len) throws IOException {
+        if (closed) {
+            throw new IOException("closed");
+        }
+
+        if (!goodToGo) {
+            throw new IllegalStateException("sendResponseHeaders must be called first");
+        }
+        try {
+            waitForWindow(len);
+            send(buf, offset, len, 0);
+        } catch (InterruptedException ex) {
+            throw new IOException(ex);
+        }
+    }
+
+    private void send(byte[] buf, int offset, int len, int flags) throws IOException {
+        ByteBuffer buffer = ByteBuffer.allocate(len);
+        buffer.put(buf, offset, len);
+        buffer.flip();
+        DataFrame df = new DataFrame();
+        assert streamid != 0;
+        df.streamid(streamid);
+        df.setFlags(flags);
+        df.setData(buffer);
+        outputQ.put(df);
+    }
+
+    byte[] one = new byte[1];
+
+    @Override
+    public void write(int b) throws IOException {
+        one[0] = (byte) b;
+        write(one, 0, 1);
+    }
+
+    @Override
+    public void close() {
+        if (closed) {
+            return;
+        }
+        closed = true;
+        try {
+            send(EMPTY_BARRAY, 0, 0, DataFrame.END_STREAM);
+        } catch (IOException ex) {
+            System.err.println("TestServer: OutputStream.close exception: " + ex);
+            ex.printStackTrace();
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/httpclient/http2/java.httpclient/java/net/http/EchoHandler.java	Tue May 03 12:25:20 2016 -0700
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net.http;
+
+import java.util.*;
+import java.util.concurrent.*;
+import java.io.*;
+import java.net.*;
+
+public class EchoHandler implements Http2Handler {
+    public EchoHandler() {}
+
+    @Override
+    public void handle(Http2TestExchange t)
+            throws IOException {
+        try {
+            System.err.println("EchoHandler received request to " + t.getRequestURI());
+            InputStream is = t.getRequestBody();
+            HttpHeadersImpl map = t.getRequestHeaders();
+            HttpHeadersImpl map1 = t.getResponseHeaders();
+            map1.addHeader("X-Hello", "world");
+            map1.addHeader("X-Bye", "universe");
+            String fixedrequest = map.firstValue("XFixed").orElse(null);
+            File outfile = File.createTempFile("foo", "bar");
+            FileOutputStream fos = new FileOutputStream(outfile);
+            int count = (int) is.transferTo(fos);
+            System.err.printf("EchoHandler read %d bytes\n", count);
+            is.close();
+            fos.close();
+            InputStream is1 = new FileInputStream(outfile);
+            OutputStream os = null;
+            // return the number of bytes received (no echo)
+            String summary = map.firstValue("XSummary").orElse(null);
+            if (fixedrequest != null && summary == null) {
+                t.sendResponseHeaders(200, count);
+                os = t.getResponseBody();
+                is1.transferTo(os);
+            } else {
+                t.sendResponseHeaders(200, 0);
+                os = t.getResponseBody();
+                int count1 = (int)is1.transferTo(os);
+                System.err.printf("EchoHandler wrote %d bytes\n", count1);
+
+                if (summary != null) {
+                    String s = Integer.toString(count);
+                    os.write(s.getBytes());
+                }
+            }
+            outfile.delete();
+            os.close();
+            is1.close();
+        } catch (Throwable e) {
+            e.printStackTrace();
+            throw new IOException(e);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/httpclient/http2/java.httpclient/java/net/http/Http2Handler.java	Tue May 03 12:25:20 2016 -0700
@@ -0,0 +1,18 @@
+package java.net.http;
+
+import java.io.IOException;
+
+/**
+ * A handler which is invoked to process HTTP exchanges. Each
+ * HTTP exchange is handled by one of these handlers.
+ */
+public interface Http2Handler {
+    /**
+     * Handle the given request and generate an appropriate response.
+     * @param exchange the exchange containing the request from the
+     *      client and used to send the response
+     * @throws NullPointerException if exchange is <code>null</code>
+     */
+    public abstract void handle (Http2TestExchange exchange) throws IOException;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/httpclient/http2/java.httpclient/java/net/http/Http2TestExchange.java	Tue May 03 12:25:20 2016 -0700
@@ -0,0 +1,126 @@
+package java.net.http;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.IOException;
+import java.net.URI;
+import java.net.InetSocketAddress;
+
+public class Http2TestExchange {
+
+    final HttpHeadersImpl reqheaders;
+    final HttpHeadersImpl rspheaders;
+    final URI uri;
+    final String method;
+    final InputStream is;
+    final BodyOutputStream os;
+    final int streamid;
+    final boolean pushAllowed;
+    final Http2TestServerConnection conn;
+    final Http2TestServer server;
+
+    int responseCode = -1;
+    long responseLength;
+
+    Http2TestExchange(int streamid, String method, HttpHeadersImpl reqheaders,
+            HttpHeadersImpl rspheaders, URI uri, InputStream is,
+            BodyOutputStream os, Http2TestServerConnection conn, boolean pushAllowed) {
+        this.reqheaders = reqheaders;
+        this.rspheaders = rspheaders;
+        this.uri = uri;
+        this.method = method;
+        this.is = is;
+        this.streamid = streamid;
+        this.os = os;
+        this.pushAllowed = pushAllowed;
+        this.conn = conn;
+        this.server = conn.server;
+    }
+
+    public HttpHeadersImpl getRequestHeaders() {
+        return reqheaders;
+    }
+
+    public HttpHeadersImpl getResponseHeaders() {
+        return rspheaders;
+    }
+
+    public URI getRequestURI() {
+        return uri;
+    }
+
+    public String getRequestMethod() {
+        return method;
+    }
+
+    public void close() {
+        try {
+            is.close();
+            os.close();
+        } catch (IOException e) {
+            System.err.println("TestServer: HttpExchange.close exception: " + e);
+            e.printStackTrace();
+        }
+    }
+
+    public InputStream getRequestBody() {
+        return is;
+    }
+
+    public OutputStream getResponseBody() {
+        return os;
+    }
+
+    public void sendResponseHeaders(int rCode, long responseLength) throws IOException {
+        this.responseLength = responseLength;
+        if (responseLength > 0 || responseLength < 0) {
+                long clen = responseLength > 0 ? responseLength : 0;
+            rspheaders.setHeader("Content-length", Long.toString(clen));
+        }
+
+        rspheaders.setHeader(":status", Integer.toString(rCode));
+
+        Http2TestServerConnection.ResponseHeaders response
+                = new Http2TestServerConnection.ResponseHeaders(rspheaders);
+        response.streamid(streamid);
+        response.setFlag(HeaderFrame.END_HEADERS);
+        conn.outputQ.put(response);
+        os.goodToGo();
+        System.err.println("Sent response headers " + rCode);
+    }
+
+    public InetSocketAddress getRemoteAddress() {
+        return (InetSocketAddress) conn.socket.getRemoteSocketAddress();
+    }
+
+    public int getResponseCode() {
+        return responseCode;
+    }
+
+    public InetSocketAddress getLocalAddress() {
+        return server.getAddress();
+    }
+
+    public String getProtocol() {
+        return "HTTP/2";
+    }
+
+    public boolean serverPushAllowed() {
+        return pushAllowed;
+    }
+
+    public void serverPush(URI uri, HttpHeadersImpl headers, InputStream content) {
+        OutgoingPushPromise pp = new OutgoingPushPromise(
+                streamid, uri, headers, content);
+        headers.setHeader(":method", "GET");
+        headers.setHeader(":scheme", uri.getScheme());
+        headers.setHeader(":authority", uri.getAuthority());
+        headers.setHeader(":path", uri.getPath());
+        try {
+            conn.outputQ.put(pp);
+            // writeLoop will spin up thread to read the InputStream
+        } catch (IOException ex) {
+            System.err.println("TestServer: pushPromise exception: " + ex);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/httpclient/http2/java.httpclient/java/net/http/Http2TestServer.java	Tue May 03 12:25:20 2016 -0700
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net.http;
+
+import java.io.IOException;
+import java.net.*;
+import java.util.HashMap;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ThreadFactory;
+import javax.net.ServerSocketFactory;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLParameters;
+import javax.net.ssl.SSLServerSocket;
+import javax.net.ssl.SSLServerSocketFactory;
+
+/**
+ * Waits for incoming TCP connections from a client and establishes
+ * a HTTP2 connection. Two threads are created per connection. One for reading
+ * and one for writing. Incoming requests are dispatched to the supplied
+ * Http2Handler on additional threads. All threads
+ * obtained from the supplied ExecutorService.
+ */
+public class Http2TestServer {
+    final ServerSocket server;
+    boolean secure;
+    SettingsFrame serverSettings, clientSettings;
+    final ExecutorService exec;
+    volatile boolean stopping = false;
+    final Http2Handler handler;
+    final SSLContext sslContext;
+    final HashMap<InetSocketAddress,Http2TestServerConnection> connections;
+
+    private static ThreadFactory defaultThreadFac =
+        (Runnable r) -> {
+            Thread t = new Thread(r);
+            t.setName("Test-server-pool");
+            return t;
+        };
+
+
+    private static ExecutorService getDefaultExecutor() {
+        return Executors.newCachedThreadPool(defaultThreadFac);
+    }
+
+    public Http2TestServer(boolean secure, int port, Http2Handler handler) throws Exception {
+        this(secure, port, handler, getDefaultExecutor(), null);
+    }
+
+    public InetSocketAddress getAddress() {
+        return (InetSocketAddress)server.getLocalSocketAddress();
+    }
+
+    /**
+     * Create a Http2Server listening on the given port. Currently needs
+     * to know in advance whether incoming connections are plain TCP "h2c"
+     * or TLS "h2"/
+     *
+     * @param secure https or http
+     * @param port listen port
+     * @param handler the handler which receives incoming requests
+     * @param exec executor service (cached thread pool is used if null)
+     * @param context the SSLContext used when secure is true
+     * @throws Exception
+     */
+    public Http2TestServer(boolean secure, int port, Http2Handler handler,
+            ExecutorService exec, SSLContext context) throws Exception {
+        if (secure) {
+            server = initSecure(port);
+        } else {
+            server = initPlaintext(port);
+        }
+        this.secure = secure;
+        this.exec = exec == null ? getDefaultExecutor() : exec;
+        this.handler = handler;
+        this.sslContext = context;
+        this.connections = new HashMap<>();
+    }
+
+    final ServerSocket initPlaintext(int port) throws Exception {
+        return new ServerSocket(port);
+    }
+
+    public void stop() {
+        // TODO: clean shutdown GoAway
+        stopping = true;
+        for (Http2TestServerConnection connection : connections.values()) {
+            connection.close();
+        }
+        try {
+            server.close();
+        } catch (IOException e) {}
+        exec.shutdownNow();
+    }
+
+
+    final ServerSocket initSecure(int port) throws Exception {
+        ServerSocketFactory fac;
+        if (sslContext != null) {
+            fac = sslContext.getServerSocketFactory();
+        } else {
+            fac = SSLServerSocketFactory.getDefault();
+        }
+        SSLServerSocket se = (SSLServerSocket) fac.createServerSocket(port);
+        SSLParameters sslp = se.getSSLParameters();
+        sslp.setApplicationProtocols(new String[]{"h2"});
+        se.setSSLParameters(sslp);
+        se.setEnabledCipherSuites(se.getSupportedCipherSuites());
+        se.setEnabledProtocols(se.getSupportedProtocols());
+        // other initialisation here
+        return se;
+    }
+
+    /**
+     * Start thread which waits for incoming connections.
+     *
+     * @throws Exception
+     */
+    public void start() {
+        exec.submit(() -> {
+            try {
+                while (!stopping) {
+                    Socket socket = server.accept();
+                    InetSocketAddress addr = (InetSocketAddress) socket.getRemoteSocketAddress();
+                    Http2TestServerConnection c = new Http2TestServerConnection(this, socket);
+                    connections.put(addr, c);
+                    c.run();
+                }
+            } catch (Throwable e) {
+                if (!stopping) {
+                    System.err.println("TestServer: start exception: " + e);
+                    e.printStackTrace();
+                }
+            }
+        });
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/httpclient/http2/java.httpclient/java/net/http/Http2TestServerConnection.java	Tue May 03 12:25:20 2016 -0700
@@ -0,0 +1,730 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net.http;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.Closeable;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.Socket;
+import java.net.URI;
+import java.net.URISyntaxException;
+import static java.net.http.SettingsFrame.HEADER_TABLE_SIZE;
+import java.nio.ByteBuffer;
+import java.nio.charset.StandardCharsets;
+import java.util.*;
+import java.util.concurrent.ExecutorService;
+import java.util.function.Consumer;
+import sun.net.httpclient.hpack.Decoder;
+import sun.net.httpclient.hpack.DecodingCallback;
+import sun.net.httpclient.hpack.Encoder;
+
+/**
+ * Represents one HTTP2 connection, either plaintext upgraded from HTTP/1.1
+ * or HTTPS opened using "h2" ALPN.
+ */
+public class Http2TestServerConnection {
+    final Http2TestServer server;
+    @SuppressWarnings({"rawtypes","unchecked"})
+    final Map<Integer, Queue> streams; // input q per stream
+    final Queue<Http2Frame> outputQ;
+    int nextstream;
+    final Socket socket;
+    final InputStream is;
+    final OutputStream os;
+    Encoder hpackOut;
+    Decoder hpackIn;
+    SettingsFrame clientSettings, serverSettings;
+    final ExecutorService exec;
+    final boolean secure;
+    final Http2Handler handler;
+    volatile boolean stopping;
+    int nextPushStreamId = 2;
+
+    final static ByteBuffer EMPTY_BUFFER = ByteBuffer.allocate(0);
+    final static byte[] EMPTY_BARRAY = new byte[0];
+
+    final static byte[] clientPreface = "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n".getBytes();
+
+    Http2TestServerConnection(Http2TestServer server, Socket socket) throws IOException {
+        System.err.println("New connection from " + socket);
+        this.server = server;
+        this.streams = Collections.synchronizedMap(new HashMap<>());
+        this.outputQ = new Queue<>();
+        this.socket = socket;
+        this.clientSettings = server.clientSettings;
+        this.serverSettings = server.serverSettings;
+        this.exec = server.exec;
+        this.secure = server.secure;
+        this.handler = server.handler;
+        is = new BufferedInputStream(socket.getInputStream());
+        os = new BufferedOutputStream(socket.getOutputStream());
+    }
+
+    void close() {
+        streams.forEach((i, q) -> {
+            q.close();
+        });
+        stopping = true;
+        try {
+            socket.close();
+            // TODO: put a reset on each stream
+        } catch (IOException e) {
+        }
+    }
+
+    private void readPreface() throws IOException {
+        int len = clientPreface.length;
+        byte[] bytes = new byte[len];
+        is.readNBytes(bytes, 0, len);
+        if (Arrays.compare(clientPreface, bytes) != 0) {
+            throw new IOException("Invalid preface: " + new String(bytes, 0, len));
+        }
+    }
+
+    String doUpgrade() throws IOException {
+        String upgrade = readHttp1Request();
+        String h2c = getHeader(upgrade, "Upgrade");
+        if (h2c == null || !h2c.equals("h2c")) {
+            throw new IOException("Bad upgrade 1 " + h2c);
+        }
+
+        sendHttp1Response(101, "Switching Protocols", "Connection", "Upgrade",
+                "Upgrade", "h2c");
+
+        sendSettingsFrame();
+        readPreface();
+
+        String clientSettingsString = getHeader(upgrade, "HTTP2-Settings");
+        clientSettings = getSettingsFromString(clientSettingsString);
+
+        return upgrade;
+    }
+
+    /**
+     * Client settings payload provided in base64 HTTP1 header. Decode it
+     * and add a header so we can interpret it.
+     *
+     * @param s
+     * @return
+     * @throws IOException
+     */
+    private SettingsFrame getSettingsFromString(String s) throws IOException {
+        Base64.Decoder decoder = Base64.getUrlDecoder();
+        byte[] payload = decoder.decode(s);
+        ByteBuffer bb1 = ByteBuffer.wrap(payload);
+        // simulate header of Settings Frame
+        ByteBuffer bb0 = ByteBuffer.wrap(
+                new byte[] {0, 0, (byte)payload.length, 4, 0, 0, 0, 0, 0});
+        ByteBufferConsumer bbc = new ByteBufferConsumer(
+                new LinkedList<ByteBuffer>(List.of(bb0, bb1)),
+                this::getBuffer);
+        Http2Frame frame = Http2Frame.readIncoming(bbc);
+        if (!(frame instanceof SettingsFrame))
+            throw new IOException("Expected SettingsFrame");
+        return (SettingsFrame)frame;
+    }
+
+    void run() throws Exception {
+        String upgrade = null;
+        if (!secure) {
+            upgrade = doUpgrade();
+        } else {
+            readPreface();
+            sendSettingsFrame(true);
+            clientSettings = (SettingsFrame) readFrame();
+            nextstream = 1;
+        }
+
+        hpackOut = new Encoder(serverSettings.getParameter(HEADER_TABLE_SIZE));
+        hpackIn = new Decoder(clientSettings.getParameter(HEADER_TABLE_SIZE));
+
+        exec.submit(() -> {
+            readLoop();
+        });
+        exec.submit(() -> {
+            writeLoop();
+        });
+        if (!secure) {
+            createPrimordialStream(upgrade);
+            nextstream = 3;
+        }
+    }
+
+    static class BufferPool implements BufferHandler {
+
+        public void setMinBufferSize(int size) {
+        }
+
+        public ByteBuffer getBuffer(int size) {
+            if (size == -1)
+                size = 32 * 1024;
+            return ByteBuffer.allocate(size);
+        }
+
+        public void returnBuffer(ByteBuffer buffer) {
+        }
+    }
+
+    static BufferPool bufferpool = new BufferPool();
+
+    private void writeFrame(Http2Frame frame) throws IOException {
+        ByteBufferGenerator bg = new ByteBufferGenerator(bufferpool);
+        frame.computeLength();
+        System.err.println("Writing frame " + frame.toString());
+        frame.writeOutgoing(bg);
+        ByteBuffer[] bufs = bg.getBufferArray();
+        int c = 0;
+        for (ByteBuffer buf : bufs) {
+            byte[] ba = buf.array();
+            int start = buf.arrayOffset() + buf.position();
+            c += buf.remaining();
+            os.write(ba, start, buf.remaining());
+        }
+        os.flush();
+        System.err.printf("wrote %d bytes\n", c);
+    }
+
+    void handleStreamReset(ResetFrame resetFrame) throws IOException {
+        // TODO: cleanup
+        throw new IOException("Stream reset");
+    }
+
+    private void handleCommonFrame(Http2Frame f) throws IOException {
+        if (f instanceof SettingsFrame) {
+            serverSettings = (SettingsFrame) f;
+            if (serverSettings.getFlag(SettingsFrame.ACK)) // ignore
+            {
+                return;
+            }
+            // otherwise acknowledge it
+            SettingsFrame frame = new SettingsFrame();
+            frame.setFlag(SettingsFrame.ACK);
+            frame.streamid(0);
+            outputQ.put(frame);
+            return;
+        }
+        System.err.println("Received ---> " + f.toString());
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    void sendWindowUpdates(int len, int streamid) throws IOException {
+        if (len == 0)
+            return;
+        WindowUpdateFrame wup = new WindowUpdateFrame();
+        wup.streamid(streamid);
+        wup.setUpdate(len);
+        outputQ.put(wup);
+        wup = new WindowUpdateFrame();
+        wup.streamid(0);
+        wup.setUpdate(len);
+        outputQ.put(wup);
+    }
+
+    HttpHeadersImpl decodeHeaders(List<HeaderFrame> frames) {
+        HttpHeadersImpl headers = new HttpHeadersImpl();
+
+        DecodingCallback cb = (name, value) -> {
+            headers.addHeader(name.toString(), value.toString());
+        };
+
+        for (HeaderFrame frame : frames) {
+            ByteBuffer[] buffers = frame.getHeaderBlock();
+            for (ByteBuffer buffer : buffers) {
+                hpackIn.decode(buffer, false, cb);
+            }
+        }
+        hpackIn.decode(EMPTY_BUFFER, true, cb);
+        return headers;
+    }
+
+    String getRequestLine(String request) {
+        int eol = request.indexOf(CRLF);
+        return request.substring(0, eol);
+    }
+
+    // First stream (1) comes from a plaintext HTTP/1.1 request
+    @SuppressWarnings({"rawtypes","unchecked"})
+    void createPrimordialStream(String request) throws IOException {
+        HttpHeadersImpl headers = new HttpHeadersImpl();
+        String requestLine = getRequestLine(request);
+        String[] tokens = requestLine.split(" ");
+        if (!tokens[2].equals("HTTP/1.1")) {
+            throw new IOException("bad request line");
+        }
+        URI uri = null;
+        try {
+            uri = new URI(tokens[1]);
+        } catch (URISyntaxException e) {
+            throw new IOException(e);
+        }
+        String host = getHeader(request, "Host");
+        if (host == null) {
+            throw new IOException("missing Host");
+        }
+
+        headers.setHeader(":method", tokens[0]);
+        headers.setHeader(":scheme", "http"); // always in this case
+        headers.setHeader(":authority", host);
+        headers.setHeader(":path", uri.getPath());
+        Queue q = new Queue();
+        String body = getRequestBody(request);
+        headers.setHeader("Content-length", Integer.toString(body.length()));
+
+        addRequestBodyToQueue(body, q);
+        streams.put(1, q);
+        exec.submit(() -> {
+            handleRequest(headers, q, 1);
+        });
+    }
+
+    // all other streams created here
+    @SuppressWarnings({"rawtypes","unchecked"})
+    void createStream(HeaderFrame frame) throws IOException {
+        List<HeaderFrame> frames = new LinkedList<>();
+        frames.add(frame);
+        int streamid = frame.streamid();
+        if (streamid != nextstream) {
+            throw new IOException("unexpected stream id");
+        }
+        nextstream += 2;
+
+        while (!frame.getFlag(HeaderFrame.END_HEADERS)) {
+            Http2Frame f = readFrame();
+            if (!(f instanceof HeaderFrame)) {
+                handleCommonFrame(f); // should only be error frames
+            } else {
+                frame = (HeaderFrame) f;
+                frames.add(frame);
+            }
+        }
+        HttpHeadersImpl headers = decodeHeaders(frames);
+        Queue q = new Queue();
+        streams.put(streamid, q);
+        exec.submit(() -> {
+            handleRequest(headers, q, streamid);
+        });
+    }
+
+    // runs in own thread. Handles request from start to finish. Incoming frames
+    // for this stream/request delivered on Q
+
+    @SuppressWarnings({"rawtypes","unchecked"})
+    void handleRequest(HttpHeadersImpl headers, Queue queue, int streamid) {
+        String method = headers.firstValue(":method").orElse("");
+        System.out.println("method = " + method);
+        String path = headers.firstValue(":path").orElse("");
+        System.out.println("path = " + path);
+        String scheme = headers.firstValue(":scheme").orElse("");
+        System.out.println("scheme = " + scheme);
+        String authority = headers.firstValue(":authority").orElse("");
+        System.out.println("authority = " + authority);
+        HttpHeadersImpl rspheaders = new HttpHeadersImpl();
+        int winsize = clientSettings.getParameter(
+                        SettingsFrame.INITIAL_WINDOW_SIZE);
+        System.err.println ("Stream window size = " + winsize);
+        try (
+            BodyInputStream bis = new BodyInputStream(queue, streamid, this);
+            BodyOutputStream bos = new BodyOutputStream(streamid, winsize, this);
+        )
+        {
+            String us = scheme + "://" + authority + path;
+            URI uri = new URI(us);
+            boolean pushAllowed = clientSettings.getParameter(SettingsFrame.ENABLE_PUSH) == 1;
+            Http2TestExchange exchange = new Http2TestExchange(streamid, method,
+                    headers, rspheaders, uri, bis, bos, this, pushAllowed);
+
+            // give to user
+            handler.handle(exchange);
+
+            // everything happens in the exchange from here. Hopefully will
+            // return though.
+        } catch (Throwable e) {
+            System.err.println("TestServer: handleRequest exception: " + e);
+            e.printStackTrace();
+        }
+    }
+
+    // Runs in own thread
+
+    @SuppressWarnings({"rawtypes","unchecked"})
+    void readLoop() {
+        try {
+            while (!stopping) {
+                Http2Frame frame = readFrame();
+                int stream = frame.streamid();
+                if (stream == 0) {
+                    if (frame.type() == WindowUpdateFrame.TYPE) {
+                        WindowUpdateFrame wup = (WindowUpdateFrame) frame;
+                        updateConnectionWindow(wup.getUpdate());
+                    } else {
+                        // other common frame types
+                        handleCommonFrame(frame);
+                    }
+                } else {
+                    Queue q = streams.get(stream);
+                    if (frame.type() == HeadersFrame.TYPE) {
+                        if (q != null) {
+                            System.err.println("HEADERS frame for existing stream! Error.");
+                            // TODO: close connection
+                            continue;
+                        } else {
+                            createStream((HeadersFrame) frame);
+                        }
+                    } else {
+                        if (q == null) {
+                            System.err.printf("Non Headers frame received with"+
+                                " non existing stream (%d) ", frame.streamid());
+                            System.err.println(frame);
+                            continue;
+                        }
+                        if (frame.type() == WindowUpdateFrame.TYPE) {
+                            WindowUpdateFrame wup = (WindowUpdateFrame) frame;
+                            synchronized (updaters) {
+                                Consumer<Integer> r = updaters.get(stream);
+                                r.accept(wup.getUpdate());
+                            }
+                        } else {
+                            q.put(frame);
+                        }
+                    }
+                }
+            }
+        } catch (Throwable e) {
+            close();
+            if (!stopping) {
+                System.err.println("Http server reader thread shutdown");
+                e.printStackTrace();
+            }
+        }
+    }
+
+    // set streamid outside plus other specific fields
+    void encodeHeaders(HttpHeadersImpl headers, HeaderFrame out) {
+        List<ByteBuffer> buffers = new LinkedList<>();
+
+        ByteBuffer buf = getBuffer();
+        boolean encoded;
+        for (Map.Entry<String, List<String>> entry : headers.map().entrySet()) {
+            List<String> values = entry.getValue();
+            String key = entry.getKey().toLowerCase();
+            for (String value : values) {
+                do {
+                    hpackOut.header(key, value);
+                    encoded = hpackOut.encode(buf);
+                    if (!encoded) {
+                        buf.flip();
+                        buffers.add(buf);
+                        buf = getBuffer();
+                    }
+                } while (!encoded);
+            }
+        }
+        buf.flip();
+        buffers.add(buf);
+        out.setFlags(HeaderFrame.END_HEADERS);
+        out.setHeaderBlock(buffers.toArray(bbarray));
+    }
+
+    static void closeIgnore(Closeable c) {
+        try {
+            c.close();
+        } catch (IOException e) {}
+    }
+
+    // Runs in own thread
+    void writeLoop() {
+        try {
+            while (!stopping) {
+                Http2Frame frame = outputQ.take();
+                if (frame instanceof ResponseHeaders) {
+                    ResponseHeaders rh = (ResponseHeaders)frame;
+                    HeadersFrame hf = new HeadersFrame();
+                    encodeHeaders(rh.headers, hf);
+                    hf.streamid(rh.streamid());
+                    writeFrame(hf);
+                } else if (frame instanceof OutgoingPushPromise) {
+                    handlePush((OutgoingPushPromise)frame);
+                } else
+                    writeFrame(frame);
+            }
+            System.err.println("Connection writer stopping");
+        } catch (Throwable e) {
+            e.printStackTrace();
+            /*close();
+            if (!stopping) {
+                e.printStackTrace();
+                System.err.println("TestServer: writeLoop exception: " + e);
+            }*/
+        }
+    }
+
+    private void handlePush(OutgoingPushPromise op) throws IOException {
+        PushPromiseFrame pp = new PushPromiseFrame();
+        encodeHeaders(op.headers, pp);
+        int promisedStreamid = nextPushStreamId;
+        nextPushStreamId += 2;
+        pp.streamid(op.parentStream);
+        pp.setPromisedStream(promisedStreamid);
+        writeFrame(pp);
+        final InputStream ii = op.is;
+        final BodyOutputStream oo = new BodyOutputStream(
+                promisedStreamid,
+                clientSettings.getParameter(
+                        SettingsFrame.INITIAL_WINDOW_SIZE), this);
+        oo.goodToGo();
+        exec.submit(() -> {
+            try {
+                ResponseHeaders oh = getPushResponse(promisedStreamid);
+                outputQ.put(oh);
+                ii.transferTo(oo);
+            } catch (Throwable ex) {
+                System.err.printf("TestServer: pushing response error: %s\n",
+                        ex.toString());
+            } finally {
+                closeIgnore(ii);
+                closeIgnore(oo);
+            }
+        });
+
+    }
+
+    // returns a minimal response with status 200
+    // that is the response to the push promise just sent
+    private ResponseHeaders getPushResponse(int streamid) {
+        HttpHeadersImpl h = new HttpHeadersImpl();
+        h.addHeader(":status", "200");
+        ResponseHeaders oh = new ResponseHeaders(h);
+        oh.streamid(streamid);
+        return oh;
+    }
+
+    private ByteBuffer getBuffer() {
+        return ByteBuffer.allocate(8 * 1024);
+    }
+
+    private Http2Frame readFrame() throws IOException {
+        byte[] buf = new byte[9];
+        if (is.readNBytes(buf, 0, 9) != 9)
+            throw new IOException("readFrame: connection closed");
+        int len = 0;
+        for (int i = 0; i < 3; i++) {
+            int n = buf[i] & 0xff;
+            //System.err.println("n = " + n);
+            len = (len << 8) + n;
+        }
+        byte[] rest = new byte[len];
+        int n = is.readNBytes(rest, 0, len);
+        if (n != len)
+            throw new IOException("Error reading frame");
+        ByteBufferConsumer bc = new ByteBufferConsumer(
+                new LinkedList<ByteBuffer>(List.of(ByteBuffer.wrap(buf), ByteBuffer.wrap(rest))),
+                this::getBuffer);
+        return Http2Frame.readIncoming(bc);
+    }
+
+    void sendSettingsFrame() throws IOException {
+        sendSettingsFrame(false);
+    }
+
+    void sendSettingsFrame(boolean now) throws IOException {
+        if (serverSettings == null) {
+            serverSettings = SettingsFrame.getDefaultSettings();
+        }
+        if (now) {
+            writeFrame(serverSettings);
+        } else {
+            outputQ.put(serverSettings);
+        }
+    }
+
+    String readUntil(String end) throws IOException {
+        int number = end.length();
+        int found = 0;
+        StringBuilder sb = new StringBuilder();
+        while (found < number) {
+            char expected = end.charAt(found);
+            int c = is.read();
+            if (c == -1) {
+                throw new IOException("Connection closed");
+            }
+            char c0 = (char) c;
+            sb.append(c0);
+            if (c0 != expected) {
+                found = 0;
+                continue;
+            }
+            found++;
+        }
+        return sb.toString();
+    }
+
+    private int getContentLength(String headers) {
+        return getIntHeader(headers, "Content-length");
+    }
+
+    private int getIntHeader(String headers, String name) {
+        String val = getHeader(headers, name);
+        if (val == null) {
+            return -1;
+        }
+        return Integer.parseInt(val);
+    }
+
+    private String getHeader(String headers, String name) {
+        String headers1 = headers.toLowerCase(); // not efficient
+        name = CRLF + name.toLowerCase();
+        int start = headers1.indexOf(name);
+        if (start == -1) {
+            return null;
+        }
+        start += 2;
+        int end = headers1.indexOf(CRLF, start);
+        String line = headers.substring(start, end);
+        start = line.indexOf(':');
+        if (start == -1) {
+            return null;
+        }
+        return line.substring(start + 1).trim();
+    }
+
+    final static String CRLF = "\r\n";
+
+    String readHttp1Request() throws IOException {
+        String headers = readUntil(CRLF + CRLF);
+        int clen = getContentLength(headers);
+        // read the content. There shouldn't be content but ..
+        byte[] buf = new byte[clen];
+        is.readNBytes(buf, 0, clen);
+        String body = new String(buf, "US-ASCII");
+        return headers + body;
+    }
+
+    void sendHttp1Response(int code, String msg, String... headers) throws IOException {
+        StringBuilder sb = new StringBuilder();
+        sb.append("HTTP/1.1 ")
+                .append(code)
+                .append(' ')
+                .append(msg)
+                .append(CRLF);
+        int numheaders = headers.length;
+        for (int i = 0; i < numheaders; i += 2) {
+            sb.append(headers[i])
+                    .append(": ")
+                    .append(headers[i + 1])
+                    .append(CRLF);
+        }
+        sb.append(CRLF);
+        String s = sb.toString();
+        os.write(s.getBytes("US-ASCII"));
+        os.flush();
+    }
+
+    private void unexpectedFrame(Http2Frame frame) {
+        System.err.println("OOPS. Unexpected");
+        assert false;
+    }
+
+    final static ByteBuffer[] bbarray = new ByteBuffer[0];
+
+    // wrapper around a BlockingQueue that throws an exception when it's closed
+    // Each stream has one of these
+
+    String getRequestBody(String request) {
+        int bodystart = request.indexOf(CRLF+CRLF);
+        String body;
+        if (bodystart == -1)
+            body = "";
+        else
+            body = request.substring(bodystart+4);
+        return body;
+    }
+
+    @SuppressWarnings({"rawtypes","unchecked"})
+    void addRequestBodyToQueue(String body, Queue q) throws IOException {
+        ByteBuffer buf = ByteBuffer.wrap(body.getBytes(StandardCharsets.US_ASCII));
+        DataFrame df = new DataFrame();
+        df.streamid(1); // only used for primordial stream
+        df.setData(buf);
+        df.computeLength();
+        df.setFlag(DataFrame.END_STREAM);
+        q.put(df);
+    }
+
+    // window updates done in main reader thread because they may
+    // be used to unblock BodyOutputStreams waiting for WUPs
+
+    HashMap<Integer,Consumer<Integer>> updaters = new HashMap<>();
+
+    void registerStreamWindowUpdater(int streamid, Consumer<Integer> r) {
+        synchronized(updaters) {
+            updaters.put(streamid, r);
+        }
+    }
+
+    int sendWindow = 64 * 1024 - 1; // connection level send window
+
+    /**
+     * BodyOutputStreams call this to get the connection window first.
+     *
+     * @param amount
+     */
+    synchronized void obtainConnectionWindow(int amount) throws InterruptedException {
+       while (amount > 0) {
+           int n = Math.min(amount, sendWindow);
+           amount -= n;
+           sendWindow -= n;
+           if (amount > 0)
+               wait();
+       }
+    }
+
+    synchronized void updateConnectionWindow(int amount) {
+        sendWindow += amount;
+        notifyAll();
+    }
+
+    // simplified output headers class. really just a type safe container
+    // for the hashmap.
+
+    static class ResponseHeaders extends Http2Frame {
+        HttpHeadersImpl headers;
+
+        ResponseHeaders(HttpHeadersImpl headers) {
+            this.headers = headers;
+        }
+
+        @Override
+        void readIncomingImpl(ByteBufferConsumer bc) throws IOException {
+            throw new UnsupportedOperationException("Not supported ever!");
+        }
+
+        @Override
+        void computeLength() {
+            throw new UnsupportedOperationException("Not supported ever!");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/httpclient/http2/java.httpclient/java/net/http/OutgoingPushPromise.java	Tue May 03 12:25:20 2016 -0700
@@ -0,0 +1,31 @@
+package java.net.http;
+
+import java.io.*;
+import java.net.*;
+
+// will be converted to a PushPromiseFrame in the writeLoop
+// a thread is then created to produce the DataFrames from the InputStream
+class OutgoingPushPromise extends Http2Frame {
+    final HttpHeadersImpl headers;
+    final URI uri;
+    final InputStream is;
+    final int parentStream; // not the pushed streamid
+
+    OutgoingPushPromise(int parentStream, URI uri, HttpHeadersImpl headers, InputStream is) {
+        this.uri = uri;
+        this.headers = headers;
+        this.is = is;
+        this.parentStream = parentStream;
+    }
+
+    @Override
+    void readIncomingImpl(ByteBufferConsumer bc) throws IOException {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    @Override
+    void computeLength() {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/httpclient/http2/java.httpclient/java/net/http/PushHandler.java	Tue May 03 12:25:20 2016 -0700
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net.http;
+
+import java.io.*;
+import java.net.*;
+import java.nio.file.*;
+import java.nio.file.attribute.*;
+import java.net.http.*;
+import java.util.*;
+import java.util.concurrent.*;
+
+public class PushHandler implements Http2Handler {
+
+    final Path tempFile;
+    final int loops;
+
+    public PushHandler(int file_size, int loops) throws Exception {
+        tempFile = TestUtil.getAFile(file_size);
+        this.loops = loops;
+    }
+
+    int invocation = 0;
+
+    public void handle(Http2TestExchange ee) {
+        try {
+            System.err.println ("Server: handle " + ee);
+            invocation++;
+
+            if (ee.serverPushAllowed()) {
+                for (int i=0; i<loops; i++) {
+                    InputStream is = new FileInputStream(tempFile.toFile());
+                    URI u = new URI ("http://www.foo.com/" + Integer.toString(i));
+                    HttpHeadersImpl h = new HttpHeadersImpl();
+                    h.addHeader("X-foo", "bar");
+                    ee.serverPush(u, h, is);
+                }
+                System.err.println ("Server: sent all pushes");
+            }
+            ee.sendResponseHeaders(200, 0);
+            OutputStream os = ee.getResponseBody();
+            InputStream iis = new FileInputStream(tempFile.toFile());
+            iis.transferTo(os);
+            os.close();
+            iis.close();
+        } catch (Exception ex) {
+            System.err.println ("Server: exception " + ex);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/net/httpclient/http2/java.httpclient/java/net/http/TestUtil.java	Tue May 03 12:25:20 2016 -0700
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net.http;
+
+import java.io.*;
+import java.net.*;
+import java.nio.file.*;
+import java.util.concurrent.*;
+import java.util.Arrays;
+
+public class TestUtil {
+
+    final static String fileContent = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; // repeated
+
+    public static Path getAFile(int size) throws IOException {
+        Path p = tempFile();
+        BufferedWriter writer = Files.newBufferedWriter(p);
+        int len = fileContent.length();
+        int iterations = size / len;
+        int remainder = size - (iterations * len);
+        for (int i=0; i<iterations; i++)
+            writer.write(fileContent, 0, len);
+        writer.write(fileContent, 0, remainder);
+        writer.close();
+        return p;
+    }
+
+    public static Path tempFile() {
+        try {
+            Path p = Files.createTempFile("foo", "test");
+            p.toFile().deleteOnExit();
+            return p;
+        } catch (IOException e) {
+            throw new UncheckedIOException(e);
+        }
+    }
+
+    public static Void compareFiles(Path path1, Path path2) {
+        try {
+            if (Files.size(path1) != Files.size(path2))
+                throw new RuntimeException("File sizes do not match");
+            compareContents(path1, path2);
+            return null;
+        } catch (IOException e) {
+            throw new UncheckedIOException(e);
+        }
+    }
+
+    static void compareContents(Path path1, Path path2) {
+        try {
+            byte[] b1 = Files.readAllBytes(path1);
+            byte[] b2 = Files.readAllBytes(path2);
+            if (!Arrays.equals(b1, b2))
+                throw new RuntimeException ("Files do not match");
+        } catch (IOException e) {
+            throw new UncheckedIOException(e);
+        }
+    }
+
+}
--- a/jdk/test/java/net/httpclient/security/15.policy	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/test/java/net/httpclient/security/15.policy	Tue May 03 12:25:20 2016 -0700
@@ -16,7 +16,7 @@
     permission java.net.URLPermission "socket://127.0.0.1:27301", "CONNECT";
 
     // Test checks for this explicitly
-    permission java.net.RuntimePermission "foobar"; 
+    permission java.net.RuntimePermission "foobar";
 };
 
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/nio/file/WatchService/DeleteInterference.java	Tue May 03 12:25:20 2016 -0700
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2016, Red Hat, Inc. and/or its affiliates.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute 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.
+ */
+
+/**
+ * @test
+ * @bug 8153925
+ * @summary Tests potential interference between a thread creating and closing
+ *     a WatchService with another thread that is deleting and re-creating the
+ *     directory at around the same time. This scenario tickled a timing bug
+ *     in the Windows implementation.
+ */
+
+import java.io.IOException;
+import java.nio.file.DirectoryStream;
+import java.nio.file.FileSystem;
+import java.nio.file.FileSystems;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.WatchService;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+
+import static java.nio.file.StandardWatchEventKinds.*;
+
+public class DeleteInterference {
+
+    private static final int ITERATIONS_COUNT = 1024;
+
+    /**
+     * Execute two tasks in a thread pool. One task loops on creating and
+     * closing a WatchService, the other task deletes and re-creates the
+     * directory.
+     */
+    public static void main(String[] args) throws Exception {
+        Path dir = Files.createTempDirectory("work");
+        ExecutorService pool = Executors.newCachedThreadPool();
+        try {
+            Future<?> task1 = pool.submit(() -> openAndCloseWatcher(dir));
+            Future<?> task2 = pool.submit(() -> deleteAndRecreateDirectory(dir));
+            task1.get();
+            task2.get();
+        } finally {
+            pool.shutdown();
+            deleteFileTree(dir);
+        }
+    }
+
+    private static void openAndCloseWatcher(Path dir) {
+        FileSystem fs = FileSystems.getDefault();
+        for (int i = 0; i < ITERATIONS_COUNT; i++) {
+            try (WatchService watcher = fs.newWatchService()) {
+                dir.register(watcher, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY);
+            } catch (IOException ioe) {
+                // ignore
+            }
+        }
+    }
+
+    private static void deleteAndRecreateDirectory(Path dir) {
+        for (int i = 0; i < ITERATIONS_COUNT; i++) {
+            try {
+                deleteFileTree(dir);
+                Path subdir = Files.createDirectories(dir.resolve("subdir"));
+                Files.createFile(subdir.resolve("test"));
+            } catch (IOException ioe) {
+                // ignore
+            }
+        }
+    }
+
+    private static void deleteFileTree(Path file) {
+        try {
+            if (Files.isDirectory(file)) {
+                try (DirectoryStream<Path> stream = Files.newDirectoryStream(file)) {
+                    for (Path pa : stream) {
+                        deleteFileTree(pa);
+                    }
+                }
+            }
+            Files.delete(file);
+        } catch (IOException ioe) {
+            // ignore
+        }
+    }
+}
--- a/jdk/test/java/util/ResourceBundle/Bug6299235Test.sh	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/test/java/util/ResourceBundle/Bug6299235Test.sh	Tue May 03 12:25:20 2016 -0700
@@ -68,7 +68,7 @@
 ${TESTJAVA}/bin/jar xf ${TESTSRC}/awtres.jar
 
 echo 
-${TESTJAVA}/bin/java ${TESTVMOPTS} -Xpatch:${PATCHDIR} \
+${TESTJAVA}/bin/java ${TESTVMOPTS} -Xpatch:java.desktop=${PATCHDIR}/java.desktop \
      -cp ${TESTCLASSES} Bug6299235Test
 
 if [ $? -ne 0 ]
--- a/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/DoublePrimitiveOpsTests.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/DoublePrimitiveOpsTests.java	Tue May 03 12:25:20 2016 -0700
@@ -27,11 +27,18 @@
 
 import java.util.Arrays;
 import java.util.Random;
+import java.util.Spliterator;
 import java.util.stream.DoubleStream;
 import java.util.stream.LongStream;
 
 import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
 
+/**
+ * @test
+ * @bug 8153293
+ */
 @Test
 public class DoublePrimitiveOpsTests {
 
@@ -42,6 +49,13 @@
         assertEquals(sum, 1.0 + 2.0 + 3.0 + 4.0 + 5.0);
     }
 
+    public void testFlags() {
+        assertTrue(LongStream.range(1, 10).asDoubleStream().boxed().spliterator()
+                      .hasCharacteristics(Spliterator.SORTED));
+        assertFalse(DoubleStream.of(1, 10).boxed().spliterator()
+                      .hasCharacteristics(Spliterator.SORTED));
+    }
+
     public void testToArray() {
         {
             double[] array =  LongStream.range(1, 10).asDoubleStream().map(i -> i * 2).toArray();
@@ -72,6 +86,22 @@
         }
     }
 
+    public void testSortDistinct() {
+        {
+            double[] range = LongStream.range(0, 10).asDoubleStream().toArray();
+
+            assertEquals(LongStream.range(0, 10).asDoubleStream().sorted().distinct().toArray(), range);
+            assertEquals(LongStream.range(0, 10).asDoubleStream().parallel().sorted().distinct().toArray(), range);
+
+            double[] data = {5, 3, 1, 1, 5, Double.NaN, 3, 9, Double.POSITIVE_INFINITY,
+                             Double.NEGATIVE_INFINITY, 2, 9, 1, 0, 8, Double.NaN, -0.0};
+            double[] expected = {Double.NEGATIVE_INFINITY, -0.0, 0, 1, 2, 3, 5, 8, 9,
+                                 Double.POSITIVE_INFINITY, Double.NaN};
+            assertEquals(DoubleStream.of(data).sorted().distinct().toArray(), expected);
+            assertEquals(DoubleStream.of(data).parallel().sorted().distinct().toArray(), expected);
+        }
+    }
+
     public void testSortSort() {
         Random r = new Random();
 
--- a/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/IntPrimitiveOpsTests.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/IntPrimitiveOpsTests.java	Tue May 03 12:25:20 2016 -0700
@@ -28,13 +28,21 @@
 import java.util.Arrays;
 import java.util.List;
 import java.util.Random;
+import java.util.Spliterator;
+import java.util.TreeSet;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.function.IntConsumer;
 import java.util.stream.Collectors;
 import java.util.stream.IntStream;
 
 import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
 
+/**
+ * @test
+ * @bug 8153293
+ */
 @Test
 public class IntPrimitiveOpsTests {
 
@@ -85,6 +93,29 @@
         assertEquals(sum, 15);
     }
 
+    public void testFlags() {
+        assertTrue(IntStream.range(1, 10).boxed().spliterator()
+                      .hasCharacteristics(Spliterator.SORTED | Spliterator.DISTINCT));
+        assertFalse(IntStream.of(1, 10).boxed().spliterator()
+                      .hasCharacteristics(Spliterator.SORTED));
+        assertFalse(IntStream.of(1, 10).boxed().spliterator()
+                      .hasCharacteristics(Spliterator.DISTINCT));
+
+        assertTrue(IntStream.range(1, 10).asLongStream().spliterator()
+                      .hasCharacteristics(Spliterator.SORTED | Spliterator.DISTINCT));
+        assertFalse(IntStream.of(1, 10).asLongStream().spliterator()
+                      .hasCharacteristics(Spliterator.SORTED));
+        assertFalse(IntStream.of(1, 10).asLongStream().spliterator()
+                      .hasCharacteristics(Spliterator.DISTINCT));
+
+        assertTrue(IntStream.range(1, 10).asDoubleStream().spliterator()
+                      .hasCharacteristics(Spliterator.SORTED | Spliterator.DISTINCT));
+        assertFalse(IntStream.of(1, 10).asDoubleStream().spliterator()
+                      .hasCharacteristics(Spliterator.SORTED));
+        assertFalse(IntStream.of(1, 10).asDoubleStream().spliterator()
+                      .hasCharacteristics(Spliterator.DISTINCT));
+    }
+
     public void testToArray() {
         {
             int[] array =  IntStream.range(1, 10).map(i -> i * 2).toArray();
@@ -115,6 +146,35 @@
         }
     }
 
+    public void testSortDistinct() {
+        {
+            int[] range = IntStream.range(0, 10).toArray();
+
+            assertEquals(IntStream.range(0, 10).sorted().distinct().toArray(), range);
+            assertEquals(IntStream.range(0, 10).parallel().sorted().distinct().toArray(), range);
+
+            int[] data = {5, 3, 1, 1, 5, 3, 9, 2, 9, 1, 0, 8};
+            int[] expected = {0, 1, 2, 3, 5, 8, 9};
+            assertEquals(IntStream.of(data).sorted().distinct().toArray(), expected);
+            assertEquals(IntStream.of(data).parallel().sorted().distinct().toArray(), expected);
+        }
+
+        {
+            int[] input = new Random().ints(100, -10, 10).map(x -> x+Integer.MAX_VALUE).toArray();
+            TreeSet<Long> longs = new TreeSet<>();
+            for(int i : input) longs.add((long)i);
+            long[] expectedLongs = longs.stream().mapToLong(Long::longValue).toArray();
+            assertEquals(IntStream.of(input).sorted().asLongStream().sorted().distinct().toArray(),
+                         expectedLongs);
+
+            TreeSet<Double> doubles = new TreeSet<>();
+            for(int i : input) doubles.add((double)i);
+            double[] expectedDoubles = doubles.stream().mapToDouble(Double::doubleValue).toArray();
+            assertEquals(IntStream.of(input).sorted().distinct().asDoubleStream()
+                         .sorted().distinct().toArray(), expectedDoubles);
+        }
+    }
+
     public void testSortSort() {
         Random r = new Random();
 
--- a/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/LongPrimitiveOpsTests.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/LongPrimitiveOpsTests.java	Tue May 03 12:25:20 2016 -0700
@@ -28,13 +28,21 @@
 import java.util.Arrays;
 import java.util.List;
 import java.util.Random;
+import java.util.Spliterator;
+import java.util.TreeSet;
 import java.util.concurrent.atomic.AtomicLong;
 import java.util.function.LongConsumer;
 import java.util.stream.Collectors;
 import java.util.stream.LongStream;
 
 import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
 
+/**
+ * @test
+ * @bug 8153293
+ */
 @Test
 public class LongPrimitiveOpsTests {
 
@@ -85,6 +93,22 @@
         assertEquals(sum, 15);
     }
 
+    public void testFlags() {
+        assertTrue(LongStream.range(1, 10).boxed().spliterator()
+                      .hasCharacteristics(Spliterator.SORTED | Spliterator.DISTINCT));
+        assertFalse(LongStream.of(1, 10).boxed().spliterator()
+                      .hasCharacteristics(Spliterator.SORTED));
+        assertFalse(LongStream.of(1, 10).boxed().spliterator()
+                      .hasCharacteristics(Spliterator.DISTINCT));
+
+        assertTrue(LongStream.range(1, 10).asDoubleStream().spliterator()
+                      .hasCharacteristics(Spliterator.SORTED));
+        assertFalse(LongStream.range(1, 10).asDoubleStream().spliterator()
+                      .hasCharacteristics(Spliterator.DISTINCT));
+        assertFalse(LongStream.of(1, 10).asDoubleStream().spliterator()
+                      .hasCharacteristics(Spliterator.SORTED));
+    }
+
     public void testToArray() {
         {
             long[] array =  LongStream.range(1, 10).map(i -> i * 2).toArray();
@@ -115,6 +139,30 @@
         }
     }
 
+    public void testSortDistinct() {
+        {
+            long[] range = LongStream.range(0, 10).toArray();
+
+            assertEquals(LongStream.range(0, 10).sorted().distinct().toArray(), range);
+            assertEquals(LongStream.range(0, 10).parallel().sorted().distinct().toArray(), range);
+
+            long[] data = {5, 3, 1, 1, 5, 3, 9, 2, 9, 1, 0, 8};
+            long[] expected = {0, 1, 2, 3, 5, 8, 9};
+            assertEquals(LongStream.of(data).sorted().distinct().toArray(), expected);
+            assertEquals(LongStream.of(data).parallel().sorted().distinct().toArray(), expected);
+        }
+
+        {
+            long[] input = new Random().longs(100, -10, 10).map(x -> x+Long.MAX_VALUE).toArray();
+
+            TreeSet<Double> doubles = new TreeSet<>();
+            for(long i : input) doubles.add((double)i);
+            double[] expectedDoubles = doubles.stream().mapToDouble(Double::doubleValue).toArray();
+            assertEquals(LongStream.of(input).sorted().distinct().asDoubleStream()
+                         .sorted().distinct().toArray(), expectedDoubles);
+        }
+    }
+
     public void testSortSort() {
         Random r = new Random();
 
--- a/jdk/test/javax/crypto/Cipher/CipherStreamClose.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/test/javax/crypto/Cipher/CipherStreamClose.java	Tue May 03 12:25:20 2016 -0700
@@ -27,6 +27,8 @@
  * @summary Make sure Cipher IO streams doesn't call extra doFinal if close()
  * is called multiple times.  Additionally, verify the input and output streams
  * match with encryption and decryption with non-stream crypto.
+ * @compile -addmods java.xml.bind CipherStreamClose.java
+ * @run main/othervm -addmods java.xml.bind CipherStreamClose
  */
 
 import java.io.*;
--- a/jdk/test/javax/rmi/PortableRemoteObject/ConcurrentHashMapTest.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/test/javax/rmi/PortableRemoteObject/ConcurrentHashMapTest.java	Tue May 03 12:25:20 2016 -0700
@@ -27,8 +27,10 @@
  * @summary test RMI-IIOP call with ConcurrentHashMap as an argument
  * @library /lib/testlibrary
  * @build jdk.testlibrary.*
- * @build Test HelloInterface HelloServer HelloClient HelloImpl _HelloImpl_Tie _HelloInterface_Stub ConcurrentHashMapTest
- * @run main/othervm -Djava.naming.provider.url=iiop://localhost:1050 -Djava.naming.factory.initial=com.sun.jndi.cosnaming.CNCtxFactory  ConcurrentHashMapTest
+ * @compile -addmods java.corba Test.java HelloInterface.java HelloServer.java HelloClient.java
+ *    HelloImpl.java _HelloImpl_Tie.java _HelloInterface_Stub.java ConcurrentHashMapTest.java
+ * @run main/othervm -addmods java.corba -Djava.naming.provider.url=iiop://localhost:1050
+ *    -Djava.naming.factory.initial=com.sun.jndi.cosnaming.CNCtxFactory ConcurrentHashMapTest
  * @key intermittent
  */
 
@@ -101,6 +103,8 @@
         // -Djava.naming.provider.url=iiop://localhost:1050 HelloServer
         List<String> commands = new ArrayList<>();
         commands.add(ConcurrentHashMapTest.JAVA);
+        commands.add("-addmods");
+        commands.add("java.corba");
         commands.add("-Djava.naming.factory.initial=com.sun.jndi.cosnaming.CNCtxFactory");
         commands.add("-Djava.naming.provider.url=iiop://localhost:1050");
         commands.add("-cp");
--- a/jdk/test/javax/smartcardio/CommandAPDUTest.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/test/javax/smartcardio/CommandAPDUTest.java	Tue May 03 12:25:20 2016 -0700
@@ -26,7 +26,8 @@
  * @bug 8049021
  * @summary Test different constructors for CommandAPDU and check CLA,INS,NC,NE,
  * P1,and P2
- * @run testng CommandAPDUTest
+ * @compile -addmods java.smartcardio CommandAPDUTest.java
+ * @run testng/othervm -addmods java.smartcardio CommandAPDUTest
  */
 import java.nio.ByteBuffer;
 import javax.smartcardio.CommandAPDU;
--- a/jdk/test/javax/smartcardio/HistoricalBytes.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/test/javax/smartcardio/HistoricalBytes.java	Tue May 03 12:25:20 2016 -0700
@@ -26,7 +26,9 @@
  * @bug 6445367
  * @summary Verify that ATR.getHistoricalBytes() works
  * @author Andreas Sterbenz
-**/
+ * @compile -addmods java.smartcardio HistoricalBytes.java
+ * @run main/othervm -addmods java.smartcardio HistoricalBytes
+ */
 
 import java.util.Arrays;
 
--- a/jdk/test/javax/smartcardio/ResponseAPDUTest.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/test/javax/smartcardio/ResponseAPDUTest.java	Tue May 03 12:25:20 2016 -0700
@@ -25,7 +25,8 @@
  * @test
  * @bug 8049021
  * @summary Construct ResponseAPDU from byte array and check NR< SW, SW1 and SW2
- * @run testng ResponseAPDUTest
+ * @compile -addmods java.smartcardio ResponseAPDUTest.java
+ * @run testng/othervm -addmods java.smartcardio ResponseAPDUTest
  */
 import javax.smartcardio.ResponseAPDU;
 import static org.testng.Assert.*;
--- a/jdk/test/javax/smartcardio/Serialize.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/test/javax/smartcardio/Serialize.java	Tue May 03 12:25:20 2016 -0700
@@ -26,6 +26,8 @@
  * @bug 6445367
  * @summary make sure serialization works
  * @author Andreas Sterbenz
+ * @compile -addmods java.smartcardio Serialize.java
+ * @run main/othervm -addmods java.smartcardio Serialize
  */
 
 import java.io.*;
--- a/jdk/test/javax/smartcardio/TerminalFactorySpiTest.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/test/javax/smartcardio/TerminalFactorySpiTest.java	Tue May 03 12:25:20 2016 -0700
@@ -25,7 +25,8 @@
  * @test
  * @bug 8049021
  * @summary Test if we can write new provider for smart card
- * @run main/othervm/policy=policy TerminalFactorySpiTest
+ * @compile -addmods java.smartcardio TerminalFactorySpiTest.java
+ * @run main/othervm/policy=policy -addmods java.smartcardio TerminalFactorySpiTest
  */
 import java.security.Provider;
 import java.security.Security;
--- a/jdk/test/javax/smartcardio/TestCardPermission.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/test/javax/smartcardio/TestCardPermission.java	Tue May 03 12:25:20 2016 -0700
@@ -26,6 +26,8 @@
  * @bug 6293767
  * @summary Test for the CardPermission class
  * @author Andreas Sterbenz
+ * @compile -addmods java.smartcardio TestCardPermission.java
+ * @run main/othervm -addmods java.smartcardio TestCardPermission
  */
 
 import javax.smartcardio.*;
--- a/jdk/test/javax/smartcardio/TestCommandAPDU.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/test/javax/smartcardio/TestCommandAPDU.java	Tue May 03 12:25:20 2016 -0700
@@ -27,6 +27,8 @@
  * @summary Test for the CommandAPDU class
  * @author Andreas Sterbenz
  * @key randomness
+ * @compile -addmods java.smartcardio TestCommandAPDU.java
+ * @run main/othervm -addmods java.smartcardio TestCommandAPDU
  */
 
 import java.util.*;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/javax/transaction/testng/Driver.java	Tue May 03 12:25:20 2016 -0700
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @compile -addmods java.transaction
+ *   test/transaction/InvalidTransactionExceptionTests.java
+ *   test/transaction/TransactionRequiredExceptionTests.java
+ *   test/transaction/TransactionRolledbackExceptionTests.java
+ *   test/transaction/XAExceptionTests.java
+ *   util/SerializedTransactionExceptions.java
+ * @run testng/othervm -addmods java.transaction test.transaction.InvalidTransactionExceptionTests
+ * @run testng/othervm -addmods java.transaction test.transaction.TransactionRequiredExceptionTests
+ * @run testng/othervm -addmods java.transaction test.transaction.TransactionRolledbackExceptionTests
+ * @run testng/othervm -addmods java.transaction util.SerializedTransactionExceptions
+ */
--- a/jdk/test/javax/transaction/testng/TEST.properties	Tue May 03 09:48:02 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,4 +0,0 @@
-# JDBC unit tests uses TestNG
-TestNG.dirs= .
-othervm.dirs= .
-
--- a/jdk/test/javax/xml/bind/xjc/8032884/XjcOptionalPropertyTest.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/test/javax/xml/bind/xjc/8032884/XjcOptionalPropertyTest.java	Tue May 03 12:25:20 2016 -0700
@@ -26,6 +26,7 @@
  * @bug 8032884
  * @summary Globalbindings optionalProperty="primitive" does not work when minOccurs=0
  * @run shell compile-schema.sh
+ * @compile -addmods java.xml.bind XjcOptionalPropertyTest.java
  * @run main/othervm XjcOptionalPropertyTest
  */
 
--- a/jdk/test/javax/xml/jaxp/common/8035437/run.sh	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/test/javax/xml/jaxp/common/8035437/run.sh	Tue May 03 12:25:20 2016 -0700
@@ -34,12 +34,12 @@
    -d compile/java.xml -Xmodule:java.xml $TESTSRC/Document.java $TESTSRC/Node.java || exit 1
 
 $COMPILEJAVA/bin/javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} \
-   -d exec/java.xml -Xpatch:compile -Xmodule:java.xml $TESTSRC/DocumentImpl.java || exit 2
+   -d exec/java.xml -Xpatch:java.xml=compile/java.xml -Xmodule:java.xml $TESTSRC/DocumentImpl.java || exit 2
 
 $COMPILEJAVA/bin/javac ${TESTJAVACOPTS} ${TESTTOOLVMOPTS} \
    $TESTSRC/AbstractMethodErrorTest.java -d exec || exit 3
 
-$TESTJAVA/bin/java ${TESTVMOPTS} -Xpatch:exec -cp exec AbstractMethodErrorTest || exit 4
+$TESTJAVA/bin/java ${TESTVMOPTS} -Xpatch:java.xml=exec -cp exec AbstractMethodErrorTest || exit 4
 
 exit 0
 
--- a/jdk/test/javax/xml/soap/XmlTest.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/test/javax/xml/soap/XmlTest.java	Tue May 03 12:25:20 2016 -0700
@@ -38,6 +38,8 @@
 
 /*
  * @test
+ * @compile -addmods java.xml.ws XmlTest.java
+ * @run main/othervm -addmods java.xml.ws XmlTest
  * @summary tests JAF DataHandler can be instantiated; test serialize and
  *   deserialize SOAP message containing xml attachment
  */
--- a/jdk/test/javax/xml/soap/spi/SAAJFactoryTest.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/test/javax/xml/soap/spi/SAAJFactoryTest.java	Tue May 03 12:25:20 2016 -0700
@@ -49,29 +49,29 @@
  * run main/othervm SAAJFactoryTest saaj.factory.Valid -
  *      scenario14 javax.xml.soap.MessageFactory=saaj.factory.Valid saaj.factory.Valid2 -
  *
- * @build saaj.factory.*
+ * @compile -addmods java.xml.ws saaj/factory/Invalid.java saaj/factory/Valid.java
+ *     saaj/factory/Valid2.java saaj/factory/Valid3.java SAAJFactoryTest.java
  *
- * @run main/othervm SAAJFactoryTest com.sun.xml.internal.messaging.saaj.soap.ver1_1.SOAPMessageFactory1_1Impl -
- *      scenario2 - -
- * @run main/othervm -Djavax.xml.soap.MessageFactory=saaj.factory.Valid SAAJFactoryTest saaj.factory.Valid -
- *      scenario5 - -
- * @run main/othervm -Djavax.xml.soap.MessageFactory=saaj.factory.NonExisting SAAJFactoryTest
- *      - javax.xml.soap.SOAPException
- *      scenario6 - -
- * @run main/othervm -Djavax.xml.soap.MessageFactory=saaj.factory.Invalid SAAJFactoryTest - javax.xml.soap.SOAPException
- *      scenario7 - -
- * @run main/othervm SAAJFactoryTest saaj.factory.Valid -
- *      scenario8 - saaj.factory.Valid
- * @run main/othervm SAAJFactoryTest saaj.factory.Valid -
- *      scenario9 - saaj.factory.Valid
- * @run main/othervm SAAJFactoryTest - javax.xml.soap.SOAPException
- *      scenario10 - saaj.factory.NonExisting
- * @run main/othervm SAAJFactoryTest - javax.xml.soap.SOAPException
- *      scenario11 - saaj.factory.Invalid
- * @run main/othervm SAAJFactoryTest com.sun.xml.internal.messaging.saaj.soap.ver1_1.SOAPMessageFactory1_1Impl -
- *      scenario12 - -
- * @run main/othervm SAAJFactoryTest saaj.factory.Valid -
- *      scenario15 - saaj.factory.Valid
+ * @run main/othervm -addmods java.xml.ws
+ *      SAAJFactoryTest com.sun.xml.internal.messaging.saaj.soap.ver1_1.SOAPMessageFactory1_1Impl - scenario2 - -
+ * @run main/othervm -addmods java.xml.ws -Djavax.xml.soap.MessageFactory=saaj.factory.Valid
+ *      SAAJFactoryTest saaj.factory.Valid - scenario5 - -
+ * @run main/othervm -addmods java.xml.ws -Djavax.xml.soap.MessageFactory=saaj.factory.NonExisting
+ *      SAAJFactoryTest - javax.xml.soap.SOAPException scenario6 - -
+ * @run main/othervm -addmods java.xml.ws -Djavax.xml.soap.MessageFactory=saaj.factory.Invalid
+ *      SAAJFactoryTest - javax.xml.soap.SOAPException scenario7 - -
+ * @run main/othervm  -addmods java.xml.ws
+ *      SAAJFactoryTest saaj.factory.Valid - scenario8 - saaj.factory.Valid
+ * @run main/othervm -addmods java.xml.ws
+ *      SAAJFactoryTest saaj.factory.Valid - scenario9 - saaj.factory.Valid
+ * @run main/othervm -addmods java.xml.ws
+ *      SAAJFactoryTest - javax.xml.soap.SOAPException scenario10 - saaj.factory.NonExisting
+ * @run main/othervm -addmods java.xml.ws
+ *      SAAJFactoryTest - javax.xml.soap.SOAPException scenario11 - saaj.factory.Invalid scenario11 - saaj.factory.Invalid
+ * @run main/othervm  -addmods java.xml.ws
+ *      SAAJFactoryTest com.sun.xml.internal.messaging.saaj.soap.ver1_1.SOAPMessageFactory1_1Impl - scenario12 - -
+ * @run main/othervm -addmods java.xml.ws
+ *      SAAJFactoryTest saaj.factory.Valid - scenario15 - saaj.factory.Valid
  */
 public class SAAJFactoryTest {
 
--- a/jdk/test/javax/xml/ws/8043129/MailTest.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/test/javax/xml/ws/8043129/MailTest.java	Tue May 03 12:25:20 2016 -0700
@@ -27,8 +27,8 @@
  * @summary JAF initialisation in SAAJ clashing with the one in javax.mail
  * @author mkos
  * @library javax.mail.jar
- * @build MailTest
- * @run main MailTest
+ * @compile -addmods java.xml.ws MailTest.java
+ * @run main/othervm -addmods java.xml.ws MailTest
  */
 
 import javax.activation.CommandMap;
--- a/jdk/test/javax/xml/ws/clientjar/TestWsImport.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/test/javax/xml/ws/clientjar/TestWsImport.java	Tue May 03 12:25:20 2016 -0700
@@ -25,7 +25,8 @@
  * @test
  * @bug 8016271 8026405
  * @summary wsimport -clientjar does not create portable jar on windows due to hardcoded '\'
- * @run main/othervm TestWsImport
+ * @compile -addmods java.xml.ws TestWsImport.java
+ * @run main/othervm -addmods java.xml.ws TestWsImport
  */
 
 import javax.xml.namespace.QName;
--- a/jdk/test/javax/xml/ws/publish/WSTest.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/test/javax/xml/ws/publish/WSTest.java	Tue May 03 12:25:20 2016 -0700
@@ -25,7 +25,8 @@
  * @test
  * @bug 8146086
  * @summary Publishing two webservices on same port fails with "java.net.BindException: Address already in use"
- * @run main/othervm WSTest
+ * @compile -addmods java.xml.ws WSTest.java
+ * @run main/othervm -addmods java.xml.ws WSTest
  */
 import javax.jws.WebMethod;
 import javax.jws.WebService;
--- a/jdk/test/javax/xml/ws/xsanymixed/Test.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/test/javax/xml/ws/xsanymixed/Test.java	Tue May 03 12:25:20 2016 -0700
@@ -27,7 +27,8 @@
  * @summary the content of xs:any content:mixed should remain as is,
  *          no white space changes and no changes to namespace prefixes
  * @run shell compile-wsdl.sh
- * @run main/othervm Test
+ * @compile -addmods java.xml.ws Test.java
+ * @run main/othervm -addmods java.xml.ws Test
  */
 
 import com.sun.net.httpserver.HttpServer;
--- a/jdk/test/sun/security/pkcs11/KeyStore/SecretKeysBasic.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/test/sun/security/pkcs11/KeyStore/SecretKeysBasic.java	Tue May 03 12:25:20 2016 -0700
@@ -26,7 +26,6 @@
 import java.security.*;
 import javax.crypto.*;
 import javax.crypto.spec.*;
-import javax.xml.bind.DatatypeConverter;
 
 public class SecretKeysBasic extends PKCS11Test {
 
@@ -131,8 +130,11 @@
         System.out.println(info + "> " + key);
         System.out.println("\tALGO=" + key.getAlgorithm());
         if (key.getFormat() != null) {
-            System.out.println("\t[" + key.getFormat() + "] VALUE=" +
-                    DatatypeConverter.printHexBinary(key.getEncoded()));
+            StringBuilder sb = new StringBuilder();
+            for (byte b : key.getEncoded()) {
+                sb.append(String.format("%02x", b & 0xff));
+            }
+            System.out.println("\t[" + key.getFormat() + "] VALUE=" + sb);
         } else {
             System.out.println("\tVALUE=n/a");
         }
--- a/jdk/test/sun/security/provider/PolicyFile/Modules.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/test/sun/security/provider/PolicyFile/Modules.java	Tue May 03 12:25:20 2016 -0700
@@ -25,7 +25,9 @@
  * @test
  * @bug 8047771
  * @summary check permissions and principals from various modules
- * @run main/othervm/java.security.policy==modules.policy Modules
+ * @compile -addmods java.xml.ws,java.smartcardio Modules.java
+ * @run main/othervm/java.security.policy==modules.policy
+ *     -addmods java.xml.ws,java.smartcardio Modules
  */
 
 import java.security.AccessController;
--- a/jdk/test/sun/security/tools/jarsigner/Warning.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/test/sun/security/tools/jarsigner/Warning.java	Tue May 03 12:25:20 2016 -0700
@@ -89,7 +89,7 @@
         issueCert("c");
         run("jarsigner", "a.jar c")
                 .shouldContain("chain is not validated. " +
-                        "Reason: algorithm constraints check failed");
+                        "Reason: Algorithm constraints check failed");
 
         recreateJar();
 
--- a/jdk/test/tools/jar/modularJar/Basic.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/test/tools/jar/modularJar/Basic.java	Tue May 03 12:25:20 2016 -0700
@@ -340,43 +340,43 @@
             "--file=" + modularJar.toString())
             .assertSuccess()
             .resultChecker(r -> {
-                // Expect similar output: "Name:bar,  Requires: foo,...
-                // Conceals: jdk.test.foo, jdk.test.foo.internal"
-                Pattern p = Pattern.compile("\\s+Name:\\s+bar\\s+Requires:\\s+foo");
+                // Expect similar output: "bar, requires mandated foo, ...
+                // conceals jdk.test.foo, conceals jdk.test.foo.internal"
+                Pattern p = Pattern.compile("\\s+bar\\s+requires\\s++foo");
                 assertTrue(p.matcher(r.output).find(),
-                           "Expecting to find \"Name: bar, Requires: foo,...\"",
+                           "Expecting to find \"bar, requires foo,...\"",
                            "in output, but did not: [" + r.output + "]");
                 p = Pattern.compile(
-                        "Conceals:\\s+jdk.test.foo\\s+jdk.test.foo.internal");
+                        "conceals\\s+jdk.test.foo\\s+conceals\\s+jdk.test.foo.internal");
                 assertTrue(p.matcher(r.output).find(),
-                           "Expecting to find \"Conceals: jdk.test.foo,...\"",
+                           "Expecting to find \"conceals jdk.test.foo,...\"",
                            "in output, but did not: [" + r.output + "]");
             });
     }
 
     @Test
-    public void dependencesFooBar() throws IOException {
+    public void hashBarInFooModule() throws IOException {
         Path mp = Paths.get("dependencesFooBar");
         createTestDir(mp);
 
-        Path modClasses = MODULE_CLASSES.resolve(FOO.moduleName);
-        Path modularJar = mp.resolve(FOO.moduleName + ".jar");
+        Path modClasses = MODULE_CLASSES.resolve(BAR.moduleName);
+        Path modularJar = mp.resolve(BAR.moduleName + ".jar");
+        jar("--create",
+            "--file=" + modularJar.toString(),
+            "--main-class=" + BAR.mainClass,
+            "--module-version=" + BAR.version,
+            "--no-manifest",
+            "-C", modClasses.toString(), ".")
+            .assertSuccess();
+
+        modClasses = MODULE_CLASSES.resolve(FOO.moduleName);
+        modularJar = mp.resolve(FOO.moduleName + ".jar");
         jar("--create",
             "--file=" + modularJar.toString(),
             "--main-class=" + FOO.mainClass,
             "--module-version=" + FOO.version,
-            "--no-manifest",
-            "-C", modClasses.toString(), ".")
-            .assertSuccess();
-
-        modClasses = MODULE_CLASSES.resolve(BAR.moduleName);
-        modularJar = mp.resolve(BAR.moduleName + ".jar");
-        jar("--create",
-            "--file=" + modularJar.toString(),
-            "--main-class=" + BAR.mainClass,
-            "--module-version=" + BAR.version,
             "--modulepath=" + mp.toString(),
-            "--hash-dependencies=" + "foo",  // dependency on foo
+            "--hash-modules=" + "bar",
             "--no-manifest",
             "-C", modClasses.toString(), ".")
             .assertSuccess();
@@ -392,49 +392,49 @@
     }
 
     @Test
-    public void badDependencyFooBar() throws IOException {
+    public void invalidHashInFooModule() throws IOException {
         Path mp = Paths.get("badDependencyFooBar");
         createTestDir(mp);
 
-        Path fooClasses = MODULE_CLASSES.resolve(FOO.moduleName);
-        Path fooJar = mp.resolve(FOO.moduleName + ".jar");
-        jar("--create",
-            "--file=" + fooJar.toString(),
-            "--main-class=" + FOO.mainClass,
-            "--module-version=" + FOO.version,
-            "--no-manifest",
-            "-C", fooClasses.toString(), ".").assertSuccess();
-
         Path barClasses = MODULE_CLASSES.resolve(BAR.moduleName);
         Path barJar = mp.resolve(BAR.moduleName + ".jar");
         jar("--create",
             "--file=" + barJar.toString(),
             "--main-class=" + BAR.mainClass,
             "--module-version=" + BAR.version,
-            "--modulepath=" + mp.toString(),
-            "--hash-dependencies=" + "foo",  // dependency on foo
             "--no-manifest",
             "-C", barClasses.toString(), ".").assertSuccess();
 
-        // Rebuild foo.jar with a change that will cause its hash to be different
-        FileUtils.deleteFileWithRetry(fooJar);
+        Path fooClasses = MODULE_CLASSES.resolve(FOO.moduleName);
+        Path fooJar = mp.resolve(FOO.moduleName + ".jar");
         jar("--create",
             "--file=" + fooJar.toString(),
             "--main-class=" + FOO.mainClass,
-            "--module-version=" + FOO.version + ".1", // a newer version
+            "--module-version=" + FOO.version,
+            "--modulepath=" + mp.toString(),
+            "--hash-modules=" + "bar",
             "--no-manifest",
             "-C", fooClasses.toString(), ".").assertSuccess();
 
+        // Rebuild bar.jar with a change that will cause its hash to be different
+        FileUtils.deleteFileWithRetry(barJar);
+        jar("--create",
+            "--file=" + barJar.toString(),
+            "--main-class=" + BAR.mainClass,
+            "--module-version=" + BAR.version + ".1", // a newer version
+            "--no-manifest",
+            "-C", barClasses.toString(), ".").assertSuccess();
+
         java(mp, BAR.moduleName + "/" + BAR.mainClass,
              "-XaddExports:java.base/jdk.internal.module=bar")
             .assertFailure()
             .resultChecker(r -> {
                 // Expect similar output: "java.lang.module.ResolutionException: Hash
-                // of foo (WdktSIQSkd4+CEacpOZoeDrCosMATNrIuNub9b5yBeo=) differs to
+                // of bar (WdktSIQSkd4+CEacpOZoeDrCosMATNrIuNub9b5yBeo=) differs to
                 // expected hash (iepvdv8xTeVrFgMtUhcFnmetSub6qQHCHc92lSaSEg0=)"
-                Pattern p = Pattern.compile(".*Hash of foo.*differs to expected hash.*");
+                Pattern p = Pattern.compile(".*Hash of bar.*differs to expected hash.*");
                 assertTrue(p.matcher(r.output).find(),
-                      "Expecting error message containing \"Hash of foo ... differs to"
+                      "Expecting error message containing \"Hash of bar ... differs to"
                               + " expected hash...\" but got: [", r.output + "]");
             });
     }
@@ -454,7 +454,7 @@
 
          jar("--create",
              "--file=" + modularJar.toString(),
-             "--hash-dependencies=" + ".*",   // no module-info.class
+             "--hash-modules=" + ".*",   // no module-info.class
              "-C", modClasses.toString(), "jdk")
              .assertFailure();      // TODO: expected failure message
     }
--- a/jdk/test/tools/jar/modularJar/src/bar/jdk/test/bar/Bar.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/test/tools/jar/modularJar/src/bar/jdk/test/bar/Bar.java	Tue May 03 12:25:20 2016 -0700
@@ -30,7 +30,7 @@
 import java.util.Optional;
 import java.util.StringJoiner;
 
-import jdk.internal.module.Hasher;
+import jdk.internal.module.ModuleHashes;
 import jdk.test.bar.internal.Message;
 
 public class Bar {
@@ -43,10 +43,11 @@
 
         Method m = ModuleDescriptor.class.getDeclaredMethod("hashes");
         m.setAccessible(true);
-        Optional<Hasher.DependencyHashes> optHashes =
-                (Optional<Hasher.DependencyHashes>) m.invoke(md);
+        ModuleDescriptor foo = jdk.test.foo.Foo.class.getModule().getDescriptor();
+        Optional<ModuleHashes> oHashes =
+                (Optional<ModuleHashes>) m.invoke(foo);
 
-        System.out.println("hashes:" + optHashes.get().hashFor("foo"));
+        System.out.println("hashes:" + oHashes.get().hashFor("bar"));
 
         StringJoiner sj = new StringJoiner(",");
         md.conceals().forEach(sj::add);
--- a/jdk/test/tools/jlink/ImageFileCreatorTest.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/test/tools/jlink/ImageFileCreatorTest.java	Tue May 03 12:25:20 2016 -0700
@@ -214,14 +214,12 @@
             }
 
             @Override
-            public void storeFiles(Pool content, String bom) {
-
+            public void storeFiles(Pool content) {
             }
-
         };
 
         ImagePluginStack stack = new ImagePluginStack(noopBuilder, Collections.emptyList(),
-                null, Collections.emptyList(), "");
+                null, Collections.emptyList());
 
         ImageFileCreator.create(archives, ByteOrder.nativeOrder(), stack);
     }
--- a/jdk/test/tools/jlink/IntegrationTest.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/test/tools/jlink/IntegrationTest.java	Tue May 03 12:25:20 2016 -0700
@@ -241,7 +241,7 @@
             lst.add(new MyPostProcessor());
         }
         // Image builder
-        DefaultImageBuilder builder = new DefaultImageBuilder(true, output);
+        DefaultImageBuilder builder = new DefaultImageBuilder(output);
         PluginsConfiguration plugins
                 = new Jlink.PluginsConfiguration(lst, builder, null);
 
@@ -254,10 +254,6 @@
         if (!jimage.exists()) {
             throw new AssertionError("jimage not generated");
         }
-        File bom = new File(output.toString(), "bom");
-        if (!bom.exists()) {
-            throw new AssertionError("bom not generated");
-        }
         File release = new File(output.toString(), "release");
         if (!release.exists()) {
             throw new AssertionError("release not generated");
@@ -311,7 +307,7 @@
         }
 
         // Image builder
-        DefaultImageBuilder builder = new DefaultImageBuilder(false, output);
+        DefaultImageBuilder builder = new DefaultImageBuilder(output);
         PluginsConfiguration plugins
                 = new Jlink.PluginsConfiguration(lst, builder, null);
 
@@ -359,7 +355,7 @@
         }
 
         // Image builder
-        DefaultImageBuilder builder = new DefaultImageBuilder(false, output);
+        DefaultImageBuilder builder = new DefaultImageBuilder(output);
         PluginsConfiguration plugins
                 = new Jlink.PluginsConfiguration(lst, builder, null);
         boolean failed = false;
--- a/jdk/test/tools/jlink/JLink2Test.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/test/tools/jlink/JLink2Test.java	Tue May 03 12:25:20 2016 -0700
@@ -66,8 +66,6 @@
 
         // This test case must be first one, the JlinkTask is clean
         // and reveals possible bug related to plugin options in defaults
-        // e. g.: --genbom
-        testBomFile(helper);
         testSameNames(helper);
         testModulePath(helper);
         testOptions();
@@ -136,35 +134,6 @@
         validator.validate();
     }
 
-    private static void testBomFile(Helper helper) throws Exception {
-        String[] userOptions = {
-            "--compress",
-            "2",
-            "--addmods",
-            "bomzip",
-            "--strip-debug",
-            "--genbom",
-            "--exclude-resources",
-            "*.jcov,*/META-INF/*"};
-        String moduleName = "bomzip";
-        helper.generateDefaultJModule(moduleName, "composite2");
-        Path imgDir = helper.generateDefaultImage(userOptions, moduleName).assertSuccess();
-        helper.checkImage(imgDir, moduleName, userOptions, null, null);
-        File bom = new File(imgDir.toFile(), "bom");
-        if (!bom.exists()) {
-            throw new RuntimeException(bom.getAbsolutePath() + " not generated");
-        }
-        String bomcontent = new String(Files.readAllBytes(bom.toPath()));
-        if (!bomcontent.contains("--strip-debug")
-                || !bomcontent.contains("--compress")
-                || !bomcontent.contains("--genbom")
-                || !bomcontent.contains("--exclude-resources *.jcov,"
-                        + "*/META-INF/*")
-                || !bomcontent.contains("--addmods bomzip")) {
-            throw new Exception("Not expected content in " + bom);
-        }
-    }
-
     private static void testOptions() throws Exception {
         List<Plugin> builtInPlugins = new ArrayList<>();
         builtInPlugins.addAll(PluginRepository.getPlugins(Layer.boot()));
--- a/jdk/test/tools/jlink/JLinkTest.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/test/tools/jlink/JLinkTest.java	Tue May 03 12:25:20 2016 -0700
@@ -204,7 +204,7 @@
             String[] userOptions = {"--compress", "invalid"};
             String moduleName = "invalidCompressLevel";
             helper.generateDefaultJModule(moduleName, "composite2");
-            helper.generateDefaultImage(userOptions, moduleName).assertFailure("Error: Invalid level invalid");
+            helper.generateDefaultImage(userOptions, moduleName).assertFailure("Error: Invalid compression level invalid");
         }
 
         // @file
--- a/jdk/test/tools/jlink/hashes/HashesTest.java	Tue May 03 09:48:02 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,160 +0,0 @@
-/**
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-/*
- * @test
- * @summary Test the recording and checking of dependency hashes
- * @author Andrei Eremeev
- * @library /lib/testlibrary
- * @modules java.base/jdk.internal.module
- *          jdk.jlink/jdk.tools.jlink
- *          jdk.jlink/jdk.tools.jmod
- *          jdk.compiler
- * @ignore
- * @build jdk.testlibrary.ProcessTools jdk.testlibrary.OutputAnalyzer CompilerUtils
- * @run main HashesTest
- */
-
-import java.io.File;
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.nio.file.FileVisitResult;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.nio.file.SimpleFileVisitor;
-import java.nio.file.attribute.BasicFileAttributes;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.stream.Collectors;
-
-import jdk.testlibrary.OutputAnalyzer;
-import jdk.testlibrary.ProcessTools;
-
-public class HashesTest {
-
-    private final Path jdkHome = Paths.get(System.getProperty("test.jdk"));
-    private final Path stdJmods = jdkHome.resolve("jmods");
-    private final Path testSrc = Paths.get(System.getProperty("test.src"));
-    private final Path modSrc = testSrc.resolve("src");
-    private final Path newModSrc = testSrc.resolve("newsrc");
-    private final Path classes = Paths.get("classes");
-    private final Path jmods = Paths.get("jmods");
-
-    public static void main(String[] args) throws Exception {
-        new HashesTest().run();
-    }
-
-    private void run() throws Exception {
-        if (!Files.exists(stdJmods)) {
-            return;
-        }
-        Files.createDirectories(jmods);
-        Path m1Classes = classes.resolve("m1");
-        Path m2Classes = classes.resolve("m2");
-        Path m3Classes = classes.resolve("not_matched");
-        // build the second module
-        compileClasses(modSrc, m2Classes);
-        runJmod(m2Classes.toString(), m2Classes.getFileName().toString());
-
-        // build the third module
-        compileClasses(modSrc, m3Classes);
-        runJmod(m3Classes.toString(), m3Classes.getFileName().toString());
-
-        compileClasses(modSrc, m1Classes, "-mp", jmods.toString());
-        runJmod(m1Classes.toString(), m1Classes.getFileName().toString(),
-                "--modulepath", jmods.toString(), "--hash-dependencies", "m2");
-        runJava(0, "-mp", jmods.toString(), "-m", "m1/org.m1.Main");
-
-        deleteDirectory(m3Classes);
-        Files.delete(jmods.resolve("not_matched.jmod"));
-
-        // build the new third module
-        compileClasses(newModSrc, m3Classes);
-        runJmod(m3Classes.toString(), m3Classes.getFileName().toString());
-        runJava(0, "-mp", jmods.toString(), "-m", "m1/org.m1.Main");
-
-        deleteDirectory(m2Classes);
-        Files.delete(jmods.resolve("m2.jmod"));
-
-        compileClasses(newModSrc, m2Classes);
-        runJmod(m2Classes.toString(), m2Classes.getFileName().toString());
-
-        runJava(1, "-mp", jmods.toString(), "-m", "m1/org.m1.Main");
-
-        if (jdk.tools.jlink.internal.Main.run(new String[]{
-                "--modulepath", stdJmods.toString() + File.pathSeparator + jmods.toString(),
-                "--addmods", "m1", "--output", "myimage"}, new PrintWriter(System.out)) == 0) {
-            throw new AssertionError("Expected failure. rc = 0");
-        }
-    }
-
-    private void deleteDirectory(Path dir) throws IOException {
-        Files.walkFileTree(dir, new SimpleFileVisitor<Path>() {
-            @Override
-            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
-                Files.delete(file);
-                return FileVisitResult.CONTINUE;
-            }
-
-            @Override
-            public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
-                Files.delete(dir);
-                return FileVisitResult.CONTINUE;
-            }
-        });
-    }
-
-    private void runJava(int expectedExitCode, String... args) throws Exception {
-        OutputAnalyzer analyzer = ProcessTools.executeTestJava(args);
-        if (analyzer.getExitValue() != expectedExitCode) {
-            throw new AssertionError("Expected exit code: " + expectedExitCode +
-                    ", got: " + analyzer.getExitValue());
-        }
-    }
-
-    private void compileClasses(Path src, Path output, String... options) throws IOException {
-        List<String> args = new ArrayList<>();
-        Collections.addAll(args, options);
-        Collections.addAll(args, "-d", output.toString());
-        args.add(src.toString());
-        System.out.println("javac options: " + args.stream().collect(Collectors.joining(" ")));
-        if (!CompilerUtils.compile(src.resolve(output.getFileName()), output, options)) {
-            throw new AssertionError("Compilation failure. See log.");
-        }
-    }
-
-    private void runJmod(String cp, String modName, String... options) {
-        List<String> args = new ArrayList<>();
-        args.add("create");
-        Collections.addAll(args, options);
-        Collections.addAll(args, "--class-path", cp,
-                jmods + File.separator + modName + ".jmod");
-        int rc = jdk.tools.jmod.Main.run(args.toArray(new String[args.size()]), System.out);
-        System.out.println("jmod options: " + args.stream().collect(Collectors.joining(" ")));
-        if (rc != 0) {
-            throw new AssertionError("Jmod failed: rc = " + rc);
-        }
-    }
-}
--- a/jdk/test/tools/jlink/hashes/newsrc/m2/module-info.java	Tue May 03 09:48:02 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,26 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-module m2 {
-    exports org.m2;
-}
--- a/jdk/test/tools/jlink/hashes/newsrc/m2/org/m2/Util.java	Tue May 03 09:48:02 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,32 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package org.m2;
-
-public class Util {
-    private Util() { }
-
-    public static String timeOfDay() {
-        return "Time for a beer";
-    }
-}
--- a/jdk/test/tools/jlink/hashes/newsrc/not_matched/module-info.java	Tue May 03 09:48:02 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,26 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-module not_matched {
-    exports org.not_matched;
-}
--- a/jdk/test/tools/jlink/hashes/newsrc/not_matched/org/not_matched/Name.java	Tue May 03 09:48:02 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,32 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package org.not_matched;
-
-public class Name {
-    private Name() { }
-
-    public static String name() {
-        return "new_module";
-    }
-}
--- a/jdk/test/tools/jlink/hashes/src/m1/module-info.java	Tue May 03 09:48:02 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,27 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-module m1 {
-    requires m2;
-    requires not_matched;
-}
--- a/jdk/test/tools/jlink/hashes/src/m1/org/m1/Main.java	Tue May 03 09:48:02 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,34 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package org.m1;
-
-import org.m2.Util;
-import org.not_matched.Name;
-
-public class Main {
-    public static void main(String[] args) {
-        System.out.println(Util.timeOfDay());
-        System.out.println(Name.name());
-    }
-}
--- a/jdk/test/tools/jlink/hashes/src/m2/module-info.java	Tue May 03 09:48:02 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,26 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-module m2 {
-    exports org.m2;
-}
--- a/jdk/test/tools/jlink/hashes/src/m2/org/m2/Util.java	Tue May 03 09:48:02 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,32 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package org.m2;
-
-public class Util {
-    private Util() { }
-
-    public static String timeOfDay() {
-        return "Time for lunch";
-    }
-}
--- a/jdk/test/tools/jlink/hashes/src/not_matched/module-info.java	Tue May 03 09:48:02 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,26 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-module not_matched {
-    exports org.not_matched;
-}
--- a/jdk/test/tools/jlink/hashes/src/not_matched/org/not_matched/Name.java	Tue May 03 09:48:02 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,32 +0,0 @@
-/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package org.not_matched;
-
-public class Name {
-    private Name() { }
-
-    public static String name() {
-        return "old_module";
-    }
-}
--- a/jdk/test/tools/jlink/plugins/FileCopierPluginTest.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/test/tools/jlink/plugins/FileCopierPluginTest.java	Tue May 03 12:25:20 2016 -0700
@@ -101,9 +101,8 @@
 
         }
         Path root = new File(".").toPath();
-        DefaultImageBuilder imgbuilder = new DefaultImageBuilder(false,
-                root);
-        imgbuilder.storeFiles(pool, "");
+        DefaultImageBuilder imgbuilder = new DefaultImageBuilder(root);
+        imgbuilder.storeFiles(pool);
 
         if (lic.exists()) {
             File license = new File(root.toFile(), "LICENSE");
--- a/jdk/test/tools/jmod/JmodNegativeTest.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/test/tools/jmod/JmodNegativeTest.java	Tue May 03 12:25:20 2016 -0700
@@ -76,7 +76,7 @@
         jmod()
             .assertFailure()
             .resultChecker(r ->
-                assertContains(r.output, "Error: one of create, list, or describe must be specified")
+                assertContains(r.output, "Error: one of create, list, describe, or hash must be specified")
             );
     }
 
@@ -85,7 +85,7 @@
         jmod("badAction")
             .assertFailure()
             .resultChecker(r ->
-                assertContains(r.output, "Error: mode must be one of create, list, or describe")
+                assertContains(r.output, "Error: mode must be one of create, list, describe, or hash")
             );
 
         jmod("--badOption")
@@ -170,14 +170,14 @@
     }
 
     @Test
-    public void testHashDependenciesModulePathNotSpecified() {
+    public void testHashModulesModulePathNotSpecified() {
         jmod("create",
-             "--hash-dependencies", "anyPattern.*",
+             "--hash-modules", "anyPattern.*",
              "output.jmod")
             .assertFailure()
             .resultChecker(r ->
                 assertContains(r.output, "Error: --module-path must be "
-                        +"specified when hashing dependencies")
+                        +"specified when hashing modules")
             );
     }
 
@@ -317,7 +317,7 @@
     }
 
     @Test
-    public void testDependencyNotFound() throws IOException {
+    public void testNoModuleHash() throws IOException {
         Path jmod = MODS_DIR.resolve("output.jmod");
         FileUtils.deleteFileIfExistsWithRetry(jmod);
         Path emptyDir = Paths.get("empty");
@@ -328,13 +328,12 @@
 
         jmod("create",
              "--class-path", cp,
-             "--hash-dependencies", ".*",
+             "--hash-modules", ".*",
              "--modulepath", emptyDir.toString(),
             jmod.toString())
-            .assertFailure()
             .resultChecker(r ->
-                assertContains(r.output, "Hashing module foo dependencies, "
-                        + "unable to find module java.base on module path")
+                assertContains(r.output, "No hashes recorded: " +
+                    "no module specified for hashing depends on foo")
             );
     }
 
@@ -350,13 +349,10 @@
 
             jmod("create",
                  "--class-path", cp,
-                 "--hash-dependencies", ".*",
+                 "--hash-modules", ".*",
                  "--modulepath", MODS_DIR.toString(),
                  jmod.toString())
-                .assertFailure()
-                .resultChecker(r ->
-                    assertContains(r.output, "Error: error reading module path")
-                );
+                .assertFailure();
         } finally {
             FileUtils.deleteFileWithRetry(empty);
         }
@@ -371,7 +367,7 @@
         Files.createFile(file);
 
         jmod("create",
-             "--hash-dependencies", ".*",
+             "--hash-modules", ".*",
              "--modulepath", file.toString(),
              jmod.toString())
             .assertFailure()
@@ -388,7 +384,7 @@
 
         List<Supplier<JmodResult>> tasks = Arrays.asList(
                 () -> jmod("create",
-                           "--hash-dependencies", "anyPattern",
+                           "--hash-modules", "anyPattern",
                            "--modulepath", "doesNotExist",
                            "output.jmod"),
                 () -> jmod("create",
@@ -436,7 +432,7 @@
 
         List<Supplier<JmodResult>> tasks = Arrays.asList(
             () -> jmod("create",
-                       "--hash-dependencies", "anyPattern",
+                       "--hash-modules", "anyPattern",
                        "--modulepath","empty" + pathSeparator + "doesNotExist",
                        "output.jmod"),
             () -> jmod("create",
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/jmod/hashes/HashesTest.java	Tue May 03 12:25:20 2016 -0700
@@ -0,0 +1,213 @@
+/**
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @summary Test the recording and checking of module hashes
+ * @author Andrei Eremeev
+ * @library /lib/testlibrary
+ * @modules java.base/jdk.internal.module
+ *          jdk.jlink/jdk.tools.jlink.internal
+ *          jdk.jlink/jdk.tools.jmod
+ *          jdk.compiler
+ * @build CompilerUtils
+ * @run testng HashesTest
+ */
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.module.ModuleDescriptor;
+import java.lang.module.ModuleFinder;
+import java.lang.module.ModuleReader;
+import java.lang.module.ModuleReference;
+import java.lang.reflect.Method;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import jdk.internal.module.ConfigurableModuleFinder;
+import jdk.internal.module.ModuleHashes;
+import org.testng.annotations.BeforeTest;
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.*;
+
+public class HashesTest {
+
+    private final Path testSrc = Paths.get(System.getProperty("test.src"));
+    private final Path modSrc = testSrc.resolve("src");
+    private final Path mods = Paths.get("mods");
+    private final Path jmods = Paths.get("jmods");
+    private final String[] modules = new String[] { "m1", "m2", "m3"};
+
+    private static Method hashesMethod;
+    @BeforeTest
+    private void setup() throws Exception {
+        if (Files.exists(jmods)) {
+            deleteDirectory(jmods);
+        }
+        Files.createDirectories(jmods);
+
+        // build m2, m3 required by m1
+        compileModule("m2", modSrc);
+        jmod("m2");
+
+        compileModule("m3", modSrc);
+        jmod("m3");
+
+        // build m1
+        compileModule("m1", modSrc);
+        // no hash is recorded since m1 has outgoing edges
+        jmod("m1", "--modulepath", jmods.toString(), "--hash-modules", ".*");
+
+        // compile org.bar and org.foo
+        compileModule("org.bar", modSrc);
+        compileModule("org.foo", modSrc);
+
+        try {
+            hashesMethod = ModuleDescriptor.class.getDeclaredMethod("hashes");
+            hashesMethod.setAccessible(true);
+        } catch (ReflectiveOperationException x) {
+            throw new InternalError(x);
+        }
+    }
+
+    @Test
+    public void test() throws Exception {
+        for (String mn : modules) {
+            assertFalse(hashes(mn).isPresent());
+        }
+
+        // hash m1 in m2
+        jmod("m2", "--modulepath", jmods.toString(), "--hash-modules", "m1");
+        checkHashes(hashes("m2").get(), "m1");
+
+        // hash m1 in m2
+        jmod("m2", "--modulepath", jmods.toString(), "--hash-modules", ".*");
+        checkHashes(hashes("m2").get(), "m1");
+
+        // create m2.jmod with no hash
+        jmod("m2");
+        // run jmod hash command to hash m1 in m2 and m3
+        runJmod(Arrays.asList("hash", "--modulepath", jmods.toString(),
+                "--hash-modules", ".*"));
+        checkHashes(hashes("m2").get(), "m1");
+        checkHashes(hashes("m3").get(), "m1");
+
+        jmod("org.bar");
+        jmod("org.foo");
+
+        jmod("org.bar", "--modulepath", jmods.toString(), "--hash-modules", "org.*");
+        checkHashes(hashes("org.bar").get(), "org.foo");
+
+        jmod("m3", "--modulepath", jmods.toString(), "--hash-modules", ".*");
+        checkHashes(hashes("m3").get(), "org.foo", "org.bar", "m1");
+    }
+
+    private void checkHashes(ModuleHashes hashes, String... hashModules) {
+        assertTrue(hashes.names().equals(Set.of(hashModules)));
+    }
+
+    private Optional<ModuleHashes> hashes(String name) throws Exception {
+        ModuleFinder finder = ModuleFinder.of(jmods.resolve(name + ".jmod"));
+        if (finder instanceof ConfigurableModuleFinder) {
+            ((ConfigurableModuleFinder) finder)
+                .configurePhase(ConfigurableModuleFinder.Phase.LINK_TIME);
+        }
+        ModuleReference mref = finder.find(name).orElseThrow(RuntimeException::new);
+        ModuleReader reader = mref.open();
+        try (InputStream in = reader.open("module-info.class").get()) {
+            ModuleDescriptor md = ModuleDescriptor.read(in);
+            Optional<ModuleHashes> hashes =
+                (Optional<ModuleHashes>) hashesMethod.invoke(md);
+            System.out.format("hashes in module %s %s%n", name,
+                              hashes.isPresent() ? "present" : "absent");
+            if (hashes.isPresent()) {
+                hashes.get().names().stream()
+                    .sorted()
+                    .forEach(n -> System.out.format("  %s %s%n", n, hashes.get().hashFor(n)));
+            }
+            return hashes;
+        } finally {
+            reader.close();
+        }
+    }
+
+    private void deleteDirectory(Path dir) throws IOException {
+        Files.walkFileTree(dir, new SimpleFileVisitor<Path>() {
+            @Override
+            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
+                throws IOException
+            {
+                Files.delete(file);
+                return FileVisitResult.CONTINUE;
+            }
+
+            @Override
+            public FileVisitResult postVisitDirectory(Path dir, IOException exc)
+                throws IOException
+            {
+                Files.delete(dir);
+                return FileVisitResult.CONTINUE;
+            }
+        });
+    }
+
+    private void compileModule(String moduleName, Path src) throws IOException {
+        Path msrc = src.resolve(moduleName);
+        assertTrue(CompilerUtils.compile(msrc, mods, "-modulesourcepath", src.toString()));
+    }
+
+    private void jmod(String moduleName, String... options) throws IOException {
+        Path mclasses = mods.resolve(moduleName);
+        Path outfile = jmods.resolve(moduleName + ".jmod");
+        List<String> args = new ArrayList<>();
+        args.add("create");
+        Collections.addAll(args, options);
+        Collections.addAll(args, "--class-path", mclasses.toString(),
+                           outfile.toString());
+
+        if (Files.exists(outfile))
+            Files.delete(outfile);
+
+        runJmod(args);
+    }
+
+    private void runJmod(List<String> args) {
+        int rc = jdk.tools.jmod.Main.run(args.toArray(new String[args.size()]), System.out);
+        System.out.println("jmod options: " + args.stream().collect(Collectors.joining(" ")));
+        if (rc != 0) {
+            throw new AssertionError("Jmod failed: rc = " + rc);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/jmod/hashes/src/m1/module-info.java	Tue May 03 12:25:20 2016 -0700
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module m1 {
+    requires m2;
+    requires m3;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/jmod/hashes/src/m1/org/m1/Main.java	Tue May 03 12:25:20 2016 -0700
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.m1;
+
+import org.m2.Util;
+import org.m3.Name;
+
+public class Main {
+    public static void main(String[] args) {
+        System.out.println(Util.timeOfDay());
+        System.out.println(Name.name());
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/jmod/hashes/src/m2/module-info.java	Tue May 03 12:25:20 2016 -0700
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module m2 {
+    exports org.m2;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/jmod/hashes/src/m2/org/m2/Util.java	Tue May 03 12:25:20 2016 -0700
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.m2;
+
+public class Util {
+    private Util() { }
+
+    public static String timeOfDay() {
+        return "Time for lunch";
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/jmod/hashes/src/m3/module-info.java	Tue May 03 12:25:20 2016 -0700
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module m3 {
+    exports org.m3;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/jmod/hashes/src/m3/org/m3/Name.java	Tue May 03 12:25:20 2016 -0700
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.m3;
+
+public class Name {
+    private Name() { }
+
+    public static String name() {
+        return "m3";
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/jmod/hashes/src/org.bar/module-info.java	Tue May 03 12:25:20 2016 -0700
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module org.bar {
+    requires public m1;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/jmod/hashes/src/org.foo/module-info.java	Tue May 03 12:25:20 2016 -0700
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module org.foo {
+    requires public org.bar;
+}
--- a/jdk/test/tools/launcher/ToolsOpts.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/test/tools/launcher/ToolsOpts.java	Tue May 03 12:25:20 2016 -0700
@@ -151,29 +151,26 @@
         init();
         TestResult tr;
         int jpos = -1;
+        String xPatch = "-J-Xpatch:jdk.compiler=jdk.compiler";
         for (String arg[] : optionPatterns) {
             jpos = indexOfJoption(arg);
             //Build a cmd string for output in results reporting.
-            String cmdString = javacCmd + " -J-Xpatch:.";
+            String cmdString = javacCmd + " " + xPatch;
             for (String opt : arg) {
                 cmdString = cmdString.concat(" " + opt);
             }
             switch (arg.length) {
                 case 1:
-                    tr = doExec(javacCmd, "-J-Xpatch:.",
-                            arg[0]);
+                    tr = doExec(javacCmd, xPatch, arg[0]);
                     break;
                 case 2:
-                    tr = doExec(javacCmd, "-J-Xpatch:.",
-                            arg[0], arg[1]);
+                    tr = doExec(javacCmd, xPatch, arg[0], arg[1]);
                     break;
                 case 3:
-                    tr = doExec(javacCmd, "-J-Xpatch:.",
-                            arg[0], arg[1], arg[2]);
+                    tr = doExec(javacCmd, xPatch, arg[0], arg[1], arg[2]);
                     break;
                 case 4:
-                    tr = doExec(javacCmd, "-J-Xpatch:.",
-                            arg[0], arg[1], arg[2], arg[3]);
+                    tr = doExec(javacCmd, xPatch, arg[0], arg[1], arg[2], arg[3]);
                     break;
                 default:
                     tr = null;
--- a/jdk/test/tools/launcher/modules/addmods/AddModsTest.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/test/tools/launcher/modules/addmods/AddModsTest.java	Tue May 03 12:25:20 2016 -0700
@@ -47,120 +47,179 @@
     private static final String TEST_SRC = System.getProperty("test.src");
 
     private static final Path SRC_DIR = Paths.get(TEST_SRC, "src");
-    private static final Path MODS_DIR = Paths.get("mods");
-
-    // the module name of the library module
-    private static final String LIB_MODULE = "lib";
+    private static final Path MODS1_DIR = Paths.get("mods1");
+    private static final Path MODS2_DIR = Paths.get("mods2");
 
-    // application source directory
-    private static final String APP_SRC = "app";
+    // test module / main class
+    private static final String TEST_MODULE = "test";
+    private static final String TEST_MAIN_CLASS = "test.Main";
+    private static final String TEST_MID = TEST_MODULE + "/" + TEST_MAIN_CLASS;
 
-    // application is compiled to classes
-    private static final Path CLASSES_DIR = Paths.get("classes");
-
-    // application main class
-    private static final String MAIN_CLASS = "app.Main";
+    // logger module
+    private static final String LOGGER_MODULE = "logger";
 
 
     @BeforeTest
     public void compile() throws Exception {
-
-        // javac -d mods/$LIB_MODULE src/$LIB_MODULE/**
+        // javac -d mods1/test src/test/**
         boolean compiled = CompilerUtils.compile(
-            SRC_DIR.resolve(LIB_MODULE),
-            MODS_DIR.resolve(LIB_MODULE)
+            SRC_DIR.resolve(TEST_MODULE),
+            MODS1_DIR.resolve(TEST_MODULE)
         );
-        assertTrue(compiled, "library module did not compile");
+        assertTrue(compiled, "test did not compile");
 
-        // javac -d classes -mp mods src/$APP_DIR/**
-        compiled = CompilerUtils.compile(
-            SRC_DIR.resolve(APP_SRC),
-            CLASSES_DIR,
-            "-mp", MODS_DIR.toString(),
-            "-addmods", LIB_MODULE
+        // javac -d mods1/logger src/logger/**
+        compiled= CompilerUtils.compile(
+            SRC_DIR.resolve(LOGGER_MODULE),
+            MODS2_DIR.resolve(LOGGER_MODULE)
         );
-        assertTrue(compiled, "app did not compile");
+        assertTrue(compiled, "test did not compile");
     }
 
 
     /**
-     * Basic test of -addmods ALL-SYSTEM, using the output of -listmods to
-     * check that the a sample of the system modules are resolved.
+     * Basic test of -addmods ALL-DEFAULT. Module java.sql should be
+     * resolved and the types in that module should be visible.
      */
-    public void testAddSystemModules() throws Exception {
-
-        executeTestJava("-addmods", "ALL-SYSTEM",
-                        "-listmods",
-                        "-m", "java.base")
-            .outputTo(System.out)
-            .errorTo(System.out)
-            .shouldContain("java.sql")
-            .shouldContain("java.corba");
+    public void testAddDefaultModules1() throws Exception {
 
-        // no exit value to check as -m java.base will likely fail
-    }
-
-
-    /**
-     * Run application on class path that makes use of module on the
-     * application module path. Uses {@code -addmods lib}
-     */
-    public void testRunWithAddMods() throws Exception {
-
-        // java -mp mods -addmods lib -cp classes app.Main
+        // java -addmods ALL-DEFAULT -mp mods1 -m test ...
         int exitValue
-            = executeTestJava("-mp", MODS_DIR.toString(),
-                              "-addmods", LIB_MODULE,
-                              "-cp", CLASSES_DIR.toString(),
-                              MAIN_CLASS)
+            = executeTestJava("-mp", MODS1_DIR.toString(),
+                              "-addmods", "ALL-DEFAULT",
+                              "-m", TEST_MID,
+                              "java.sql.Connection")
                 .outputTo(System.out)
                 .errorTo(System.out)
                 .getExitValue();
 
         assertTrue(exitValue == 0);
-
     }
 
     /**
-     * Run application on class path that makes use of module on the
-     * application module path. Uses {@code -addmods ALL-MODULE-PATH}.
+     * Basic test of -addmods ALL-DEFAULT. Module java.annotations.common
+     * should not resolved and so the types in that module should not be
+     * visible.
      */
-    public void testAddAllModulePath() throws Exception {
+    public void testAddDefaultModules2() throws Exception {
+
+        // java -addmods ALL-DEFAULT -mp mods1 -m test ...
+        int exitValue
+            = executeTestJava("-mp", MODS1_DIR.toString(),
+                              "-addmods", "ALL-DEFAULT",
+                              "-m", TEST_MID,
+                              "javax.annotation.Generated")
+                .outputTo(System.out)
+                .errorTo(System.out)
+                .shouldContain("ClassNotFoundException")
+                .getExitValue();
 
-        // java -mp mods -addmods lib -cp classes app.Main
+        assertTrue(exitValue != 0);
+    }
+
+    /**
+     * Basic test of -addmods ALL-SYSTEM. All system modules should be resolved
+     * and thus all types in those modules should be visible.
+     */
+    public void testAddSystemModules() throws Exception {
+
+        // java -addmods ALL-SYSTEM -mp mods1 -m test ...
         int exitValue
-            = executeTestJava("-mp", MODS_DIR.toString(),
-                              "-addmods", "ALL-MODULE-PATH",
-                              "-cp", CLASSES_DIR.toString(),
-                              MAIN_CLASS)
+            = executeTestJava("-mp", MODS1_DIR.toString(),
+                              "-addmods", "ALL-SYSTEM",
+                              "-m", TEST_MID,
+                              "java.sql.Connection",
+                              "javax.annotation.Generated")
                 .outputTo(System.out)
                 .errorTo(System.out)
                 .getExitValue();
 
         assertTrue(exitValue == 0);
-
     }
 
 
     /**
-     * Run application on class path that makes use of module on the
-     * application module path. Does not use -addmods and so will
-     * fail at run-time.
+     * Run test on class path to load a type in a module on the application
+     * module path, uses {@code -addmods logger}.
      */
-    public void testRunMissingAddMods() throws Exception {
+    public void testRunWithAddMods() throws Exception {
 
-        // java -mp mods -cp classes app.Main
+        // java -mp mods -addmods logger -cp classes test.Main
+        String classpath = MODS1_DIR.resolve(TEST_MODULE).toString();
+        String modulepath = MODS2_DIR.toString();
         int exitValue
-            = executeTestJava("-mp", MODS_DIR.toString(),
-                              "-cp", CLASSES_DIR.toString(),
-                              MAIN_CLASS)
+            = executeTestJava("-mp", modulepath,
+                              "-addmods", LOGGER_MODULE,
+                              "-cp", classpath,
+                              TEST_MAIN_CLASS,
+                              "logger.Logger")
                 .outputTo(System.out)
                 .errorTo(System.out)
                 .getExitValue();
 
-        // CNFE or other error/exception
-        assertTrue(exitValue != 0);
+        assertTrue(exitValue == 0);
+    }
+
+     /**
+      * Run application on class path that makes use of module on the
+      * application module path. Does not use -addmods and so should
+      * fail at run-time.
+      */
+     public void testRunMissingAddMods() throws Exception {
+
+         // java -mp mods -cp classes test.Main
+         String classpath = MODS1_DIR.resolve(TEST_MODULE).toString();
+         String modulepath = MODS1_DIR.toString();
+         int exitValue
+             = executeTestJava("-mp", modulepath,
+                               "-cp", classpath,
+                               TEST_MAIN_CLASS,
+                               "logger.Logger")
+                 .outputTo(System.out)
+                 .errorTo(System.out)
+                 .shouldContain("ClassNotFoundException")
+                 .getExitValue();
+
+         assertTrue(exitValue != 0);
+     }
+
 
+    /**
+     * Run test on class path to load a type in a module on the application
+     * module path, uses {@code -addmods ALL-MODULE-PATH}.
+     */
+    public void testAddAllModulePath() throws Exception {
+
+        // java -mp mods -addmods ALL-MODULE-PATH -cp classes test.Main
+        String classpath = MODS1_DIR.resolve(TEST_MODULE).toString();
+        String modulepath = MODS1_DIR.toString();
+        int exitValue
+            = executeTestJava("-mp", modulepath,
+                              "-addmods", "ALL-MODULE-PATH",
+                              "-cp", classpath,
+                              TEST_MAIN_CLASS)
+                .outputTo(System.out)
+                .errorTo(System.out)
+                .getExitValue();
+
+        assertTrue(exitValue == 0);
+    }
+
+
+    /**
+     * Test {@code -addmods ALL-MODULE-PATH} without {@code -modulepath}.
+     */
+    public void testAddAllModulePathWithNoModulePath() throws Exception {
+
+        // java -addmods ALL-MODULE-PATH -version
+        int exitValue
+            = executeTestJava("-addmods", "ALL-MODULE-PATH",
+                              "-version")
+                .outputTo(System.out)
+                .errorTo(System.out)
+                .getExitValue();
+
+        assertTrue(exitValue == 0);
     }
 
 
@@ -169,18 +228,17 @@
      */
     public void testRunWithBadAddMods() throws Exception {
 
-        // java -mp mods -addmods,DoesNotExist lib -cp classes app.Main
+        // java -mp mods -addmods DoesNotExist -m test ...
         int exitValue
-            = executeTestJava("-mp", MODS_DIR.toString(),
-                              "-addmods", LIB_MODULE + ",DoesNotExist",
-                              "-cp", CLASSES_DIR.toString(),
-                              MAIN_CLASS)
+            = executeTestJava("-mp", MODS1_DIR.toString(),
+                              "-addmods", "DoesNotExist",
+                              "-m", TEST_MID)
                 .outputTo(System.out)
                 .errorTo(System.out)
+                .shouldContain("DoesNotExist")
                 .getExitValue();
 
         assertTrue(exitValue != 0);
-
     }
 
 }
--- a/jdk/test/tools/launcher/modules/addmods/src/app/Main.java	Tue May 03 09:48:02 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,32 +0,0 @@
-/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package app;
-
-import jdk.lib.Util;
-
-public class Main {
-    public static void main(String[] args) {
-        Object obj = Util.makeObject();
-    }
-}
--- a/jdk/test/tools/launcher/modules/addmods/src/lib/jdk/lib/Util.java	Tue May 03 09:48:02 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,32 +0,0 @@
-/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package jdk.lib;
-
-public class Util {
-    private Util() { }
-
-    public static Object makeObject() {
-        return new Object();
-    }
-}
--- a/jdk/test/tools/launcher/modules/addmods/src/lib/module-info.java	Tue May 03 09:48:02 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,26 +0,0 @@
-/*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-module lib {
-    exports jdk.lib;
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/launcher/modules/addmods/src/logger/logger/Logger.java	Tue May 03 12:25:20 2016 -0700
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package logger;
+
+/**
+ * No-op user module for use by the {@code java -addmods} tests.
+ */
+public class Logger {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/launcher/modules/addmods/src/logger/module-info.java	Tue May 03 12:25:20 2016 -0700
@@ -0,0 +1,24 @@
+/**
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module logger { }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/launcher/modules/addmods/src/test/module-info.java	Tue May 03 12:25:20 2016 -0700
@@ -0,0 +1,24 @@
+/**
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+module test { }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/tools/launcher/modules/addmods/src/test/test/Main.java	Tue May 03 12:25:20 2016 -0700
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package test;
+
+/**
+ * Invoked by tests for the {@code java -addmods} option to check that types
+ * are visible.
+ */
+public class Main {
+    public static void main(String[] args) throws Exception {
+        for (String cn : args) {
+            Class<?> c = Class.forName(cn);
+            System.out.println("Loaded: " + c);
+        }
+    }
+}
--- a/jdk/test/tools/launcher/modules/addreads/AddReadsTest.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/test/tools/launcher/modules/addreads/AddReadsTest.java	Tue May 03 12:25:20 2016 -0700
@@ -25,7 +25,7 @@
  * @test
  * @library /lib/testlibrary
  * @modules jdk.compiler
- * @build AddReadsTest CompilerUtils jdk.testlibrary.*
+ * @build AddReadsTest CompilerUtils JarUtils jdk.testlibrary.*
  * @run testng AddReadsTest
  * @summary Basic tests for java -XaddReads
  */
--- a/jdk/test/tools/launcher/modules/patch/PatchTest.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/test/tools/launcher/modules/patch/PatchTest.java	Tue May 03 12:25:20 2016 -0700
@@ -25,7 +25,7 @@
  * @test
  * @library /lib/testlibrary
  * @modules jdk.compiler
- * @build PatchTest CompilerUtils jdk.testlibrary.*
+ * @build PatchTest CompilerUtils JarUtils jdk.testlibrary.*
  * @run testng PatchTest
  * @summary Basic test for -Xpatch
  */
@@ -72,6 +72,9 @@
     private static final Path SRC2_DIR = Paths.get(TEST_SRC, "src2");
     private static final Path PATCHES2_DIR = Paths.get("patches2");
 
+    // destination directory for patches packaged as JAR files
+    private static final Path PATCHES_DIR = Paths.get("patches");
+
 
     // the classes overridden or added with -Xpatch
     private static final String[] CLASSES = {
@@ -95,7 +98,7 @@
 
 
     @BeforeTest
-    public void compile() throws Exception {
+    public void setup() throws Exception {
 
         // javac -d mods/test src/test/**
         boolean compiled= CompilerUtils.compile(SRC_DIR.resolve("test"),
@@ -103,36 +106,40 @@
         assertTrue(compiled, "classes did not compile");
 
         // javac -Xmodule:$MODULE -d patches1/$MODULE patches1/$MODULE/**
+        // jar cf patches/$MODULE-1.jar -C patches1/$MODULE .
         for (Path src : Files.newDirectoryStream(SRC1_DIR)) {
             Path output = PATCHES1_DIR.resolve(src.getFileName());
             String mn = src.getFileName().toString();
             compiled  = CompilerUtils.compile(src, output, "-Xmodule:" + mn);
             assertTrue(compiled, "classes did not compile");
+            JarUtils.createJarFile(PATCHES_DIR.resolve(mn + "-1.jar"), output);
         }
 
         // javac -Xmodule:$MODULE -d patches2/$MODULE patches2/$MODULE/**
+        // jar cf patches/$MODULE-2.jar -C patches2/$MODULE .
         for (Path src : Files.newDirectoryStream(SRC2_DIR)) {
             Path output = PATCHES2_DIR.resolve(src.getFileName());
             String mn = src.getFileName().toString();
             compiled  = CompilerUtils.compile(src, output, "-Xmodule:" + mn);
             assertTrue(compiled, "classes did not compile");
+            JarUtils.createJarFile(PATCHES_DIR.resolve(mn + "-2.jar"), output);
         }
 
     }
 
     /**
-     * Run the test with -Xpatch
+     * Run test with patches to java.base, jdk.naming.dns and jdk.compiler
      */
-    public void testRunWithXPatch() throws Exception {
-
-        // value for -Xpatch
-        String patchPath = PATCHES1_DIR + File.pathSeparator + PATCHES2_DIR;
-
+    void runTest(String basePatches, String dnsPatches, String compilerPatches)
+        throws Exception
+    {
         // the argument to the test is the list of classes overridden or added
         String arg = Stream.of(CLASSES).collect(Collectors.joining(","));
 
         int exitValue
-            =  executeTestJava("-Xpatch:" + patchPath,
+            =  executeTestJava("-Xpatch:java.base=" + basePatches,
+                               "-Xpatch:jdk.naming.dns=" + dnsPatches,
+                               "-Xpatch:jdk.compiler=" + compilerPatches,
                                "-XaddExports:java.base/java.lang2=test",
                                "-XaddExports:jdk.naming.dns/com.sun.jndi.dns=test",
                                "-XaddExports:jdk.naming.dns/com.sun.jndi.dns2=test",
@@ -145,6 +152,44 @@
                 .getExitValue();
 
         assertTrue(exitValue == 0);
+    }
+
+
+    /**
+     * Run test with -Xpatch and exploded patches
+     */
+    public void testWithExplodedPatches() throws Exception {
+
+        // patches1/java.base:patches2/java.base
+        String basePatches = PATCHES1_DIR.resolve("java.base")
+                + File.pathSeparator + PATCHES2_DIR.resolve("java.base");
+
+        String dnsPatches = PATCHES1_DIR.resolve("jdk.naming.dns")
+                + File.pathSeparator + PATCHES2_DIR.resolve("jdk.naming.dns");
+
+        String compilerPatches = PATCHES1_DIR.resolve("jdk.compiler")
+                + File.pathSeparator + PATCHES2_DIR.resolve("jdk.compiler");
+
+        runTest(basePatches, dnsPatches, compilerPatches);
+    }
+
+
+    /**
+     * Run test with -Xpatch and patches in JAR files
+     */
+    public void testWitJarPatches() throws Exception {
+
+        // patches/java.base-1.jar:patches/java-base-2.jar
+        String basePatches = PATCHES_DIR.resolve("java.base-1.jar")
+                + File.pathSeparator + PATCHES_DIR.resolve("java.base-2.jar");
+
+        String dnsPatches = PATCHES_DIR.resolve("jdk.naming.dns-1.jar")
+                +  File.pathSeparator + PATCHES_DIR.resolve("jdk.naming.dns-2.jar");
+
+        String compilerPatches = PATCHES_DIR.resolve("jdk.compiler-1.jar")
+                +  File.pathSeparator + PATCHES_DIR.resolve("jdk.compiler-2.jar");
+
+        runTest(basePatches, dnsPatches, compilerPatches);
 
     }
 
--- a/jdk/test/tools/lib/tests/JImageGenerator.java	Tue May 03 09:48:02 2016 -0700
+++ b/jdk/test/tools/lib/tests/JImageGenerator.java	Tue May 03 12:25:20 2016 -0700
@@ -113,7 +113,7 @@
 
     private static final String CMDS_OPTION = "--cmds";
     private static final String CONFIG_OPTION = "--config";
-    private static final String HASH_DEPENDENCIES_OPTION = "--hash-dependencies";
+    private static final String HASH_MODULES_OPTION = "--hash-modules";
     private static final String LIBS_OPTION = "--libs";
     private static final String MODULE_VERSION_OPTION = "--module-version";
 
@@ -347,7 +347,7 @@
         private final List<Path> jmods = new ArrayList<>();
         private final List<String> options = new ArrayList<>();
         private Path output;
-        private String hashDependencies;
+        private String hashModules;
         private String mainClass;
         private String moduleVersion;
 
@@ -356,8 +356,8 @@
             return this;
         }
 
-        public JModTask hashDependencies(String hash) {
-            this.hashDependencies = hash;
+        public JModTask hashModules(String hash) {
+            this.hashModules = hash;
             return this;
         }
 
@@ -430,9 +430,9 @@
                 options.add(CONFIG_OPTION);
                 options.add(toPath(config));
             }
-            if (hashDependencies != null) {
-                options.add(HASH_DEPENDENCIES_OPTION);
-                options.add(hashDependencies);
+            if (hashModules != null) {
+                options.add(HASH_MODULES_OPTION);
+                options.add(hashModules);
             }
             if (mainClass != null) {
                 options.add(MAIN_CLASS_OPTION);
--- a/langtools/.hgtags	Tue May 03 09:48:02 2016 -0700
+++ b/langtools/.hgtags	Tue May 03 12:25:20 2016 -0700
@@ -358,3 +358,4 @@
 4e87682893e662421af10a62d29ae822ce0fea04 jdk-9+113
 cba09a2e6ae969b029783eb59bb01017b78f8eef jdk-9+114
 31c8b18fdc5b94a2ddd5ea0694f350a2c907e9f7 jdk-9+115
+3e3553ee39d9e081573bc7c88a252214a3152763 jdk-9+116
--- a/langtools/src/java.compiler/share/classes/javax/tools/ToolProvider.java	Tue May 03 09:48:02 2016 -0700
+++ b/langtools/src/java.compiler/share/classes/javax/tools/ToolProvider.java	Tue May 03 12:25:20 2016 -0700
@@ -123,7 +123,9 @@
     private static <T> T getSystemTool(Class<T> clazz, String moduleName, String className) {
         if (useLegacy) {
             try {
-                return Class.forName(className, true, ClassLoader.getSystemClassLoader()).asSubclass(clazz).newInstance();
+                @SuppressWarnings("deprecation")
+                T result = Class.forName(className, true, ClassLoader.getSystemClassLoader()).asSubclass(clazz).newInstance();
+                return result;
             } catch (ReflectiveOperationException e) {
                 throw new Error(e);
             }
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symtab.java	Tue May 03 09:48:02 2016 -0700
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symtab.java	Tue May 03 12:25:20 2016 -0700
@@ -698,7 +698,7 @@
      */
     public boolean packageExists(ModuleSymbol msym, Name fullname) {
         Assert.checkNonNull(msym);
-        return enterPackage(msym, fullname).exists();
+        return lookupPackage(msym, fullname).exists();
     }
 
     /** Make a package, given its fully qualified name.
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/MemberEnter.java	Tue May 03 09:48:02 2016 -0700
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/MemberEnter.java	Tue May 03 12:25:20 2016 -0700
@@ -53,10 +53,6 @@
 public class MemberEnter extends JCTree.Visitor {
     protected static final Context.Key<MemberEnter> memberEnterKey = new Context.Key<>();
 
-    /** A switch to determine whether we check for package/class conflicts
-     */
-    final static boolean checkClash = true;
-
     private final Enter enter;
     private final Log log;
     private final Check chk;
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassWriter.java	Tue May 03 09:48:02 2016 -0700
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassWriter.java	Tue May 03 12:25:20 2016 -0700
@@ -826,7 +826,7 @@
         }
         public void visitClass(Attribute.Class clazz) {
             databuf.appendByte('c');
-            databuf.appendChar(pool.put(typeSig(clazz.classType)));
+            databuf.appendChar(pool.put(typeSig(types.erasure(clazz.classType))));
         }
         public void visitCompound(Attribute.Compound compound) {
             databuf.appendByte('@');
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java	Tue May 03 09:48:02 2016 -0700
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java	Tue May 03 12:25:20 2016 -0700
@@ -1086,17 +1086,19 @@
                 genStat(body, loopEnv, CRT_STATEMENT | CRT_FLOW_TARGET);
                 code.resolve(loopEnv.info.cont);
                 genStats(step, loopEnv);
-                CondItem c;
-                if (cond != null) {
-                    code.statBegin(cond.pos);
+                if (code.isAlive()) {
+                    CondItem c;
+                    if (cond != null) {
+                        code.statBegin(cond.pos);
+                        Assert.check(code.state.stacksize == 0);
+                        c = genCond(TreeInfo.skipParens(cond), CRT_FLOW_CONTROLLER);
+                    } else {
+                        c = items.makeCondItem(goto_);
+                    }
+                    code.resolve(c.jumpTrue(), startpc);
                     Assert.check(code.state.stacksize == 0);
-                    c = genCond(TreeInfo.skipParens(cond), CRT_FLOW_CONTROLLER);
-                } else {
-                    c = items.makeCondItem(goto_);
+                    code.resolve(c.falseJumps);
                 }
-                code.resolve(c.jumpTrue(), startpc);
-                Assert.check(code.state.stacksize == 0);
-                code.resolve(c.falseJumps);
             }
             Chain exit = loopEnv.info.exit;
             if (exit != null) {
@@ -1647,6 +1649,7 @@
 
     public void visitConditional(JCConditional tree) {
         Chain thenExit = null;
+        code.statBegin(tree.cond.pos);
         CondItem c = genCond(tree.cond, CRT_FLOW_CONTROLLER);
         Chain elseChain = c.jumpFalse();
         if (!c.isFalse()) {
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java	Tue May 03 09:48:02 2016 -0700
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java	Tue May 03 12:25:20 2016 -0700
@@ -282,6 +282,7 @@
 
         if (options.isSet(XPRINT)) {
             try {
+                @SuppressWarnings("deprecation")
                 Processor processor = PrintingProcessor.class.newInstance();
                 processorIterator = List.of(processor).iterator();
             } catch (Throwable t) {
@@ -549,8 +550,9 @@
                         try {
                             Class<?> processorClass = processorCL.loadClass(processorName);
                             ensureReadable(processorClass);
-                            processor =
-                                (Processor) (processorClass.newInstance());
+                            @SuppressWarnings("deprecation")
+                            Object tmp = processorClass.newInstance();
+                            processor = (Processor) tmp;
                         } catch (ClassNotFoundException cnfe) {
                             log.error("proc.processor.not.found", processorName);
                             return false;
--- a/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/options/Option.java	Tue May 03 09:48:02 2016 -0700
+++ b/langtools/src/jdk.compiler/share/classes/com/sun/tools/sjavac/options/Option.java	Tue May 03 12:25:20 2016 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -151,6 +151,7 @@
             // Construct transformer
             try {
                 Class<?> trCls = Class.forName(classname);
+                @SuppressWarnings("deprecation")
                 Transformer transformer = (Transformer) trCls.newInstance();
                 transformer.setExtra(extra);
                 helper.addTransformer(suffix, transformer);
--- a/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/formats/html/resources/standard.properties	Tue May 03 09:48:02 2016 -0700
+++ b/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/formats/html/resources/standard.properties	Tue May 03 12:25:20 2016 -0700
@@ -1,4 +1,4 @@
-doclet.build_version=Standard Doclet version {0}
+doclet.build_version=Standard Doclet (Old) version {0}
 doclet.Contents=Contents
 doclet.Overview=Overview
 doclet.Window_Overview=Overview List
--- a/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/internal/toolkit/taglets/TagletManager.java	Tue May 03 09:48:02 2016 -0700
+++ b/langtools/src/jdk.javadoc/share/classes/com/sun/tools/doclets/internal/toolkit/taglets/TagletManager.java	Tue May 03 12:25:20 2016 -0700
@@ -242,7 +242,6 @@
             }
 
             customTagClass = tagClassLoader.loadClass(classname);
-            ensureReadable(customTagClass);
 
             Method meth = customTagClass.getMethod("register",
                                                    Map.class);
@@ -270,27 +269,6 @@
     }
 
     /**
-     * Ensures that the module of the given class is readable to this
-     * module.
-     * @param targetClass class in module to be made readable
-     */
-    private void ensureReadable(Class<?> targetClass) {
-        try {
-            Method getModuleMethod = Class.class.getMethod("getModule");
-            Object thisModule = getModuleMethod.invoke(this.getClass());
-            Object targetModule = getModuleMethod.invoke(targetClass);
-
-            Class<?> moduleClass = getModuleMethod.getReturnType();
-            Method addReadsMethod = moduleClass.getMethod("addReads", moduleClass);
-            addReadsMethod.invoke(thisModule, targetModule);
-        } catch (NoSuchMethodException e) {
-            // ignore
-        } catch (Exception e) {
-            throw new InternalError(e);
-        }
-    }
-
-    /**
      * Export javadoc internal API to the unnamed module for a classloader.
      * This is to support continued use of existing non-standard doclets that
      * use the internal toolkit API and related classes.
--- a/langtools/src/jdk.javadoc/share/classes/com/sun/tools/javadoc/DocletInvoker.java	Tue May 03 09:48:02 2016 -0700
+++ b/langtools/src/jdk.javadoc/share/classes/com/sun/tools/javadoc/DocletInvoker.java	Tue May 03 12:25:20 2016 -0700
@@ -102,7 +102,6 @@
         this.apiMode = apiMode;
         this.exportInternalAPI = exportInternalAPI; // for backdoor use by standard doclet for taglets
 
-        ensureReadable(docletClass);
         // this may not be soon enough if the class has already been loaded
         if (exportInternalAPI) {
             exportInternalAPI(docletClass.getClassLoader());
@@ -149,8 +148,6 @@
             messager.exit();
         }
         docletClass = dc;
-
-        ensureReadable(docletClass);
     }
 
     /*
@@ -362,27 +359,6 @@
     }
 
     /**
-     * Ensures that the module of the given class is readable to this
-     * module.
-     * @param targetClass class in module to be made readable
-     */
-    private void ensureReadable(Class<?> targetClass) {
-        try {
-            Method getModuleMethod = Class.class.getMethod("getModule");
-            Object thisModule = getModuleMethod.invoke(this.getClass());
-            Object targetModule = getModuleMethod.invoke(targetClass);
-
-            Class<?> moduleClass = getModuleMethod.getReturnType();
-            Method addReadsMethod = moduleClass.getMethod("addReads", moduleClass);
-            addReadsMethod.invoke(thisModule, targetModule);
-        } catch (NoSuchMethodException e) {
-            // ignore
-        } catch (Exception e) {
-            throw new InternalError(e);
-        }
-    }
-
-    /**
      * Export javadoc internal API to the unnamed module for a classloader.
      * This is to support continued use of existing non-standard doclets that
      * use the internal toolkit API and related classes.
--- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ModuleWriterImpl.java	Tue May 03 09:48:02 2016 -0700
+++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ModuleWriterImpl.java	Tue May 03 12:25:20 2016 -0700
@@ -168,6 +168,21 @@
     }
 
     /**
+     * {@inheritDoc}
+     */
+    public void addModuleDescription(Content moduleContentTree) {
+        if (!utils.getBody(mdle).isEmpty()) {
+            Content tree = configuration.allowTag(HtmlTag.SECTION) ? HtmlTree.SECTION() : moduleContentTree;
+            tree.addContent(HtmlConstants.START_OF_MODULE_DESCRIPTION);
+            tree.addContent(getMarkerAnchor(SectionName.MODULE_DESCRIPTION));
+            addInlineComment(mdle, tree);
+            if (configuration.allowTag(HtmlTag.SECTION)) {
+                moduleContentTree.addContent(tree);
+            }
+        }
+    }
+
+    /**
      * Adds list of packages in the package summary table. Generate link to each package.
      *
      * @param packages Packages to which link is to be generated
--- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SectionName.java	Tue May 03 09:48:02 2016 -0700
+++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SectionName.java	Tue May 03 12:25:20 2016 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -53,6 +53,7 @@
     METHOD_DETAIL("method.detail"),
     METHODS_INHERITANCE("methods.inherited.from.class."),
     METHOD_SUMMARY("method.summary"),
+    MODULE_DESCRIPTION("module.description"),
     NAVBAR_BOTTOM("navbar.bottom"),
     NAVBAR_BOTTOM_FIRSTROW("navbar.bottom.firstrow"),
     NAVBAR_TOP("navbar.top"),
--- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlConstants.java	Tue May 03 09:48:02 2016 -0700
+++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlConstants.java	Tue May 03 12:25:20 2016 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -64,6 +64,12 @@
             new Comment("======== END OF BOTTOM NAVBAR =======");
 
     /**
+     * Marker to identify start of module description.
+     */
+    public static final Content START_OF_MODULE_DESCRIPTION =
+            new Comment("============ MODULE DESCRIPTION ===========");
+
+    /**
      * Marker to identify start of class data.
      */
     public static final Content START_OF_CLASS_DATA =
--- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard.properties	Tue May 03 09:48:02 2016 -0700
+++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard.properties	Tue May 03 12:25:20 2016 -0700
@@ -1,4 +1,4 @@
-doclet.build_version=Standard Doclet (Next) version {0}
+doclet.build_version=Standard Doclet version {0}
 doclet.Contents=Contents
 doclet.Overview=Overview
 doclet.Window_Overview=Overview List
--- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/ModuleSummaryWriter.java	Tue May 03 09:48:02 2016 -0700
+++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/ModuleSummaryWriter.java	Tue May 03 12:25:20 2016 -0700
@@ -74,6 +74,14 @@
     public abstract Content getSummaryTree(Content summaryContentTree);
 
     /**
+     * Adds the module description.
+     *
+     * @param moduleContentTree the content tree to which the module description
+     *                           will be added
+     */
+    public abstract void addModuleDescription(Content moduleContentTree);
+
+    /**
      * Adds the table of packages to the documentation tree.
      *
      * @param packages the set of packages that should be added.
--- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/ModuleSummaryBuilder.java	Tue May 03 09:48:02 2016 -0700
+++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/ModuleSummaryBuilder.java	Tue May 03 12:25:20 2016 -0700
@@ -185,4 +185,17 @@
                     packageTableSummary, summaryContentTree);
         }
     }
+
+    /**
+     * Build the description for the module.
+     *
+     * @param node the XML element that specifies which components to document
+     * @param moduleContentTree the tree to which the module description will
+     *                           be added
+     */
+    public void buildModuleDescription(XMLNode node, Content moduleContentTree) {
+        if (!configuration.nocomment) {
+            moduleWriter.addModuleDescription(moduleContentTree);
+        }
+    }
 }
--- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclet.xml	Tue May 03 09:48:02 2016 -0700
+++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/doclet.xml	Tue May 03 12:25:20 2016 -0700
@@ -30,6 +30,7 @@
 
     <ModuleDoc>
         <Content>
+            <ModuleDescription/>
             <Summary>
                 <PackageSummary/>
             </Summary>
--- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/TagletManager.java	Tue May 03 09:48:02 2016 -0700
+++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/TagletManager.java	Tue May 03 12:25:20 2016 -0700
@@ -246,7 +246,7 @@
             }
             tagClassLoader = fileManager.getClassLoader(TAGLET_PATH);
             Class<?> customTagClass = tagClassLoader.loadClass(classname);
-            ensureReadable(customTagClass);
+            @SuppressWarnings("deprecation")
             Object instance = customTagClass.newInstance();
             Taglet newLegacy = new UserTaglet((jdk.javadoc.doclet.taglet.Taglet)instance);
             String tname = newLegacy.getName();
@@ -262,27 +262,6 @@
     }
 
     /**
-     * Ensures that the module of the given class is readable to this
-     * module.
-     * @param targetClass class in module to be made readable
-     */
-    private void ensureReadable(Class<?> targetClass) {
-        try {
-            Method getModuleMethod = Class.class.getMethod("getModule");
-            Object thisModule = getModuleMethod.invoke(this.getClass());
-            Object targetModule = getModuleMethod.invoke(targetClass);
-
-            Class<?> moduleClass = getModuleMethod.getReturnType();
-            Method addReadsMethod = moduleClass.getMethod("addReads", moduleClass);
-            addReadsMethod.invoke(thisModule, targetModule);
-        } catch (NoSuchMethodException e) {
-            // ignore
-        } catch (Exception e) {
-            throw new InternalError(e.toString());
-        }
-    }
-
-    /**
      * Add a new <code>SimpleTaglet</code>.  If this tag already exists
      * and the header passed as an argument is null, move tag to the back of the
      * list. If this tag already exists and the header passed as an argument is
--- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/IndexBuilder.java	Tue May 03 09:48:02 2016 -0700
+++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/IndexBuilder.java	Tue May 03 12:25:20 2016 -0700
@@ -73,6 +73,7 @@
 
     private final Configuration configuration;
     private final Utils utils;
+    private final Comparator<Element> comparator;
 
     /**
      * Constructor. Build the index map.
@@ -106,6 +107,9 @@
         this.classesOnly = classesOnly;
         this.javafx = configuration.javafx;
         this.indexmap = new TreeMap<>();
+        comparator = classesOnly
+                ? utils.makeAllClassesComparator()
+                : utils.makeIndexUseComparator();
         buildIndexMap(configuration.root);
     }
 
@@ -175,7 +179,7 @@
                           Character.toUpperCase(name.charAt(0));
                 Character unicode = ch;
                 SortedSet<Element> list = indexmap.computeIfAbsent(unicode,
-                        c -> new TreeSet<>(utils.makeIndexUseComparator()));
+                        c -> new TreeSet<>(comparator));
                 list.add(element);
             }
         }
--- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Utils.java	Tue May 03 09:48:02 2016 -0700
+++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Utils.java	Tue May 03 12:25:20 2016 -0700
@@ -1628,6 +1628,7 @@
 
     /**
      * Comparator for ModuleElements, simply compares the fully qualified names
+     * @return a Comparator
      */
     public Comparator<Element> makeModuleComparator() {
         return new Utils.ElementComparator<Element>() {
@@ -1639,7 +1640,28 @@
     }
 
     /**
-     * Comparator for PackageElements, simply compares the fully qualified names
+     * Returns a Comparator for all classes, compares the simple names of
+     * TypeElement, if equal then the fully qualified names.
+     *
+     * @return Comparator
+     */
+    public Comparator<Element> makeAllClassesComparator() {
+        return new Utils.ElementComparator<Element>() {
+            @Override
+            public int compare(Element e1, Element e2) {
+                int result =  compareNames(e1, e2);
+                if (result == 0)
+                    result =  compareFullyQualifiedNames(e1, e2);
+
+                return result;
+            }
+        };
+    }
+
+    /**
+     * Returns a Comparator for packages, by comparing the fully qualified names.
+     *
+     * @return a Comparator
      */
     public Comparator<Element> makePackageComparator() {
         return new Utils.ElementComparator<Element>() {
@@ -1650,6 +1672,10 @@
         };
     }
 
+    /**
+     * Returns a Comparator for SerialFieldTree.
+     * @return a Comparator
+     */
     public Comparator<SerialFieldTree> makeSerialFieldTreeComparator() {
         return (SerialFieldTree o1, SerialFieldTree o2) -> {
             String s1 = o1.getName().toString();
@@ -1659,18 +1685,19 @@
     }
 
     /**
-     * Comparator for General Purpose
-     * @return a ElementComparatorForClassUse
+     * Returns a general purpose comparator.
+     * @return a Comparator
      */
     public Comparator<Element> makeGeneralPurposeComparator() {
         return makeClassUseComparator();
     }
 
     /**
-     * A Comparator for Overrides and Implements use used on ExecutableElements
-     * compares the name first, then compares the SimpleName of the enclosing
-     * class and the FullyQualifiedName of the enclosing class.
-     * @return
+     * Returns a Comparator for overrides and implements,
+     * used primarily on methods, compares the name first,
+     * then compares the simple names of the enclosing
+     * TypeElement and the fully qualified name of the enclosing TypeElement.
+     * @return a Comparator
      */
     public Comparator<Element> makeOverrideUseComparator() {
         return new Utils.ElementComparator<Element>() {
@@ -1696,21 +1723,24 @@
     }
 
     /**
-     * A comparator for index file presentations, and are sorted as follows:
+     * Returns a Comparator for index file presentations, and are sorted as follows.
+     *  If comparing packages then simply compare the qualified names, otherwise
      *  1. sort on simple names of entities
      *  2. if equal, then compare the ElementKind ex: Package, Interface etc.
      *  3a. if equal and if the type is of ExecutableElement(Constructor, Methods),
      *      a case insensitive comparison of parameter the type signatures
      *  3b. if equal, case sensitive comparison of the type signatures
      *  4. finally, if equal, compare the FQNs of the entities
+     * Iff comparing packages then simply sort on qualified names.
      * @return a comparator for index file use
      */
     public Comparator<Element> makeIndexUseComparator() {
         return new Utils.ElementComparator<Element>() {
             /**
-             * Compare two given elements, first sort on names, then on the kinds,
-             * then on the parameters only if the type is an instance of ExecutableElement,
-             * the parameters are compared and finally the fully qualified names.
+             * Compare two given elements, if comparing two packages, return the
+             * comparison of FullyQualifiedName, first sort on names, then on the
+             * kinds, then on the parameters only if the type is an ExecutableElement,
+             * the parameters are compared and finally the qualified names.
              *
              * @param e1 - an element.
              * @param e2 - an element.
@@ -1719,10 +1749,7 @@
              */
             @Override
             public int compare(Element e1, Element e2) {
-                int result = compareElementTypeKinds(e1, e2);
-                if (result != 0) {
-                    return result;
-                }
+                int result = 0;
                 if (isPackage(e1) && isPackage(e2)) {
                     return compareFullyQualifiedNames(e1, e2);
                 }
@@ -1730,6 +1757,10 @@
                 if (result != 0) {
                     return result;
                 }
+                result = compareElementTypeKinds(e1, e2);
+                if (result != 0) {
+                    return result;
+                }
                 if (hasParameters(e1)) {
                     List<? extends VariableElement> parameters1 = ((ExecutableElement)e1).getParameters();
                     List<? extends VariableElement> parameters2 = ((ExecutableElement)e2).getParameters();
--- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/DocEnv.java	Tue May 03 09:48:02 2016 -0700
+++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/DocEnv.java	Tue May 03 12:25:20 2016 -0700
@@ -550,7 +550,7 @@
         // Messager should be replaced by a more general
         // compilation environment.  This can probably
         // subsume DocEnv as well.
-        messager.exit();
+        throw new Messager.ExitJavadoc();
     }
 
     /**
--- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/Main.java	Tue May 03 09:48:02 2016 -0700
+++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/Main.java	Tue May 03 12:25:20 2016 -0700
@@ -59,13 +59,6 @@
      * @return The return code.
      */
     public static int execute(String... args) {
-        // NOTE: the following should be removed when the old doclet
-        // is removed.
-        if (args != null && args.length > 0 && "-Xold".equals(args[0])) {
-            String[] nargs = new String[args.length - 1];
-            System.arraycopy(args, 1, nargs, 0, nargs.length);
-            return com.sun.tools.javadoc.Main.execute(nargs);
-        }
         Start jdoc = new Start();
         return jdoc.begin(args);
     }
--- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/Messager.java	Tue May 03 09:48:02 2016 -0700
+++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/Messager.java	Tue May 03 12:25:20 2016 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -139,7 +139,7 @@
         }
     }
 
-    public class ExitJavadoc extends Error {
+    public static class ExitJavadoc extends Error {
         private static final long serialVersionUID = 0;
     }
 
@@ -416,15 +416,6 @@
         }
     }
 
-    /**
-     * Force program exit, e.g., from a fatal error.
-     * <p>
-     * TODO: This method does not really belong here.
-     */
-    public void exit() {
-        throw new ExitJavadoc();
-    }
-
     private void report(DiagnosticType type, String pos, String msg) {
         switch (type) {
             case ERROR:
--- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/Start.java	Tue May 03 09:48:02 2016 -0700
+++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/Start.java	Tue May 03 12:25:20 2016 -0700
@@ -66,6 +66,7 @@
 import jdk.javadoc.doclet.DocletEnvironment;
 
 import static com.sun.tools.javac.main.Option.*;
+
 /**
  * Main program of Javadoc.
  * Previously named "Main".
@@ -79,6 +80,12 @@
  * @author Neal Gafter (rewrite)
  */
 public class Start extends ToolOption.Helper {
+
+    private static final Class<?> OldStdDoclet =
+            com.sun.tools.doclets.standard.Standard.class;
+
+    private static final Class<?> StdDoclet =
+            jdk.javadoc.internal.doclets.standard.Standard.class;
     /** Context for this invocation. */
     private final Context context;
 
@@ -193,18 +200,26 @@
         if (foot != null)
             messager.notice(foot);
 
-        if (exit) exit();
+        if (exit)
+            throw new Messager.ExitJavadoc();
     }
 
+
     /**
-     * Exit
-     */
-    private void exit() {
-        messager.exit();
-    }
-
-    /**
-     * Main program - external wrapper
+     * Main program - external wrapper. In order to maintain backward
+     * CLI  compatibility, we dispatch to the old tool or the old doclet's
+     * Start mechanism, based on the options present on the command line
+     * with the following precedence:
+     *   1. presence of -Xold, dispatch to old tool
+     *   2. doclet variant, if old, dispatch to old Start
+     *   3. taglet variant, if old, dispatch to old Start
+     *
+     * Thus the presence of -Xold switches the tool, soon after command files
+     * if any, are expanded, this is performed here, noting that the messager
+     * is available at this point in time.
+     * The doclet/taglet tests are performed in the begin method, further on,
+     * this is to minimize argument processing and most importantly the impact
+     * of class loader creation, needed to detect the doclet/taglet class variants.
      */
     int begin(String... argv) {
         // Preprocess @file arguments
@@ -212,14 +227,18 @@
             argv = CommandLine.parse(argv);
         } catch (FileNotFoundException e) {
             messager.error("main.cant.read", e.getMessage());
-            exit();
+            throw new Messager.ExitJavadoc();
         } catch (IOException e) {
             e.printStackTrace(System.err);
-            exit();
+            throw new Messager.ExitJavadoc();
         }
 
-        List<String> argList = Arrays.asList(argv);
-        boolean ok = begin(argList, Collections.<JavaFileObject> emptySet());
+        if (argv.length > 0 && "-Xold".equals(argv[0])) {
+            messager.warning("main.legacy_api");
+            String[] nargv = Arrays.copyOfRange(argv, 1, argv.length);
+            return com.sun.tools.javadoc.Main.execute(nargv);
+        }
+        boolean ok = begin(Arrays.asList(argv), Collections.<JavaFileObject> emptySet());
         return ok ? 0 : 1;
     }
 
@@ -231,11 +250,11 @@
         List<String> opts = new ArrayList<>();
         for (String opt: options)
             opts.add(opt);
+
         return begin(opts, fileObjects);
     }
 
     private boolean begin(List<String> options, Iterable<? extends JavaFileObject> fileObjects) {
-
         fileManager = context.get(JavaFileManager.class);
         if (fileManager == null) {
             JavacFileManager.preRegister(context);
@@ -244,20 +263,21 @@
                 ((BaseFileManager) fileManager).autoClose = true;
             }
         }
-        // locale and doclet needs to be determined first
+        // locale, doclet and maybe taglet, needs to be determined first
         docletClass = preProcess(fileManager, options);
-
         if (jdk.javadoc.doclet.Doclet.class.isAssignableFrom(docletClass)) {
             // no need to dispatch to old, safe to init now
             initMessager();
             messager.setLocale(locale);
             try {
-                doclet = (Doclet) docletClass.newInstance();
+                @SuppressWarnings("deprecation")
+                Object o = docletClass.newInstance();
+                doclet = (Doclet) o;
             } catch (InstantiationException | IllegalAccessException exc) {
                 exc.printStackTrace();
                 if (!apiMode) {
                     error("main.could_not_instantiate_class", docletClass);
-                    messager.exit();
+                    throw new Messager.ExitJavadoc();
                 }
                 throw new ClientCodeException(exc);
             }
@@ -267,6 +287,7 @@
                         = new com.sun.tools.javadoc.Start(context);
                 return ostart.begin(docletClass, options, fileObjects);
             }
+            warn("main.legacy_api");
             String[] array = options.toArray(new String[options.size()]);
             return com.sun.tools.javadoc.Main.execute(array) == 0;
         }
@@ -312,27 +333,6 @@
     }
 
     /**
-     * Ensures that the module of the given class is readable to this
-     * module.
-     * @param targetClass class in module to be made readable
-     */
-    private void ensureReadable(Class<?> targetClass) {
-        try {
-            Method getModuleMethod = Class.class.getMethod("getModule");
-            Object thisModule = getModuleMethod.invoke(this.getClass());
-            Object targetModule = getModuleMethod.invoke(targetClass);
-
-            Class<?> moduleClass = getModuleMethod.getReturnType();
-            Method addReadsMethod = moduleClass.getMethod("addReads", moduleClass);
-            addReadsMethod.invoke(thisModule, targetModule);
-        } catch (NoSuchMethodException e) {
-            // ignore
-        } catch (Exception e) {
-            throw new InternalError(e);
-        }
-    }
-
-    /**
      * Main program - internal
      */
     private boolean parseAndExecute(List<String> argList,
@@ -459,6 +459,11 @@
         String userDocletPath = null;
         String userDocletName = null;
 
+        // taglet specifying arguments, since tagletpath is a doclet
+        // functionality, assume they are repeated and inspect all.
+        List<File> userTagletPath = new ArrayList<>();
+        List<String> userTagletNames = new ArrayList<>();
+
         // Step 1: loop through the args, set locale early on, if found.
         for (int i = 0 ; i < argv.size() ; i++) {
             String arg = argv.get(i);
@@ -470,7 +475,7 @@
                 oneArg(argv, i++);
                 if (userDocletName != null) {
                     usageError("main.more_than_one_doclet_specified_0_and_1",
-                               userDocletName, argv.get(i));
+                            userDocletName, argv.get(i));
                 }
                 if (docletName != null) {
                     usageError("main.more_than_one_doclet_specified_0_and_1",
@@ -484,13 +489,20 @@
                 } else {
                     userDocletPath += File.pathSeparator + argv.get(i);
                 }
+            } else if ("-taglet".equals(arg)) {
+                userTagletNames.add(argv.get(i + 1));
+            } else if ("-tagletpath".equals(arg)) {
+                for (String pathname : argv.get(i + 1).split(File.pathSeparator)) {
+                    userTagletPath.add(new File(pathname));
+                }
             }
         }
-        // Step 2: a doclet has already been provided,
-        // nothing more to do.
+
+        // Step 2: a doclet is provided, nothing more to do.
         if (docletClass != null) {
             return docletClass;
         }
+
         // Step 3: doclet name specified ? if so find a ClassLoader,
         // and load it.
         if (userDocletName != null) {
@@ -506,38 +518,78 @@
                     try {
                         ((StandardJavaFileManager)fileManager).setLocation(DOCLET_PATH, paths);
                     } catch (IOException ioe) {
-                        panic("main.doclet_no_classloader_found", ioe);
-                        return null; // keep compiler happy
+                        error("main.doclet_could_not_set_location", paths);
+                        throw new Messager.ExitJavadoc();
                     }
                 }
                 cl = fileManager.getClassLoader(DOCLET_PATH);
                 if (cl == null) {
                     // despite doclet specified on cmdline no classloader found!
-                    panic("main.doclet_no_classloader_found", userDocletName);
-                    return null; // keep compiler happy
-                }
-                try {
-                    Class<?> klass = cl.loadClass(userDocletName);
-                    ensureReadable(klass);
-                    return klass;
-                } catch (ClassNotFoundException cnfe) {
-                    panic("main.doclet_class_not_found", userDocletName);
-                    return null; // keep compiler happy
+                    error("main.doclet_no_classloader_found", userDocletName);
+                    throw new Messager.ExitJavadoc();
                 }
             }
+            try {
+                Class<?> klass = cl.loadClass(userDocletName);
+                return klass;
+            } catch (ClassNotFoundException cnfe) {
+                error("main.doclet_class_not_found", userDocletName);
+                throw new Messager.ExitJavadoc();
+            }
         }
-        // Step 4: we have a doclet, try loading it, otherwise
-        // return back the standard doclet
+
+        // Step 4: we have a doclet, try loading it
         if (docletName != null) {
             try {
                 return Class.forName(docletName, true, getClass().getClassLoader());
             } catch (ClassNotFoundException cnfe) {
-                panic("main.doclet_class_not_found", userDocletName);
-                return null; // happy compiler, should not happen
+                error("main.doclet_class_not_found", userDocletName);
+                throw new Messager.ExitJavadoc();
             }
-        } else {
-            return jdk.javadoc.internal.doclets.standard.Standard.class;
+        }
+
+        // Step 5: we don't have a doclet specified, do we have taglets ?
+        if (!userTagletNames.isEmpty() && hasOldTaglet(userTagletNames, userTagletPath)) {
+            // found a bogey, return the old doclet
+            return OldStdDoclet;
         }
+
+        // finally
+        return StdDoclet;
+    }
+
+    /*
+     * This method returns true iff it finds a legacy taglet, but for
+     * all other conditions including errors it returns false, allowing
+     * nature to take its own course.
+     */
+    private boolean hasOldTaglet(List<String> tagletNames, List<File> tagletPaths) {
+        if (!fileManager.hasLocation(TAGLET_PATH)) {
+            try {
+                ((StandardJavaFileManager) fileManager).setLocation(TAGLET_PATH, tagletPaths);
+            } catch (IOException ioe) {
+                error("main.doclet_could_not_set_location", tagletPaths);
+                throw new Messager.ExitJavadoc();
+            }
+        }
+        ClassLoader cl = fileManager.getClassLoader(TAGLET_PATH);
+        if (cl == null) {
+            // no classloader found!
+            error("main.doclet_no_classloader_found", tagletNames.get(0));
+            throw new Messager.ExitJavadoc();
+        }
+        for (String tagletName : tagletNames) {
+            try {
+                Class<?> klass = cl.loadClass(tagletName);
+                if (com.sun.tools.doclets.Taglet.class.isAssignableFrom(klass)) {
+                    return true;
+                }
+            } catch (ClassNotFoundException cnfe) {
+                error("main.doclet_class_not_found", tagletName);
+                throw new Messager.ExitJavadoc();
+            }
+        }
+        return false;
     }
 
     private void parseArgs(List<String> args, List<String> javaNames) {
@@ -595,14 +647,12 @@
         usage(true);
     }
 
-    // a terminal call, will not return
-    void panic(String key, Object... args) {
-        error(key, args);
-        messager.exit();
+    void error(String key, Object... args) {
+        messager.error(key, args);
     }
 
-    void error(String key, Object... args) {
-        messager.error(key, args);
+    void warn(String key, Object... args)  {
+        messager.warning(key, args);
     }
 
     /**
--- a/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/resources/javadoc.properties	Tue May 03 09:48:02 2016 -0700
+++ b/langtools/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/resources/javadoc.properties	Tue May 03 12:25:20 2016 -0700
@@ -73,7 +73,8 @@
 \                                   given module. <other-module> may be ALL-UNNAMED to require\n\
 \                                   the unnamed module.\n\
 \  -Xmodule:<module-name>           Specify a module to which the classes being compiled belong.\n\
-\  -Xpatch:<path>                   Specify location of module class files to patch\n  
+\  -Xpatch:<path>                   Specify location of module class files to patch\n\
+\  -Xold                            Invoke the legacy javadoc tool\n
 
 main.Xusage.foot=\
 These options are non-standard and subject to change without notice.
@@ -96,6 +97,7 @@
 such as -J-Xmx32m.
 main.done_in=[done in {0} ms]
 main.more_than_one_doclet_specified_0_and_1=More than one doclet specified ({0} and {1}).
+main.doclet_could_not_set_location=Could not set location for {0}
 main.doclet_no_classloader_found=Could not obtain classloader to load {0}
 main.could_not_instantiate_class=Could not instantiate class {0}
 main.doclet_class_not_found=Cannot find doclet class {0}
@@ -109,10 +111,15 @@
 main.unsupported.release.version=release version {0} not supported
 main.release.not.standard.file.manager=-release option specified, but the provided JavaFileManager is not a StandardJavaFileManager.
 main.unknown.error=an unknown error has occurred
+main.legacy_api=The old Doclet and Taglet APIs in the packages\n\
+    com.sun.javadoc, com.sun.tools.doclets and their implementations\n\
+    are planned to be removed in a future JDK release. These\n\
+    components have been superseded by the new APIs in jdk.javadoc.doclet.\n\
+    Users are strongly recommended to migrate to the new APIs.\n
+
 javadoc.class_not_found=Class {0} not found.
 javadoc.error=error
 javadoc.warning=warning
-
 javadoc.error.msg={0}: error - {1}
 javadoc.warning.msg={0}: warning - {1}
 javadoc.note.msg = {1}
--- a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/ArgTokenizer.java	Tue May 03 09:48:02 2016 -0700
+++ b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/ArgTokenizer.java	Tue May 03 12:25:20 2016 -0700
@@ -35,6 +35,7 @@
 class ArgTokenizer {
 
     private final String str;
+    private final String prefix;
     private final int length;
     private int next = 0;
     private char buf[] = new char[20];
@@ -49,7 +50,12 @@
     private boolean isQuoted = false;
 
     ArgTokenizer(String arg) {
+        this("", arg);
+    }
+
+    ArgTokenizer(String prefix, String arg) {
         this.str = arg;
+        this.prefix = prefix;
         this.length = arg.length();
         quoteChar('"');
         quoteChar('\'');
@@ -88,7 +94,7 @@
     }
 
     String whole() {
-        return str;
+        return prefix + str;
     }
 
     void mark() {
--- a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/Feedback.java	Tue May 03 09:48:02 2016 -0700
+++ b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/Feedback.java	Tue May 03 12:25:20 2016 -0700
@@ -95,20 +95,20 @@
         return mode.getContinuationPrompt(nextId);
     }
 
-    public boolean setFeedback(JShellTool tool, ArgTokenizer at) {
-        return new Setter(tool, at).setFeedback();
+    public boolean setFeedback(MessageHandler messageHandler, ArgTokenizer at) {
+        return new Setter(messageHandler, at).setFeedback();
     }
 
-    public boolean setFormat(JShellTool tool, ArgTokenizer at) {
-        return new Setter(tool, at).setFormat();
+    public boolean setFormat(MessageHandler messageHandler, ArgTokenizer at) {
+        return new Setter(messageHandler, at).setFormat();
     }
 
-    public boolean setNewMode(JShellTool tool, ArgTokenizer at) {
-        return new Setter(tool, at).setNewMode();
+    public boolean setNewMode(MessageHandler messageHandler, ArgTokenizer at) {
+        return new Setter(messageHandler, at).setNewMode();
     }
 
-    public boolean setPrompt(JShellTool tool, ArgTokenizer at) {
-        return new Setter(tool, at).setPrompt();
+    public boolean setPrompt(MessageHandler messageHandler, ArgTokenizer at) {
+        return new Setter(messageHandler, at).setPrompt();
     }
 
     {
@@ -529,26 +529,26 @@
     private class Setter {
 
         private final ArgTokenizer at;
-        private final JShellTool tool;
+        private final MessageHandler messageHandler;
         boolean valid = true;
 
-        Setter(JShellTool tool, ArgTokenizer at) {
-            this.tool = tool;
+        Setter(MessageHandler messageHandler, ArgTokenizer at) {
+            this.messageHandler = messageHandler;
             this.at = at;
         }
 
         void fluff(String format, Object... args) {
-            tool.fluff(format, args);
+            messageHandler.fluff(format, args);
         }
 
-        void fluffmsg(String format, Object... args) {
-            tool.fluffmsg(format, args);
+        void fluffmsg(String messageKey, Object... args) {
+            messageHandler.fluffmsg(messageKey, args);
         }
 
         void errorat(String messageKey, Object... args) {
             Object[] a2 = Arrays.copyOf(args, args.length + 2);
-            a2[args.length] = "/set " + at.whole();
-            tool.errormsg(messageKey, a2);
+            a2[args.length] = at.whole();
+            messageHandler.errormsg(messageKey, a2);
         }
 
         // For /set prompt <mode> "<prompt>" "<continuation-prompt>"
--- a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java	Tue May 03 09:48:02 2016 -0700
+++ b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/JShellTool.java	Tue May 03 12:25:20 2016 -0700
@@ -108,7 +108,7 @@
  * Command line REPL tool for Java using the JShell API.
  * @author Robert Field
  */
-public class JShellTool {
+public class JShellTool implements MessageHandler {
 
     private static final String LINE_SEP = System.getProperty("line.separator");
     private static final Pattern LINEBREAK = Pattern.compile("\\R");
@@ -166,6 +166,8 @@
     private boolean regenerateOnDeath = true;
     private boolean live = false;
     private boolean feedbackInitialized = false;
+    private String initialMode = null;
+    private List<String> remoteVMOptions = new ArrayList<>();
 
     SourceCodeAnalysis analysis;
     JShell state = null;
@@ -256,7 +258,8 @@
      * @param format printf format
      * @param args printf args
      */
-    void fluff(String format, Object... args) {
+    @Override
+    public void fluff(String format, Object... args) {
         if (feedback.shouldDisplayCommandFluff() && interactive()) {
             hard(format, args);
         }
@@ -362,7 +365,8 @@
      * @param key the resource key
      * @param args
      */
-    void errormsg(String key, Object... args) {
+    @Override
+    public void errormsg(String key, Object... args) {
         cmdout.println(prefix(messageFormat(key, args), feedback.getErrorPre()));
     }
 
@@ -383,7 +387,8 @@
      * @param key the resource key
      * @param args
      */
-    void fluffmsg(String key, Object... args) {
+    @Override
+    public void fluffmsg(String key, Object... args) {
         if (feedback.shouldDisplayCommandFluff() && interactive()) {
             hardmsg(key, args);
         }
@@ -512,6 +517,23 @@
                     case "-fullversion":
                         cmdout.printf("jshell %s\n", fullVersion());
                         return null;
+                    case "-feedback":
+                        if (ai.hasNext()) {
+                            initialMode = ai.next();
+                        } else {
+                            startmsg("jshell.err.opt.feedback.arg");
+                            return null;
+                        }
+                        break;
+                    case "-q":
+                        initialMode = "concise";
+                        break;
+                    case "-qq":
+                        initialMode = "silent";
+                        break;
+                    case "-v":
+                        initialMode = "verbose";
+                        break;
                     case "-startup":
                         if (cmdlineStartup != null) {
                             startmsg("jshell.err.opt.startup.conflict");
@@ -530,6 +552,10 @@
                         cmdlineStartup = "";
                         break;
                     default:
+                        if (arg.startsWith("-R")) {
+                            remoteVMOptions.add(arg.substring(2));
+                            break;
+                        }
                         startmsg("jshell.err.opt.unknown", arg);
                         printUsage();
                         return null;
@@ -567,6 +593,7 @@
                 .idGenerator((sn, i) -> (currentNameSpace == startNamespace || state.status(sn).isActive)
                         ? currentNameSpace.tid(sn)
                         : errorNamespace.tid(sn))
+                .remoteVMOptions(remoteVMOptions.toArray(new String[remoteVMOptions.size()]))
                 .build();
         shutdownSubscription = state.onShutdown((JShell deadState) -> {
             if (deadState == state) {
@@ -596,6 +623,26 @@
             start = cmdlineStartup;
         }
         startUpRun(start);
+        if (initialMode != null) {
+            MessageHandler mh = new MessageHandler() {
+                @Override
+                public void fluff(String format, Object... args) {
+                }
+
+                @Override
+                public void fluffmsg(String messageKey, Object... args) {
+                }
+
+                @Override
+                public void errormsg(String messageKey, Object... args) {
+                    startmsg(messageKey, args);
+                }
+            };
+            if (!feedback.setFeedback(mh, new ArgTokenizer("-feedback ", initialMode))) {
+                regenerateOnDeath = false;
+            }
+            initialMode = null;
+        }
         currentNameSpace = mainNamespace;
     }
     //where
@@ -1050,7 +1097,7 @@
         "format", "feedback", "newmode", "prompt", "editor", "start"};
 
     final boolean cmdSet(String arg) {
-        ArgTokenizer at = new ArgTokenizer(arg.trim());
+        ArgTokenizer at = new ArgTokenizer("/set ", arg.trim());
         String which = setSubCommand(at);
         if (which == null) {
             return false;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/MessageHandler.java	Tue May 03 12:25:20 2016 -0700
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.internal.jshell.tool;
+
+
+/**
+ * User message reporting support
+ *
+ * @author Robert Field
+ */
+public interface MessageHandler {
+
+    void fluff(String format, Object... args);
+
+    void fluffmsg(String messageKey, Object... args);
+
+    void errormsg(String messageKey, Object... args);
+}
--- a/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/resources/l10n.properties	Tue May 03 09:48:02 2016 -0700
+++ b/langtools/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/resources/l10n.properties	Tue May 03 12:25:20 2016 -0700
@@ -28,6 +28,7 @@
 For an introduction type: /help intro\n
 jshell.err.opt.classpath.conflict = Conflicting -classpath option.
 jshell.err.opt.classpath.arg = Argument to -classpath missing.
+jshell.err.opt.feedback.arg = Argument to -feedback missing. Mode required.
 jshell.err.opt.startup.conflict = Conflicting -startup or -nostartup option.
 jshell.err.opt.unknown = Unknown option: {0}
 
@@ -128,13 +129,23 @@
 
 help.usage = \
 Usage:   jshell <options> <load files>\n\
-where possible options include:\n\t\
-  -classpath <path>          Specify where to find user class files\n\t\
-  -cp <path>                 Specify where to find user class files\n\t\
-  -startup <file>            One run replacement for the start-up definitions\n\t\
-  -nostartup                 Do not run the start-up definitions\n\t\
-  -help                      Print a synopsis of standard options\n\t\
-  -version                   Version information\n
+where possible options include:\n\
+\    -classpath <path>    Specify where to find user class files\n\
+\    -cp <path>           Specify where to find user class files\n\
+\    -startup <file>      One run replacement for the start-up definitions\n\
+\    -nostartup           Do not run the start-up definitions\n\
+\    -feedback <mode>     Specify the initial feedback mode. The mode may be\n\
+\                         predefined (silent, concise, normal, or verbose) or\n\
+\                         previously user-defined\n\
+\    -q                   Quiet feedback.  Same as: -feedback concise\n\
+\    -qq                  Really quiet feedback.  Same as: -feedback silent\n\
+\    -v                   Verbose feedback.  Same as: -feedback verbose\n\
+\    -J<flag>             Pass <flag> directly to the runtime system.\n\
+\                         Use one -J for each runtime flag or flag argument\n\
+\    -R<flag>             Pass <flag> to the remote runtime system.\n\
+\                         Use one -R for each remote flag or flag argument\n\
+\    -help                Print this synopsis of standard options\n\
+\    -version             Version information\n
 
 help.list.summary = list the source you have typed
 help.list.args = [all|start|<name or id>]
--- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/Diag.java	Tue May 03 09:48:02 2016 -0700
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/Diag.java	Tue May 03 12:25:20 2016 -0700
@@ -36,12 +36,18 @@
     // Simplified view on compiler Diagnostic.
 
     /**
+     * In-package creation only.
+     */
+    Diag() {
+    }
+
+    /**
      * Used to signal that no position is available.
      */
     public final static long NOPOS = Diagnostic.NOPOS;
 
     /**
-     * Is this diagnostic and error (as opposed to a warning or note)
+     * Is this diagnostic an error (as opposed to a warning or note)
      * @return true if this diagnostic is an error
      */
     public abstract boolean isError();
--- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/Eval.java	Tue May 03 09:48:02 2016 -0700
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/Eval.java	Tue May 03 12:25:20 2016 -0700
@@ -452,7 +452,7 @@
 
         // If appropriate, execute the snippet
         String value = null;
-        Exception exception = null;
+        JShellException exception = null;
         if (si.status().isDefined) {
             if (si.isExecutable()) {
                 try {
@@ -462,7 +462,8 @@
                             : "";
                 } catch (EvalException ex) {
                     exception = translateExecutionException(ex);
-                } catch (UnresolvedReferenceException ex) {
+                } catch (JShellException ex) {
+                    // UnresolvedReferenceException
                     exception = ex;
                 }
             } else if (si.subKind() == SubKind.VAR_DECLARATION_SUBKIND) {
@@ -499,7 +500,7 @@
                     || e.exception() != null;
     }
 
-    private List<SnippetEvent> events(Unit c, Collection<Unit> outs, String value, Exception exception) {
+    private List<SnippetEvent> events(Unit c, Collection<Unit> outs, String value, JShellException exception) {
         List<SnippetEvent> events = new ArrayList<>();
         events.add(c.event(value, exception));
         events.addAll(outs.stream()
--- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/EvalException.java	Tue May 03 09:48:02 2016 -0700
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/EvalException.java	Tue May 03 12:25:20 2016 -0700
@@ -40,7 +40,7 @@
  * empty string.
  */
 @SuppressWarnings("serial")             // serialVersionUID intentionally omitted
-public class EvalException extends Exception {
+public class EvalException extends JShellException {
     private final String exceptionClass;
 
     EvalException(String message, String exceptionClass, StackTraceElement[] stackElements) {
--- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/ExecutionControl.java	Tue May 03 09:48:02 2016 -0700
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/ExecutionControl.java	Tue May 03 12:25:20 2016 -0700
@@ -57,11 +57,19 @@
     private ObjectInputStream in;
     private ObjectOutputStream out;
     private final JShell proc;
+    private final String remoteVMOptions;
 
-    ExecutionControl(JDIEnv env, SnippetMaps maps, JShell proc) {
+    ExecutionControl(JDIEnv env, SnippetMaps maps, JShell proc, List<String> extraRemoteVMOptions) {
         this.env = env;
         this.maps = maps;
         this.proc = proc;
+        StringBuilder sb = new StringBuilder();
+        extraRemoteVMOptions.stream()
+                .forEach(s -> {
+                    sb.append(" ");
+                    sb.append(s);
+                });
+        this.remoteVMOptions = sb.toString();
     }
 
     void launch() throws IOException {
@@ -111,7 +119,7 @@
         }
     }
 
-    String commandInvoke(String classname) throws EvalException, UnresolvedReferenceException {
+    String commandInvoke(String classname) throws JShellException {
         try {
             synchronized (STOP_LOCK) {
                 userCodeRunning = true;
@@ -205,7 +213,7 @@
         }
     }
 
-    private boolean readAndReportExecutionResult() throws IOException, EvalException, UnresolvedReferenceException {
+    private boolean readAndReportExecutionResult() throws IOException, JShellException {
         int ok = in.readInt();
         switch (ok) {
             case RESULT_SUCCESS:
@@ -257,11 +265,9 @@
         //        Locale.getDefault());
 
         String connectorName = "com.sun.jdi.CommandLineLaunch";
-        String classPath = System.getProperty("java.class.path");
-        String javaArgs = "-classpath " + classPath;
         Map<String, String> argumentName2Value = new HashMap<>();
         argumentName2Value.put("main", "jdk.internal.jshell.remote.RemoteAgent " + port);
-        argumentName2Value.put("options", javaArgs);
+        argumentName2Value.put("options", remoteVMOptions);
 
         boolean launchImmediately = true;
         int traceFlags = 0;// VirtualMachine.TRACE_SENDS | VirtualMachine.TRACE_EVENTS;
--- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/JShell.java	Tue May 03 09:48:02 2016 -0700
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/JShell.java	Tue May 03 12:25:20 2016 -0700
@@ -26,10 +26,11 @@
 package jdk.jshell;
 
 import java.io.ByteArrayInputStream;
-import java.io.IOException;
 import java.io.InputStream;
 import java.io.PrintStream;
 import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
@@ -84,6 +85,7 @@
     final PrintStream err;
     final Supplier<String> tempVariableNameGenerator;
     final BiFunction<Snippet, Integer, String> idGenerator;
+    final List<String> extraRemoteVMOptions;
 
     private int nextKeyIndex = 1;
 
@@ -105,6 +107,7 @@
         this.err = b.err;
         this.tempVariableNameGenerator = b.tempVariableNameGenerator;
         this.idGenerator = b.idGenerator;
+        this.extraRemoteVMOptions = b.extraRemoteVMOptions;
 
         this.maps = new SnippetMaps(this);
         this.keyMap = new KeyMap(this);
@@ -139,6 +142,7 @@
         PrintStream err = System.err;
         Supplier<String> tempVariableNameGenerator = null;
         BiFunction<Snippet, Integer, String> idGenerator = null;
+        List<String> extraRemoteVMOptions = new ArrayList<>();
 
         Builder() { }
 
@@ -264,6 +268,18 @@
         }
 
         /**
+         * Set additional VM options for launching the VM.
+         *
+         * @param options The options for the remote VM.
+         * @return the <code>Builder</code> instance (for use in chained
+         * initialization).
+         */
+        public Builder remoteVMOptions(String... options) {
+            this.extraRemoteVMOptions.addAll(Arrays.asList(options));
+            return this;
+        }
+
+        /**
          * Build a JShell state engine. This is the entry-point to all JShell
          * functionality. This creates a remote process for execution. It is
          * thus important to close the returned instance.
@@ -621,10 +637,10 @@
 
     ExecutionControl executionControl() {
         if (executionControl == null) {
-            this.executionControl = new ExecutionControl(new JDIEnv(this), maps, this);
+            this.executionControl = new ExecutionControl(new JDIEnv(this), maps, this, extraRemoteVMOptions);
             try {
                 executionControl.launch();
-            } catch (IOException ex) {
+            } catch (Throwable ex) {
                 throw new InternalError("Launching JDI execution engine threw: " + ex.getMessage(), ex);
             }
         }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/JShellException.java	Tue May 03 12:25:20 2016 -0700
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.jshell;
+
+/**
+ * The superclass of JShell generated exceptions
+ */
+@SuppressWarnings("serial")             // serialVersionUID intentionally omitted
+public class JShellException extends Exception {
+
+    JShellException(String message) {
+        super(message);
+    }
+}
--- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/SnippetEvent.java	Tue May 03 09:48:02 2016 -0700
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/SnippetEvent.java	Tue May 03 12:25:20 2016 -0700
@@ -44,7 +44,7 @@
 
     SnippetEvent(Snippet snippet, Status previousStatus, Status status,
             boolean isSignatureChange, Snippet causeSnippet,
-            String value, Exception exception) {
+            String value, JShellException exception) {
         this.snippet = snippet;
         this.previousStatus = previousStatus;
         this.status = status;
@@ -60,7 +60,7 @@
     private final boolean isSignatureChange;
     private final Snippet causeSnippet;
     private final String value;
-    private final Exception exception;
+    private final JShellException exception;
 
     /**
      * The Snippet which has changed
@@ -121,7 +121,7 @@
      * during execution, otherwise <code>null</code>.
      * @return the exception or <code>null</code>.
      */
-    public Exception exception() {
+    public JShellException exception() {
         return exception;
     }
 
--- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/Unit.java	Tue May 03 09:48:02 2016 -0700
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/Unit.java	Tue May 03 12:25:20 2016 -0700
@@ -440,7 +440,7 @@
                 : msi.parameterTypes();
     }
 
-    SnippetEvent event(String value, Exception exception) {
+    SnippetEvent event(String value, JShellException exception) {
         boolean wasSignatureChanged = sigChanged();
         state.debug(DBG_EVNT, "Snippet: %s id: %s before: %s status: %s sig: %b cause: %s\n",
                 si, si.id(), prevStatus, si.status(), wasSignatureChanged, causalSnippet);
--- a/langtools/src/jdk.jshell/share/classes/jdk/jshell/UnresolvedReferenceException.java	Tue May 03 09:48:02 2016 -0700
+++ b/langtools/src/jdk.jshell/share/classes/jdk/jshell/UnresolvedReferenceException.java	Tue May 03 12:25:20 2016 -0700
@@ -38,7 +38,7 @@
  * empty string.
  */
 @SuppressWarnings("serial")             // serialVersionUID intentionally omitted
-public class UnresolvedReferenceException extends Exception {
+public class UnresolvedReferenceException extends JShellException {
 
     final DeclarationSnippet snippet;
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/jdk/javadoc/doclet/testModules/TestModules.java	Tue May 03 12:25:20 2016 -0700
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8154119
+ * @summary Test modules support in javadoc.
+ * @author bpatel
+ * @library ../lib
+ * @modules jdk.javadoc/jdk.javadoc.internal.tool
+ * @build JavadocTester
+ * @run main TestModules
+ */
+
+public class TestModules extends JavadocTester {
+
+    public static void main(String... args) throws Exception {
+        TestModules tester = new TestModules();
+        tester.runTests();
+    }
+
+    @Test
+    void test1() {
+        javadoc("-d", "out",
+                "-modulesourcepath", testSrc,
+                "-addmods", "module1,module2",
+                "testpkgmdl1", "testpkgmdl2");
+        checkExit(Exit.OK);
+        testDescription(true);
+        testNoDescription(false);
+    }
+
+    @Test
+    void test2() {
+        javadoc("-d", "out-html5", "-html5",
+                "-modulesourcepath", testSrc,
+                "-addmods", "module1,module2",
+                "testpkgmdl1", "testpkgmdl2");
+        checkExit(Exit.OK);
+        testHtml5Description(true);
+        testHtml5NoDescription(false);
+    }
+
+    @Test
+    void test3() {
+        javadoc("-d", "out-nocomment", "-nocomment",
+                "-modulesourcepath", testSrc,
+                "-addmods", "module1,module2",
+                "testpkgmdl1", "testpkgmdl2");
+        checkExit(Exit.OK);
+        testDescription(false);
+        testNoDescription(true);
+    }
+
+    @Test
+    void test4() {
+        javadoc("-d", "out-html5-nocomment", "-nocomment", "-html5",
+                "-modulesourcepath", testSrc,
+                "-addmods", "module1,module2",
+                "testpkgmdl1", "testpkgmdl2");
+        checkExit(Exit.OK);
+        testHtml5Description(false);
+        testHtml5NoDescription(true);
+    }
+
+    void testDescription(boolean found) {
+        checkOutput("module1-summary.html", found,
+                "<!-- ============ MODULE DESCRIPTION =========== -->\n"
+                + "<a name=\"module.description\">\n"
+                + "<!--   -->\n"
+                + "</a>\n"
+                + "<div class=\"block\">This is a test description for the module1 module.</div>");
+        checkOutput("module2-summary.html", found,
+                "<!-- ============ MODULE DESCRIPTION =========== -->\n"
+                + "<a name=\"module.description\">\n"
+                + "<!--   -->\n"
+                + "</a>\n"
+                + "<div class=\"block\">This is a test description for the module2 module.</div>");
+    }
+
+    void testNoDescription(boolean found) {
+        checkOutput("module1-summary.html", found,
+                "<div class=\"contentContainer\">\n"
+                + "<ul class=\"blockList\">\n"
+                + "<li class=\"blockList\">\n"
+                + "<table class=\"overviewSummary\" summary=\"Package Summary table, listing packages, and an explanation\">");
+        checkOutput("module2-summary.html", found,
+                "<div class=\"contentContainer\">\n"
+                + "<ul class=\"blockList\">\n"
+                + "<li class=\"blockList\">\n"
+                + "<table class=\"overviewSummary\" summary=\"Package Summary table, listing packages, and an explanation\">");
+    }
+
+    void testHtml5Description(boolean found) {
+        checkOutput("module1-summary.html", found,
+                "<section role=\"region\">\n"
+                + "<!-- ============ MODULE DESCRIPTION =========== -->\n"
+                + "<a id=\"module.description\">\n"
+                + "<!--   -->\n"
+                + "</a>\n"
+                + "<div class=\"block\">This is a test description for the module1 module.</div>\n"
+                + "</section>");
+        checkOutput("module2-summary.html", found,
+                "<section role=\"region\">\n"
+                + "<!-- ============ MODULE DESCRIPTION =========== -->\n"
+                + "<a id=\"module.description\">\n"
+                + "<!--   -->\n"
+                + "</a>\n"
+                + "<div class=\"block\">This is a test description for the module2 module.</div>\n"
+                + "</section>");
+    }
+
+    void testHtml5NoDescription(boolean found) {
+        checkOutput("module1-summary.html", found,
+                "<div class=\"contentContainer\">\n"
+                + "<ul class=\"blockList\">\n"
+                + "<li class=\"blockList\">\n"
+                + "<table class=\"overviewSummary\">");
+        checkOutput("module2-summary.html", found,
+                "<div class=\"contentContainer\">\n"
+                + "<ul class=\"blockList\">\n"
+                + "<li class=\"blockList\">\n"
+                + "<table class=\"overviewSummary\">");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/jdk/javadoc/doclet/testModules/module1/module-info.java	Tue May 03 12:25:20 2016 -0700
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+  * This is a test description for the module1 module.
+  */
+module module1 {
+    requires module2;
+
+    exports testpkgmdl1;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/jdk/javadoc/doclet/testModules/module1/testpkgmdl1/TestClassInModule1.java	Tue May 03 12:25:20 2016 -0700
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package testpkgmdl1;
+
+public class TestClassInModule1 {
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/jdk/javadoc/doclet/testModules/module2/module-info.java	Tue May 03 12:25:20 2016 -0700
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+  * This is a test description for the module2 module.
+  */
+module module2 {
+    exports testpkgmdl2;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/jdk/javadoc/doclet/testModules/module2/testpkgmdl2/TestClassInModule2.java	Tue May 03 12:25:20 2016 -0700
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package testpkgmdl2;
+
+public class TestClassInModule2 {
+}
--- a/langtools/test/jdk/javadoc/doclet/testOrdering/TestOrdering.java	Tue May 03 09:48:02 2016 -0700
+++ b/langtools/test/jdk/javadoc/doclet/testOrdering/TestOrdering.java	Tue May 03 12:25:20 2016 -0700
@@ -23,7 +23,7 @@
 
 /*
  * @test
- * @bug 8039410 8042601 8042829 8049393 8050031
+ * @bug 8039410 8042601 8042829 8049393 8050031 8155061
  * @summary test to determine if members are ordered correctly
  * @author ksrini
  * @library ../lib/
@@ -72,6 +72,8 @@
         checkOrder("pkg1/class-use/UsedClass.html", expectedInnerClassContructors);
         checkOrder("pkg1/ImplementsOrdering.html", expectedImplementsOrdering);
         checkOrder("pkg1/OverrideOrdering.html", expectedOverrideOrdering);
+        checkOrder("allclasses-noframe.html", expectedAllClasses);
+        checkOrder("allclasses-frame.html", expectedAllClasses);
     }
 
     enum ListOrder { NONE, REVERSE, SHUFFLE };
@@ -179,6 +181,22 @@
     };
     String[] composeTestVectors() {
         List<String> testList = new ArrayList<>();
+
+        testList.addAll(Arrays.asList(expectedPackageOrdering));
+
+        for (String x : expectedMethodOrdering) {
+            testList.add(x);
+            for (int i = 0; i < MAX_PACKAGES; i++) {
+                String wpkg = "add" + i;
+                testList.add(wpkg + "/" + x);
+                String dpkg = wpkg;
+                for (int j = 1; j < MAX_SUBPACKAGES_DEPTH; j++) {
+                    dpkg = dpkg + "/" + "add";
+                    testList.add(dpkg + "/" + x);
+                }
+            }
+        }
+
         for (String x : expectedEnumOrdering) {
             testList.add(x.replace("REPLACE_ME", "&lt;Unnamed&gt;"));
             for (int i = 0; i < MAX_PACKAGES; i++) {
@@ -194,20 +212,9 @@
 
         testList.addAll(Arrays.asList(expectedFieldOrdering));
 
-        for (String x : expectedMethodOrdering) {
-            testList.add(x);
-            for (int i = 0; i < MAX_PACKAGES; i++) {
-                String wpkg = "add" + i;
-                testList.add(wpkg + "/" + x);
-                String dpkg = wpkg;
-                for (int j = 1; j < MAX_SUBPACKAGES_DEPTH; j++) {
-                    dpkg = dpkg + "/" + "add";
-                    testList.add(dpkg + "/" + x);
-                }
-            }
-        }
         return testList.toArray(new String[testList.size()]);
     }
+
     void checkExecutableMemberOrdering(String usePage) {
         String contents = readFile(usePage);
         // check constructors
@@ -309,6 +316,22 @@
         return in.replace("/", ".");
     }
 
+    final String expectedAllClasses[] = {
+        "pkg1/A.html\" title=\"class in pkg1",
+        "pkg1/A.C.html\" title=\"class in pkg1",
+        "pkg1/B.html\" title=\"class in pkg1",
+        "pkg1/B.A.html\" title=\"class in pkg1",
+        "pkg1/C1.html\" title=\"class in pkg1",
+        "pkg1/C2.html\" title=\"class in pkg1",
+        "pkg1/C3.html\" title=\"class in pkg1",
+        "pkg1/C4.html\" title=\"class in pkg1",
+        "pkg1/ImplementsOrdering.html\" title=\"interface in pkg1",
+        "pkg1/MethodOrder.html\" title=\"class in pkg1",
+        "pkg1/OverrideOrdering.html\" title=\"class in pkg1",
+        "pkg1/UsedClass.html\" title=\"class in pkg1"
+
+    };
+
     final String expectedInnerClassContructors[] = {
         "../../pkg1/A.html#A-pkg1.UsedClass-",
         "../../pkg1/B.A.html#A-pkg1.UsedClass-",
@@ -342,12 +365,33 @@
         "../../pkg1/MethodOrder.html#m-java.util.Collection-",
         "../../pkg1/MethodOrder.html#m-java.util.List-"
     };
+
     final String expectedClassUseWithTypeParams[] = {
         "../../pkg1/MethodOrder.html#tpm-pkg1.UsedClass-",
         "../../pkg1/MethodOrder.html#tpm-pkg1.UsedClass-pkg1.UsedClass-",
         "../../pkg1/MethodOrder.html#tpm-pkg1.UsedClass-pkg1.UsedClass:A-",
         "../../pkg1/MethodOrder.html#tpm-pkg1.UsedClass-java.lang.String-"
     };
+
+    final String expectedPackageOrdering[] = {
+        "\"add0/package-summary.html\">add0</a> - package add0",
+        "\"add0/add/package-summary.html\">add0.add</a> - package add0.add",
+        "\"add0/add/add/package-summary.html\">add0.add.add</a> - package add0.add.add",
+        "\"add0/add/add/add/package-summary.html\">add0.add.add.add</a> - package add0.add.add.add",
+        "\"add1/package-summary.html\">add1</a> - package add1",
+        "\"add1/add/package-summary.html\">add1.add</a> - package add1.add",
+        "\"add1/add/add/package-summary.html\">add1.add.add</a> - package add1.add.add",
+        "\"add1/add/add/add/package-summary.html\">add1.add.add.add</a> - package add1.add.add.add",
+        "\"add2/package-summary.html\">add2</a> - package add2",
+        "\"add2/add/package-summary.html\">add2.add</a> - package add2.add",
+        "\"add2/add/add/package-summary.html\">add2.add.add</a> - package add2.add.add",
+        "\"add2/add/add/add/package-summary.html\">add2.add.add.add</a> - package add2.add.add.add",
+        "\"add3/package-summary.html\">add3</a> - package add3",
+        "\"add3/add/package-summary.html\">add3.add</a> - package add3.add",
+        "\"add3/add/add/package-summary.html\">add3.add.add</a> - package add3.add.add",
+        "\"add3/add/add/add/package-summary.html\">add3.add.add.add</a> - package add3.add.add.add"
+    };
+
     final String expectedMethodOrdering[] = {
         "Add.html#add--",
         "Add.html#add-double-",
@@ -361,10 +405,12 @@
         "Add.html#add-java.lang.Double-",
         "Add.html#add-java.lang.Integer-"
     };
+
     final String expectedEnumOrdering[] = {
         "Add.add.html\" title=\"enum in REPLACE_ME\"",
         "Add.ADD.html\" title=\"enum in REPLACE_ME\""
     };
+
     final String expectedFieldOrdering[] = {
         "Add.html#addadd\"",
         "add0/add/add/add/Add.html#addadd\"",
@@ -418,10 +464,12 @@
         "add3/add/Add.html#ADDADD\"",
         "add3/Add.html#ADDADD\""
     };
+
     final String expectedPackageTreeOrdering[] = {
         "<a href=\"../../add0/add/Add.add.html\" title=\"enum in add0.add\">",
         "<a href=\"../../add0/add/Add.ADD.html\" title=\"enum in add0.add\">"
     };
+
     final String expectedOverviewOrdering[] = {
         "<a href=\"Add.add.html\" title=\"enum in &lt;Unnamed&gt;\">",
         "<a href=\"add0/Add.add.html\" title=\"enum in add0\">",
@@ -458,6 +506,7 @@
         "<a href=\"add3/add/add/Add.ADD.html\" title=\"enum in add3.add.add\">",
         "<a href=\"add3/add/add/add/Add.ADD.html\" title=\"enum in add3.add.add.add\">",
     };
+
     final static String expectedOverviewFrameOrdering[] = {
         "<a href=\"package-frame.html\" target=\"packageFrame\">&lt;unnamed package&gt;</a>",
         "<a href=\"add0/package-frame.html\" target=\"packageFrame\">add0</a>",
@@ -477,11 +526,13 @@
         "<a href=\"add3/add/add/package-frame.html\" target=\"packageFrame\">add3.add.add</a>",
         "<a href=\"add3/add/add/add/package-frame.html\" target=\"packageFrame\">add3.add.add.add</a></li>"
     };
+
     final static String expectedImplementsOrdering[] = {
         "<dd><code>close</code>&nbsp;in interface&nbsp;<code>java.lang.AutoCloseable</code></dd>",
         "<dd><code>close</code>&nbsp;in interface&nbsp;<code>java.nio.channels.Channel</code></dd>",
         "<dd><code>close</code>&nbsp;in interface&nbsp;<code>java.io.Closeable</code></dd>"
     };
+
     final static String expectedOverrideOrdering[] = {
         "<dd><code>iterator</code>&nbsp;in interface&nbsp;<code>java.util.Collection&lt;",
         "<dd><code>iterator</code>&nbsp;in interface&nbsp;<code>java.lang.Iterable&lt;"
--- a/langtools/test/jdk/javadoc/tool/EnsureNewOldDoclet.java	Tue May 03 09:48:02 2016 -0700
+++ b/langtools/test/jdk/javadoc/tool/EnsureNewOldDoclet.java	Tue May 03 12:25:20 2016 -0700
@@ -23,96 +23,349 @@
 
 /*
  * @test
- * @bug 8035473
- * @summary make sure the new doclet is invoked by default, and -Xold
+ * @bug 8035473 8154482
+ * @summary make sure the javadoc tool responds correctly to Xold,
+ *          old doclets and taglets.
+ * @library /tools/lib
+ * @build toolbox.ToolBox toolbox.TestRunner
+ * @run main EnsureNewOldDoclet
  */
 
 import java.io.*;
-import java.util.ArrayList;
+import java.nio.file.Path;
+import java.util.Arrays;
+import java.util.Collections;
 import java.util.List;
+import java.util.Map;
+import java.util.Set;
 import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+
+import com.sun.javadoc.Tag;
+import com.sun.source.doctree.DocTree;
+
+import toolbox.*;
+
 
 /**
- * Dummy javadoc comment.
+ * This test ensures the doclet responds correctly when given
+ * various conditions that force a fall back to the old javadoc
+ * tool. The following condition in the order described will
+ * force a dispatch to the old tool, -Xold, old doclet and old taglet.
+ *
  */
-public class EnsureNewOldDoclet {
+public class EnsureNewOldDoclet extends TestRunner {
+
+    final ToolBox tb;
+    final File testSrc;
+    final Path javadocPath;
+    final ExecTask task;
+    final String testClasses;
+    final PrintStream ostream;
 
-    final File javadoc;
-    final File testSrc;
-    final String thisClassName;
+    final static String CLASS_NAME = "EnsureNewOldDoclet";
+    final static String OLD_DOCLET_CLASS_NAME = CLASS_NAME + "$OldDoclet";
+    final static String NEW_DOCLET_CLASS_NAME = CLASS_NAME + "$NewDoclet"; //unused
+    final static String OLD_TAGLET_CLASS_NAME = CLASS_NAME + "$OldTaglet";
+    final static String NEW_TAGLET_CLASS_NAME = CLASS_NAME + "$NewTaglet";
+
+    final static Pattern OLD_HEADER = Pattern.compile("^Standard Doclet \\(Old\\) version.*");
+    final static Pattern NEW_HEADER = Pattern.compile("^Standard Doclet version.*");
+
+
+    final static String OLD_DOCLET_MARKER = "OLD_DOCLET_MARKER";
+    final static String OLD_TAGLET_MARKER = "Registered: OldTaglet";
+
+    final static String NEW_DOCLET_MARKER = "NEW_DOCLET_MARKER";
+    final static String NEW_TAGLET_MARKER = "Registered Taglet " + CLASS_NAME + "\\$NewTaglet";
 
-    final static Pattern Expected1 = Pattern.compile("^Standard Doclet \\(Next\\) version.*");
-    final static Pattern Expected2 = Pattern.compile("^Standard Doclet version.*");
+    final static Pattern WARN_TEXT = Pattern.compile("Users are strongly recommended to migrate" +
+                                                    " to the new APIs.");
+    final static String OLD_DOCLET_ERROR = "java.lang.NoSuchMethodException: " +
+            CLASS_NAME +"\\$NewTaglet";
+    final static Pattern NEW_DOCLET_ERROR = Pattern.compile(".*java.lang.ClassCastException.*Taglet " +
+            CLASS_NAME + "\\$OldTaglet.*");
+
+    final static String OLD_STDDOCLET = "com.sun.tools.doclets.standard.Standard";
+    final static String NEW_STDDOCLET = "jdk.javadoc.internal.doclets.standard.Standard";
+
 
-    public EnsureNewOldDoclet() {
-        File javaHome = new File(System.getProperty("java.home"));
-        if (javaHome.getName().endsWith("jre"))
-            javaHome = javaHome.getParentFile();
-        javadoc = new File(new File(javaHome, "bin"), "javadoc");
-        testSrc = new File(System.getProperty("test.src"));
-        thisClassName = EnsureNewOldDoclet.class.getName();
+    public EnsureNewOldDoclet() throws Exception {
+        super(System.err);
+        ostream = System.err;
+        testClasses = System.getProperty("test.classes");
+        tb = new ToolBox();
+        javadocPath = tb.getJDKTool("javadoc");
+        task = new ExecTask(tb, javadocPath);
+        testSrc = new File("Foo.java");
+        generateSample(testSrc);
+    }
+
+    void generateSample(File testSrc) throws Exception {
+        String nl = System.getProperty("line.separator");
+        String src = Arrays.asList(
+            "/**",
+            " * A test class to test javadoc. Nothing more nothing less.",
+            " */",
+            " public class Foo{}").stream().collect(Collectors.joining(nl));
+        tb.writeFile(testSrc.getPath(), src);
     }
 
     public static void main(String... args) throws Exception {
-        EnsureNewOldDoclet test = new EnsureNewOldDoclet();
-        test.run1();
-        test.run2();
+        new EnsureNewOldDoclet().runTests();
+    }
+
+    // input: nothing, default mode
+    // outcome: new tool and new doclet
+    @Test
+    public void testDefault() throws Exception {
+        setArgs("-classpath", ".", // insulates us from ambient classpath
+                  testSrc.toString());
+        Task.Result tr = task.run(Task.Expect.SUCCESS);
+        List<String> out = tr.getOutputLines(Task.OutputKind.STDOUT);
+        checkOutput(testName, out, NEW_HEADER);
+    }
+
+    // input: -Xold
+    // outcome: old tool
+    @Test
+    public void testXold() throws Exception {
+        setArgs("-Xold",
+                "-classpath", ".", // ambient classpath insulation
+                testSrc.toString());
+        Task.Result tr = task.run(Task.Expect.SUCCESS);
+        List<String> out = tr.getOutputLines(Task.OutputKind.STDOUT);
+        List<String> err = tr.getOutputLines(Task.OutputKind.STDERR);
+        checkOutput(testName, out, OLD_HEADER);
+        checkOutput(testName, err, WARN_TEXT);
+    }
+
+    // input: old doclet
+    // outcome: old tool
+    @Test
+    public void testOldDoclet() throws Exception {
+        setArgs("-classpath", ".", // ambient classpath insulation
+                "-doclet",
+                OLD_DOCLET_CLASS_NAME,
+                "-docletpath",
+                testClasses,
+                testSrc.toString());
+        Task.Result tr = task.run(Task.Expect.SUCCESS);
+        List<String> out = tr.getOutputLines(Task.OutputKind.STDOUT);
+        List<String> err = tr.getOutputLines(Task.OutputKind.STDERR);
+        checkOutput(testName, out, OLD_DOCLET_MARKER);
+        checkOutput(testName, err, WARN_TEXT);
+    }
+
+    // input: old taglet
+    // outcome: old tool
+    @Test
+    public void testOldTaglet() throws Exception {
+        setArgs("-classpath", ".", // ambient classpath insulation
+            "-taglet",
+            OLD_TAGLET_CLASS_NAME,
+            "-tagletpath",
+            testClasses,
+            testSrc.toString());
+        Task.Result tr = task.run(Task.Expect.SUCCESS);
+        List<String> out = tr.getOutputLines(Task.OutputKind.STDOUT);
+        List<String> err = tr.getOutputLines(Task.OutputKind.STDERR);
+        checkOutput(testName, out, OLD_TAGLET_MARKER);
+        checkOutput(testName, err, WARN_TEXT);
     }
 
-    // make sure new doclet is invoked by default
-    void run1() throws Exception {
-        List<String> output = doTest(javadoc.getPath(),
-                "-classpath", ".", // insulates us from ambient classpath
-                "-Xdoclint:none",
-                "-package",
-                new File(testSrc, thisClassName + ".java").getPath());
-        System.out.println(output);
-        for (String x : output) {
-            if (Expected1.matcher(x).matches()) {
+    // input: new doclet and old taglet
+    // outcome: new doclet with failure
+    @Test
+    public void testNewDocletOldTaglet() throws Exception {
+        setArgs("-classpath", ".", // ambient classpath insulation
+                "-doclet",
+                NEW_STDDOCLET,
+                "-taglet",
+                OLD_TAGLET_CLASS_NAME,
+                "-tagletpath",
+                testClasses,
+                testSrc.toString());
+        Task.Result tr = task.run(Task.Expect.FAIL, 1);
+        //Task.Result tr = task.run();
+        List<String> out = tr.getOutputLines(Task.OutputKind.STDOUT);
+        List<String> err = tr.getOutputLines(Task.OutputKind.STDERR);
+        checkOutput(testName, out, NEW_HEADER);
+        checkOutput(testName, err, NEW_DOCLET_ERROR);
+    }
+
+    // input: old doclet and old taglet
+    // outcome: old doclet and old taglet should register
+    @Test
+    public void testOldDocletOldTaglet() throws Exception {
+        setArgs("-classpath", ".", // ambient classpath insulation
+                "-doclet",
+                OLD_STDDOCLET,
+                "-taglet",
+                OLD_TAGLET_CLASS_NAME,
+                "-tagletpath",
+                testClasses,
+                testSrc.toString());
+        Task.Result tr = task.run(Task.Expect.SUCCESS);
+        List<String> out = tr.getOutputLines(Task.OutputKind.STDOUT);
+        List<String> err = tr.getOutputLines(Task.OutputKind.STDERR);
+        checkOutput(testName, out, OLD_HEADER);
+        checkOutput(testName, out, OLD_TAGLET_MARKER);
+        checkOutput(testName, err, WARN_TEXT);
+    }
+
+    // input: new doclet and new taglet
+    // outcome: new doclet and new taglet should register
+    @Test
+    public void testNewDocletNewTaglet() throws Exception {
+        setArgs("-classpath", ".", // ambient classpath insulation
+                "-doclet",
+                NEW_STDDOCLET,
+                "-taglet",
+                NEW_TAGLET_CLASS_NAME,
+                "-tagletpath",
+                testClasses,
+                testSrc.toString());
+        Task.Result tr = task.run(Task.Expect.SUCCESS);
+        List<String> out = tr.getOutputLines(Task.OutputKind.STDOUT);
+        List<String> err = tr.getOutputLines(Task.OutputKind.STDERR);
+        checkOutput(testName, out, NEW_HEADER);
+        checkOutput(testName, out, NEW_TAGLET_MARKER);
+    }
+
+    // input: old doclet and new taglet
+    // outcome: old doclet and error
+    @Test
+    public void testOldDocletNewTaglet() throws Exception {
+        setArgs("-classpath", ".", // ambient classpath insulation
+                "-doclet",
+                OLD_STDDOCLET,
+                "-taglet",
+                NEW_TAGLET_CLASS_NAME,
+                "-tagletpath",
+                testClasses,
+                testSrc.toString());
+        Task.Result tr = task.run(Task.Expect.FAIL, 1);
+        List<String> out = tr.getOutputLines(Task.OutputKind.STDOUT);
+        List<String> err = tr.getOutputLines(Task.OutputKind.STDERR);
+        checkOutput(testName, out, OLD_HEADER);
+        checkOutput(testName, err, WARN_TEXT);
+        checkOutput(testName, err, OLD_DOCLET_ERROR);
+    }
+
+    void setArgs(String... args) {
+        ostream.println("cmds: " + Arrays.asList(args));
+        task.args(args);
+    }
+
+    void checkOutput(String testCase, List<String> content, String toFind) throws Exception {
+        checkOutput(testCase, content, Pattern.compile(".*" + toFind + ".*"));
+    }
+
+    void checkOutput(String testCase, List<String> content, Pattern toFind) throws Exception {
+        ostream.println("---" + testCase + "---");
+        content.stream().forEach(x -> System.out.println(x));
+        for (String x : content) {
+            ostream.println(x);
+            if (toFind.matcher(x).matches()) {
                 return;
             }
         }
-        throw new Exception("run1: Expected string not found:");
+        throw new Exception(testCase + ": Expected string not found: " +  toFind);
     }
 
-    // make sure the old doclet is invoked with -Xold
-    void run2() throws Exception {
-        List<String> output = doTest(javadoc.getPath(),
-                "-Xold",
-                "-classpath", ".", // insulates us from ambient classpath
-                "-Xdoclint:none",
-                "-package",
-                new File(testSrc, thisClassName + ".java").getPath());
-
-        for (String x : output) {
-            if (Expected2.matcher(x).matches()) {
-                throw new Exception("run2: Expected string not found");
-            }
-            return;
+    public static class OldDoclet extends com.sun.javadoc.Doclet {
+        public static boolean start(com.sun.javadoc.RootDoc root) {
+            System.out.println(OLD_DOCLET_MARKER);
+            return true;
         }
     }
 
-    /**
-     * More dummy comments.
-     */
-    List<String> doTest(String... args) throws Exception {
-        List<String> output = new ArrayList<>();
-        // run javadoc in separate process to ensure doclet executed under
-        // normal user conditions w.r.t. classloader
-        Process p = new ProcessBuilder()
-                .command(args)
-                .redirectErrorStream(true)
-                .start();
-        try (BufferedReader in = new BufferedReader(new InputStreamReader(p.getInputStream()))) {
-            String line = in.readLine();
-            while (line != null) {
-                output.add(line.trim());
-                line = in.readLine();
-            }
+    public static class OldTaglet implements com.sun.tools.doclets.Taglet {
+
+        public static void register(Map map) {
+            EnsureNewOldDoclet.OldTaglet tag = new OldTaglet();
+            com.sun.tools.doclets.Taglet t = (com.sun.tools.doclets.Taglet) map.get(tag.getName());
+            System.out.println(OLD_TAGLET_MARKER);
+        }
+
+        @Override
+        public boolean inField() {
+            return true;
+        }
+
+        @Override
+        public boolean inConstructor() {
+            return true;
+        }
+
+        @Override
+        public boolean inMethod() {
+            return true;
+        }
+
+        @Override
+        public boolean inOverview() {
+            return true;
+        }
+
+        @Override
+        public boolean inPackage() {
+            return true;
+        }
+
+        @Override
+        public boolean inType() {
+            return true;
+        }
+
+        @Override
+        public boolean isInlineTag() {
+            return true;
         }
-        int rc = p.waitFor();
-        if (rc != 0)
-            throw new Exception("javadoc failed, rc:" + rc);
-        return output;
+
+        @Override
+        public String getName() {
+            return "OldTaglet";
+        }
+
+        @Override
+        public String toString(Tag tag) {
+            return getName();
+        }
+
+        @Override
+        public String toString(Tag[] tags) {
+            return getName();
+        }
+    }
+
+    public static class NewTaglet implements jdk.javadoc.doclet.taglet.Taglet {
+
+        @Override
+        public Set<Location> getAllowedLocations() {
+            return Collections.emptySet();
+        }
+
+        @Override
+        public boolean isInlineTag() {
+            return true;
+        }
+
+        @Override
+        public String getName() {
+            return "NewTaglet";
+        }
+
+        @Override
+        public String toString(DocTree tag) {
+            return tag.toString();
+        }
+
+        @Override
+        public String toString(List<? extends DocTree> tags) {
+            return tags.toString();
+        }
+
     }
 }
--- a/langtools/test/jdk/jshell/StartOptionTest.java	Tue May 03 09:48:02 2016 -0700
+++ b/langtools/test/jdk/jshell/StartOptionTest.java	Tue May 03 12:25:20 2016 -0700
@@ -22,7 +22,7 @@
  */
 
 /*
- * @test
+ * @test 8151754
  * @summary Testing start-up options.
  * @modules jdk.compiler/com.sun.tools.javac.api
  *          jdk.compiler/com.sun.tools.javac.main
@@ -34,6 +34,7 @@
  */
 
 import java.io.ByteArrayOutputStream;
+import java.io.OutputStream;
 import java.io.PrintStream;
 import java.nio.charset.StandardCharsets;
 import java.nio.file.Path;
@@ -47,6 +48,7 @@
 
 import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
 
 @Test
 public class StartOptionTest {
@@ -55,9 +57,24 @@
     private ByteArrayOutputStream err;
 
     private JShellTool getShellTool() {
-        return new JShellTool(null, new PrintStream(out), new PrintStream(err), null, null, null,
-                              null, new ReplToolTesting.MemoryPreferences(),
-                              Locale.ROOT);
+        class NoOutputAllowedStream extends OutputStream {
+            private final String label;
+            NoOutputAllowedStream(String label) {
+               this.label = label;
+            }
+            @Override
+            public void write(int b) { fail("Unexpected output to: " + label); }
+        }
+        return new JShellTool(
+                new TestingInputStream(),
+                new PrintStream(out),
+                new PrintStream(err),
+                new PrintStream(new NoOutputAllowedStream("console")),
+                new TestingInputStream(),
+                new PrintStream(new NoOutputAllowedStream("userout")),
+                new PrintStream(new NoOutputAllowedStream("usererr")),
+                new ReplToolTesting.MemoryPreferences(),
+                Locale.ROOT);
     }
 
     private String getOutput() {
@@ -133,6 +150,12 @@
     }
 
     @Test
+    public void testNegFeedbackOption() throws Exception {
+        start("", "Argument to -feedback missing. Mode required.", "-feedback");
+        start("", "Does not match any current feedback mode: blorp -- -feedback blorp", "-feedback", "blorp");
+    }
+
+    @Test
     public void testVersion() throws Exception {
         start(s -> assertTrue(s.startsWith("jshell")), null, "-version");
     }
--- a/langtools/test/jdk/jshell/ToolSimpleTest.java	Tue May 03 09:48:02 2016 -0700
+++ b/langtools/test/jdk/jshell/ToolSimpleTest.java	Tue May 03 12:25:20 2016 -0700
@@ -23,7 +23,7 @@
 
 /*
  * @test
- * @bug 8153716 8143955
+ * @bug 8153716 8143955 8151754 8150382
  * @summary Simple jshell tool tests
  * @modules jdk.compiler/com.sun.tools.javac.api
  *          jdk.compiler/com.sun.tools.javac.main
@@ -349,4 +349,39 @@
             System.setProperty("java.awt.headless", prevHeadless==null? "false" : prevHeadless);
         }
     }
+
+    public void testOptionQ() {
+        test(new String[]{"-q", "-nostartup"},
+                (a) -> assertCommand(a, "1+1", "$1 ==> 2"),
+                (a) -> assertCommand(a, "int x = 5", "")
+        );
+    }
+
+    public void testOptionQq() {
+        test(new String[]{"-qq", "-nostartup"},
+                (a) -> assertCommand(a, "1+1", "")
+        );
+    }
+
+    public void testOptionV() {
+        test(new String[]{"-v", "-nostartup"},
+                (a) -> assertCommand(a, "1+1",
+                        "$1 ==> 2\n" +
+                        "|  created scratch variable $1 : int")
+        );
+    }
+
+    public void testOptionFeedback() {
+        test(new String[]{"-feedback", "concise", "-nostartup"},
+                (a) -> assertCommand(a, "1+1", "$1 ==> 2"),
+                (a) -> assertCommand(a, "int x = 5", "")
+        );
+    }
+
+    public void testOptionR() {
+        test(new String[]{"-R-Dthe.sound=blorp", "-nostartup"},
+                (a) -> assertCommand(a, "System.getProperty(\"the.sound\")",
+                        "$1 ==> \"blorp\"")
+        );
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/UnreachableLoopCond.java	Tue May 03 12:25:20 2016 -0700
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8155028
+ * @summary javac crashes in silly do-while loop
+ * @compile UnreachableLoopCond.java
+ */
+
+class UnreachableLoopCond {
+
+    public void foo() {
+        Integer i = 100;
+        do {
+            return;
+        } while (i++ < 10);
+    }
+
+    public void goo() {
+        Integer i = 100;
+        do {
+            break;
+        } while (i++ < 10);
+    }
+
+    public void zoo() {
+        Integer i = 100;
+        do {
+            throw new RuntimeException();
+        } while (i++ < 10);
+    }
+
+    public void loo() {
+        Integer i = 100;
+        Integer j = 100;
+        do {
+           do {
+               return;
+           } while (i++ < 10);
+        } while (j++ < 10);
+    }
+
+    public void moo() {
+        Integer i = 100;
+        do {
+            if (true) {
+                return;
+            } else {
+                return;
+            }
+        } while (i++ < 10);
+    }
+
+    public void moo(boolean cond) {
+        Integer i = 100;
+        do {
+            if (cond) {
+                return;
+            } else {
+                return;
+            }
+        } while (i++ < 10);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/annotations/T8154270/EraseClassInfoAnnotationValueTest.java	Tue May 03 12:25:20 2016 -0700
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2016 Google 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Arrays;
+
+/*
+ * @test
+ * @bug 8154270
+ * @summary javac wrongly rejects some class literals as annotation element values
+ * @compile EraseClassInfoAnnotationValueTest.java
+ * @compile -implicit:none Other.java
+ * @run main EraseClassInfoAnnotationValueTest
+ */
+public class EraseClassInfoAnnotationValueTest {
+
+  @Retention(RetentionPolicy.RUNTIME)
+  public @interface A {
+    Class<?> value();
+  }
+
+  static class ParametricType<T> {
+
+    @A(Inner.class)
+    public static class Nested {}
+
+    public class Inner {}
+  }
+
+  public static void main(String[] args) {
+    Class<?> clazz = ParametricType.Nested.class.getAnnotation(A.class).value();
+    if (!clazz.equals(ParametricType.Inner.class)) {
+      throw new AssertionError(clazz);
+    }
+  }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/annotations/T8154270/Other.java	Tue May 03 12:25:20 2016 -0700
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2016 Google 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * Tests separate compilation.
+ */
+public class Other {
+  Class<?> clazz = EraseClassInfoAnnotationValueTest.ParametricType.Nested.class;
+}
--- a/langtools/test/tools/javac/classfiles/attributes/LineNumberTable/LineNumberTestBase.java	Tue May 03 09:48:02 2016 -0700
+++ b/langtools/test/tools/javac/classfiles/attributes/LineNumberTable/LineNumberTestBase.java	Tue May 03 12:25:20 2016 -0700
@@ -191,7 +191,7 @@
         CONDITION("int res = \n" +
                 "testField == 2 ?\n" +
                 "10\n" +
-                ":9;", 1, 3, 4), // see issue https://bugs.openjdk.java.net/browse/JDK-8050993
+                ":9;", 2, 3, 4),
         TRY("try{\n" +
                 "    --testField;\n" +
                 "}\n" +
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/classfiles/attributes/LineNumberTable/T8050993.java	Tue May 03 12:25:20 2016 -0700
@@ -0,0 +1,53 @@
+/*
+ * @test /nodynamiccopyright/
+ * @bug 8050993
+ * @summary Verify that the condition in the conditional lexpression gets a LineNumberTable entry
+ * @modules jdk.jdeps/com.sun.tools.classfile
+ * @compile -g T8050993.java
+ * @run main T8050993
+ */
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Objects;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import com.sun.tools.classfile.*;
+
+public class T8050993 {
+    public static void main(String[] args) throws IOException, ConstantPoolException {
+        ClassFile someTestIn = ClassFile.read(T8050993.class.getResourceAsStream("T8050993.class"));
+        Set<Integer> expectedLineNumbers = new HashSet<>(Arrays.asList(49, 50, 47, 48));
+        for (Method m : someTestIn.methods) {
+            if ("method".equals(m.getName(someTestIn.constant_pool))) {
+                Code_attribute code_attribute = (Code_attribute) m.attributes.get(Attribute.Code);
+                for (Attribute at : code_attribute.attributes) {
+                    if (Attribute.LineNumberTable.equals(at.getName(someTestIn.constant_pool))) {
+                        LineNumberTable_attribute att = (LineNumberTable_attribute) at;
+                        Set<Integer> actualLinesNumbers = Arrays.stream(att.line_number_table)
+                                                                .map(e -> e.line_number)
+                                                                .collect(Collectors.toSet());
+                        if (!Objects.equals(expectedLineNumbers, actualLinesNumbers)) {
+                            throw new AssertionError("Expected LineNumber entries not found;" +
+                                                     "actual=" + actualLinesNumbers + ";" +
+                                                     "expected=" + expectedLineNumbers);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    public static int field;
+
+    public static String method() {
+        String s =
+                field % 2 == 0 ?
+                "true" + field :
+                "false" + field;
+        return s;
+    }
+
+}
--- a/langtools/test/tools/javac/modules/AbstractOrInnerClassServiceImplTest.java	Tue May 03 09:48:02 2016 -0700
+++ b/langtools/test/tools/javac/modules/AbstractOrInnerClassServiceImplTest.java	Tue May 03 12:25:20 2016 -0700
@@ -47,7 +47,7 @@
     }
 
     @Test
-    void testAbstractServiceImpl(Path base) throws Exception {
+    public void testAbstractServiceImpl(Path base) throws Exception {
         Path src = base.resolve("src");
         tb.writeJavaFiles(src,
                 "module m { provides p1.Service with p2.Impl; }",
@@ -68,7 +68,7 @@
     }
 
     @Test
-    void testInnerClassServiceImpl(Path base) throws Exception {
+    public void testInnerClassServiceImpl(Path base) throws Exception {
         Path src = base.resolve("src");
         tb.writeJavaFiles(src,
                 "module m { provides p1.Service with p2.Outer.Inner; }",
@@ -89,7 +89,7 @@
     }
 
     @Test
-    void testInnerInterfaceServiceImpl(Path base) throws Exception {
+    public void testInnerInterfaceServiceImpl(Path base) throws Exception {
         Path src = base.resolve("src");
         tb.writeJavaFiles(src,
                 "module m { provides p1.Service with p2.Outer.Inner; }",
--- a/langtools/test/tools/javac/modules/AddLimitMods.java	Tue May 03 09:48:02 2016 -0700
+++ b/langtools/test/tools/javac/modules/AddLimitMods.java	Tue May 03 12:25:20 2016 -0700
@@ -79,7 +79,7 @@
     }
 
     @Test
-    void testManual(Path base) throws Exception {
+    public void testManual(Path base) throws Exception {
         Path moduleSrc = base.resolve("module-src");
         Path m1 = moduleSrc.resolve("m1");
 
@@ -176,7 +176,7 @@
     }
 
     @Test
-    void testAllModulePath(Path base) throws Exception {
+    public void testAllModulePath(Path base) throws Exception {
         if (Files.isDirectory(base))
             tb.cleanDirectory(base);
 
@@ -284,7 +284,7 @@
     }
 
     @Test
-    void testRuntime2Compile(Path base) throws Exception {
+    public void testRuntime2Compile(Path base) throws Exception {
         Path classpathSrc = base.resolve("classpath-src");
         Path classpathOut = base.resolve("classpath-out");
 
--- a/langtools/test/tools/javac/modules/AddReadsTest.java	Tue May 03 09:48:02 2016 -0700
+++ b/langtools/test/tools/javac/modules/AddReadsTest.java	Tue May 03 12:25:20 2016 -0700
@@ -58,7 +58,7 @@
     }
 
     @Test
-    void testAddReads(Path base) throws Exception {
+    public void testAddReads(Path base) throws Exception {
         Path src = base.resolve("src");
         Path src_m1 = src.resolve("m1");
         tb.writeJavaFiles(src_m1,
@@ -150,7 +150,7 @@
     }
 
     @Test
-    void testAddReadsUnnamedModule(Path base) throws Exception {
+    public void testAddReadsUnnamedModule(Path base) throws Exception {
         Path jar = prepareTestJar(base);
 
         Path moduleSrc = base.resolve("module-src");
@@ -175,7 +175,7 @@
     }
 
     @Test
-    void testAddReadsUnnamedModulePackageConflict(Path base) throws Exception {
+    public void testAddReadsUnnamedModulePackageConflict(Path base) throws Exception {
         Path jar = prepareTestJar(base);
 
         Path moduleSrc = base.resolve("module-src");
@@ -202,7 +202,7 @@
     }
 
     @Test
-    void testAddReadsUnnamedToJavaBase(Path base) throws Exception {
+    public void testAddReadsUnnamedToJavaBase(Path base) throws Exception {
         Path jar = prepareTestJar(base);
         Path src = base.resolve("src");
         Path classes = base.resolve("classes");
@@ -223,7 +223,7 @@
     }
 
     @Test
-    void testAddReadsToJavaBase(Path base) throws Exception {
+    public void testAddReadsToJavaBase(Path base) throws Exception {
         Path src = base.resolve("src");
         Path classes = base.resolve("classes");
 
@@ -275,7 +275,7 @@
     }
 
     @Test
-    void testX(Path base) throws Exception {
+    public void testX(Path base) throws Exception {
         Path src = base.resolve("src");
         Path src_m1 = src.resolve("m1");
         tb.writeJavaFiles(src_m1,
--- a/langtools/test/tools/javac/modules/AnnotationProcessing.java	Tue May 03 09:48:02 2016 -0700
+++ b/langtools/test/tools/javac/modules/AnnotationProcessing.java	Tue May 03 12:25:20 2016 -0700
@@ -68,7 +68,7 @@
     }
 
     @Test
-    void testAPSingleModule(Path base) throws Exception {
+    public void testAPSingleModule(Path base) throws Exception {
         Path moduleSrc = base.resolve("module-src");
         Path m1 = moduleSrc.resolve("m1");
 
@@ -95,7 +95,7 @@
     }
 
     @Test
-    void testAPMultiModule(Path base) throws Exception {
+    public void testAPMultiModule(Path base) throws Exception {
         Path moduleSrc = base.resolve("module-src");
         Path m1 = moduleSrc.resolve("m1");
         Path m2 = moduleSrc.resolve("m2");
@@ -196,7 +196,7 @@
     }
 
     @Test
-    void testVerifyUsesProvides(Path base) throws Exception {
+    public void testVerifyUsesProvides(Path base) throws Exception {
         Path moduleSrc = base.resolve("module-src");
         Path m1 = moduleSrc.resolve("m1");
 
@@ -254,7 +254,7 @@
     }
 
     @Test
-    void testPackageNoModule(Path base) throws Exception {
+    public void testPackageNoModule(Path base) throws Exception {
         Path src = base.resolve("src");
         Path classes = base.resolve("classes");
 
--- a/langtools/test/tools/javac/modules/AnnotationProcessorsInModulesTest.java	Tue May 03 09:48:02 2016 -0700
+++ b/langtools/test/tools/javac/modules/AnnotationProcessorsInModulesTest.java	Tue May 03 12:25:20 2016 -0700
@@ -156,7 +156,7 @@
     Path classes;
 
     @Test
-    void testUseOnlyOneProcessor(Path base) throws Exception {
+    public void testUseOnlyOneProcessor(Path base) throws Exception {
         initialization(base);
         String log = new JavacTask(tb)
                 .options("-processormodulepath", processorCompiledModules.toString(),
@@ -172,7 +172,7 @@
     }
 
     @Test
-    void testAnnotationProcessorExecutionOrder(Path base) throws Exception {
+    public void testAnnotationProcessorExecutionOrder(Path base) throws Exception {
         initialization(base);
         List<String> log = new JavacTask(tb)
                 .options("-processormodulepath", processorCompiledModules.toString(),
@@ -202,7 +202,7 @@
     }
 
     @Test
-    void testErrorOutputIfOneProcessorNameIsIncorrect(Path base) throws Exception {
+    public void testErrorOutputIfOneProcessorNameIsIncorrect(Path base) throws Exception {
         initialization(base);
         String log = new JavacTask(tb)
                 .options("-XDrawDiagnostics", "-processormodulepath", processorCompiledModules.toString(),
@@ -218,7 +218,7 @@
     }
 
     @Test
-    void testOptionsExclusion(Path base) throws Exception {
+    public void testOptionsExclusion(Path base) throws Exception {
         initialization(base);
         List<String> log = new JavacTask(tb)
                 .options("-XDrawDiagnostics", "-processormodulepath", processorCompiledModules.toString(),
--- a/langtools/test/tools/javac/modules/AutomaticModules.java	Tue May 03 09:48:02 2016 -0700
+++ b/langtools/test/tools/javac/modules/AutomaticModules.java	Tue May 03 12:25:20 2016 -0700
@@ -48,7 +48,7 @@
     }
 
     @Test
-    void testSimple(Path base) throws Exception {
+    public void testSimple(Path base) throws Exception {
         Path legacySrc = base.resolve("legacy-src");
         tb.writeJavaFiles(legacySrc,
                           "package api; import java.awt.event.ActionListener; public abstract class Api implements ActionListener {}");
@@ -98,7 +98,7 @@
     }
 
     @Test
-    void testUnnamedModule(Path base) throws Exception {
+    public void testUnnamedModule(Path base) throws Exception {
         Path legacySrc = base.resolve("legacy-src");
         tb.writeJavaFiles(legacySrc,
                           "package api; public abstract class Api { public void run(CharSequence str) { } private void run(base.Base base) { } }",
@@ -156,7 +156,7 @@
     }
 
     @Test
-    void testModuleInfoFromClassFileDependsOnAutomatic(Path base) throws Exception {
+    public void testModuleInfoFromClassFileDependsOnAutomatic(Path base) throws Exception {
         Path automaticSrc = base.resolve("automaticSrc");
         tb.writeJavaFiles(automaticSrc, "package api; public class Api {}");
         Path automaticClasses = base.resolve("automaticClasses");
--- a/langtools/test/tools/javac/modules/DoclintOtherModules.java	Tue May 03 09:48:02 2016 -0700
+++ b/langtools/test/tools/javac/modules/DoclintOtherModules.java	Tue May 03 12:25:20 2016 -0700
@@ -47,7 +47,7 @@
     }
 
     @Test
-    void testSimple(Path base) throws Exception {
+    public void testSimple(Path base) throws Exception {
         Path src = base.resolve("src");
         Path m1 = src.resolve("m1");
         Path m2 = src.resolve("m2");
--- a/langtools/test/tools/javac/modules/DuplicateClassTest.java	Tue May 03 09:48:02 2016 -0700
+++ b/langtools/test/tools/javac/modules/DuplicateClassTest.java	Tue May 03 12:25:20 2016 -0700
@@ -47,7 +47,7 @@
     }
 
     @Test
-    void testSimple(Path base) throws Exception {
+    public void testSimple(Path base) throws Exception {
         Path m1 = base.resolve("m1");
         Path m2 = base.resolve("m2");
         tb.writeJavaFiles(m1,
--- a/langtools/test/tools/javac/modules/EdgeCases.java	Tue May 03 09:48:02 2016 -0700
+++ b/langtools/test/tools/javac/modules/EdgeCases.java	Tue May 03 12:25:20 2016 -0700
@@ -23,6 +23,7 @@
 
 /*
  * @test
+ * @bug 8154283
  * @summary tests for multi-module mode compilation
  * @library /tools/lib
  * @modules
@@ -57,7 +58,6 @@
 import toolbox.JarTask;
 import toolbox.JavacTask;
 import toolbox.Task;
-import toolbox.ToolBox;
 
 public class EdgeCases extends ModuleTestBase {
 
@@ -66,7 +66,7 @@
     }
 
     @Test
-    void testAddExportUndefinedModule(Path base) throws Exception {
+    public void testAddExportUndefinedModule(Path base) throws Exception {
         Path src = base.resolve("src");
         tb.writeJavaFiles(src, "package test; import undef.Any; public class Test {}");
         Path classes = base.resolve("classes");
@@ -89,7 +89,7 @@
     }
 
     @Test
-    void testModuleSymbolOutterMostClass(Path base) throws Exception {
+    public void testModuleSymbolOutterMostClass(Path base) throws Exception {
         JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
         try (StandardJavaFileManager fm = compiler.getStandardFileManager(null, null, null)) {
             Path moduleSrc = base.resolve("module-src");
@@ -110,7 +110,7 @@
     }
 
     @Test
-    void testParseEnterAnalyze(Path base) throws Exception {
+    public void testParseEnterAnalyze(Path base) throws Exception {
         JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
         try (StandardJavaFileManager fm = compiler.getStandardFileManager(null, null, null)) {
             Path moduleSrc = base.resolve("module-src");
@@ -148,7 +148,7 @@
     }
 
     @Test
-    void testModuleImplicitModuleBoundaries(Path base) throws Exception {
+    public void testModuleImplicitModuleBoundaries(Path base) throws Exception {
         Path src = base.resolve("src");
         Path src_m1 = src.resolve("m1");
         tb.writeJavaFiles(src_m1,
@@ -180,7 +180,7 @@
     }
 
     @Test
-    void testAssignClassToAutomaticModule(Path base) throws Exception {
+    public void testAssignClassToAutomaticModule(Path base) throws Exception {
         //check that if a ClassSymbol belongs to an automatic module, it is properly assigned and not
         //duplicated when being accessed through a classfile.
         Path automaticSrc = base.resolve("automaticSrc");
@@ -239,7 +239,7 @@
     }
 
     @Test
-    void testEmptyImplicitModuleInfo(Path base) throws Exception {
+    public void testEmptyImplicitModuleInfo(Path base) throws Exception {
         Path src = base.resolve("src");
         Path src_m1 = src.resolve("m1");
         Files.createDirectories(src_m1);
@@ -269,4 +269,39 @@
 
     }
 
+    @Test
+    public void testClassPackageClash(Path base) throws Exception {
+        Path src = base.resolve("src");
+        Path src_m1 = src.resolve("m1");
+        tb.writeJavaFiles(src_m1,
+                          "module m1 { exports test.m1; }",
+                          "package test.m1;\n" +
+                          "public class Test {}\n");
+        Path src_m2 = src.resolve("m2");
+        tb.writeJavaFiles(src_m2,
+                          "module m2 { requires m1; }",
+                          "package test;\n" +
+                          "public class m1 {}\n");
+        Path classes = base.resolve("classes");
+        tb.createDirectories(classes);
+
+        List<String> log = new JavacTask(tb)
+                .options("-modulesourcepath", src.toString(),
+                         "-XDrawDiagnostics")
+                .outdir(classes)
+                .files(findJavaFiles(src))
+                .run(Task.Expect.FAIL)
+                .writeAll()
+                .getOutputLines(Task.OutputKind.DIRECT);
+
+        List<String> expected = Arrays.asList(
+            "m1.java:2:8: compiler.err.clash.with.pkg.of.same.name: kindname.class, test.m1",
+            "1 error"
+        );
+
+        if (!expected.equals(log)) {
+            throw new IllegalStateException(log.toString());
+        }
+    }
+
 }
--- a/langtools/test/tools/javac/modules/GraphsTest.java	Tue May 03 09:48:02 2016 -0700
+++ b/langtools/test/tools/javac/modules/GraphsTest.java	Tue May 03 12:25:20 2016 -0700
@@ -28,7 +28,8 @@
  * @modules
  *      jdk.compiler/com.sun.tools.javac.api
  *      jdk.compiler/com.sun.tools.javac.main
- * @build toolbox.ToolBox toolbox.JarTask toolbox.JavacTask ModuleTestBase
+ * @build toolbox.ToolBox toolbox.JarTask toolbox.JavacTask toolbox.ModuleBuilder
+ *      ModuleTestBase
  * @run main GraphsTest
  */
 
@@ -41,6 +42,7 @@
 
 import toolbox.JarTask;
 import toolbox.JavacTask;
+import toolbox.ModuleBuilder;
 import toolbox.Task;
 import toolbox.ToolBox;
 
@@ -69,11 +71,11 @@
      *
      */
     @Test
-    void diamond(Path base) throws Exception {
+    public void diamond(Path base) throws Exception {
 
         Path modules = Files.createDirectories(base.resolve("modules"));
 
-        new ModuleBuilder("J")
+        new ModuleBuilder(tb, "J")
                 .exports("openJ")
                 .classes("package openJ; public class J { }")
                 .classes("package closedJ; public class J { }")
@@ -87,25 +89,25 @@
                 .run()
                 .writeAll();
 
-        new ModuleBuilder("O")
+        new ModuleBuilder(tb, "O")
                 .exports("openO")
                 .requiresPublic("J", jarModules)
                 .classes("package openO; public class O { openJ.J j; }")
                 .classes("package closedO; public class O { }")
                 .build(modules);
-        new ModuleBuilder("N")
+        new ModuleBuilder(tb, "N")
                 .requiresPublic("O", modules, jarModules)
                 .exports("openN")
                 .classes("package openN; public class N { }")
                 .classes("package closedN; public class N { }")
                 .build(modules);
-        new ModuleBuilder("L")
+        new ModuleBuilder(tb, "L")
                 .requiresPublic("O", modules, jarModules)
                 .exports("openL")
                 .classes("package openL; public class L { }")
                 .classes("package closedL; public class L { }")
                 .build(modules);
-        ModuleBuilder m = new ModuleBuilder("M");
+        ModuleBuilder m = new ModuleBuilder(tb, "M");
         //positive case
         Path positiveSrc = m
                 .requires("N", modules)
@@ -178,14 +180,14 @@
     @Test
     public void reexportOfQualifiedExport(Path base) throws Exception {
         Path modules = base.resolve("modules");
-        new ModuleBuilder("M")
+        new ModuleBuilder(tb, "M")
                 .requiresPublic("N")
                 .write(modules);
-        new ModuleBuilder("N")
+        new ModuleBuilder(tb, "N")
                 .exportsTo("pack", "M")
                 .classes("package pack; public class Clazz { }")
                 .write(modules);
-        new ModuleBuilder("L")
+        new ModuleBuilder(tb, "L")
                 .requires("M")
                 .classes("package p; public class A { A(pack.Clazz cl){} } ")
                 .write(modules);
--- a/langtools/test/tools/javac/modules/HelloWorldTest.java	Tue May 03 09:48:02 2016 -0700
+++ b/langtools/test/tools/javac/modules/HelloWorldTest.java	Tue May 03 12:25:20 2016 -0700
@@ -58,7 +58,7 @@
         + HELLO_WORLD;
 
     @Test
-    void testLegacyMode(Path base) throws Exception {
+    public void testLegacyMode(Path base) throws Exception {
         Path src = base.resolve("src");
         tb.writeJavaFiles(src, HELLO_WORLD);
 
@@ -85,7 +85,7 @@
     }
 
     @Test
-    void testUnnamedModule(Path base) throws Exception {
+    public void testUnnamedModule(Path base) throws Exception {
         Path src = base.resolve("src");
         tb.writeJavaFiles(src, HELLO_WORLD);
 
@@ -101,7 +101,7 @@
     }
 
     @Test
-    void testSingleModule(Path base) throws Exception {
+    public void testSingleModule(Path base) throws Exception {
         Path src = base.resolve("src");
         tb.writeFile(src.resolve("module-info.java"), "module m { }");
         tb.writeJavaFiles(src, PKG_HELLO_WORLD);
@@ -121,7 +121,7 @@
     }
 
     @Test
-    void testModuleSourcePath(Path base) throws Exception {
+    public void testModuleSourcePath(Path base) throws Exception {
         Path src = base.resolve("src");
         Path src_m1 = src.resolve("m1");
         tb.writeFile(src_m1.resolve("module-info.java"), "module m1 { }");
--- a/langtools/test/tools/javac/modules/MOptionTest.java	Tue May 03 09:48:02 2016 -0700
+++ b/langtools/test/tools/javac/modules/MOptionTest.java	Tue May 03 12:25:20 2016 -0700
@@ -47,7 +47,7 @@
     }
 
     @Test
-    void testOneModule(Path base) throws Exception {
+    public void testOneModule(Path base) throws Exception {
         Path src = base.resolve("src");
         Path m1 = src.resolve("m1");
         Path build = base.resolve("build");
@@ -112,7 +112,7 @@
     }
 
     @Test
-    void testNoOutputDir(Path base) throws Exception {
+    public void testNoOutputDir(Path base) throws Exception {
         Path src = base.resolve("src");
         Path m1 = src.resolve("m1");
         Path build = base.resolve("build");
@@ -135,7 +135,7 @@
     }
 
     @Test
-    void testNoModuleSourcePath(Path base) throws Exception {
+    public void testNoModuleSourcePath(Path base) throws Exception {
         Path src = base.resolve("src");
         Path m1 = src.resolve("m1");
         Path build = base.resolve("build");
@@ -158,7 +158,7 @@
     }
 
     @Test
-    void testMultiModule(Path base) throws Exception {
+    public void testMultiModule(Path base) throws Exception {
         Path src = base.resolve("src");
         Path m1 = src.resolve("m1");
         Path m2 = src.resolve("m2");
--- a/langtools/test/tools/javac/modules/ModuleFinderTest.java	Tue May 03 09:48:02 2016 -0700
+++ b/langtools/test/tools/javac/modules/ModuleFinderTest.java	Tue May 03 12:25:20 2016 -0700
@@ -48,7 +48,7 @@
     }
 
     @Test
-    void testDuplicateModulesOnPath(Path base) throws Exception {
+    public void testDuplicateModulesOnPath(Path base) throws Exception {
         Path src = base.resolve("src");
         tb.writeJavaFiles(src, "module m1 { }");
 
--- a/langtools/test/tools/javac/modules/ModuleInfoTest.java	Tue May 03 09:48:02 2016 -0700
+++ b/langtools/test/tools/javac/modules/ModuleInfoTest.java	Tue May 03 12:25:20 2016 -0700
@@ -51,7 +51,7 @@
      * Check error message if module declaration not in module-info.java.
      */
     @Test
-    void testModuleDeclNotInModuleJava(Path base) throws Exception {
+    public void testModuleDeclNotInModuleJava(Path base) throws Exception {
         Path src = base.resolve("src");
         tb.writeFile(src.resolve("M.java"), "module M { }");
         String log = new JavacTask(tb)
@@ -69,7 +69,7 @@
      * Verify that a package private class can be put in module-info.java.
      */
     @Test
-    void testNotModuleDeclInModuleJava_1(Path base) throws Exception {
+    public void testNotModuleDeclInModuleJava_1(Path base) throws Exception {
         Path src = base.resolve("src");
         tb.writeFile(src.resolve("module-info.java"), "class C { }");
         new JavacTask(tb)
@@ -83,7 +83,7 @@
      * Verify that a public class cannot be put in module-info.java.
      */
     @Test
-    void testNotModuleDeclInModuleJava_2(Path base) throws Exception {
+    public void testNotModuleDeclInModuleJava_2(Path base) throws Exception {
         Path src = base.resolve("src");
         tb.writeFile(src.resolve("module-info.java"), "public class C { }");
         String log = new JavacTask(tb)
@@ -101,7 +101,7 @@
      * Verify that only one module decl can be put in module-info.java.
      */
     @Test
-    void testSingleModuleDecl(Path base) throws Exception {
+    public void testSingleModuleDecl(Path base) throws Exception {
         Path src = base.resolve("src");
         tb.writeJavaFiles(src, "module M1 { } /*...*/ module M2 { }");
         String log = new JavacTask(tb)
@@ -119,7 +119,7 @@
      * Verify that missing requires are reported.
      */
     @Test
-    void testRequiresNotFound(Path base) throws Exception {
+    public void testRequiresNotFound(Path base) throws Exception {
         Path src = base.resolve("src");
         tb.writeJavaFiles(src, "module M1 { requires M2; }");
         String log = new JavacTask(tb)
@@ -137,7 +137,7 @@
      * Verify that missing exports are reported.
      */
     @Test
-    void testExportsNotFound(Path base) throws Exception {
+    public void testExportsNotFound(Path base) throws Exception {
         Path src = base.resolve("src");
         tb.writeJavaFiles(src, "module M1 { exports p to M2; }");
         String log = new JavacTask(tb)
@@ -155,7 +155,7 @@
      * Verify that a simple loop is detected.
      */
     @Test
-    void testRequiresSelf(Path base) throws Exception {
+    public void testRequiresSelf(Path base) throws Exception {
         Path src = base.resolve("src");
         tb.writeJavaFiles(src, "module M { requires M; }");
         String log = new JavacTask(tb)
@@ -173,7 +173,7 @@
      * Verify that a multi-module loop is detected.
      */
     @Test
-    void testRequiresLoop(Path base) throws Exception {
+    public void testRequiresLoop(Path base) throws Exception {
         Path src = base.resolve("src");
         Path src_m1 = src.resolve("m1");
         tb.writeFile(src_m1.resolve("module-info.java"), "module m1 { requires m2; }");
@@ -201,7 +201,7 @@
      * Verify that a multi-module loop is detected.
      */
     @Test
-    void testRequiresPublicLoop(Path base) throws Exception {
+    public void testRequiresPublicLoop(Path base) throws Exception {
         Path src = base.resolve("src");
         Path src_m1 = src.resolve("m1");
         tb.writeFile(src_m1.resolve("module-info.java"), "module m1 { requires m2; }");
@@ -229,7 +229,7 @@
      * Verify that duplicate requires are detected.
      */
     @Test
-    void testDuplicateRequires(Path base) throws Exception {
+    public void testDuplicateRequires(Path base) throws Exception {
         Path src = base.resolve("src");
         Path src_m1 = src.resolve("m1");
         tb.writeFile(src_m1.resolve("module-info.java"), "module m1 { }");
@@ -255,7 +255,7 @@
      * Verify that duplicate exported packages are detected.
      */
     @Test
-    void testDuplicateExports_packages(Path base) throws Exception {
+    public void testDuplicateExports_packages(Path base) throws Exception {
         Path src = base.resolve("src");
         tb.writeJavaFiles(src, "module m1 { exports p; exports p; }");
 
@@ -278,7 +278,7 @@
      * Verify that duplicate exported packages are detected.
      */
     @Test
-    void testDuplicateExports_packages2(Path base) throws Exception {
+    public void testDuplicateExports_packages2(Path base) throws Exception {
         Path src = base.resolve("src");
         tb.writeJavaFiles(src.resolve("m1"), "module m1 { exports p; exports p to m2; }");
         tb.writeJavaFiles(src.resolve("m2"), "module m2 { }");
@@ -302,7 +302,7 @@
      * Verify that duplicate exported packages are detected.
      */
     @Test
-    void testDuplicateExports_modules(Path base) throws Exception {
+    public void testDuplicateExports_modules(Path base) throws Exception {
         Path src = base.resolve("src");
         Path src_m1 = src.resolve("m1");
         tb.writeFile(src_m1.resolve("module-info.java"), "module m1 { }");
--- a/langtools/test/tools/javac/modules/ModuleInfoTreeAccess.java	Tue May 03 09:48:02 2016 -0700
+++ b/langtools/test/tools/javac/modules/ModuleInfoTreeAccess.java	Tue May 03 12:25:20 2016 -0700
@@ -61,7 +61,7 @@
     }
 
     @Test
-    void testTreePathForModuleDecl(Path base) throws Exception {
+    public void testTreePathForModuleDecl(Path base) throws Exception {
 
         JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
         try (StandardJavaFileManager fm = compiler.getStandardFileManager(null, null, null)) {
--- a/langtools/test/tools/javac/modules/ModulePathTest.java	Tue May 03 09:48:02 2016 -0700
+++ b/langtools/test/tools/javac/modules/ModulePathTest.java	Tue May 03 12:25:20 2016 -0700
@@ -30,7 +30,8 @@
  *      jdk.compiler/com.sun.tools.javac.main
  *      jdk.jdeps/com.sun.tools.javap
  *      jdk.jlink/jdk.tools.jmod
- * @build toolbox.ToolBox toolbox.JarTask toolbox.JavacTask ModuleTestBase
+ * @build toolbox.ToolBox toolbox.JarTask toolbox.JavacTask toolbox.ModuleBuilder
+ *      ModuleTestBase
  * @run main ModulePathTest
  */
 
@@ -41,6 +42,7 @@
 
 import toolbox.JarTask;
 import toolbox.JavacTask;
+import toolbox.ModuleBuilder;
 import toolbox.Task;
 import toolbox.ToolBox;
 
@@ -54,7 +56,7 @@
     }
 
     @Test
-    void testNotExistsOnPath(Path base) throws Exception {
+    public void testNotExistsOnPath(Path base) throws Exception {
         Path src = base.resolve("src");
         tb.writeJavaFiles(src, "class C { }");
 
@@ -71,7 +73,7 @@
     }
 
     @Test
-    void testNotADirOnPath_1(Path base) throws Exception {
+    public void testNotADirOnPath_1(Path base) throws Exception {
         Path src = base.resolve("src");
         tb.writeJavaFiles(src, "class C { }");
         tb.writeFile("dummy.txt", "");
@@ -89,7 +91,7 @@
     }
 
     @Test
-    void testNotADirOnPath_2(Path base) throws Exception {
+    public void testNotADirOnPath_2(Path base) throws Exception {
         Path src = base.resolve("src");
         tb.writeJavaFiles(src, "class C { }");
         tb.writeFile("dummy.jimage", "");
@@ -107,7 +109,7 @@
     }
 
     @Test
-    void testExplodedModuleOnPath(Path base) throws Exception {
+    public void testExplodedModuleOnPath(Path base) throws Exception {
         Path modSrc = base.resolve("modSrc");
         tb.writeJavaFiles(modSrc,
                 "module m1 { exports p; }",
@@ -137,7 +139,7 @@
     }
 
     @Test
-    void testBadExplodedModuleOnPath(Path base) throws Exception {
+    public void testBadExplodedModuleOnPath(Path base) throws Exception {
         Path modClasses = base.resolve("modClasses");
         tb.writeFile(modClasses.resolve("module-info.class"), "module m1 { }");
 
@@ -162,7 +164,7 @@
     }
 
     @Test
-    void testAutoJarOnPath(Path base) throws Exception {
+    public void testAutoJarOnPath(Path base) throws Exception {
         Path jarSrc = base.resolve("jarSrc");
         tb.writeJavaFiles(jarSrc,
                 "package p; public class CC { }");
@@ -195,7 +197,7 @@
     }
 
     @Test
-    void testModJarOnPath(Path base) throws Exception {
+    public void testModJarOnPath(Path base) throws Exception {
         Path jarSrc = base.resolve("jarSrc");
         tb.writeJavaFiles(jarSrc,
                 "module m1 { exports p; }",
@@ -231,7 +233,7 @@
     }
 
     @Test
-    void testBadJarOnPath(Path base) throws Exception {
+    public void testBadJarOnPath(Path base) throws Exception {
         Path src = base.resolve("src");
         tb.writeJavaFiles(src, "class C { }");
         tb.writeFile("dummy.jar", "");
@@ -249,7 +251,7 @@
     }
 
     @Test
-    void testJModOnPath(Path base) throws Exception {
+    public void testJModOnPath(Path base) throws Exception {
         Path jmodSrc = base.resolve("jmodSrc");
         tb.writeJavaFiles(jmodSrc,
                 "module m1 { exports p; }",
@@ -282,7 +284,7 @@
     }
 
     @Test
-    void testBadJModOnPath(Path base) throws Exception {
+    public void testBadJModOnPath(Path base) throws Exception {
         Path src = base.resolve("src");
         tb.writeJavaFiles(src, "class C { }");
         tb.writeFile("dummy.jmod", "");
@@ -300,9 +302,9 @@
     }
 
     @Test
-    void relativePath(Path base) throws Exception {
+    public void relativePath(Path base) throws Exception {
         final Path modules = base.resolve("modules");
-        new ModuleBuilder("m1").build(modules);
+        new ModuleBuilder(tb, "m1").build(modules);
 
         Path src = base.resolve("src");
         tb.writeJavaFiles(src, "module m2 { requires m1; }", "class A { }");
@@ -316,9 +318,9 @@
     }
 
     @Test
-    void duplicatePaths_1(Path base) throws Exception {
+    public void duplicatePaths_1(Path base) throws Exception {
         final Path modules = base.resolve("modules");
-        new ModuleBuilder("m1").build(modules);
+        new ModuleBuilder(tb, "m1").build(modules);
 
         Path src = base.resolve("src");
         tb.writeJavaFiles(src, "module m2 { requires m1; }", "class A { }");
@@ -332,9 +334,9 @@
     }
 
     @Test
-    void duplicatePaths_2(Path base) throws Exception {
+    public void duplicatePaths_2(Path base) throws Exception {
         final Path modules = base.resolve("modules");
-        new ModuleBuilder("m1").build(modules);
+        new ModuleBuilder(tb, "m1").build(modules);
 
         Path src = base.resolve("src");
         tb.writeJavaFiles(src, "module m2 { requires m1; }", "class A { }");
@@ -349,15 +351,15 @@
     }
 
     @Test
-    void oneModuleHidesAnother(Path base) throws Exception {
+    public void oneModuleHidesAnother(Path base) throws Exception {
         final Path module = base.resolve("modules");
-        new ModuleBuilder("m1")
+        new ModuleBuilder(tb, "m1")
                 .exports("pkg1")
                 .classes("package pkg1; public class E { }")
                 .build(module);
 
         final Path deepModuleDir = module.resolve("deepModuleDir");
-        new ModuleBuilder("m1")
+        new ModuleBuilder(tb, "m1")
                 .exports("pkg2")
                 .classes("package pkg2; public class E { }")
                 .build(deepModuleDir);
@@ -374,19 +376,19 @@
     }
 
     @Test
-    void modulesInDifferentContainers(Path base) throws Exception {
+    public void modulesInDifferentContainers(Path base) throws Exception {
         final Path modules = base.resolve("modules");
-        new ModuleBuilder("m1")
+        new ModuleBuilder(tb, "m1")
                 .exports("one")
                 .classes("package one; public class A { }")
                 .build(modules);
 
-        new ModuleBuilder("m2")
+        new ModuleBuilder(tb, "m2")
                 .requires("m1", modules)
                 .build(base.resolve("tmp"));
         jar(base.resolve("tmp/m2"), modules.resolve("m2.jar"));
 
-        new ModuleBuilder("m3")
+        new ModuleBuilder(tb, "m3")
                 .requires("m2", modules)
                 .build(base.resolve("tmp"));
         jmod(base.resolve("tmp/m3"), modules.resolve("m3.jmod"));
--- a/langtools/test/tools/javac/modules/ModuleSourcePathTest.java	Tue May 03 09:48:02 2016 -0700
+++ b/langtools/test/tools/javac/modules/ModuleSourcePathTest.java	Tue May 03 12:25:20 2016 -0700
@@ -56,7 +56,7 @@
     }
 
     @Test
-    void testSourcePathConflict(Path base) throws Exception {
+    public void testSourcePathConflict(Path base) throws Exception {
         Path sp = base.resolve("src");
         Path msp = base.resolve("srcmodules");
 
@@ -74,7 +74,7 @@
     }
 
     @Test
-    void testUnnormalizedPath1(Path base) throws Exception {
+    public void testUnnormalizedPath1(Path base) throws Exception {
         Path src = base.resolve("src");
         Path src_m1 = src.resolve("m1");
         tb.writeJavaFiles(src_m1, "module m1 { }");
@@ -91,7 +91,7 @@
     }
 
     @Test
-    void testUnnormalizedPath2(Path base) throws Exception {
+    public void testUnnormalizedPath2(Path base) throws Exception {
         Path src = base.resolve("src");
         Path src_m1 = src.resolve("m1");
         tb.writeJavaFiles(src_m1, "module m1 { }");
@@ -115,7 +115,7 @@
     }
 
     @Test
-    void regularBraces(Path base) throws Exception {
+    public void regularBraces(Path base) throws Exception {
         generateModules(base, "src1", "src2/inner_dir");
 
         final Path modules = base.resolve("modules");
@@ -136,7 +136,7 @@
     }
 
     @Test
-    void mismatchedBraces(Path base) throws Exception {
+    public void mismatchedBraces(Path base) throws Exception {
         final List<String> sourcePaths = Arrays.asList(
                 "{",
                 "}",
@@ -165,7 +165,7 @@
     }
 
     @Test
-    void deepBraces(Path base) throws Exception {
+    public void deepBraces(Path base) throws Exception {
         String[] modulePaths = {"src/src1",
                 "src/src2",
                 "src/src3",
@@ -197,7 +197,7 @@
     }
 
     @Test
-    void fileInPath(Path base) throws Exception {
+    public void fileInPath(Path base) throws Exception {
         Path src = base.resolve("src");
         tb.writeJavaFiles(src.resolve("kettle$"), "module kettle$ { }", "package electric; class Heater { }");
         tb.writeFile(base.resolve("dummy.txt"), "");
@@ -218,7 +218,7 @@
     }
 
     @Test
-    void noAlternative(Path base) throws Exception {
+    public void noAlternative(Path base) throws Exception {
         Path src = base.resolve("src");
         tb.writeJavaFiles(src.resolve("kettle$"), "module kettle$ { }", "package electric; class Heater { }");
 
@@ -238,7 +238,7 @@
     }
 
     @Test
-    void noChoice(Path base) throws Exception {
+    public void noChoice(Path base) throws Exception {
         tb.writeJavaFiles(base.resolve("kettle$"), "module kettle$ { }", "package electric; class Heater { }");
 
         final Path modules = base.resolve("modules");
@@ -257,7 +257,7 @@
     }
 
     @Test
-    void nestedModules(Path src) throws Exception {
+    public void nestedModules(Path src) throws Exception {
         Path carModule = src.resolve("car");
         tb.writeJavaFiles(carModule, "module car { }", "package light; class Headlight { }");
         tb.writeJavaFiles(carModule.resolve("engine"), "module engine { }", "package flat; class Piston { }");
@@ -277,7 +277,7 @@
     }
 
     @Test
-    void relativePaths(Path base) throws Exception {
+    public void relativePaths(Path base) throws Exception {
         Path src = base.resolve("src");
         tb.writeJavaFiles(src.resolve("kettle"), "module kettle { }", "package electric; class Heater { }");
 
@@ -296,7 +296,7 @@
     }
 
     @Test
-    void duplicatePaths(Path base) throws Exception {
+    public void duplicatePaths(Path base) throws Exception {
         Path src = base.resolve("src");
         tb.writeJavaFiles(src.resolve("m1"), "module m1 { }", "package a; class A { }");
 
@@ -315,7 +315,7 @@
     }
 
     @Test
-    void notExistentPaths(Path base) throws Exception {
+    public void notExistentPaths(Path base) throws Exception {
         tb.writeJavaFiles(base.resolve("m1"), "module m1 { requires m0; }", "package a; class A { }");
 
         final Path modules = base.resolve("modules");
@@ -334,7 +334,7 @@
     }
 
     @Test
-    void notExistentPathShouldBeSkipped(Path base) throws Exception {
+    public void notExistentPathShouldBeSkipped(Path base) throws Exception {
         tb.writeJavaFiles(base.resolve("m1"), "module m1 { }", "package a; class A { }");
 
         final Path modules = base.resolve("modules");
@@ -352,7 +352,7 @@
     }
 
     @Test
-    void commas(Path base) throws Exception {
+    public void commas(Path base) throws Exception {
         Path src = base.resolve("src");
         tb.writeJavaFiles(src.resolve("m1"), "module m1 { }", "package a; class A { }");
 
@@ -371,7 +371,7 @@
     }
 
     @Test
-    void asterisk(Path base) throws Exception {
+    public void asterisk(Path base) throws Exception {
         tb.writeJavaFiles(base.resolve("kettle").resolve("classes"), "module kettle { }",
                 "package electric; class Heater { }");
 
@@ -391,7 +391,7 @@
     }
 
     @Test
-    void asteriskInDifferentSets(Path base) throws Exception {
+    public void asteriskInDifferentSets(Path base) throws Exception {
         Path src = base.resolve("src");
         final Path module = src.resolve("kettle");
         tb.writeJavaFiles(module.resolve("classes"), "module kettle { }", "package electric; class Heater { }");
@@ -417,7 +417,7 @@
     }
 
     @Test
-    void asteriskIllegalUse(Path base) throws Exception {
+    public void asteriskIllegalUse(Path base) throws Exception {
         final List<String> sourcePaths = Arrays.asList(
                 "*",
                 "**",
--- a/langtools/test/tools/javac/modules/ModuleTestBase.java	Tue May 03 09:48:02 2016 -0700
+++ b/langtools/test/tools/javac/modules/ModuleTestBase.java	Tue May 03 12:25:20 2016 -0700
@@ -43,19 +43,20 @@
 import java.util.stream.Collectors;
 
 import toolbox.JavacTask;
+import toolbox.TestRunner;
 import toolbox.ToolBox;
 
 /**
  * Base class for module tests.
  */
-public class ModuleTestBase {
+public class ModuleTestBase extends TestRunner {
     protected ToolBox tb;
-    protected PrintStream out;
     private int errors;
 
-    /** Marker annotation for test methods to be invoked by runTests. */
-    @Retention(RetentionPolicy.RUNTIME)
-    @interface Test { }
+    ModuleTestBase() {
+        super(System.err);
+        tb = new ToolBox();
+    }
 
     /**
      * Run all methods annotated with @Test, and throw an exception if any
@@ -63,47 +64,12 @@
      *
      * @throws Exception if any errors occurred
      */
-    void runTests() throws Exception {
-        if (tb == null)
-            tb = new ToolBox();
-        out = System.err;
-
-        for (Method m: getClass().getDeclaredMethods()) {
-            Annotation a = m.getAnnotation(Test.class);
-            if (a != null) {
-                try {
-                    out.println("Running test " + m.getName());
-                    Path baseDir = Paths.get(m.getName());
-                    m.invoke(this, new Object[] { baseDir });
-                } catch (InvocationTargetException e) {
-                    Throwable cause = e.getCause();
-                    error("Exception: " + e.getCause());
-                    cause.printStackTrace(out);
-                }
-                out.println();
-            }
-        }
-        if (errors > 0)
-            throw new Exception(errors + " errors occurred");
+    protected void runTests() throws Exception {
+        runTests(m -> new Object[] { Paths.get(m.getName()) });
     }
 
-    // move to ToolBox?
-    // change returntyp to List<Path> -- means updating ToolBox methods
     Path[] findJavaFiles(Path... paths) throws IOException {
-        Set<Path> files = new TreeSet<>();
-        for (Path p : paths) {
-            Files.walkFileTree(p, new SimpleFileVisitor<Path>() {
-                @Override
-                public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
-                        throws IOException {
-                    if (file.getFileName().toString().endsWith(".java")) {
-                        files.add(file);
-                    }
-                    return FileVisitResult.CONTINUE;
-                }
-            });
-        }
-        return files.toArray(new Path[files.size()]);
+        return tb.findJavaFiles(paths);
     }
 
     void error(String message) {
@@ -111,79 +77,4 @@
         errors++;
     }
 
-    public class ModuleBuilder {
-
-        private final String name;
-        private String requires = "";
-        private String exports = "";
-        private String uses = "";
-        private String provides = "";
-        private String modulePath = "";
-        private List<String> content = new ArrayList<>();
-
-        public ModuleBuilder(String name) {
-            this.name = name;
-        }
-
-        public ModuleBuilder requiresPublic(String requires, Path... modulePath) {
-            return requires("public " + requires, modulePath);
-        }
-
-        public ModuleBuilder requires(String requires, Path... modulePath) {
-            this.requires += "    requires " + requires + ";\n";
-            this.modulePath += Arrays.stream(modulePath)
-                    .map(Path::toString)
-                    .collect(Collectors.joining(File.pathSeparator));
-            return this;
-        }
-
-        public ModuleBuilder exportsTo(String pkg, String module) {
-            return exports(pkg + " to " + module);
-        }
-
-        public ModuleBuilder exports(String pkg) {
-            this.exports += "    exports " + pkg + ";\n";
-            return this;
-        }
-
-        public ModuleBuilder uses(String uses) {
-            this.uses += "    uses " + uses + ";\n";
-            return this;
-        }
-
-        public ModuleBuilder provides(String service, String implementation) {
-            this.provides += "    provides " + service + " with " + implementation + ";\n";
-            return this;
-        }
-
-        public ModuleBuilder classes(String... content) {
-            this.content.addAll(Arrays.asList(content));
-            return this;
-        }
-
-        public Path write(Path where) throws IOException {
-            Files.createDirectories(where);
-            List<String> sources = new ArrayList<>();
-            sources.add("module " + name + "{"
-                    + requires
-                    + exports
-                    + uses
-                    + provides
-                    + "}");
-            sources.addAll(content);
-            Path moduleSrc = where.resolve(name + "/src");
-            tb.writeJavaFiles(moduleSrc, sources.toArray(new String[]{}));
-            return moduleSrc;
-        }
-
-        public void build(Path where) throws IOException {
-            Path moduleSrc = write(where);
-            new JavacTask(tb)
-                    .outdir(where.resolve(name))
-                    .options("-mp", modulePath)
-                    .files(findJavaFiles(moduleSrc))
-                    .run()
-                    .writeAll();
-        }
-    }
 }
--- a/langtools/test/tools/javac/modules/ModulesAndClassPathTest.java	Tue May 03 09:48:02 2016 -0700
+++ b/langtools/test/tools/javac/modules/ModulesAndClassPathTest.java	Tue May 03 12:25:20 2016 -0700
@@ -55,7 +55,7 @@
     }
 
     @Test
-    void testModulesAndClassPath(Path base) throws Exception {
+    public void testModulesAndClassPath(Path base) throws Exception {
         Path jar = prepareTestJar(base);
 
         Path moduleSrc = base.resolve("module-src");
@@ -106,7 +106,7 @@
     }
 
     @Test
-    void testImplicitSourcePathModuleInfo(Path base) throws Exception {
+    public void testImplicitSourcePathModuleInfo(Path base) throws Exception {
         Path jar = prepareTestJar(base);
 
         Path moduleSrc = base.resolve("module-src");
@@ -139,7 +139,7 @@
     }
 
     @Test
-    void testModuleInfoFromOutput(Path base) throws Exception {
+    public void testModuleInfoFromOutput(Path base) throws Exception {
         Path jar = prepareTestJar(base);
 
         Path moduleSrc = base.resolve("module-src");
@@ -221,7 +221,7 @@
     }
 
     @Test
-    void testClassOutputVisibleForIncrementalCompilation(Path base) throws Exception {
+    public void testClassOutputVisibleForIncrementalCompilation(Path base) throws Exception {
         Path moduleSrc = base.resolve("module-src");
         Path m1 = moduleSrc.resolve("m1");
 
--- a/langtools/test/tools/javac/modules/MultiModuleModeTest.java	Tue May 03 09:48:02 2016 -0700
+++ b/langtools/test/tools/javac/modules/MultiModuleModeTest.java	Tue May 03 12:25:20 2016 -0700
@@ -49,7 +49,7 @@
     }
 
     @Test
-    void testDuplicateModules(Path base) throws Exception {
+    public void testDuplicateModules(Path base) throws Exception {
         Path src = base.resolve("src");
         Path src_m1 = src.resolve("m1");
         tb.writeJavaFiles(src_m1, "module m1 { }");
@@ -72,7 +72,7 @@
     }
 
     @Test
-    void testCantFindModule(Path base) throws Exception {
+    public void testCantFindModule(Path base) throws Exception {
         Path src = base.resolve("src");
         Path src_m1 = src.resolve("m1");
         tb.writeJavaFiles(src_m1, "module m1 { }");
@@ -95,7 +95,7 @@
     }
 
     @Test
-    void testModuleNameMismatch(Path base) throws Exception {
+    public void testModuleNameMismatch(Path base) throws Exception {
         Path src = base.resolve("src");
         Path src_m1 = src.resolve("m1");
         tb.writeJavaFiles(src_m1, "module m2 { }");
@@ -116,7 +116,7 @@
     }
 
     @Test
-    void testImplicitModuleSource(Path base) throws Exception {
+    public void testImplicitModuleSource(Path base) throws Exception {
         Path src = base.resolve("src");
         tb.writeJavaFiles(src.resolve("m1"), "module m1 { }");
         tb.writeJavaFiles(src.resolve("m2"), "module m2 { requires m1; }");
@@ -132,7 +132,7 @@
     }
 
     @Test
-    void testImplicitModuleClass(Path base) throws Exception {
+    public void testImplicitModuleClass(Path base) throws Exception {
         Path src1 = base.resolve("src1");
         tb.writeJavaFiles(src1.resolve("m1"), "module m1 { }");
         Path modules1 = base.resolve("modules1");
--- a/langtools/test/tools/javac/modules/NPECompilingModuleInfoTest.java	Tue May 03 09:48:02 2016 -0700
+++ b/langtools/test/tools/javac/modules/NPECompilingModuleInfoTest.java	Tue May 03 12:25:20 2016 -0700
@@ -45,7 +45,7 @@
     }
 
     @Test
-    void testCompileNoError(Path base) throws Exception {
+    public void testCompileNoError(Path base) throws Exception {
         Path mod = base.resolve("mod");
         tb.writeJavaFiles(mod, "module mod { exports pkg; }");
         Path pkg = mod.resolve("pkg");
--- a/langtools/test/tools/javac/modules/NPEEmptyFileTest.java	Tue May 03 09:48:02 2016 -0700
+++ b/langtools/test/tools/javac/modules/NPEEmptyFileTest.java	Tue May 03 12:25:20 2016 -0700
@@ -45,7 +45,7 @@
     }
 
     @Test
-    void compileEmptyFile(Path base) throws Exception {
+    public void compileEmptyFile(Path base) throws Exception {
         Path modules = base.resolve("modules");
         Files.createDirectories(modules);
         Path emptyJavaFile = base.resolve("Test.java");
--- a/langtools/test/tools/javac/modules/OutputDirTest.java	Tue May 03 09:48:02 2016 -0700
+++ b/langtools/test/tools/javac/modules/OutputDirTest.java	Tue May 03 12:25:20 2016 -0700
@@ -60,7 +60,7 @@
     }
 
     @Test
-    void testError(Path base) throws Exception {
+    public void testError(Path base) throws Exception {
         String log = new JavacTask(tb)
                 .options("-XDrawDiagnostics",
                         "-modulesourcepath", src.toString())
@@ -74,7 +74,7 @@
     }
 
     @Test
-    void testProcOnly(Path base) throws IOException {
+    public void testProcOnly(Path base) throws IOException {
         new JavacTask(tb)
                 .options("-XDrawDiagnostics",
                         "-proc:only",
@@ -85,7 +85,7 @@
     }
 
     @Test
-    void testClassOutDir(Path base) throws IOException {
+    public void testClassOutDir(Path base) throws IOException {
         Path classes = base.resolve("classes");
         new JavacTask(tb)
                 .options("-XDrawDiagnostics",
@@ -97,7 +97,7 @@
     }
 
     @Test
-    void testExplodedOutDir(Path base) throws Exception {
+    public void testExplodedOutDir(Path base) throws Exception {
         Path modSrc = base.resolve("modSrc");
         tb.writeJavaFiles(modSrc,
                 "module m1 { exports p; }",
@@ -131,7 +131,7 @@
     }
 
     @Test
-    void testInExplodedOutDir(Path base) throws Exception {
+    public void testInExplodedOutDir(Path base) throws Exception {
         Path modSrc = base.resolve("modSrc");
         tb.writeJavaFiles(modSrc,
                 "module m1 { exports p; }",
--- a/langtools/test/tools/javac/modules/PackageConflictTest.java	Tue May 03 09:48:02 2016 -0700
+++ b/langtools/test/tools/javac/modules/PackageConflictTest.java	Tue May 03 12:25:20 2016 -0700
@@ -28,7 +28,7 @@
  * @modules
  *      jdk.compiler/com.sun.tools.javac.api
  *      jdk.compiler/com.sun.tools.javac.main
- * @build toolbox.ToolBox toolbox.JavacTask ModuleTestBase
+ * @build toolbox.ToolBox toolbox.JavacTask toolbox.ModuleBuilder ModuleTestBase
  * @run main PackageConflictTest
  */
 
@@ -38,6 +38,7 @@
 import java.util.List;
 
 import toolbox.JavacTask;
+import toolbox.ModuleBuilder;
 import toolbox.Task;
 import toolbox.ToolBox;
 
@@ -48,7 +49,7 @@
     }
 
     @Test
-    void testSimple(Path base) throws Exception {
+    public void testSimple(Path base) throws Exception {
         Path src = base.resolve("src");
         tb.writeJavaFiles(src,
                 "package java.util; public class MyList { }");
@@ -68,7 +69,7 @@
     }
 
     @Test
-    void testDisjoint(Path base) throws Exception {
+    public void testDisjoint(Path base) throws Exception {
         Path m1 = base.resolve("m1");
         Path m2 = base.resolve("m2");
         tb.writeJavaFiles(m1,
@@ -89,7 +90,7 @@
     }
 
     @Test
-    void testConflictInDependencies(Path base) throws Exception {
+    public void testConflictInDependencies(Path base) throws Exception {
         Path m1 = base.resolve("m1");
         Path m2 = base.resolve("m2");
         Path m3 = base.resolve("m3");
@@ -123,13 +124,13 @@
     }
 
     @Test
-    void testSimple2(Path base) throws Exception {
+    public void testSimple2(Path base) throws Exception {
         Path modules = base.resolve("modules");
-        new ModuleBuilder("N")
+        new ModuleBuilder(tb, "N")
                 .exports("pack")
                 .classes("package pack; public class A { }")
                 .build(modules);
-        new ModuleBuilder("M")
+        new ModuleBuilder(tb, "M")
                 .requires("N")
                 .classes("package pack; public class B { pack.A f; }")
                 .write(modules);
@@ -147,14 +148,14 @@
     }
 
     @Test
-    void testPrivateConflict(Path base) throws Exception {
+    public void testPrivateConflict(Path base) throws Exception {
         Path modules = base.resolve("modules");
-        new ModuleBuilder("N")
+        new ModuleBuilder(tb, "N")
                 .exports("publ")
                 .classes("package pack; public class A { }")
                 .classes("package publ; public class B { }")
                 .write(modules);
-        new ModuleBuilder("M")
+        new ModuleBuilder(tb, "M")
                 .requires("N")
                 .classes("package pack; public class C { publ.B b; }")
                 .write(modules);
@@ -173,14 +174,14 @@
     }
 
     @Test
-    void testPrivateConflictOnModulePath(Path base) throws Exception {
+    public void testPrivateConflictOnModulePath(Path base) throws Exception {
         Path modules = base.resolve("modules");
-        new ModuleBuilder("N")
+        new ModuleBuilder(tb, "N")
                 .exports("publ")
                 .classes("package pack; public class A { }")
                 .classes("package publ; public class B { }")
                 .build(modules);
-        new ModuleBuilder("M")
+        new ModuleBuilder(tb, "M")
                 .requires("N")
                 .classes("package pack; public class C { publ.B b; }")
                 .write(modules);
@@ -199,17 +200,17 @@
     }
 
     @Test
-    void testRequiresConflictExports(Path base) throws Exception {
+    public void testRequiresConflictExports(Path base) throws Exception {
         Path modules = base.resolve("modules");
-        new ModuleBuilder("M")
+        new ModuleBuilder(tb, "M")
                 .exports("pack")
                 .classes("package pack; public class A { }")
                 .build(modules);
-        new ModuleBuilder("N")
+        new ModuleBuilder(tb, "N")
                 .exports("pack")
                 .classes("package pack; public class B { }")
                 .build(modules);
-        new ModuleBuilder("K")
+        new ModuleBuilder(tb, "K")
                 .requires("M")
                 .requires("N")
                 .classes("package pkg; public class C { pack.A a; pack.B b; }")
@@ -231,18 +232,18 @@
     }
 
     @Test
-    void testQulifiedExportsToDifferentModules(Path base) throws Exception {
+    public void testQulifiedExportsToDifferentModules(Path base) throws Exception {
         Path modules = base.resolve("modules");
-        new ModuleBuilder("U").write(modules);
-        new ModuleBuilder("M")
+        new ModuleBuilder(tb, "U").write(modules);
+        new ModuleBuilder(tb, "M")
                 .exports("pkg to U")
                 .classes("package pkg; public class A { public static boolean flagM; }")
                 .write(modules);
-        new ModuleBuilder("N")
+        new ModuleBuilder(tb, "N")
                 .exports("pkg to K")
                 .classes("package pkg; public class A { public static boolean flagN; }")
                 .write(modules);
-        ModuleBuilder moduleK = new ModuleBuilder("K");
+        ModuleBuilder moduleK = new ModuleBuilder(tb, "K");
         moduleK.requires("M")
                 .requires("N")
                 .classes("package p; public class DependsOnN { boolean f = pkg.A.flagN; } ")
--- a/langtools/test/tools/javac/modules/PackageMultipleModules.java	Tue May 03 09:48:02 2016 -0700
+++ b/langtools/test/tools/javac/modules/PackageMultipleModules.java	Tue May 03 12:25:20 2016 -0700
@@ -49,7 +49,7 @@
     }
 
     @Test
-    void testSimple(Path base) throws Exception {
+    public void testSimple(Path base) throws Exception {
         Path m1 = base.resolve("m1");
         Path m2 = base.resolve("m2");
         tb.writeJavaFiles(m1,
--- a/langtools/test/tools/javac/modules/PluginsInModulesTest.java	Tue May 03 09:48:02 2016 -0700
+++ b/langtools/test/tools/javac/modules/PluginsInModulesTest.java	Tue May 03 12:25:20 2016 -0700
@@ -127,7 +127,7 @@
     Path classes;
 
     @Test
-    void testUseOnlyOneProcessor(Path base) throws Exception {
+    public void testUseOnlyOneProcessor(Path base) throws Exception {
         initialization(base);
         List<String> log = new JavacTask(tb)
                 .options("-processormodulepath", processorCompiledModules.toString(),
--- a/langtools/test/tools/javac/modules/ProvidesTest.java	Tue May 03 09:48:02 2016 -0700
+++ b/langtools/test/tools/javac/modules/ProvidesTest.java	Tue May 03 12:25:20 2016 -0700
@@ -48,7 +48,7 @@
     }
 
     @Test
-    void testSimple(Path base) throws Exception {
+    public void testSimple(Path base) throws Exception {
         Path src = base.resolve("src");
         tb.writeJavaFiles(src,
                 "module m { provides p1.C1 with p2.C2; }",
@@ -65,7 +65,7 @@
     }
 
     @Test
-    void testMulti(Path base) throws Exception {
+    public void testMulti(Path base) throws Exception {
         Path src = base.resolve("src");
         tb.writeJavaFiles(src.resolve("m1"),
                 "module m1 { exports p1; }",
@@ -86,7 +86,7 @@
     }
 
     @Test
-    void testMissingWith(Path base) throws Exception {
+    public void testMissingWith(Path base) throws Exception {
         Path src = base.resolve("src");
         tb.writeJavaFiles(src,
                 "module m { provides p.C; }",
@@ -108,7 +108,7 @@
     }
 
     @Test
-    void testDuplicateProvides(Path base) throws Exception {
+    public void testDuplicateProvides(Path base) throws Exception {
         Path src = base.resolve("src");
         tb.writeJavaFiles(src,
                 "module m { provides p1.C1 with p2.C2; provides p1.C1 with p2.C2; }",
@@ -126,7 +126,7 @@
     }
 
     @Test
-    void testMissingService(Path base) throws Exception {
+    public void testMissingService(Path base) throws Exception {
         Path src = base.resolve("src");
         tb.writeJavaFiles(src,
                 "module m { provides p.Missing with p.C; }",
@@ -151,7 +151,7 @@
     }
 
     @Test
-    void testProvidesFromAnotherModule(Path base) throws Exception {
+    public void testProvidesFromAnotherModule(Path base) throws Exception {
         Path modules = base.resolve("modules");
         tb.writeJavaFiles(modules.resolve("M"),
                 "module M { exports p; }",
@@ -177,7 +177,7 @@
     }
 
     @Test
-    void testServiceIsNotImplemented(Path base) throws Exception {
+    public void testServiceIsNotImplemented(Path base) throws Exception {
         Path src = base.resolve("src");
         tb.writeJavaFiles(src,
                 "module m { provides p.A with p.B; }",
@@ -200,7 +200,7 @@
     }
 
     @Test
-    void testMissingImplementation(Path base) throws Exception {
+    public void testMissingImplementation(Path base) throws Exception {
         Path src = base.resolve("src");
         tb.writeJavaFiles(src,
                 "module m { provides p.C with p.Impl; }",
@@ -222,7 +222,7 @@
     }
 
     @Test
-    void testSeveralImplementations(Path base) throws Exception {
+    public void testSeveralImplementations(Path base) throws Exception {
         Path src = base.resolve("src");
         tb.writeJavaFiles(src,
                 "module m { provides p.C with p.Impl1; provides p.C with p.Impl2; }",
@@ -238,7 +238,7 @@
     }
 
     @Test
-    void testOneImplementationsForServices(Path base) throws Exception {
+    public void testOneImplementationsForServices(Path base) throws Exception {
         Path src = base.resolve("src");
         tb.writeJavaFiles(src,
                 "module m { provides p.Service1 with p.Impl; provides p.Service2 with p.Impl; }",
@@ -254,7 +254,7 @@
     }
 
     @Test
-    void testAbstractImplementation(Path base) throws Exception {
+    public void testAbstractImplementation(Path base) throws Exception {
         Path src = base.resolve("src");
         tb.writeJavaFiles(src,
                 "module m { provides p1.C1 with p2.C2; }",
@@ -277,7 +277,7 @@
     }
 
     @Test
-    void testInterfaceImplementation(Path base) throws Exception {
+    public void testInterfaceImplementation(Path base) throws Exception {
         Path src = base.resolve("src");
         tb.writeJavaFiles(src,
                 "module m { provides p1.Service with p2.Impl; }",
@@ -300,7 +300,7 @@
     }
 
     @Test
-    void testProtectedImplementation(Path base) throws Exception {
+    public void testProtectedImplementation(Path base) throws Exception {
         Path src = base.resolve("src");
         tb.writeJavaFiles(src,
                 "module m { provides p1.C1 with p2.C2; }",
@@ -323,7 +323,7 @@
     }
 
     @Test
-    void testNoNoArgConstructor(Path base) throws Exception {
+    public void testNoNoArgConstructor(Path base) throws Exception {
         Path src = base.resolve("src");
         tb.writeJavaFiles(src,
                 "module m { uses p1.C1; provides p1.C1 with p2.C2; }",
@@ -346,7 +346,7 @@
     }
 
     @Test
-    void testPrivateNoArgConstructor(Path base) throws Exception {
+    public void testPrivateNoArgConstructor(Path base) throws Exception {
         Path src = base.resolve("src");
         tb.writeJavaFiles(src,
                 "module m { uses p1.C1; provides p1.C1 with p2.C2; }",
@@ -369,7 +369,7 @@
     }
 
     @Test
-    void testServiceIndirectlyImplemented(Path base) throws Exception {
+    public void testServiceIndirectlyImplemented(Path base) throws Exception {
         Path src = base.resolve("src");
         tb.writeJavaFiles(src,
                 "module m { provides p1.C1 with p2.C3; }",
@@ -385,7 +385,7 @@
     }
 
     @Test
-    void testServiceImplementationInnerClass(Path base) throws Exception {
+    public void testServiceImplementationInnerClass(Path base) throws Exception {
         Path src = base.resolve("src");
         tb.writeJavaFiles(src,
                 "module m { provides p1.C1 with p2.C2.Inner; }",
@@ -408,7 +408,7 @@
     }
 
     @Test
-    void testServiceDefinitionInnerClass(Path base) throws Exception {
+    public void testServiceDefinitionInnerClass(Path base) throws Exception {
         Path src = base.resolve("src");
         tb.writeJavaFiles(src,
                 "module m { provides p1.C1.InnerDefinition with p2.C2; }",
--- a/langtools/test/tools/javac/modules/QueryBeforeEnter.java	Tue May 03 09:48:02 2016 -0700
+++ b/langtools/test/tools/javac/modules/QueryBeforeEnter.java	Tue May 03 12:25:20 2016 -0700
@@ -65,7 +65,7 @@
     }
 
     @Test
-    void testEmpty(Path base) throws Exception {
+    public void testEmpty(Path base) throws Exception {
         JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler();
         com.sun.source.util.JavacTask task =
             (com.sun.source.util.JavacTask) javaCompiler.getTask(null, null, null, null, null, null);
@@ -75,7 +75,7 @@
     }
 
     @Test
-    void testUnnamed(Path base) throws Exception {
+    public void testUnnamed(Path base) throws Exception {
         Path moduleSrc = base.resolve("module-src");
         Path m1 = moduleSrc.resolve("m1");
 
@@ -151,7 +151,7 @@
     }
 
     @Test
-    void testSingleNamed(Path base) throws Exception {
+    public void testSingleNamed(Path base) throws Exception {
         Path moduleSrc = base.resolve("module-src");
         Path m1 = moduleSrc.resolve("m1");
 
@@ -226,7 +226,7 @@
     }
 
     @Test
-    void testMultiModule(Path base) throws Exception {
+    public void testMultiModule(Path base) throws Exception {
         Path modulePathSrc = base.resolve("module-path-src");
         Path m1 = modulePathSrc.resolve("m1");
 
@@ -311,7 +311,7 @@
     }
 
     @Test
-    void testTooSoon(Path base) throws Exception {
+    public void testTooSoon(Path base) throws Exception {
         Path src = base.resolve("src");
 
         tb.writeJavaFiles(src,
--- a/langtools/test/tools/javac/modules/RepeatedUsesAndProvidesTest.java	Tue May 03 09:48:02 2016 -0700
+++ b/langtools/test/tools/javac/modules/RepeatedUsesAndProvidesTest.java	Tue May 03 12:25:20 2016 -0700
@@ -46,7 +46,7 @@
     }
 
     @Test
-    void testDuplicateUses(Path base) throws Exception {
+    public void testDuplicateUses(Path base) throws Exception {
         Path src = base.resolve("src");
         tb.writeJavaFiles(src,
                 "module m { uses p1.C1; uses p1.C1; }",
@@ -66,7 +66,7 @@
     }
 
     @Test
-    void testDuplicateProvides(Path base) throws Exception {
+    public void testDuplicateProvides(Path base) throws Exception {
         Path src = base.resolve("src");
         tb.writeJavaFiles(src,
                 "module m { provides p1.C1 with p2.C2; provides p1.C1 with p2.C2; }",
--- a/langtools/test/tools/javac/modules/ReportNonExistentPackageTest.java	Tue May 03 09:48:02 2016 -0700
+++ b/langtools/test/tools/javac/modules/ReportNonExistentPackageTest.java	Tue May 03 12:25:20 2016 -0700
@@ -46,7 +46,7 @@
     }
 
     @Test
-    void testExportUnknownPackage(Path base) throws Exception {
+    public void testExportUnknownPackage(Path base) throws Exception {
         Path src = base.resolve("src");
         tb.writeJavaFiles(src, "module m { exports p1; }");
         Path classes = base.resolve("classes");
@@ -64,7 +64,7 @@
     }
 
     @Test
-    void testExportEmptyPackage(Path base) throws Exception {
+    public void testExportEmptyPackage(Path base) throws Exception {
         Path src = base.resolve("src");
         tb.writeJavaFiles(src,
                 "module m { exports p1; }",
@@ -84,7 +84,7 @@
     }
 
     @Test
-    void testPackageWithMemberWOPackageDeclaration(Path base) throws Exception {
+    public void testPackageWithMemberWOPackageDeclaration(Path base) throws Exception {
         Path src = base.resolve("src");
         tb.writeJavaFiles(src, "module m { exports p1; }");
         Path p1 = src.resolve("p1");
--- a/langtools/test/tools/javac/modules/RequiresPublicTest.java	Tue May 03 09:48:02 2016 -0700
+++ b/langtools/test/tools/javac/modules/RequiresPublicTest.java	Tue May 03 12:25:20 2016 -0700
@@ -47,7 +47,7 @@
     }
 
     @Test
-    void testJavaSE_OK(Path base) throws Exception {
+    public void testJavaSE_OK(Path base) throws Exception {
         Path src = base.resolve("src");
         tb.writeJavaFiles(src,
                 "module m { requires java.se; }",
@@ -66,7 +66,7 @@
     }
 
     @Test
-    void testJavaSE_Fail(Path base) throws Exception {
+    public void testJavaSE_Fail(Path base) throws Exception {
         Path src = base.resolve("src");
         tb.writeJavaFiles(src,
                 "module m { requires java.se; }",
@@ -90,7 +90,7 @@
     }
 
     @Test
-    void testComplex_OK(Path base) throws Exception {
+    public void testComplex_OK(Path base) throws Exception {
         Path src = getComplexSrc(base, "", "");
         Path classes = base.resolve("classes");
         Files.createDirectories(classes);
@@ -104,7 +104,7 @@
     }
 
     @Test
-    void testComplex_Fail(Path base) throws Exception {
+    public void testComplex_Fail(Path base) throws Exception {
         Path src = getComplexSrc(base,
                 "import p5.C5; import p6.C6; import p7.C7;\n",
                 "C5 c5; C6 c6; C7 c7;\n");
--- a/langtools/test/tools/javac/modules/ResolveTest.java	Tue May 03 09:48:02 2016 -0700
+++ b/langtools/test/tools/javac/modules/ResolveTest.java	Tue May 03 12:25:20 2016 -0700
@@ -45,7 +45,7 @@
     }
 
     @Test
-    void testMissingSimpleTypeUnnamedModule(Path base) throws Exception {
+    public void testMissingSimpleTypeUnnamedModule(Path base) throws Exception {
         Path src = base.resolve("src");
         tb.writeJavaFiles(src, "class C { D d; }");
 
@@ -62,7 +62,7 @@
     }
 
     @Test
-    void testMissingSimpleTypeNamedModule(Path base) throws Exception {
+    public void testMissingSimpleTypeNamedModule(Path base) throws Exception {
         Path src = base.resolve("src");
         tb.writeJavaFiles(src,
                 "module m { }",
@@ -81,7 +81,7 @@
     }
 
     @Test
-    void testUnexportedTypeUnreadableModule(Path base) throws Exception {
+    public void testUnexportedTypeUnreadableModule(Path base) throws Exception {
         Path src = base.resolve("src");
         tb.writeJavaFiles(src.resolve("m1"),
                 "module m1 { }",
@@ -105,7 +105,7 @@
     }
 
     @Test
-    void testUnexportedTypeReadableModule(Path base) throws Exception {
+    public void testUnexportedTypeReadableModule(Path base) throws Exception {
         Path src = base.resolve("src");
         tb.writeJavaFiles(src.resolve("m1"),
                 "module m1 { }",
@@ -129,7 +129,7 @@
     }
 
     @Test
-    void testQualifiedExportedTypeReadableModule(Path base) throws Exception {
+    public void testQualifiedExportedTypeReadableModule(Path base) throws Exception {
         Path src = base.resolve("src");
         tb.writeJavaFiles(src.resolve("m1"),
                 "module m1 { exports p1 to m3; }",
@@ -155,7 +155,7 @@
     }
 
     @Test
-    void testExportedTypeUnreadableModule(Path base) throws Exception {
+    public void testExportedTypeUnreadableModule(Path base) throws Exception {
         Path src = base.resolve("src");
         tb.writeJavaFiles(src.resolve("m1"),
                 "module m1 { exports p1; }",
@@ -179,7 +179,7 @@
     }
 
     @Test
-    void testExportedTypeReadableModule(Path base) throws Exception {
+    public void testExportedTypeReadableModule(Path base) throws Exception {
         Path src = base.resolve("src");
         tb.writeJavaFiles(src.resolve("m1"),
                 "module m1 { exports p1; }",
@@ -199,7 +199,7 @@
     }
 
     @Test
-    void testExportedTypeReadableModule2(Path base) throws Exception {
+    public void testExportedTypeReadableModule2(Path base) throws Exception {
         Path src = base.resolve("src");
         tb.writeJavaFiles(src.resolve("m1"),
                 "module m1 { exports p1 to m2; }",
--- a/langtools/test/tools/javac/modules/ServiceInStaticClassErrorTest.java	Tue May 03 09:48:02 2016 -0700
+++ b/langtools/test/tools/javac/modules/ServiceInStaticClassErrorTest.java	Tue May 03 12:25:20 2016 -0700
@@ -48,7 +48,7 @@
     }
 
     @Test
-    void testError(Path base) throws Exception {
+    public void testError(Path base) throws Exception {
         Path src = base.resolve("src");
         tb.writeJavaFiles(src,
                 "module m { provides p1.I with p1.Outer.A; }",
--- a/langtools/test/tools/javac/modules/ServiceProvidedButNotExportedOrUsedTest.java	Tue May 03 09:48:02 2016 -0700
+++ b/langtools/test/tools/javac/modules/ServiceProvidedButNotExportedOrUsedTest.java	Tue May 03 12:25:20 2016 -0700
@@ -49,7 +49,7 @@
     }
 
     @Test
-    void testWarning(Path base) throws Exception {
+    public void testWarning(Path base) throws Exception {
         Path src = base.resolve("src");
         tb.writeJavaFiles(src,
                 "module m { provides p1.C1 with p2.C2; }",
@@ -76,7 +76,7 @@
     }
 
     @Test
-    void testImplementationMustBeInSameModuleAsProvidesDirective(Path base) throws Exception {
+    public void testImplementationMustBeInSameModuleAsProvidesDirective(Path base) throws Exception {
         Path src = base.resolve("src");
         tb.writeJavaFiles(src.resolve("m1"),
                 "module m1 { exports p1; }",
--- a/langtools/test/tools/javac/modules/SingleModuleModeTest.java	Tue May 03 09:48:02 2016 -0700
+++ b/langtools/test/tools/javac/modules/SingleModuleModeTest.java	Tue May 03 12:25:20 2016 -0700
@@ -59,7 +59,7 @@
     }
 
     @Test
-    void testTooManyModules(Path base) throws Exception {
+    public void testTooManyModules(Path base) throws Exception {
         Path src = base.resolve("src");
         tb.writeJavaFiles(src.resolve("m1"), "module m1 { }");
         tb.writeJavaFiles(src.resolve("m2"), "module m2 { }");
@@ -76,7 +76,7 @@
     }
 
     @Test
-    void testImplicitModuleSource(Path base) throws Exception {
+    public void testImplicitModuleSource(Path base) throws Exception {
         Path src = base.resolve("src");
         tb.writeJavaFiles(src,
                 "module m { }",
@@ -90,7 +90,7 @@
     }
 
     @Test
-    void testImplicitModuleClass(Path base) throws Exception {
+    public void testImplicitModuleClass(Path base) throws Exception {
         Path src = base.resolve("src");
         tb.writeJavaFiles(src,
                 "module m { }",
@@ -112,7 +112,7 @@
     }
 
     @Test
-    void testImplicitModuleClassAP(Path base) throws Exception {
+    public void testImplicitModuleClassAP(Path base) throws Exception {
         Path src = base.resolve("src");
         tb.writeJavaFiles(src,
                 "module m { uses java.lang.Runnable; }",
@@ -137,7 +137,7 @@
     }
 
     @Test
-    void testImplicitModuleSourceAP(Path base) throws Exception {
+    public void testImplicitModuleSourceAP(Path base) throws Exception {
         Path src = base.resolve("src");
         tb.writeJavaFiles(src,
                 "module m { uses java.lang.Runnable; }",
--- a/langtools/test/tools/javac/modules/SubpackageTest.java	Tue May 03 09:48:02 2016 -0700
+++ b/langtools/test/tools/javac/modules/SubpackageTest.java	Tue May 03 12:25:20 2016 -0700
@@ -52,7 +52,7 @@
     }
 
     @Test // based on JDK-8075435
-    void testUnnamedModule(Path base) throws Exception {
+    public void testUnnamedModule(Path base) throws Exception {
         Path libsrc = base.resolve("lib/src");
         tb.writeJavaFiles(libsrc,
             "package p; public class E extends Error { }");
@@ -83,7 +83,7 @@
     }
 
     @Test
-    void testSimpleMulti(Path base) throws Exception {
+    public void testSimpleMulti(Path base) throws Exception {
         Path src = base.resolve("src");
         tb.writeJavaFiles(src.resolve("mp"),
                 "module mp { exports p; }",
--- a/langtools/test/tools/javac/modules/UpgradeModulePathTest.java	Tue May 03 09:48:02 2016 -0700
+++ b/langtools/test/tools/javac/modules/UpgradeModulePathTest.java	Tue May 03 12:25:20 2016 -0700
@@ -28,7 +28,7 @@
  * @modules
  *      jdk.compiler/com.sun.tools.javac.api
  *      jdk.compiler/com.sun.tools.javac.main
- * @build toolbox.ToolBox toolbox.JavacTask ModuleTestBase
+ * @build toolbox.ToolBox toolbox.JavacTask toolbox.ModuleBuilder ModuleTestBase
  * @run main UpgradeModulePathTest
  */
 
@@ -36,6 +36,7 @@
 import java.nio.file.Path;
 
 import toolbox.JavacTask;
+import toolbox.ModuleBuilder;
 import toolbox.Task;
 import toolbox.ToolBox;
 
@@ -47,15 +48,15 @@
     }
 
     @Test
-    void simpleUsage(Path base) throws Exception {
+    public void simpleUsage(Path base) throws Exception {
         final Path module = base.resolve("modules");
-        new ModuleBuilder("m1")
+        new ModuleBuilder(tb, "m1")
                 .exports("pkg1")
                 .classes("package pkg1; public class E { }")
                 .build(module);
 
         final Path upgradeModule = base.resolve("upgradeModule");
-        new ModuleBuilder("m1")
+        new ModuleBuilder(tb, "m1")
                 .exports("pkg2")
                 .classes("package pkg2; public class E { }")
                 .build(upgradeModule);
@@ -73,15 +74,15 @@
     }
 
     @Test
-    void onlyUpgradeModulePath(Path base) throws Exception {
+    public void onlyUpgradeModulePath(Path base) throws Exception {
         final Path module = base.resolve("modules");
-        new ModuleBuilder("m1")
+        new ModuleBuilder(tb, "m1")
                 .exports("pkg1")
                 .classes("package pkg1; public class E { }")
                 .build(module);
 
         final Path upgradeModule = base.resolve("upgradeModule");
-        new ModuleBuilder("m1")
+        new ModuleBuilder(tb, "m1")
                 .exports("pkg2")
                 .classes("package pkg2; public class E { }")
                 .build(upgradeModule);
@@ -98,15 +99,15 @@
     }
 
     @Test
-    void withModuleSourcePath(Path base) throws Exception {
+    public void withModuleSourcePath(Path base) throws Exception {
         final Path module = base.resolve("modules");
-        new ModuleBuilder("m1")
+        new ModuleBuilder(tb, "m1")
                 .exports("pkg1")
                 .classes("package pkg1; public class E { }")
                 .build(module);
 
         final Path upgradeModule = base.resolve("upgradeModule");
-        new ModuleBuilder("m1")
+        new ModuleBuilder(tb, "m1")
                 .exports("pkg2")
                 .classes("package pkg2; public class E { }")
                 .build(upgradeModule);
@@ -115,7 +116,7 @@
         tb.writeJavaFiles(s.resolve("m3"), "module m3 { }");
 
         final Path upgradeModule3 = base.resolve("upgradeModule");
-        new ModuleBuilder("m3")
+        new ModuleBuilder(tb, "m3")
                 .exports("pkg3")
                 .classes("package pkg3; public class E { }")
                 .build(upgradeModule);
@@ -135,15 +136,15 @@
     }
 
     @Test
-    void sameUpgradeAndModulePath(Path base) throws Exception {
+    public void sameUpgradeAndModulePath(Path base) throws Exception {
         final Path module = base.resolve("modules");
-        new ModuleBuilder("m1")
+        new ModuleBuilder(tb, "m1")
                 .exports("pkg1")
                 .classes("package pkg1; public class E { }")
                 .build(module);
 
         final Path upgradeModule = base.resolve("upgradeModule");
-        new ModuleBuilder("m1")
+        new ModuleBuilder(tb, "m1")
                 .exports("pkg2")
                 .classes("package pkg2; public class E { }")
                 .build(upgradeModule);
@@ -161,9 +162,9 @@
     }
 
     @Test
-    void dummyFileInUpgradeModulePath(Path base) throws Exception {
+    public void dummyFileInUpgradeModulePath(Path base) throws Exception {
         final Path module = base.resolve("modules");
-        new ModuleBuilder("m1")
+        new ModuleBuilder(tb, "m1")
                 .exports("pkg1")
                 .classes("package pkg1; public class E { }")
                 .build(module);
@@ -189,24 +190,24 @@
     }
 
     @Test
-    void severalUpgradeModules(Path base) throws Exception {
+    public void severalUpgradeModules(Path base) throws Exception {
         final Path module = base.resolve("modules");
-        new ModuleBuilder("m1")
+        new ModuleBuilder(tb, "m1")
                 .exports("pkg1")
                 .classes("package pkg1; public class A { }")
                 .build(module);
 
-        new ModuleBuilder("m2")
+        new ModuleBuilder(tb, "m2")
                 .exports("pkg2")
                 .classes("package pkg2; public class B { }")
                 .build(module);
 
         Path upgradeModule = base.resolve("upgradeModule");
-        new ModuleBuilder("m2")
+        new ModuleBuilder(tb, "m2")
                 .exports("pkg2")
                 .classes("package pkg2; public class BC { }")
                 .build(upgradeModule);
-        new ModuleBuilder("m3")
+        new ModuleBuilder(tb, "m3")
                 .exports("pkg3")
                 .classes("package pkg3; public class DC { }")
                 .build(upgradeModule);
@@ -240,21 +241,21 @@
     }
 
     @Test
-    void severalUpgradeModulePathsLastWin(Path base) throws Exception {
+    public void severalUpgradeModulePathsLastWin(Path base) throws Exception {
         final Path module = base.resolve("modules");
-        new ModuleBuilder("m1")
+        new ModuleBuilder(tb, "m1")
                 .exports("pkg1")
                 .classes("package pkg1; public class E { }")
                 .build(module);
 
         final Path upgradeModule1 = base.resolve("upgradeModule1");
-        new ModuleBuilder("m1")
+        new ModuleBuilder(tb, "m1")
                 .exports("pkg2")
                 .classes("package pkg2; public class EC1 { }")
                 .build(upgradeModule1);
 
         final Path upgradeModule2 = base.resolve("upgradeModule2");
-        new ModuleBuilder("m1")
+        new ModuleBuilder(tb, "m1")
                 .exports("pkg2")
                 .classes("package pkg2; public class EC2 { }")
                 .build(upgradeModule2);
--- a/langtools/test/tools/javac/modules/UsesTest.java	Tue May 03 09:48:02 2016 -0700
+++ b/langtools/test/tools/javac/modules/UsesTest.java	Tue May 03 12:25:20 2016 -0700
@@ -28,7 +28,7 @@
  * @modules
  *      jdk.compiler/com.sun.tools.javac.api
  *      jdk.compiler/com.sun.tools.javac.main
- * @build toolbox.ToolBox toolbox.JavacTask ModuleTestBase
+ * @build toolbox.ToolBox toolbox.JavacTask toolbox.ModuleBuilder ModuleTestBase
  * @run main UsesTest
  */
 
@@ -39,6 +39,7 @@
 import java.util.List;
 
 import toolbox.JavacTask;
+import toolbox.ModuleBuilder;
 import toolbox.Task;
 import toolbox.ToolBox;
 
@@ -49,7 +50,7 @@
     }
 
     @Test
-    void testSimple(Path base) throws Exception {
+    public void testSimple(Path base) throws Exception {
         Path src = base.resolve("src");
         tb.writeJavaFiles(src,
                 "module m { uses p.C; }",
@@ -65,7 +66,7 @@
     }
 
     @Test
-    void testSimpleInner(Path base) throws Exception {
+    public void testSimpleInner(Path base) throws Exception {
         Path src = base.resolve("src");
         tb.writeJavaFiles(src,
                 "module m { uses p.C.Inner; }",
@@ -81,7 +82,7 @@
     }
 
     @Test
-    void testSimpleAnnotation(Path base) throws Exception {
+    public void testSimpleAnnotation(Path base) throws Exception {
         Path src = base.resolve("src");
         tb.writeJavaFiles(src,
                 "module m { uses p.C; }",
@@ -97,7 +98,7 @@
     }
 
     @Test
-    void testPrivateService(Path base) throws Exception {
+    public void testPrivateService(Path base) throws Exception {
         Path src = base.resolve("src");
         tb.writeJavaFiles(src,
                 "module m { uses p.C.A; uses p.C; }",
@@ -119,7 +120,7 @@
     }
 
     @Test
-    void testMulti(Path base) throws Exception {
+    public void testMulti(Path base) throws Exception {
         Path src = base.resolve("src");
         tb.writeJavaFiles(src.resolve("m1"),
                 "module m1 { exports p; }",
@@ -138,13 +139,13 @@
     }
 
     @Test
-    void testMultiOnModulePath(Path base) throws Exception {
+    public void testMultiOnModulePath(Path base) throws Exception {
         Path modules = base.resolve("modules");
-        new ModuleBuilder("m1")
+        new ModuleBuilder(tb, "m1")
                 .exports("p")
                 .classes("package p; public class C { }")
                 .build(modules);
-        new ModuleBuilder("m2")
+        new ModuleBuilder(tb, "m2")
                 .requires("m1")
                 .uses("p.C")
                 .write(modules);
@@ -158,13 +159,13 @@
     }
 
     @Test
-    void testMultiOnModulePathInner(Path base) throws Exception {
+    public void testMultiOnModulePathInner(Path base) throws Exception {
         Path modules = base.resolve("modules");
-        new ModuleBuilder("m1")
+        new ModuleBuilder(tb, "m1")
                 .exports("p")
                 .classes("package p; public class C { public class Inner { } }")
                 .build(modules);
-        new ModuleBuilder("m2")
+        new ModuleBuilder(tb, "m2")
                 .requires("m1")
                 .uses("p.C.Inner")
                 .write(modules);
@@ -178,7 +179,7 @@
     }
 
     @Test
-    void testDuplicateUses(Path base) throws Exception {
+    public void testDuplicateUses(Path base) throws Exception {
         Path src = base.resolve("src");
         tb.writeJavaFiles(src.resolve("m"),
                 "module m { uses p.C; uses p.C; }",
@@ -199,7 +200,7 @@
     }
 
     @Test
-    void testServiceNotExist(Path base) throws Exception {
+    public void testServiceNotExist(Path base) throws Exception {
         Path src = base.resolve("src");
         tb.writeJavaFiles(src,
                 "module m { uses p.NotExist; }",
@@ -220,7 +221,7 @@
     }
 
     @Test
-    void testUsesUnexportedService(Path base) throws Exception {
+    public void testUsesUnexportedService(Path base) throws Exception {
         Path src = base.resolve("src");
         tb.writeJavaFiles(src.resolve("m1"),
                 "module m1 { }",
@@ -244,7 +245,7 @@
     }
 
     @Test
-    void testUsesUnexportedButProvidedService(Path base) throws Exception {
+    public void testUsesUnexportedButProvidedService(Path base) throws Exception {
         Path src = base.resolve("src");
         tb.writeJavaFiles(src.resolve("m1"),
                 "module m1 { provides p.C with p.C; }",
--- a/langtools/test/tools/javac/modules/XModuleTest.java	Tue May 03 09:48:02 2016 -0700
+++ b/langtools/test/tools/javac/modules/XModuleTest.java	Tue May 03 12:25:20 2016 -0700
@@ -28,7 +28,7 @@
  * @modules
  *      jdk.compiler/com.sun.tools.javac.api
  *      jdk.compiler/com.sun.tools.javac.main
- * @build toolbox.ToolBox toolbox.JavacTask ModuleTestBase
+ * @build toolbox.ToolBox toolbox.JavacTask toolbox.ModuleBuilder ModuleTestBase
  * @run main XModuleTest
  */
 
@@ -37,7 +37,9 @@
 import java.util.List;
 
 import toolbox.JavacTask;
+import toolbox.ModuleBuilder;
 import toolbox.Task;
+import toolbox.TestRunner;
 import toolbox.ToolBox;
 
 public class XModuleTest extends ModuleTestBase {
@@ -47,7 +49,7 @@
     }
 
     @Test
-    void testCorrectXModule(Path base) throws Exception {
+    public void testCorrectXModule(Path base) throws Exception {
         //note: avoiding use of java.base, as that gets special handling on some places:
         Path src = base.resolve("src");
         tb.writeJavaFiles(src, "package javax.lang.model.element; public interface Extra extends Element { }");
@@ -67,7 +69,7 @@
     }
 
     @Test
-    void testSourcePath(Path base) throws Exception {
+    public void testSourcePath(Path base) throws Exception {
         //note: avoiding use of java.base, as that gets special handling on some places:
         Path src = base.resolve("src");
         tb.writeJavaFiles(src, "package javax.lang.model.element; public interface Extra extends Element, Other { }", "package javax.lang.model.element; interface Other { }");
@@ -87,7 +89,7 @@
     }
 
     @Test
-    void testClassPath(Path base) throws Exception {
+    public void testClassPath(Path base) throws Exception {
         Path cpSrc = base.resolve("cpSrc");
         tb.writeJavaFiles(cpSrc, "package p; public interface Other { }");
         Path cpClasses = base.resolve("cpClasses");
@@ -122,7 +124,7 @@
     }
 
     @Test
-    void testNoModuleInfoOnSourcePath(Path base) throws Exception {
+    public void testNoModuleInfoOnSourcePath(Path base) throws Exception {
         //note: avoiding use of java.base, as that gets special handling on some places:
         Path src = base.resolve("src");
         tb.writeJavaFiles(src,
@@ -147,7 +149,7 @@
     }
 
     @Test
-    void testNoModuleInfoInClassOutput(Path base) throws Exception {
+    public void testNoModuleInfoInClassOutput(Path base) throws Exception {
         //note: avoiding use of java.base, as that gets special handling on some places:
         Path srcMod = base.resolve("src-mod");
         tb.writeJavaFiles(srcMod,
@@ -187,7 +189,7 @@
     }
 
     @Test
-    void testModuleSourcePathXModule(Path base) throws Exception {
+    public void testModuleSourcePathXModule(Path base) throws Exception {
         //note: avoiding use of java.base, as that gets special handling on some places:
         Path src = base.resolve("src");
         tb.writeJavaFiles(src, "package javax.lang.model.element; public interface Extra extends Element { }");
@@ -210,7 +212,7 @@
     }
 
     @Test
-    void testXModuleTooMany(Path base) throws Exception {
+    public void testXModuleTooMany(Path base) throws Exception {
         //note: avoiding use of java.base, as that gets special handling on some places:
         Path src = base.resolve("src");
         tb.writeJavaFiles(src, "package javax.lang.model.element; public interface Extra extends Element { }");
@@ -234,9 +236,9 @@
     }
 
     @Test
-    void testWithModulePath(Path base) throws Exception {
+    public void testWithModulePath(Path base) throws Exception {
         Path module = base.resolve("modules");
-        new ModuleBuilder("m1")
+        new ModuleBuilder(tb, "m1")
                 .classes("package pkg1; public interface E { }")
                 .build(module);
 
@@ -251,7 +253,7 @@
                 .writeAll();
 
         //checks module bounds still exist
-        new ModuleBuilder("m2")
+        new ModuleBuilder(tb, "m2")
                 .classes("package pkg2; public interface D { }")
                 .build(module);
 
@@ -275,14 +277,14 @@
     }
 
     @Test
-    void testWithUpgradeModulePath(Path base) throws Exception {
+    public void testWithUpgradeModulePath(Path base) throws Exception {
         Path module = base.resolve("modules");
-        new ModuleBuilder("m1")
+        new ModuleBuilder(tb, "m1")
                 .classes("package pkg1; public interface E { }")
                 .build(module);
 
         Path upgrade = base.resolve("upgrade");
-        new ModuleBuilder("m1")
+        new ModuleBuilder(tb, "m1")
                 .classes("package pkg1; public interface D { }")
                 .build(upgrade);
 
--- a/langtools/test/tools/lib/toolbox/JavacTask.java	Tue May 03 09:48:02 2016 -0700
+++ b/langtools/test/tools/lib/toolbox/JavacTask.java	Tue May 03 12:25:20 2016 -0700
@@ -103,6 +103,16 @@
     }
 
     /**
+     * Sets the classpath.
+     * @param classpath the classpath
+     * @return this task object
+     */
+    public JavacTask classpath(List<Path> classpath) {
+        this.classpath = classpath;
+        return this;
+    }
+
+    /**
      * Sets the sourcepath.
      * @param sourcepath the sourcepath
      * @return this task object
@@ -126,6 +136,16 @@
     }
 
     /**
+     * Sets the sourcepath.
+     * @param sourcepath the sourcepath
+     * @return this task object
+     */
+    public JavacTask sourcepath(List<Path> sourcepath) {
+        this.sourcepath = sourcepath;
+        return this;
+    }
+
+    /**
      * Sets the output directory.
      * @param outdir the output directory
      * @return this task object
@@ -188,6 +208,18 @@
     }
 
     /**
+     * Sets the files to be compiled or analyzed.
+     * @param files the files
+     * @return this task object
+     */
+    public JavacTask files(List<Path> files) {
+        this.files = files.stream()
+                .map(Path::toString)
+                .collect(Collectors.toList());
+        return this;
+    }
+
+    /**
      * Sets the sources to be compiled or analyzed.
      * Each source string is converted into an in-memory object that
      * can be passed directly to the compiler.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/lib/toolbox/ModuleBuilder.java	Tue May 03 12:25:20 2016 -0700
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package toolbox;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+public class ModuleBuilder {
+
+    private final ToolBox tb;
+    private final String name;
+    private String requires = "";
+    private String exports = "";
+    private String uses = "";
+    private String provides = "";
+    private String modulePath = "";
+    private List<String> content = new ArrayList<>();
+
+    public ModuleBuilder(ToolBox tb, String name) {
+        this.tb = tb;
+        this.name = name;
+    }
+
+    public ModuleBuilder requiresPublic(String requires, Path... modulePath) {
+        return requires("public " + requires, modulePath);
+    }
+
+    public ModuleBuilder requires(String requires, Path... modulePath) {
+        this.requires += "    requires " + requires + ";\n";
+        this.modulePath += Arrays.stream(modulePath)
+                .map(Path::toString)
+                .collect(Collectors.joining(File.pathSeparator));
+        return this;
+    }
+
+    public ModuleBuilder exportsTo(String pkg, String module) {
+        return exports(pkg + " to " + module);
+    }
+
+    public ModuleBuilder exports(String pkg) {
+        this.exports += "    exports " + pkg + ";\n";
+        return this;
+    }
+
+    public ModuleBuilder uses(String uses) {
+        this.uses += "    uses " + uses + ";\n";
+        return this;
+    }
+
+    public ModuleBuilder provides(String service, String implementation) {
+        this.provides += "    provides " + service + " with " + implementation + ";\n";
+        return this;
+    }
+
+    public ModuleBuilder classes(String... content) {
+        this.content.addAll(Arrays.asList(content));
+        return this;
+    }
+
+    public Path write(Path where) throws IOException {
+        Files.createDirectories(where);
+        List<String> sources = new ArrayList<>();
+        sources.add("module " + name + "{"
+                + requires
+                + exports
+                + uses
+                + provides
+                + "}");
+        sources.addAll(content);
+        Path moduleSrc = where.resolve(name + "/src");
+        tb.writeJavaFiles(moduleSrc, sources.toArray(new String[]{}));
+        return moduleSrc;
+    }
+
+    public void build(Path where) throws IOException {
+        Path moduleSrc = write(where);
+        new JavacTask(tb)
+                .outdir(where.resolve(name))
+                .options("-mp", modulePath)
+                .files(tb.findJavaFiles(moduleSrc))
+                .run()
+                .writeAll();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/lib/toolbox/TestRunner.java	Tue May 03 12:25:20 2016 -0700
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package toolbox;
+
+import java.io.PrintStream;
+import java.lang.annotation.Annotation;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.function.Function;
+
+/**
+ * Utility class to manage and execute sub-tests within a test.
+ *
+ * This class does the following:
+ * <ul>
+ * <li>  invokes those test methods annotated with @Test
+ * <li>  keeps track of successful and failed tests
+ * <li>  throws an Exception if any test fails.
+ * <li>  provides a test summary at the end of the run.
+ * </ul>
+
+ * Tests must extend this class, annotate the test methods
+ * with @Test and call one of the runTests method.
+ */
+public abstract class TestRunner {
+   /** Marker annotation for test cases. */
+    @Retention(RetentionPolicy.RUNTIME)
+    public @interface Test { }
+
+    int testCount = 0;
+    int errorCount = 0;
+
+    public String testName = null;
+
+    protected PrintStream out;
+
+    /**
+     * Constructs the Object.
+     * @param out the PrintStream to print output to.
+     */
+    public TestRunner(PrintStream out) {
+        this.out = out;
+    }
+
+    /**
+     * Invoke all methods annotated with @Test.
+     * @throws java.lang.Exception if any errors occur
+     */
+    protected void runTests() throws Exception {
+        runTests(f -> new Object[0]);
+    }
+
+    /**
+     * Invoke all methods annotated with @Test.
+     * @param f a lambda expression to specify arguments for the test method
+     * @throws java.lang.Exception if any errors occur
+     */
+    protected void runTests(Function<Method, Object[]> f) throws Exception {
+        for (Method m : getClass().getDeclaredMethods()) {
+            Annotation a = m.getAnnotation(Test.class);
+            if (a != null) {
+                testName = m.getName();
+                try {
+                    testCount++;
+                    out.println("test: " + testName);
+                    m.invoke(this, f.apply(m));
+                } catch (InvocationTargetException e) {
+                    errorCount++;
+                    Throwable cause = e.getCause();
+                    out.println("Exception: " + e.getCause());
+                    cause.printStackTrace(out);
+                }
+                out.println();
+            }
+        }
+
+        if (testCount == 0) {
+            throw new Error("no tests found");
+        }
+
+        StringBuilder summary = new StringBuilder();
+        if (testCount != 1) {
+            summary.append(testCount).append(" tests");
+        }
+        if (errorCount > 0) {
+            if (summary.length() > 0) {
+                summary.append(", ");
+            }
+            summary.append(errorCount).append(" errors");
+        }
+        out.println(summary);
+        if (errorCount > 0) {
+            throw new Exception(errorCount + " errors found");
+        }
+    }
+}
--- a/langtools/test/tools/lib/toolbox/ToolBox.java	Tue May 03 09:48:02 2016 -0700
+++ b/langtools/test/tools/lib/toolbox/ToolBox.java	Tue May 03 12:25:20 2016 -0700
@@ -41,6 +41,7 @@
 import java.nio.file.SimpleFileVisitor;
 import java.nio.file.StandardCopyOption;
 import java.nio.file.attribute.BasicFileAttributes;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
@@ -49,6 +50,7 @@
 import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
+import java.util.TreeSet;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 import java.util.stream.Collectors;
@@ -315,7 +317,7 @@
      * Reads the lines of a file.
      * The file is read using the default character encoding.
      * @param path the file to be read
-     * @return the lines of the file.
+     * @return the lines of the file
      * @throws IOException if an error occurred while reading the file
      */
     public List<String> readAllLines(String path) throws IOException {
@@ -326,7 +328,7 @@
      * Reads the lines of a file.
      * The file is read using the default character encoding.
      * @param path the file to be read
-     * @return the lines of the file.
+     * @return the lines of the file
      * @throws IOException if an error occurred while reading the file
      */
     public List<String> readAllLines(Path path) throws IOException {
@@ -348,7 +350,7 @@
      * Reads the lines of a file using the given encoding.
      * @param path the file to be read
      * @param encoding the encoding to be used to read the file
-     * @return the lines of the file.
+     * @return the lines of the file
      * @throws IOException if an error occurred while reading the file
      */
     public List<String> readAllLines(Path path, String encoding) throws IOException {
@@ -360,6 +362,30 @@
     }
 
     /**
+     * Find .java files in one or more directories.
+     * <p>Similar to the shell "find" command: {@code find paths -name \*.java}.
+     * @param paths the directories in which to search for .java files
+     * @return the .java files found
+     * @throws IOException if an error occurred while searching for files
+     */
+    public Path[] findJavaFiles(Path... paths) throws IOException {
+        Set<Path> files = new TreeSet<>();  // use TreeSet to force a consistent order
+        for (Path p : paths) {
+            Files.walkFileTree(p, new SimpleFileVisitor<Path>() {
+                @Override
+                public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
+                        throws IOException {
+                    if (file.getFileName().toString().endsWith(".java")) {
+                        files.add(file);
+                    }
+                    return FileVisitResult.CONTINUE;
+                }
+            });
+        }
+        return files.toArray(new Path[files.size()]);
+    }
+
+    /**
      * Writes a file containing the given content.
      * Any necessary directories for the file will be created.
      * @param path where to write the file
--- a/make/CompileJavaModules.gmk	Tue May 03 09:48:02 2016 -0700
+++ b/make/CompileJavaModules.gmk	Tue May 03 12:25:20 2016 -0700
@@ -99,7 +99,7 @@
 ################################################################################
 
 java.desktop_ADD_JAVAC_FLAGS := -Xdoclint:all/protected,-reference \
-    '-Xdoclint/package:java.*,javax.*' -Xlint:-deprecation
+    '-Xdoclint/package:java.*,javax.*'
 java.desktop_COPY := .gif .png .wav .txt .xml .css .pf
 java.desktop_CLEAN := iio-plugin.properties cursors.properties
 
--- a/make/CreateJmods.gmk	Tue May 03 09:48:02 2016 -0700
+++ b/make/CreateJmods.gmk	Tue May 03 12:25:20 2016 -0700
@@ -82,7 +82,7 @@
             --os-version $(REQUIRED_OS_VERSION) \
 	    --modulepath $(IMAGES_OUTPUTDIR)/jmods\
             --hash-dependencies '.*' \
-            --exclude '**_the.*' \
+            --exclude '**{_the.*,*.diz,*.debuginfo,*.dSYM/**,*.pdb,*.map}' \
 	    $(JMOD_FLAGS) $(SUPPORT_OUTPUTDIR)/jmods/$(notdir $@)
 	$(MV) $(SUPPORT_OUTPUTDIR)/jmods/$(notdir $@) $@
 
--- a/make/GensrcModuleInfo.gmk	Tue May 03 09:48:02 2016 -0700
+++ b/make/GensrcModuleInfo.gmk	Tue May 03 12:25:20 2016 -0700
@@ -78,21 +78,30 @@
   # let space represent new lines in the variable as $(shell) normalizes all
   # whitespace.
   $(foreach f, $(MOD_FILES), \
-    $(eval MOD_FILE_CONTENTS += $(shell $(GREP) -v ".\*" $f | $(TR) ' ' '/')))
+    $(eval MOD_FILE_CONTENTS += $(shell $(GREP) -v -e ".\*" -e "//" $f | $(TR) ' ' '/')))
+
+  # Separate the modifications into qualified exports and the rest
+  MODS_QUALIFIED_EXPORTS := $(call containing, /to/, $(MOD_FILE_CONTENTS))
+  MODS_REST := $(filter-out $(MODS_QUALIFIED_EXPORTS), $(MOD_FILE_CONTENTS))
 
   # Filter the contents for modules that are actually being built
   MODULES_FILTER := $(addprefix %/, $(addsuffix ;, $(ALL_MODULES)))
-  MODULES_FILTER += provides%
-  MODIFICATIONS := $(filter $(MODULES_FILTER), $(MOD_FILE_CONTENTS))
+  MODIFICATIONS := $(filter $(MODULES_FILTER), $(MODS_QUALIFIED_EXPORTS)) \
+      $(MODS_REST)
 
   # Convert the modification lines into arguments for the modification tool.
   # Filter out modifications for non existing to-modules.
   $(foreach line, $(MODIFICATIONS), \
     $(eval split_line := $(subst /,$(SPACE),$(line))) \
     $(eval command := $(word 1, $(split_line))) \
-    $(eval package := $(word 2, $(split_line))) \
+    $(eval package := $(patsubst %;,%,$(word 2, $(split_line)))) \
     $(eval to_module := $(patsubst %;,%,$(word 4, $(split_line)))) \
-    $(eval ARGS += -$(command) $(package)/$(to_module)))
+    $(if $(to_module), \
+      $(eval ARGS += -$(command) $(package)/$(to_module)) \
+    , \
+      $(eval ARGS += -$(command) $(package)) \
+    ) \
+  )
 
   ifneq ($(ARGS), )
     $(SUPPORT_OUTPUTDIR)/gensrc/$(MODULE)/module-info.java: \
--- a/make/Images.gmk	Tue May 03 09:48:02 2016 -0700
+++ b/make/Images.gmk	Tue May 03 12:25:20 2016 -0700
@@ -423,6 +423,55 @@
 endif
 
 ################################################################################
+# Debug symbols
+# Since debug symbols are not included in the jmod files, they need to be copied
+# in manually after generating the images.
+
+ALL_JDK_MODULES := $(JDK_MODULES)
+ALL_JRE_MODULES := $(sort $(JRE_MODULES), $(foreach m, $(JRE_MODULES), \
+    $(call FindTransitiveDepsForModule, $m)))
+
+ifeq ($(OPENJDK_TARGET_OS), windows)
+  LIBS_TARGET_SUBDIR := bin
+else
+  LIBS_TARGET_SUBDIR := lib
+endif
+
+DEBUGINFO_SUFFIXES := .diz .debuginfo .pdb .map
+
+# Param 1 - dir to find debuginfo files in
+FindDebuginfoFiles = \
+    $(wildcard $(addprefix $1/*, $(DEBUGINFO_SUFFIXES)) \
+        $(addprefix $1/*/*, $(DEBUGINFO_SUFFIXES)) \
+        $(addprefix $1/*/*/*, $(DEBUGINFO_SUFFIXES)))
+
+# On Macosx, if debug symbols have not been zipped, find all files inside *.dSYM
+# dirs.
+ifeq ($(OPENJDK_TARGET_OS)-$(ZIP_EXTERNAL_DEBUG_SYMBOLS), macosx-false)
+  $(eval $(call FillCacheFind, \
+      $(SUPPORT_OUTPUTDIR)/modules_cmds $(SUPPORT_OUTPUTDIR)/modules_libs/))
+  FindDebuginfoFiles = \
+      $(if $(wildcard $1), $(call containing, .dSYM/, $(call CacheFind, $1)))
+endif
+
+# Param 1 - either JDK or JRE
+SetupCopyDebuginfo = \
+    $(foreach m, $(ALL_$1_MODULES), \
+      $(eval $(call SetupCopyFiles, COPY_$1_LIBS_DEBUGINFO_$m, \
+          SRC := $(SUPPORT_OUTPUTDIR)/modules_libs/$m, \
+          DEST := $($1_IMAGE_DIR)/$(LIBS_TARGET_SUBDIR), \
+          FILES := $(call FindDebuginfoFiles, \
+              $(SUPPORT_OUTPUTDIR)/modules_libs/$m), \
+      )) \
+      $(eval $1_TARGETS += $$(COPY_$1_LIBS_DEBUGINFO_$m)) \
+    )
+
+# No space before argument to avoid having to put $(strip ) everywhere in
+# implementation above.
+$(call SetupCopyDebuginfo,JDK)
+$(call SetupCopyDebuginfo,JRE)
+
+################################################################################
 
 # Include custom post hook here to make it possible to augment the target lists
 # before actual target prerequisites are declared.
--- a/make/Init.gmk	Tue May 03 09:48:02 2016 -0700
+++ b/make/Init.gmk	Tue May 03 12:25:20 2016 -0700
@@ -268,8 +268,13 @@
   ##############################################################################
 
   MAIN_TARGETS := $(SEQUENTIAL_TARGETS) $(PARALLEL_TARGETS) $(COMPARE_BUILD_MAKE)
+  # If building the default target, add what they are to the description.
+  DESCRIPTION_TARGETS := $(strip $(MAIN_TARGETS))
+  ifeq ($(DESCRIPTION_TARGETS), default)
+    DESCRIPTION_TARGETS += ($(DEFAULT_MAKE_TARGET))
+  endif
   TARGET_DESCRIPTION := target$(if $(word 2, $(MAIN_TARGETS)),s) \
-      '$(strip $(MAIN_TARGETS))' in configuration '$(CONF_NAME)'
+      '$(strip $(DESCRIPTION_TARGETS))' in configuration '$(CONF_NAME)'
 
   # MAKEOVERRIDES is automatically set and propagated by Make to sub-Make calls.
   # We need to clear it of the init-specific variables. The user-specified
--- a/make/Javadoc.gmk	Tue May 03 09:48:02 2016 -0700
+++ b/make/Javadoc.gmk	Tue May 03 12:25:20 2016 -0700
@@ -1580,7 +1580,7 @@
 JDKNET_PACKAGES_FILE = $(DOCSTMPDIR)/jdknet.packages
 
 # The modules required to be documented
-JDKNET_MODULES = java.base
+JDKNET_MODULES = jdk.net
 
 jdknetdocs: $(JDKNET_INDEX_HTML)
 
--- a/make/Jprt.gmk	Tue May 03 09:48:02 2016 -0700
+++ b/make/Jprt.gmk	Tue May 03 12:25:20 2016 -0700
@@ -108,8 +108,8 @@
 SRC_JRE_MACOSX_BUNDLE_DIR := $(JRE_MACOSX_BUNDLE_DIR)
 
 # Bundle up the images
-JPRT_TARGET ?= all
-ifeq ($(JPRT_TARGET), all)
+JPRT_TARGET ?= default
+ifeq ($(JPRT_TARGET), default)
   bundles: $(JPRT_TARGET)
 	@$(call TargetEnter)
 	$(MKDIR) -p $(BUILD_OUTPUT)/bundles
--- a/make/Main.gmk	Tue May 03 09:48:02 2016 -0700
+++ b/make/Main.gmk	Tue May 03 12:25:20 2016 -0700
@@ -340,10 +340,10 @@
 docs-jvmtidoc:
 	+($(CD) $(SRC_ROOT)/make && $(MAKE) $(MAKE_ARGS) -f Javadoc.gmk jvmtidocs)
 
-zip-docs: docs-javadoc docs-jvmtidoc
+zip-docs:
 	+($(CD) $(SRC_ROOT)/make && $(MAKE) $(MAKE_ARGS) -f Javadoc.gmk zip-docs)
 
-ALL_TARGETS += docs-javadoc docs-jvmtidoc
+ALL_TARGETS += docs-javadoc docs-jvmtidoc zip-docs
 
 ################################################################################
 # Cross compilation support
@@ -602,6 +602,8 @@
 
   docs-jvmtidoc: hotspot
 
+  zip-docs: docs-javadoc docs-jvmtidoc
+
   test: jimages test-image
 
   create-buildjdk-copy: jdk.jlink-java java.base-gendata
@@ -703,7 +705,7 @@
 endif
 
 # This target builds the documentation image
-docs-image: zip-docs
+docs-image: docs-javadoc docs-jvmtidoc
 
 # This target builds the test image
 test-image: prepare-test-image test-image-hotspot-jtreg-native \
@@ -727,7 +729,7 @@
 docs: docs-image
 all: all-images
 
-ALL_TARGETS += default jdk images docs all zip-docs
+ALL_TARGETS += default jdk images docs all
 
 ################################################################################
 ################################################################################
@@ -829,6 +831,10 @@
 
 ################################################################################
 
+
+# workaround issue when building open targets when closed jib-profiles.js is used
+installer: product-images test-image
+
 .PHONY: $(ALL_TARGETS)
 
 FRC: # Force target
--- a/make/common/Modules.gmk	Tue May 03 09:48:02 2016 -0700
+++ b/make/common/Modules.gmk	Tue May 03 12:25:20 2016 -0700
@@ -63,6 +63,7 @@
     java.xml.crypto \
     jdk.httpserver \
     jdk.management \
+    jdk.net \
     jdk.sctp \
     jdk.security.auth \
     jdk.security.jgss \
@@ -185,7 +186,8 @@
     $(call GetModuleNameFromModuleInfo, $(MODULE_INFOS))))
 
 FindImportedModules = \
-    $(if $(IMPORT_MODULES_CLASSES), $(notdir $(wildcard $(IMPORT_MODULES_CLASSES)/*)))
+    $(filter-out $(MODULES_FILTER), \
+    $(if $(IMPORT_MODULES_CLASSES), $(notdir $(wildcard $(IMPORT_MODULES_CLASSES)/*))))
 
 # Find all source dirs for a particular module
 # $1 - Module to find source dirs for
--- a/nashorn/.hgtags	Tue May 03 09:48:02 2016 -0700
+++ b/nashorn/.hgtags	Tue May 03 12:25:20 2016 -0700
@@ -349,3 +349,4 @@
 a5d1990fd32d908da8154d79116fce8013ba4d40 jdk-9+113
 ba21793a0e4816283cc0ecdab5142a4959363529 jdk-9+114
 295ac208a4443d433214d0c1f32d2ea45a3a32d2 jdk-9+115
+208388a5622dcca8227d6ad6c268f2c88087d283 jdk-9+116
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGenerator.java	Tue May 03 09:48:02 2016 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CodeGenerator.java	Tue May 03 12:25:20 2016 -0700
@@ -4310,7 +4310,7 @@
      * @param ident identifier for block or function where applicable
      */
     private void printSymbols(final Block block, final FunctionNode function, final String ident) {
-        if (compiler.getScriptEnvironment()._print_symbols || function.getFlag(FunctionNode.IS_PRINT_SYMBOLS)) {
+        if (compiler.getScriptEnvironment()._print_symbols || function.getDebugFlag(FunctionNode.DEBUG_PRINT_SYMBOLS)) {
             final PrintWriter out = compiler.getScriptEnvironment().getErr();
             out.println("[BLOCK in '" + ident + "']");
             if (!block.printSymbols(out)) {
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CompilationPhase.java	Tue May 03 09:48:02 2016 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CompilationPhase.java	Tue May 03 12:25:20 2016 -0700
@@ -278,12 +278,12 @@
             final PrintWriter       err  = senv.getErr();
 
             //TODO separate phase for the debug printouts for abstraction and clarity
-            if (senv._print_lower_ast || fn.getFlag(FunctionNode.IS_PRINT_LOWER_AST)) {
+            if (senv._print_lower_ast || fn.getDebugFlag(FunctionNode.DEBUG_PRINT_LOWER_AST)) {
                 err.println("Lower AST for: " + quote(newFunctionNode.getName()));
                 err.println(new ASTWriter(newFunctionNode));
             }
 
-            if (senv._print_lower_parse || fn.getFlag(FunctionNode.IS_PRINT_LOWER_PARSE)) {
+            if (senv._print_lower_parse || fn.getDebugFlag(FunctionNode.DEBUG_PRINT_LOWER_PARSE)) {
                 err.println("Lower AST for: " + quote(newFunctionNode.getName()));
                 err.println(new PrintVisitor(newFunctionNode));
             }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/SplitIntoFunctions.java	Tue May 03 09:48:02 2016 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/SplitIntoFunctions.java	Tue May 03 12:25:20 2016 -0700
@@ -175,7 +175,9 @@
                 // we still use IS_SPLIT as the criteria in CompilationPhase.SERIALIZE_SPLIT_PHASE.
                 FunctionNode.IS_ANONYMOUS | FunctionNode.USES_ANCESTOR_SCOPE | FunctionNode.IS_SPLIT,
                 body,
-                null
+                null,
+                originalFn.getModule(),
+                originalFn.getDebugFlags()
         )
         .setCompileUnit(lc, splitNode.getCompileUnit());
 
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/WeighNodes.java	Tue May 03 09:48:02 2016 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/WeighNodes.java	Tue May 03 12:25:20 2016 -0700
@@ -435,7 +435,7 @@
     }
 
     @Override
-    public Node leaveBIND(final BinaryNode binaryNode) {
+    public Node leaveARROW(final BinaryNode binaryNode) {
         return binaryNodeWeight(binaryNode);
     }
 
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/AccessNode.java	Tue May 03 09:48:02 2016 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/AccessNode.java	Tue May 03 12:25:20 2016 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -48,12 +48,13 @@
      * @param property  property
      */
     public AccessNode(final long token, final int finish, final Expression base, final String property) {
-        super(token, finish, base, false);
+        super(token, finish, base, false, false);
         this.property = property;
     }
 
-    private AccessNode(final AccessNode accessNode, final Expression base, final String property, final boolean isFunction, final Type type, final int id) {
-        super(accessNode, base, isFunction, type, id);
+    private AccessNode(final AccessNode accessNode, final Expression base, final String property, final boolean isFunction,
+                       final Type type, final int id, final boolean isSuper) {
+        super(accessNode, base, isFunction, type, id, isSuper);
         this.property = property;
     }
 
@@ -105,7 +106,7 @@
         if (this.base == base) {
             return this;
         }
-        return new AccessNode(this, base, property, isFunction(), type, programPoint);
+        return new AccessNode(this, base, property, isFunction(), type, programPoint, isSuper());
     }
 
     @Override
@@ -113,7 +114,7 @@
         if (this.type == type) {
             return this;
         }
-        return new AccessNode(this, base, property, isFunction(), type, programPoint);
+        return new AccessNode(this, base, property, isFunction(), type, programPoint, isSuper());
     }
 
     @Override
@@ -121,7 +122,7 @@
         if (this.programPoint == programPoint) {
             return this;
         }
-        return new AccessNode(this, base, property, isFunction(), type, programPoint);
+        return new AccessNode(this, base, property, isFunction(), type, programPoint, isSuper());
     }
 
     @Override
@@ -129,6 +130,14 @@
         if (isFunction()) {
             return this;
         }
-        return new AccessNode(this, base, property, true, type, programPoint);
+        return new AccessNode(this, base, property, true, type, programPoint, isSuper());
+    }
+
+    @Override
+    public AccessNode setIsSuper() {
+        if (isSuper()) {
+            return this;
+        }
+        return new AccessNode(this, base, property, isFunction(), type, programPoint, true);
     }
 }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/BaseNode.java	Tue May 03 09:48:02 2016 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/BaseNode.java	Tue May 03 12:25:20 2016 -0700
@@ -52,6 +52,9 @@
     /** Program point id */
     protected final int programPoint;
 
+    /** Super property access. */
+    private final boolean isSuper;
+
     /**
      * Constructor
      *
@@ -59,13 +62,15 @@
      * @param finish finish
      * @param base   base node
      * @param isFunction is this a function
+     * @param isSuper is this a super property access
      */
-    public BaseNode(final long token, final int finish, final Expression base, final boolean isFunction) {
+    public BaseNode(final long token, final int finish, final Expression base, final boolean isFunction, final boolean isSuper) {
         super(token, base.getStart(), finish);
         this.base           = base;
         this.isFunction     = isFunction;
         this.type = null;
         this.programPoint   = INVALID_PROGRAM_POINT;
+        this.isSuper        = isSuper;
     }
 
     /**
@@ -75,13 +80,15 @@
      * @param isFunction is this a function
      * @param callSiteType  the callsite type for this base node, either optimistic or conservative
      * @param programPoint  program point id
+     * @param isSuper is this a super property access
      */
-    protected BaseNode(final BaseNode baseNode, final Expression base, final boolean isFunction, final Type callSiteType, final int programPoint) {
+    protected BaseNode(final BaseNode baseNode, final Expression base, final boolean isFunction, final Type callSiteType, final int programPoint, final boolean isSuper) {
         super(baseNode);
         this.base           = base;
         this.isFunction     = isFunction;
         this.type = callSiteType;
         this.programPoint   = programPoint;
+        this.isSuper        = isSuper;
     }
 
     /**
@@ -136,4 +143,17 @@
      */
     public abstract BaseNode setIsFunction();
 
+    /**
+     * @return {@code true} if a SuperProperty access.
+     */
+    public boolean isSuper() {
+        return isSuper;
+    }
+
+    /**
+     * Mark this node as being a SuperProperty access.
+     *
+     * @return  a base node identical to this one in all aspects except with its super flag set.
+     */
+    public abstract BaseNode setIsSuper();
 }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/Block.java	Tue May 03 09:48:02 2016 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/Block.java	Tue May 03 12:25:20 2016 -0700
@@ -65,24 +65,39 @@
     private final LocalVariableConversion conversion;
 
     /** Flag indicating that this block needs scope */
-    public static final int NEEDS_SCOPE = 1 << 0;
+    public static final int NEEDS_SCOPE        = 1 << 0;
 
     /**
      * Is this block tagged as terminal based on its contents
      * (usually the last statement)
      */
-    public static final int IS_TERMINAL = 1 << 2;
+    public static final int IS_TERMINAL        = 1 << 2;
 
     /**
      * Is this block the eager global scope - i.e. the original program. This isn't true for the
      * outermost level of recompiles
      */
-    public static final int IS_GLOBAL_SCOPE = 1 << 3;
+    public static final int IS_GLOBAL_SCOPE    = 1 << 3;
 
     /**
      * Is this block a synthetic one introduced by Parser?
      */
-    public static final int IS_SYNTHETIC = 1 << 4;
+    public static final int IS_SYNTHETIC       = 1 << 4;
+
+    /**
+     * Is this the function body block? May not be the first, if parameter list contains expressions.
+     */
+    public static final int IS_BODY            = 1 << 5;
+
+    /**
+     * Is this the parameter initialization block? If present, must be the first block, immediately wrapping the function body block.
+     */
+    public static final int IS_PARAMETER_BLOCK = 1 << 6;
+
+    /**
+     * Marks the variable declaration block for case clauses of a switch statement.
+     */
+    public static final int IS_SWITCH_BLOCK    = 1 << 7;
 
     /**
      * Constructor
@@ -489,4 +504,31 @@
     public Node accept(final NodeVisitor<? extends LexicalContext> visitor) {
         return Acceptor.accept(this, visitor);
     }
+
+    /**
+     * Checks if this is a function body.
+     *
+     * @return true if the function body flag is set
+     */
+    public boolean isFunctionBody() {
+        return getFlag(IS_BODY);
+    }
+
+    /**
+     * Checks if this is a parameter block.
+     *
+     * @return true if the parameter block flag is set
+     */
+    public boolean isParameterBlock() {
+        return getFlag(IS_PARAMETER_BLOCK);
+    }
+
+    /**
+     * Checks whether this is a switch block.
+     *
+     * @return true if this is a switch block
+     */
+    public boolean isSwitchBlock() {
+        return getFlag(IS_SWITCH_BLOCK);
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/ClassNode.java	Tue May 03 12:25:20 2016 -0700
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.nashorn.internal.ir;
+
+import java.util.Collections;
+import java.util.List;
+
+import jdk.nashorn.internal.codegen.types.Type;
+import jdk.nashorn.internal.ir.visitor.NodeVisitor;
+
+/**
+ * IR representation for class definitions.
+ */
+public class ClassNode extends Expression {
+    private static final long serialVersionUID = 1L;
+
+    private final IdentNode ident;
+    private final Expression classHeritage;
+    private final PropertyNode constructor;
+    private final List<PropertyNode> classElements;
+    private final int line;
+
+    /**
+     * Constructor.
+     *
+     * @param line line number
+     * @param token token
+     * @param finish finish
+     * @param ident ident
+     * @param classHeritage class heritage
+     * @param constructor constructor
+     * @param classElements class elements
+     */
+    public ClassNode(final int line, final long token, final int finish, final IdentNode ident, final Expression classHeritage, final PropertyNode constructor,
+                     final List<PropertyNode> classElements) {
+        super(token, finish);
+        this.line = line;
+        this.ident = ident;
+        this.classHeritage = classHeritage;
+        this.constructor = constructor;
+        this.classElements = classElements;
+    }
+
+    /**
+     * Class identifier. Optional.
+     *
+     * @return the class identifier
+     */
+    public IdentNode getIdent() {
+        return ident;
+    }
+
+    /**
+     * The expression of the {@code extends} clause. Optional.
+     *
+     * @return the class heritage
+     */
+    public Expression getClassHeritage() {
+        return classHeritage;
+    }
+
+    /**
+     * Get the constructor method definition.
+     *
+     * @return the constructor
+     */
+    public PropertyNode getConstructor() {
+        return constructor;
+    }
+
+    /**
+     * Get method definitions except the constructor.
+     *
+     * @return the class elements
+     */
+    public List<PropertyNode> getClassElements() {
+        return Collections.unmodifiableList(classElements);
+    }
+
+    /**
+     * Returns the line number.
+     *
+     * @return the line number
+     */
+    public int getLineNumber() {
+        return line;
+    }
+
+    @Override
+    public Type getType() {
+        return Type.OBJECT;
+    }
+
+    @Override
+    public Node accept(final NodeVisitor<? extends LexicalContext> visitor) {
+        if (visitor.enterClassNode(this)) {
+            return visitor.leaveClassNode(this);
+        }
+
+        return this;
+    }
+
+    @Override
+    public void toString(final StringBuilder sb, final boolean printType) {
+        sb.append("class");
+        if (ident != null) {
+            sb.append(' ');
+            ident.toString(sb, printType);
+        }
+        if (classHeritage != null) {
+            sb.append(" extends");
+            classHeritage.toString(sb, printType);
+        }
+        sb.append(" {");
+        if (constructor != null) {
+            constructor.toString(sb, printType);
+        }
+        for (final PropertyNode classElement : classElements) {
+            sb.append(" ");
+            classElement.toString(sb, printType);
+        }
+        sb.append("}");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/ExpressionList.java	Tue May 03 12:25:20 2016 -0700
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.nashorn.internal.ir;
+
+import java.util.Collections;
+import java.util.List;
+
+import jdk.nashorn.internal.codegen.types.Type;
+import jdk.nashorn.internal.ir.visitor.NodeVisitor;
+
+/**
+ * IR for CoverParenthesizedExpressionAndArrowParameterList, used only during parsing.
+ */
+public final class ExpressionList extends Expression {
+    private static final long serialVersionUID = 1L;
+
+    private final List<Expression> expressions;
+
+    /**
+     * Constructor.
+     *
+     * @param token token
+     * @param finish finish
+     * @param expressions expression
+     */
+    public ExpressionList(final long token, final int finish, final List<Expression> expressions) {
+        super(token, finish);
+        this.expressions = expressions;
+    }
+
+    /**
+     * Get the list of expressions.
+     *
+     * @return the list of expressions
+     */
+    public List<Expression> getExpressions() {
+        return Collections.unmodifiableList(expressions);
+    }
+
+    @Override
+    public Node accept(final NodeVisitor<? extends LexicalContext> visitor) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Type getType() {
+        return null;
+    }
+
+    @Override
+    public void toString(StringBuilder sb, boolean printType) {
+        sb.append("(");
+        boolean first = true;
+        for (Expression expression : expressions) {
+            if (first) {
+                first = false;
+            } else {
+                sb.append(", ");
+            }
+            expression.toString(sb, printType);
+        }
+        sb.append(")");
+    }
+}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/ForNode.java	Tue May 03 09:48:02 2016 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/ForNode.java	Tue May 03 12:25:20 2016 -0700
@@ -90,7 +90,6 @@
         this.init = init;
         this.modify = modify;
         this.iterator = null;
-
     }
 
     private ForNode(final ForNode forNode, final Expression init, final JoinPredecessorExpression test,
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/FunctionNode.java	Tue May 03 09:48:02 2016 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/FunctionNode.java	Tue May 03 12:25:20 2016 -0700
@@ -69,7 +69,13 @@
         /** a getter, @see {@link UserAccessorProperty} */
         GETTER,
         /** a setter, @see {@link UserAccessorProperty} */
-        SETTER
+        SETTER,
+        /** an arrow function */
+        ARROW,
+        /** a generator function */
+        GENERATOR,
+        /** a module function */
+        MODULE
     }
 
     /** Source of entity. */
@@ -122,6 +128,12 @@
     /** Root class for function */
     private final Class<?> rootClass;
 
+    /** The ES6 module */
+    private final Module module;
+
+    /** The debug flags */
+    private final int debugFlags;
+
     /** Is anonymous function flag. */
     public static final int IS_ANONYMOUS                = 1 << 0;
 
@@ -172,49 +184,21 @@
     /**
      * Is this function the top-level program?
      */
-    public static final int IS_PROGRAM = 1 << 13;
+    public static final int IS_PROGRAM                  = 1 << 13;
 
     /**
      * Flag indicating whether this function uses the local variable symbol for itself. Only named function expressions
      * can have this flag set if they reference themselves (e.g. "(function f() { return f })". Declared functions will
      * use the symbol in their parent scope instead when they reference themselves by name.
      */
-    public static final int USES_SELF_SYMBOL = 1 << 14;
+    public static final int USES_SELF_SYMBOL            = 1 << 14;
 
     /** Does this function use the "this" keyword? */
-    public static final int USES_THIS = 1 << 15;
+    public static final int USES_THIS                   = 1 << 15;
 
     /** Is this declared in a dynamic context */
-    public static final int IN_DYNAMIC_CONTEXT = 1 << 16;
-
-    /**
-     * The following flags are derived from directive comments within this function.
-     * Note that even IS_STRICT is one such flag but that requires special handling.
-     */
+    public static final int IN_DYNAMIC_CONTEXT          = 1 << 16;
 
-    /** parser, print parse tree */
-    public static final int IS_PRINT_PARSE       = 1 << 17;
-    /** parser, print lower parse tree */
-    public static final int IS_PRINT_LOWER_PARSE = 1 << 18;
-    /** parser, print AST */
-    public static final int IS_PRINT_AST         = 1 << 19;
-    /** parser, print lower AST */
-    public static final int IS_PRINT_LOWER_AST   = 1 << 20;
-    /** parser, print symbols */
-    public static final int IS_PRINT_SYMBOLS     = 1 << 21;
-
-    // callsite tracing, profiling within this function
-    /** profile callsites in this function? */
-    public static final int IS_PROFILE         = 1 << 22;
-
-    /** trace callsite enterexit in this function? */
-    public static final int IS_TRACE_ENTEREXIT = 1 << 23;
-
-    /** trace callsite misses in this function? */
-    public static final int IS_TRACE_MISSES    = 1 << 24;
-
-    /** trace callsite values in this function? */
-    public static final int IS_TRACE_VALUES    = 1 << 25;
 
     /**
      * Whether this function needs the callee {@link ScriptFunction} instance passed to its code as a
@@ -222,18 +206,41 @@
      * Rather, it is always calculated (see {@link #needsCallee()}). {@link RecompilableScriptFunctionData}
      * will, however, cache the value of this flag.
      */
-    public static final int NEEDS_CALLEE       = 1 << 26;
+    public static final int NEEDS_CALLEE                = 1 << 17;
 
     /**
      * Is the function node cached?
      */
-    public static final int IS_CACHED = 1 << 27;
+    public static final int IS_CACHED                   = 1 << 18;
+
+    /**
+     * Does this function contain a super call? (cf. ES6 14.3.5 Static Semantics: HasDirectSuper)
+     */
+    public static final int ES6_HAS_DIRECT_SUPER        = 1 << 19;
+
+    /**
+     * Does this function use the super binding?
+     */
+    public static final int ES6_USES_SUPER              = 1 << 20;
 
-    /** extension callsite flags mask */
-    public static final int EXTENSION_CALLSITE_FLAGS = IS_PRINT_PARSE |
-        IS_PRINT_LOWER_PARSE | IS_PRINT_AST | IS_PRINT_LOWER_AST |
-        IS_PRINT_SYMBOLS | IS_PROFILE | IS_TRACE_ENTEREXIT |
-        IS_TRACE_MISSES | IS_TRACE_VALUES;
+    /**
+     * Is this function a (class or object) method?
+     */
+    public static final int ES6_IS_METHOD               = 1 << 21;
+
+    /**
+     * Is this the constructor method?
+     */
+    public static final int ES6_IS_CLASS_CONSTRUCTOR    = 1 << 22;
+
+    /** Is this the constructor of a subclass (i.e., a class with an extends declaration)? */
+    public static final int ES6_IS_SUBCLASS_CONSTRUCTOR = 1 << 23;
+
+    /** is this a strong mode function? */
+    public static final int ES6_IS_STRONG               = 1 << 24;
+
+    /** Does this function use new.target? */
+    public static final int ES6_USES_NEW_TARGET         = 1 << 25;
 
     /** Does this function or any nested functions contain an eval? */
     private static final int HAS_DEEP_EVAL = HAS_EVAL | HAS_NESTED_EVAL;
@@ -247,8 +254,44 @@
     /** Does this function need the parent scope? It needs it if either it or its descendants use variables from it, or have a deep eval, or it's the program. */
     public static final int NEEDS_PARENT_SCOPE = USES_ANCESTOR_SCOPE | HAS_DEEP_EVAL | IS_PROGRAM;
 
+
+    /**
+     * The following flags are derived from directive comments within this function.
+     * Note that even IS_STRICT is one such flag but that requires special handling.
+     */
+
+    /** parser, print parse tree */
+    public static final int DEBUG_PRINT_PARSE       = 1 << 0;
+    /** parser, print lower parse tree */
+    public static final int DEBUG_PRINT_LOWER_PARSE = 1 << 1;
+    /** parser, print AST */
+    public static final int DEBUG_PRINT_AST         = 1 << 2;
+    /** parser, print lower AST */
+    public static final int DEBUG_PRINT_LOWER_AST   = 1 << 3;
+    /** parser, print symbols */
+    public static final int DEBUG_PRINT_SYMBOLS     = 1 << 4;
+
+    // callsite tracing, profiling within this function
+    /** profile callsites in this function? */
+    public static final int DEBUG_PROFILE           = 1 << 5;
+
+    /** trace callsite enterexit in this function? */
+    public static final int DEBUG_TRACE_ENTEREXIT   = 1 << 6;
+
+    /** trace callsite misses in this function? */
+    public static final int DEBUG_TRACE_MISSES      = 1 << 7;
+
+    /** trace callsite values in this function? */
+    public static final int DEBUG_TRACE_VALUES      = 1 << 8;
+
+    /** extension callsite flags mask */
+    public static final int DEBUG_CALLSITE_FLAGS = DEBUG_PRINT_PARSE |
+            DEBUG_PRINT_LOWER_PARSE | DEBUG_PRINT_AST | DEBUG_PRINT_LOWER_AST |
+            DEBUG_PRINT_SYMBOLS | DEBUG_PROFILE | DEBUG_TRACE_ENTEREXIT |
+            DEBUG_TRACE_MISSES | DEBUG_TRACE_VALUES;
+
     /** What is the return type of this function? */
-    private Type returnType = Type.UNKNOWN;
+    public Type returnType = Type.UNKNOWN;
 
     /**
      * Constructor
@@ -267,6 +310,8 @@
      * @param flags      initial flags
      * @param body       body of the function
      * @param endParserState The parser state at the end of the parsing.
+     * @param module     the module
+     * @param debugFlags the debug flags
      */
     public FunctionNode(
         final Source source,
@@ -282,7 +327,9 @@
         final FunctionNode.Kind kind,
         final int flags,
         final Block body,
-        final Object endParserState) {
+        final Object endParserState,
+        final Module module,
+        final int debugFlags) {
         super(token, finish);
 
         this.source           = source;
@@ -299,7 +346,9 @@
         this.body             = body;
         this.thisProperties   = 0;
         this.rootClass        = null;
-        this.endParserState    = endParserState;
+        this.endParserState   = endParserState;
+        this.module           = module;
+        this.debugFlags       = debugFlags;
     }
 
     private FunctionNode(
@@ -335,6 +384,8 @@
         this.ident           = functionNode.ident;
         this.kind            = functionNode.kind;
         this.firstToken      = functionNode.firstToken;
+        this.module          = functionNode.module;
+        this.debugFlags      = functionNode.debugFlags;
     }
 
     @Override
@@ -366,23 +417,23 @@
         }
 
         // quick check for extension callsite flags turned on by directives.
-        if ((flags & EXTENSION_CALLSITE_FLAGS) == 0) {
+        if ((debugFlags & DEBUG_CALLSITE_FLAGS) == 0) {
             return callsiteFlags;
         }
 
-        if (getFlag(IS_PROFILE)) {
+        if (getDebugFlag(DEBUG_PROFILE)) {
             callsiteFlags |= CALLSITE_PROFILE;
         }
 
-        if (getFlag(IS_TRACE_MISSES)) {
+        if (getDebugFlag(DEBUG_TRACE_MISSES)) {
             callsiteFlags |= CALLSITE_TRACE | CALLSITE_TRACE_MISSES;
         }
 
-        if (getFlag(IS_TRACE_VALUES)) {
+        if (getDebugFlag(DEBUG_TRACE_VALUES)) {
             callsiteFlags |= CALLSITE_TRACE | CALLSITE_TRACE_ENTEREXIT | CALLSITE_TRACE_VALUES;
         }
 
-        if (getFlag(IS_TRACE_ENTEREXIT)) {
+        if (getDebugFlag(DEBUG_TRACE_ENTEREXIT)) {
             callsiteFlags |= CALLSITE_TRACE | CALLSITE_TRACE_ENTEREXIT;
         }
 
@@ -466,23 +517,23 @@
     public static int getDirectiveFlag(final String directive) {
         switch (directive) {
             case "nashorn callsite trace enterexit":
-                return IS_TRACE_ENTEREXIT;
+                return DEBUG_TRACE_ENTEREXIT;
             case "nashorn callsite trace misses":
-                return IS_TRACE_MISSES;
+                return DEBUG_TRACE_MISSES;
             case "nashorn callsite trace objects":
-                return IS_TRACE_VALUES;
+                return DEBUG_TRACE_VALUES;
             case "nashorn callsite profile":
-                return IS_PROFILE;
+                return DEBUG_PROFILE;
             case "nashorn print parse":
-                return IS_PRINT_PARSE;
+                return DEBUG_PRINT_PARSE;
             case "nashorn print lower parse":
-                return IS_PRINT_LOWER_PARSE;
+                return DEBUG_PRINT_LOWER_PARSE;
             case "nashorn print ast":
-                return IS_PRINT_AST;
+                return DEBUG_PRINT_AST;
             case "nashorn print lower ast":
-                return IS_PRINT_LOWER_AST;
+                return DEBUG_PRINT_LOWER_AST;
             case "nashorn print symbols":
-                return IS_PRINT_SYMBOLS;
+                return DEBUG_PRINT_SYMBOLS;
             default:
                 // unknown/unsupported directive
                 return 0;
@@ -579,6 +630,25 @@
     }
 
     /**
+     * Returns the debug flags for this function.
+     *
+     * @return the debug flags
+     */
+    public int getDebugFlags() {
+        return debugFlags;
+    }
+
+    /**
+     * Checks whether a debug flag is set for this function.
+     *
+     * @param debugFlag the debug flag
+     * @return true if the flag is set
+     */
+    public boolean getDebugFlag(final int debugFlag) {
+        return (debugFlags & debugFlag) != 0;
+    }
+
+    /**
      * Returns true if the function is the top-level program.
      * @return True if this function node represents the top-level program.
      */
@@ -1065,6 +1135,86 @@
         return setFlag(lc, IS_CACHED);
     }
 
+    /**
+     * Checks if the function is generated in strong mode.
+     *
+     * @return true if strong mode enabled for function
+     */
+    public boolean isStrong() {
+        return getFlag(ES6_IS_STRONG);
+    }
+
+    /**
+     * Checks if this is an ES6 method.
+     *
+     * @return true if the ES6 method flag is set
+     */
+    public boolean isMethod() {
+        return getFlag(ES6_IS_METHOD);
+    }
+
+    /**
+     * Checks if this function uses the ES6 super binding.
+     *
+     * @return true if the ES6 super flag is set
+     */
+    public boolean usesSuper() {
+        return getFlag(ES6_USES_SUPER);
+    }
+
+    /**
+     * Checks if this function directly uses the super binding.
+     *
+     * @return true if the ES6 has-direct-super flag is set
+     */
+    public boolean hasDirectSuper() {
+        return getFlag(ES6_HAS_DIRECT_SUPER);
+    }
+
+    /**
+     * Checks if this is an ES6 class constructor.
+     *
+     * @return true if the ES6 class constructor flag is set
+     */
+    public boolean isClassConstructor() {
+        return getFlag(ES6_IS_CLASS_CONSTRUCTOR);
+    }
+
+    /**
+     * Checks if this is an ES6 subclass constructor.
+     *
+     * @return true if the ES6 subclass constructor flag is set
+     */
+    public boolean isSubclassConstructor() {
+        return getFlag(ES6_IS_SUBCLASS_CONSTRUCTOR);
+    }
+
+    /**
+     * Checks if this function uses the ES6 new-targert.
+     *
+     * @return true if the ES6 new-target flag is set
+     */
+    public boolean usesNewTarget() {
+        return getFlag(ES6_USES_NEW_TARGET);
+    }
+
+    /**
+     * Checks if this is an ES6 module.
+     *
+     * @return true if this is an ES6 module
+     */
+    public boolean isModule() {
+        return kind == Kind.MODULE;
+    }
+
+    /**
+     * Returns the functions's ES6 module.
+     *
+     * @return the module, or null if this function is not part of one
+     */
+    public Module getModule() {
+        return module;
+    }
 
     /**
      * Get the compile unit used to compile this function
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/IdentNode.java	Tue May 03 09:48:02 2016 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/IdentNode.java	Tue May 03 12:25:20 2016 -0700
@@ -49,6 +49,11 @@
     private static final int FUTURESTRICT_NAME = 1 << 3;
     private static final int IS_DECLARED_HERE  = 1 << 4;
     private static final int IS_DEAD           = 1 << 5;
+    private static final int DIRECT_SUPER      = 1 << 6;
+    private static final int REST_PARAMETER    = 1 << 7;
+    private static final int PROTO_PROPERTY    = 1 << 8;
+    private static final int DEFAULT_PARAMETER = 1 << 9;
+    private static final int DESTRUCTURED_PARAMETER = 1 << 10;
 
     /** Identifier. */
     private final String name;
@@ -382,4 +387,94 @@
     public LocalVariableConversion getLocalVariableConversion() {
         return conversion;
     }
+
+    /**
+     * Checks if this is a direct super identifier
+     *
+     * @return true if the direct super flag is set
+     */
+    public boolean isDirectSuper() {
+        return (flags & DIRECT_SUPER) != 0;
+    }
+
+    /**
+     * Return a new identifier with the direct super flag set.
+     *
+     * @return the new identifier
+     */
+    public IdentNode setIsDirectSuper() {
+        return new IdentNode(this, name, type, flags | DIRECT_SUPER, programPoint, conversion);
+    }
+
+    /**
+     * Checks if this is a rest parameter
+     *
+     * @return true if the rest parameter flag is set
+     */
+    public boolean isRestParameter() {
+        return (flags & REST_PARAMETER) != 0;
+    }
+
+    /**
+     * Return a new identifier with the rest parameter flag set.
+     *
+     * @return the new identifier
+     */
+    public IdentNode setIsRestParameter() {
+        return new IdentNode(this, name, type, flags | REST_PARAMETER, programPoint, conversion);
+    }
+
+    /**
+     * Checks if this is a proto property name.
+     *
+     * @return true if this is the proto property name
+     */
+    public boolean isProtoPropertyName() {
+        return (flags & PROTO_PROPERTY) != 0;
+    }
+
+    /**
+     * Return a new identifier with the proto property name flag set.
+     *
+     * @return the new identifier
+     */
+    public IdentNode setIsProtoPropertyName() {
+        return new IdentNode(this, name, type, flags | PROTO_PROPERTY, programPoint, conversion);
+    }
+
+    /**
+     * Checks whether this is a default parameter.
+     *
+     * @return true if this is a default parameter
+     */
+    public boolean isDefaultParameter() {
+        return (flags & DEFAULT_PARAMETER) != 0;
+    }
+
+    /**
+     * Return a new identifier with the default parameter flag set.
+     *
+     * @return the new identifier
+     */
+    public IdentNode setIsDefaultParameter() {
+        return new IdentNode(this, name, type, flags | DEFAULT_PARAMETER, programPoint, conversion);
+    }
+
+    /**
+     * Checks whether this is a destructured parameter.
+     *
+     * @return true if this is a destructured parameter
+     */
+    public boolean isDestructuredParameter() {
+        return (flags & DESTRUCTURED_PARAMETER) != 0;
+    }
+
+    /**
+     * Return a new identifier with the destructured parameter flag set.
+     *
+     * @return the new identifier
+     */
+    public IdentNode setIsDestructuredParameter() {
+        return new IdentNode(this, name, type, flags | DESTRUCTURED_PARAMETER, programPoint, conversion);
+    }
 }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/IndexNode.java	Tue May 03 09:48:02 2016 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/IndexNode.java	Tue May 03 12:25:20 2016 -0700
@@ -47,12 +47,13 @@
      * @param index   index for access
      */
     public IndexNode(final long token, final int finish, final Expression base, final Expression index) {
-        super(token, finish, base, false);
+        super(token, finish, base, false, false);
         this.index = index;
     }
 
-    private IndexNode(final IndexNode indexNode, final Expression base, final Expression index, final boolean isFunction, final Type type, final int programPoint) {
-        super(indexNode, base, isFunction, type, programPoint);
+    private IndexNode(final IndexNode indexNode, final Expression base, final Expression index, final boolean isFunction,
+                      final Type type, final int programPoint, final boolean isSuper) {
+        super(indexNode, base, isFunction, type, programPoint, isSuper);
         this.index = index;
     }
 
@@ -101,7 +102,7 @@
         if (this.base == base) {
             return this;
         }
-        return new IndexNode(this, base, index, isFunction(), type, programPoint);
+        return new IndexNode(this, base, index, isFunction(), type, programPoint, isSuper());
     }
 
     /**
@@ -113,7 +114,7 @@
         if(this.index == index) {
             return this;
         }
-        return new IndexNode(this, base, index, isFunction(), type, programPoint);
+        return new IndexNode(this, base, index, isFunction(), type, programPoint, isSuper());
     }
 
     @Override
@@ -121,7 +122,7 @@
         if (this.type == type) {
             return this;
         }
-        return new IndexNode(this, base, index, isFunction(), type, programPoint);
+        return new IndexNode(this, base, index, isFunction(), type, programPoint, isSuper());
     }
 
     @Override
@@ -129,7 +130,7 @@
         if (isFunction()) {
             return this;
         }
-        return new IndexNode(this, base, index, true, type, programPoint);
+        return new IndexNode(this, base, index, true, type, programPoint, isSuper());
     }
 
     @Override
@@ -137,6 +138,14 @@
         if (this.programPoint == programPoint) {
             return this;
         }
-        return new IndexNode(this, base, index, isFunction(), type, programPoint);
+        return new IndexNode(this, base, index, isFunction(), type, programPoint, isSuper());
+    }
+
+    @Override
+    public IndexNode setIsSuper() {
+        if (isSuper()) {
+            return this;
+        }
+        return new IndexNode(this, base, index, isFunction(), type, programPoint, true);
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/Module.java	Tue May 03 12:25:20 2016 -0700
@@ -0,0 +1,338 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.nashorn.internal.ir;
+
+import java.util.List;
+
+/**
+ * ES6 Module information.
+ */
+public final class Module {
+
+    /** The synthetic binding name assigned to export default declarations with unnamed expressions. */
+    public static final String DEFAULT_EXPORT_BINDING_NAME = "*default*";
+
+    /** The {@code export default} name. */
+    public static final String DEFAULT_NAME = "default";
+
+    /** The {@code export *} name. */
+    public static final String STAR_NAME = "*";
+
+    /**
+     * A module ExportEntry record.
+     *
+     * @link http://www.ecma-international.org/ecma-262/6.0/#sec-source-text-module-records
+     */
+    public static final class ExportEntry {
+        private final String exportName;
+        private final String moduleRequest;
+        private final String importName;
+        private final String localName;
+
+        private ExportEntry(final String exportName, final String moduleRequest, final String importName, final String localName) {
+            this.exportName = exportName;
+            this.moduleRequest = moduleRequest;
+            this.importName = importName;
+            this.localName = localName;
+        }
+
+        /**
+         * Creates a {@code export *} export entry.
+         *
+         * @param moduleRequest the module request
+         * @return the export entry
+         */
+        public static ExportEntry exportStarFrom(final String moduleRequest) {
+            return new ExportEntry(null, moduleRequest, STAR_NAME, null);
+        }
+
+        /**
+         * Creates a {@code export default} export entry.
+         *
+         * @return the export entry
+         */
+        public static ExportEntry exportDefault() {
+            return exportDefault(DEFAULT_EXPORT_BINDING_NAME);
+        }
+
+        /**
+         * Creates a {@code export default} export entry with a local name.
+         *
+         * @param localName the local name
+         * @return the export entry
+         */
+        public static ExportEntry exportDefault(final String localName) {
+            return new ExportEntry(DEFAULT_NAME, null, null, localName);
+        }
+
+        /**
+         * Creates a export entry with a local name and export name.
+         *
+         * @param exportName the export name
+         * @param localName the local name
+         * @return the export entry
+         */
+        public static ExportEntry exportSpecifier(final String exportName, final String localName) {
+            return new ExportEntry(exportName, null, null, localName);
+        }
+
+        /**
+         * Creates a export entry with an export name.
+         *
+         * @param exportName the export name
+         * @return the export entry
+         */
+        public static ExportEntry exportSpecifier(final String exportName) {
+            return exportSpecifier(exportName, exportName);
+        }
+
+        /**
+         * Create a copy of this entry with the specified {@code module request} string.
+         *
+         * @param moduleRequest the module request
+         * @return the new export entry
+         */
+        public ExportEntry withFrom(@SuppressWarnings("hiding") final String moduleRequest) {
+            return new ExportEntry(exportName, moduleRequest, localName, null);
+        }
+
+        /**
+         * Returns the entry's export name.
+         *
+         * @return the export name
+         */
+        public String getExportName() {
+            return exportName;
+        }
+
+        /**
+         * Returns the entry's module request.
+         *
+         * @return the module request
+         */
+        public String getModuleRequest() {
+            return moduleRequest;
+        }
+
+        /**
+         * Returns the entry's import name.
+         *
+         * @return the import name
+         */
+        public String getImportName() {
+            return importName;
+        }
+
+        /**
+         * Returns the entry's local name.
+         *
+         * @return the local name
+         */
+        public String getLocalName() {
+            return localName;
+        }
+
+        @Override
+        public String toString() {
+            return "ExportEntry [exportName=" + exportName + ", moduleRequest=" + moduleRequest + ", importName=" + importName + ", localName=" + localName + "]";
+        }
+    }
+
+    /**
+     * An ImportEntry record.
+     *
+     * @link http://www.ecma-international.org/ecma-262/6.0/#sec-source-text-module-records
+     */
+    public static final class ImportEntry {
+        private final String moduleRequest;
+        private final String importName;
+        private final String localName;
+
+        private ImportEntry(final String moduleRequest, final String importName, final String localName) {
+            this.moduleRequest = moduleRequest;
+            this.importName = importName;
+            this.localName = localName;
+        }
+
+        /**
+         * Creates an import entry with default name.
+         *
+         * @param localName the local name
+         * @return the import entry
+         */
+        public static ImportEntry importDefault(final String localName) {
+            return new ImportEntry(null, DEFAULT_NAME, localName);
+        }
+
+        /**
+         * Creates an import entry with {@code *} import name.
+         *
+         * @param localName the local name
+         * @return the import entry
+         */
+        public static ImportEntry importStarAsNameSpaceFrom(final String localName) {
+            return new ImportEntry(null, STAR_NAME, localName);
+        }
+
+        /**
+         * Creates an import entry with the given import and local names.
+         *
+         * @param importName the import name
+         * @param localName the local name
+         * @return the import entry
+         */
+        public static ImportEntry importSpecifier(final String importName, final String localName) {
+            return new ImportEntry(null, importName, localName);
+        }
+
+        /**
+         * Creates a new import entry with the given import name.
+         *
+         * @param importName the import name
+         * @return the import entry
+         */
+        public static ImportEntry importSpecifier(final String importName) {
+            return importSpecifier(importName, importName);
+        }
+
+        /**
+         * Returns a copy of this import entry with the given module request.
+         *
+         * @param moduleRequest the module request
+         * @return the new import entry
+         */
+        public ImportEntry withFrom(@SuppressWarnings("hiding") final String moduleRequest) {
+            return new ImportEntry(moduleRequest, importName, localName);
+        }
+
+        /**
+         * Returns the entry's module request.
+         *
+         * @return the module request
+         */
+        public String getModuleRequest() {
+            return moduleRequest;
+        }
+
+        /**
+         * Returns the entry's import name.
+         *
+         * @return the import name
+         */
+        public String getImportName() {
+            return importName;
+        }
+
+        /**
+         * Returns the entry's local name.
+         *
+         * @return the local name
+         */
+        public String getLocalName() {
+            return localName;
+        }
+
+        @Override
+        public String toString() {
+            return "ImportEntry [moduleRequest=" + moduleRequest + ", importName=" + importName + ", localName=" + localName + "]";
+        }
+    }
+
+    private final List<String> requestedModules;
+    private final List<ImportEntry> importEntries;
+    private final List<ExportEntry> localExportEntries;
+    private final List<ExportEntry> indirectExportEntries;
+    private final List<ExportEntry> starExportEntries;
+
+    /**
+     * Creates a module with the specified requested modules and import and export entries.
+     *
+     * @param requestedModules the requested modules
+     * @param importEntries the import entries
+     * @param localExportEntries local export entries
+     * @param indirectExportEntries indirect export entries
+     * @param starExportEntries star export entries
+     */
+    public Module(final List<String> requestedModules, final List<ImportEntry> importEntries, final List<ExportEntry> localExportEntries,
+                  final List<ExportEntry> indirectExportEntries, final List<ExportEntry> starExportEntries) {
+        this.requestedModules = requestedModules;
+        this.importEntries = importEntries;
+        this.localExportEntries = localExportEntries;
+        this.indirectExportEntries = indirectExportEntries;
+        this.starExportEntries = starExportEntries;
+    }
+
+    /**
+     * Returns the list of requested modules.
+     *
+     * @return the requested modules
+     */
+    public List<String> getRequestedModules() {
+        return requestedModules;
+    }
+
+    /**
+     * Returns the list of import entries.
+     *
+     * @return the import entries
+     */
+    public List<ImportEntry> getImportEntries() {
+        return importEntries;
+    }
+
+    /**
+     * Returns the list of local export entries.
+     *
+     * @return the local export entries
+     */
+    public List<ExportEntry> getLocalExportEntries() {
+        return localExportEntries;
+    }
+
+    /**
+     * Returns the list of indirect export entries.
+     *
+     * @return the indirect export entries
+     */
+    public List<ExportEntry> getIndirectExportEntries() {
+        return indirectExportEntries;
+    }
+
+    /**
+     * Returns the list of star export entries.
+     *
+     * @return the star export entries
+     */
+    public List<ExportEntry> getStarExportEntries() {
+        return starExportEntries;
+    }
+
+    @Override
+    public String toString() {
+        return "Module [requestedModules=" + requestedModules + ", importEntries=" + importEntries + ", localExportEntries=" + localExportEntries + ", indirectExportEntries=" +
+                indirectExportEntries + ", starExportEntries=" + starExportEntries + "]";
+    }
+}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/PropertyNode.java	Tue May 03 09:48:02 2016 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/PropertyNode.java	Tue May 03 12:25:20 2016 -0700
@@ -36,7 +36,7 @@
     private static final long serialVersionUID = 1L;
 
     /** Property key. */
-    private final PropertyKey key;
+    private final Expression key;
 
     /** Property value. */
     private final Expression value;
@@ -47,6 +47,12 @@
     /** Property getter. */
     private final FunctionNode setter;
 
+    /** static property flag */
+    private final boolean isStatic;
+
+    /** Computed property flag */
+    private final boolean computed;
+
     /**
      * Constructor
      *
@@ -56,21 +62,27 @@
      * @param value   the value of this property
      * @param getter  getter function body
      * @param setter  setter function body
+     * @param isStatic is this a static property?
+     * @param computed is this a computed property?
      */
-    public PropertyNode(final long token, final int finish, final PropertyKey key, final Expression value, final FunctionNode getter, final FunctionNode setter) {
+    public PropertyNode(final long token, final int finish, final Expression key, final Expression value, final FunctionNode getter, final FunctionNode setter, final boolean isStatic, final boolean computed) {
         super(token, finish);
         this.key    = key;
         this.value  = value;
         this.getter = getter;
         this.setter = setter;
+        this.isStatic = isStatic;
+        this.computed = computed;
     }
 
-    private PropertyNode(final PropertyNode propertyNode, final PropertyKey key, final Expression value, final FunctionNode getter, final FunctionNode setter) {
+    private PropertyNode(final PropertyNode propertyNode, final Expression key, final Expression value, final FunctionNode getter, final FunctionNode setter, final boolean isStatic, final boolean computed) {
         super(propertyNode);
         this.key    = key;
         this.value  = value;
         this.getter = getter;
         this.setter = setter;
+        this.isStatic = isStatic;
+        this.computed = computed;
     }
 
     /**
@@ -78,14 +90,14 @@
      * @return key name
      */
     public String getKeyName() {
-        return key.getPropertyName();
+        return key instanceof PropertyKey ? ((PropertyKey) key).getPropertyName() : null;
     }
 
     @Override
     public Node accept(final NodeVisitor<? extends LexicalContext> visitor) {
         if (visitor.enterPropertyNode(this)) {
             return visitor.leavePropertyNode(
-                setKey((PropertyKey)((Node)key).accept(visitor)).
+                setKey((Expression) key.accept(visitor)).
                 setValue(value == null ? null : (Expression)value.accept(visitor)).
                 setGetter(getter == null ? null : (FunctionNode)getter.accept(visitor)).
                 setSetter(setter == null ? null : (FunctionNode)setter.accept(visitor)));
@@ -134,7 +146,7 @@
         if (this.getter == getter) {
             return this;
         }
-        return new PropertyNode(this, key, value, getter, setter);
+        return new PropertyNode(this, key, value, getter, setter, isStatic, computed);
     }
 
     /**
@@ -142,14 +154,14 @@
      * @return the key
      */
     public Expression getKey() {
-        return (Expression)key;
+        return key;
     }
 
-    private PropertyNode setKey(final PropertyKey key) {
+    private PropertyNode setKey(final Expression key) {
         if (this.key == key) {
             return this;
         }
-        return new PropertyNode(this, key, value, getter, setter);
+        return new PropertyNode(this, key, value, getter, setter, isStatic, computed);
     }
 
     /**
@@ -169,7 +181,7 @@
         if (this.setter == setter) {
             return this;
         }
-        return new PropertyNode(this, key, value, getter, setter);
+        return new PropertyNode(this, key, value, getter, setter, isStatic, computed);
     }
 
     /**
@@ -189,6 +201,24 @@
         if (this.value == value) {
             return this;
         }
-        return new PropertyNode(this, key, value, getter, setter);
-   }
+        return new PropertyNode(this, key, value, getter, setter, isStatic, computed);
+    }
+
+    /**
+     * Returns true if this is a static property.
+     *
+     * @return true if static flag is set
+     */
+    public boolean isStatic() {
+        return isStatic;
+    }
+
+    /**
+     * Returns true if this is a computed property.
+     *
+     * @return true if the computed flag is set
+     */
+    public boolean isComputed() {
+        return computed;
+    }
 }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/visitor/NodeOperatorVisitor.java	Tue May 03 09:48:02 2016 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/visitor/NodeOperatorVisitor.java	Tue May 03 12:25:20 2016 -0700
@@ -133,8 +133,8 @@
             return enterASSIGN_SHR(binaryNode);
         case ASSIGN_SUB:
             return enterASSIGN_SUB(binaryNode);
-        case BIND:
-            return enterBIND(binaryNode);
+        case ARROW:
+            return enterARROW(binaryNode);
         case BIT_AND:
             return enterBIT_AND(binaryNode);
         case BIT_OR:
@@ -217,8 +217,8 @@
             return leaveASSIGN_SHR(binaryNode);
         case ASSIGN_SUB:
             return leaveASSIGN_SUB(binaryNode);
-        case BIND:
-            return leaveBIND(binaryNode);
+        case ARROW:
+            return leaveARROW(binaryNode);
         case BIT_AND:
             return leaveBIT_AND(binaryNode);
         case BIT_OR:
@@ -735,22 +735,22 @@
     }
 
     /**
-     * Binary enter - callback for entering a bind operator
+     * Binary enter - callback for entering a arrow operator
      *
      * @param  binaryNode the node
      * @return true if traversal should continue and node children be traversed, false otherwise
      */
-    public boolean enterBIND(final BinaryNode binaryNode) {
+    public boolean enterARROW(final BinaryNode binaryNode) {
         return enterDefault(binaryNode);
     }
 
     /**
-     * Binary leave - callback for leaving a bind operator
+     * Binary leave - callback for leaving a arrow operator
      *
      * @param  binaryNode the node
      * @return processed node, which will replace the original one, or the original node
      */
-    public Node leaveBIND(final BinaryNode binaryNode) {
+    public Node leaveARROW(final BinaryNode binaryNode) {
         return leaveDefault(binaryNode);
     }
 
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/visitor/NodeVisitor.java	Tue May 03 09:48:02 2016 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/ir/visitor/NodeVisitor.java	Tue May 03 12:25:20 2016 -0700
@@ -33,6 +33,7 @@
 import jdk.nashorn.internal.ir.CallNode;
 import jdk.nashorn.internal.ir.CaseNode;
 import jdk.nashorn.internal.ir.CatchNode;
+import jdk.nashorn.internal.ir.ClassNode;
 import jdk.nashorn.internal.ir.ContinueNode;
 import jdk.nashorn.internal.ir.DebuggerNode;
 import jdk.nashorn.internal.ir.EmptyNode;
@@ -897,5 +898,23 @@
         return leaveDefault(withNode);
     }
 
+    /**
+     * Callback for entering a ClassNode
+     *
+     * @param  classNode  the node
+     * @return true if traversal should continue and node children be traversed, false otherwise
+     */
+    public boolean enterClassNode(final ClassNode classNode) {
+        return enterDefault(classNode);
+    }
 
+    /**
+     * Callback for leaving a ClassNode
+     *
+     * @param  classNode  the node
+     * @return processed node, which will replace the original one, or the original node
+     */
+    public Node leaveClassNode(final ClassNode classNode) {
+        return leaveDefault(classNode);
+    }
 }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Parser.java	Tue May 03 09:48:02 2016 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Parser.java	Tue May 03 12:25:20 2016 -0700
@@ -28,35 +28,55 @@
 import static jdk.nashorn.internal.codegen.CompilerConstants.ANON_FUNCTION_PREFIX;
 import static jdk.nashorn.internal.codegen.CompilerConstants.EVAL;
 import static jdk.nashorn.internal.codegen.CompilerConstants.PROGRAM;
+import static jdk.nashorn.internal.parser.TokenType.ARROW;
 import static jdk.nashorn.internal.parser.TokenType.ASSIGN;
 import static jdk.nashorn.internal.parser.TokenType.CASE;
 import static jdk.nashorn.internal.parser.TokenType.CATCH;
+import static jdk.nashorn.internal.parser.TokenType.CLASS;
 import static jdk.nashorn.internal.parser.TokenType.COLON;
 import static jdk.nashorn.internal.parser.TokenType.COMMARIGHT;
+import static jdk.nashorn.internal.parser.TokenType.COMMENT;
 import static jdk.nashorn.internal.parser.TokenType.CONST;
 import static jdk.nashorn.internal.parser.TokenType.DECPOSTFIX;
 import static jdk.nashorn.internal.parser.TokenType.DECPREFIX;
+import static jdk.nashorn.internal.parser.TokenType.ELLIPSIS;
 import static jdk.nashorn.internal.parser.TokenType.ELSE;
 import static jdk.nashorn.internal.parser.TokenType.EOF;
 import static jdk.nashorn.internal.parser.TokenType.EOL;
+import static jdk.nashorn.internal.parser.TokenType.EQ_STRICT;
+import static jdk.nashorn.internal.parser.TokenType.ESCSTRING;
+import static jdk.nashorn.internal.parser.TokenType.EXPORT;
+import static jdk.nashorn.internal.parser.TokenType.EXTENDS;
 import static jdk.nashorn.internal.parser.TokenType.FINALLY;
 import static jdk.nashorn.internal.parser.TokenType.FUNCTION;
 import static jdk.nashorn.internal.parser.TokenType.IDENT;
 import static jdk.nashorn.internal.parser.TokenType.IF;
+import static jdk.nashorn.internal.parser.TokenType.IMPORT;
 import static jdk.nashorn.internal.parser.TokenType.INCPOSTFIX;
 import static jdk.nashorn.internal.parser.TokenType.LBRACE;
+import static jdk.nashorn.internal.parser.TokenType.LBRACKET;
 import static jdk.nashorn.internal.parser.TokenType.LET;
 import static jdk.nashorn.internal.parser.TokenType.LPAREN;
+import static jdk.nashorn.internal.parser.TokenType.MUL;
+import static jdk.nashorn.internal.parser.TokenType.PERIOD;
 import static jdk.nashorn.internal.parser.TokenType.RBRACE;
 import static jdk.nashorn.internal.parser.TokenType.RBRACKET;
 import static jdk.nashorn.internal.parser.TokenType.RPAREN;
 import static jdk.nashorn.internal.parser.TokenType.SEMICOLON;
+import static jdk.nashorn.internal.parser.TokenType.SPREAD_ARRAY;
+import static jdk.nashorn.internal.parser.TokenType.STATIC;
+import static jdk.nashorn.internal.parser.TokenType.STRING;
+import static jdk.nashorn.internal.parser.TokenType.SUPER;
 import static jdk.nashorn.internal.parser.TokenType.TEMPLATE;
 import static jdk.nashorn.internal.parser.TokenType.TEMPLATE_HEAD;
 import static jdk.nashorn.internal.parser.TokenType.TEMPLATE_MIDDLE;
 import static jdk.nashorn.internal.parser.TokenType.TEMPLATE_TAIL;
 import static jdk.nashorn.internal.parser.TokenType.TERNARY;
+import static jdk.nashorn.internal.parser.TokenType.VAR;
+import static jdk.nashorn.internal.parser.TokenType.VOID;
 import static jdk.nashorn.internal.parser.TokenType.WHILE;
+import static jdk.nashorn.internal.parser.TokenType.YIELD;
+import static jdk.nashorn.internal.parser.TokenType.YIELD_STAR;
 
 import java.io.Serializable;
 import java.util.ArrayDeque;
@@ -68,6 +88,8 @@
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
+import java.util.function.Consumer;
 import jdk.nashorn.internal.codegen.CompilerConstants;
 import jdk.nashorn.internal.codegen.Namespace;
 import jdk.nashorn.internal.ir.AccessNode;
@@ -79,11 +101,13 @@
 import jdk.nashorn.internal.ir.CallNode;
 import jdk.nashorn.internal.ir.CaseNode;
 import jdk.nashorn.internal.ir.CatchNode;
+import jdk.nashorn.internal.ir.ClassNode;
 import jdk.nashorn.internal.ir.ContinueNode;
 import jdk.nashorn.internal.ir.DebuggerNode;
 import jdk.nashorn.internal.ir.EmptyNode;
 import jdk.nashorn.internal.ir.ErrorNode;
 import jdk.nashorn.internal.ir.Expression;
+import jdk.nashorn.internal.ir.ExpressionList;
 import jdk.nashorn.internal.ir.ExpressionStatement;
 import jdk.nashorn.internal.ir.ForNode;
 import jdk.nashorn.internal.ir.FunctionNode;
@@ -92,7 +116,9 @@
 import jdk.nashorn.internal.ir.IndexNode;
 import jdk.nashorn.internal.ir.JoinPredecessorExpression;
 import jdk.nashorn.internal.ir.LabelNode;
+import jdk.nashorn.internal.ir.LexicalContext;
 import jdk.nashorn.internal.ir.LiteralNode;
+import jdk.nashorn.internal.ir.Module;
 import jdk.nashorn.internal.ir.Node;
 import jdk.nashorn.internal.ir.ObjectNode;
 import jdk.nashorn.internal.ir.PropertyKey;
@@ -110,6 +136,7 @@
 import jdk.nashorn.internal.ir.WithNode;
 import jdk.nashorn.internal.ir.debug.ASTWriter;
 import jdk.nashorn.internal.ir.debug.PrintVisitor;
+import jdk.nashorn.internal.ir.visitor.NodeVisitor;
 import jdk.nashorn.internal.runtime.Context;
 import jdk.nashorn.internal.runtime.ErrorManager;
 import jdk.nashorn.internal.runtime.JSErrorType;
@@ -254,6 +281,14 @@
     }
 
     /**
+     * Set up first token. Skips opening EOL.
+     */
+    private void scanFirstToken() {
+        k = -1;
+        next();
+    }
+
+    /**
      * Execute parse and return the resulting function node.
      * Errors will be thrown and the error manager will contain information
      * if parsing should fail
@@ -280,9 +315,7 @@
             lexer.line = lexer.pendingLine = lineOffset + 1;
             line = lineOffset;
 
-            // Set up first token (skips opening EOL.)
-            k = -1;
-            next();
+            scanFirstToken();
             // Begin parse.
             return program(scriptName, allowPropertyFunction);
         } catch (final Exception e) {
@@ -301,6 +334,44 @@
     }
 
     /**
+     * Parse and return the resulting module.
+     * Errors will be thrown and the error manager will contain information
+     * if parsing should fail
+     *
+     * @param moduleName name for the module, given to the parsed FunctionNode
+     * @param startPos start position in source
+     * @param len length of parse
+     *
+     * @return function node resulting from successful parse
+     */
+    public FunctionNode parseModule(final String moduleName, final int startPos, final int len) {
+        try {
+            stream = new TokenStream();
+            lexer  = new Lexer(source, startPos, len, stream, scripting && !env._no_syntax_extensions, env._es6, reparsedFunction != null);
+            lexer.line = lexer.pendingLine = lineOffset + 1;
+            line = lineOffset;
+
+            scanFirstToken();
+            // Begin parse.
+            return module(moduleName);
+        } catch (final Exception e) {
+            handleParseException(e);
+
+            return null;
+        }
+    }
+
+    /**
+     * Entry point for parsing a module.
+     *
+     * @param moduleName the module name
+     * @return the parsed module
+     */
+    public FunctionNode parseModule(final String moduleName) {
+        return parseModule(moduleName, 0, source.getLength());
+    }
+
+    /**
      * Parse and return the list of function parameter list. A comma
      * separated list of function parameter identifiers is expected to be parsed.
      * Errors will be thrown and the error manager will contain information
@@ -314,11 +385,9 @@
             stream = new TokenStream();
             lexer  = new Lexer(source, stream, scripting && !env._no_syntax_extensions, env._es6);
 
-            // Set up first token (skips opening EOL.)
-            k = -1;
-            next();
-
-            return formalParameterList(TokenType.EOF);
+            scanFirstToken();
+
+            return formalParameterList(TokenType.EOF, false);
         } catch (final Exception e) {
             handleParseException(e);
             return null;
@@ -339,9 +408,7 @@
             lexer  = new Lexer(source, stream, scripting && !env._no_syntax_extensions, env._es6);
             final int functionLine = line;
 
-            // Set up first token (skips opening EOL.)
-            k = -1;
-            next();
+            scanFirstToken();
 
             // Make a fake token for the function.
             final long functionToken = Token.toDesc(FUNCTION, 0, source.getLength());
@@ -432,7 +499,7 @@
         }
 
         // Skip to a recovery point.
-loop:
+        loop:
         while (true) {
             switch (type) {
             case EOF:
@@ -474,7 +541,7 @@
         sb.append(ident.getName());
 
         final String name = namespace.uniqueName(sb.toString());
-        assert parentFunction != null || name.equals(PROGRAM.symbolName()) || name.startsWith(RecompilableScriptFunctionData.RECOMPILATION_PREFIX) : "name = " + name;
+        assert parentFunction != null || name.equals(PROGRAM.symbolName()) : "name = " + name;
 
         int flags = 0;
         if (isStrictMode) {
@@ -489,7 +556,8 @@
         return functionNode;
     }
 
-    private FunctionNode createFunctionNode(final ParserContextFunctionNode function, final long startToken, final IdentNode ident, final List<IdentNode> parameters, final FunctionNode.Kind kind, final int functionLine, final Block body){
+    private FunctionNode createFunctionNode(final ParserContextFunctionNode function, final long startToken, final IdentNode ident, final List<IdentNode> parameters, final FunctionNode.Kind kind, final int functionLine, final Block body) {
+        // assert body.isFunctionBody() || body.getFlag(Block.IS_PARAMETER_BLOCK) && ((BlockStatement) body.getLastStatement()).getBlock().isFunctionBody();
         // Start new block.
         final FunctionNode functionNode =
             new FunctionNode(
@@ -506,7 +574,9 @@
                 kind,
                 function.getFlags(),
                 body,
-                function.getEndParserState());
+                function.getEndParserState(),
+                function.getModule(),
+                function.getDebugFlags());
 
         printAST(functionNode);
 
@@ -544,23 +614,39 @@
             expect(RBRACE);
         }
 
-        final int flags = newBlock.getFlags() | (needsBraces? 0 : Block.IS_SYNTHETIC);
+        final int flags = newBlock.getFlags() | (needsBraces ? 0 : Block.IS_SYNTHETIC);
         return new Block(blockToken, finish, flags, newBlock.getStatements());
     }
 
+    /**
+     * Get the statements in a case clause.
+     */
+    private List<Statement> caseStatementList() {
+        final ParserContextBlockNode newBlock = newBlock();
+        try {
+            statementList();
+        } finally {
+            restoreBlock(newBlock);
+        }
+        return newBlock.getStatements();
+    }
 
     /**
      * Get all the statements generated by a single statement.
      * @return Statements.
      */
     private Block getStatement() {
+        return getStatement(false);
+    }
+
+    private Block getStatement(boolean labelledStatement) {
         if (type == LBRACE) {
             return getBlock(true);
         }
         // Set up new block. Captures first token.
         final ParserContextBlockNode newBlock = newBlock();
         try {
-            statement(false, false, true);
+            statement(false, false, true, labelledStatement);
         } finally {
             restoreBlock(newBlock);
         }
@@ -576,6 +662,9 @@
 
         if (EVAL.symbolName().equals(name)) {
             markEval(lc);
+        } else if (SUPER.getName().equals(name)) {
+            assert ident.isDirectSuper();
+            markSuperCall(lc);
         }
     }
 
@@ -585,7 +674,8 @@
      */
     private void detectSpecialProperty(final IdentNode ident) {
         if (isArguments(ident)) {
-            lc.getCurrentFunction().setFlag(FunctionNode.USES_ARGUMENTS);
+            // skip over arrow functions, e.g. function f() { return (() => arguments.length)(); }
+            getCurrentNonArrowFunction().setFlag(FunctionNode.USES_ARGUMENTS);
         }
     }
 
@@ -593,11 +683,15 @@
         return env._es6;
     }
 
+    private boolean isES6() {
+        return env._es6;
+    }
+
     private static boolean isArguments(final String name) {
         return ARGUMENTS_NAME.equals(name);
     }
 
-    private static boolean isArguments(final IdentNode ident) {
+    static boolean isArguments(final IdentNode ident) {
         return isArguments(ident.getName());
     }
 
@@ -634,20 +728,20 @@
         case ASSIGN_SHL:
         case ASSIGN_SHR:
         case ASSIGN_SUB:
-            if (!(lhs instanceof AccessNode ||
-                  lhs instanceof IndexNode ||
-                  lhs instanceof IdentNode)) {
-                return referenceError(lhs, rhs, env._early_lvalue_error);
-            }
-
             if (lhs instanceof IdentNode) {
                 if (!checkIdentLValue((IdentNode)lhs)) {
                     return referenceError(lhs, rhs, false);
                 }
-                verifyStrictIdent((IdentNode)lhs, "assignment");
+                verifyIdent((IdentNode)lhs, "assignment");
+                break;
+            } else if (lhs instanceof AccessNode || lhs instanceof IndexNode) {
+                break;
+            } else if (opType == ASSIGN && isDestructuringLhs(lhs)) {
+                verifyDestructuringAssignmentPattern(lhs, "assignment");
+                break;
+            } else {
+                return referenceError(lhs, rhs, env._early_lvalue_error);
             }
-            break;
-
         default:
             break;
         }
@@ -659,6 +753,114 @@
         return new BinaryNode(op, lhs, rhs);
     }
 
+    private boolean isDestructuringLhs(Expression lhs) {
+        if (lhs instanceof ObjectNode || lhs instanceof LiteralNode.ArrayLiteralNode) {
+            return isES6();
+        }
+        return false;
+    }
+
+    private void verifyDestructuringAssignmentPattern(Expression pattern, String contextString) {
+        assert pattern instanceof ObjectNode || pattern instanceof LiteralNode.ArrayLiteralNode;
+        pattern.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
+            @Override
+            public boolean enterLiteralNode(LiteralNode<?> literalNode) {
+                if (literalNode.isArray()) {
+                    boolean restElement = false;
+                    for (Expression element : literalNode.getElementExpressions()) {
+                        if (element != null) {
+                            if (restElement) {
+                                throw error(String.format("Unexpected element after rest element"), element.getToken());
+                            }
+                            if (element.isTokenType(SPREAD_ARRAY)) {
+                                restElement = true;
+                                Expression lvalue = ((UnaryNode) element).getExpression();
+                                if (!checkValidLValue(lvalue, contextString)) {
+                                    throw error(AbstractParser.message("invalid.lvalue"), lvalue.getToken());
+                                }
+                            }
+                            element.accept(this);
+                        }
+                    }
+                    return false;
+                } else {
+                    return enterDefault(literalNode);
+                }
+            }
+
+            @Override
+            public boolean enterObjectNode(ObjectNode objectNode) {
+                return true;
+            }
+
+            @Override
+            public boolean enterPropertyNode(PropertyNode propertyNode) {
+                if (propertyNode.getValue() != null) {
+                    propertyNode.getValue().accept(this);
+                    return false;
+                } else {
+                    return enterDefault(propertyNode);
+                }
+            }
+
+            @Override
+            public boolean enterIdentNode(IdentNode identNode) {
+                verifyIdent(identNode, contextString);
+                if (!checkIdentLValue(identNode)) {
+                    referenceError(identNode, null, true);
+                    return false;
+                }
+                return false;
+            }
+
+            @Override
+            public boolean enterAccessNode(AccessNode accessNode) {
+                return false;
+            }
+
+            @Override
+            public boolean enterIndexNode(IndexNode indexNode) {
+                return false;
+            }
+
+            @Override
+            public boolean enterBinaryNode(BinaryNode binaryNode) {
+                if (binaryNode.isTokenType(ASSIGN)) {
+                    binaryNode.lhs().accept(this);
+                    // Initializer(rhs) can be any AssignmentExpression
+                    return false;
+                } else {
+                    return enterDefault(binaryNode);
+                }
+            }
+
+            @Override
+            public boolean enterUnaryNode(UnaryNode unaryNode) {
+                if (unaryNode.isTokenType(SPREAD_ARRAY)) {
+                    // rest element
+                    return true;
+                } else {
+                    return enterDefault(unaryNode);
+                }
+            }
+
+            @Override
+            protected boolean enterDefault(Node node) {
+                throw error(String.format("unexpected node in AssignmentPattern: %s", node));
+            }
+        });
+    }
+
+    private static Expression newBinaryExpression(final long op, final Expression lhs, final Expression rhs) {
+        final TokenType opType = Token.descType(op);
+
+        // Build up node.
+        if (BinaryNode.isLogical(opType)) {
+            return new BinaryNode(op, new JoinPredecessorExpression(lhs), new JoinPredecessorExpression(rhs));
+        }
+        return new BinaryNode(op, lhs, rhs);
+    }
+
 
     /**
      * Reduce increment/decrement to simpler operations.
@@ -717,7 +919,7 @@
 
         restoreBlock(body);
         body.setFlag(Block.NEEDS_SCOPE);
-        final Block programBody = new Block(functionToken, finish, body.getFlags() | Block.IS_SYNTHETIC, body.getStatements());
+        final Block programBody = new Block(functionToken, finish, body.getFlags() | Block.IS_SYNTHETIC | Block.IS_BODY, body.getStatements());
         lc.pop(script);
         script.setLastToken(token);
 
@@ -776,7 +978,7 @@
 
                 try {
                     // Get the next element.
-                    statement(true, allowPropertyFunction, false);
+                    statement(true, allowPropertyFunction, false, false);
                     allowPropertyFunction = false;
 
                     // check for directive prologues
@@ -816,16 +1018,16 @@
 
                                     // verify that function name as well as parameter names
                                     // satisfy strict mode restrictions.
-                                    verifyStrictIdent(function.getIdent(), "function name");
+                                    verifyIdent(function.getIdent(), "function name");
                                     for (final IdentNode param : function.getParameters()) {
-                                        verifyStrictIdent(param, "function parameter");
+                                        verifyIdent(param, "function parameter");
                                     }
                                 }
                             } else if (Context.DEBUG) {
-                                final int flag = FunctionNode.getDirectiveFlag(directive);
-                                if (flag != 0) {
+                                final int debugFlag = FunctionNode.getDirectiveFlag(directive);
+                                if (debugFlag != 0) {
                                     final ParserContextFunctionNode function = lc.getCurrentFunction();
-                                    function.setFlag(flag);
+                                    function.setDebugFlag(debugFlag);
                                 }
                             }
                         }
@@ -849,29 +1051,53 @@
     }
 
     /**
+     * Parse any of the basic statement types.
+     *
      * Statement :
-     *      Block
+     *      BlockStatement
      *      VariableStatement
      *      EmptyStatement
      *      ExpressionStatement
      *      IfStatement
-     *      IterationStatement
+     *      BreakableStatement
      *      ContinueStatement
      *      BreakStatement
      *      ReturnStatement
      *      WithStatement
      *      LabelledStatement
-     *      SwitchStatement
      *      ThrowStatement
      *      TryStatement
      *      DebuggerStatement
      *
-     * see 12
+     * BreakableStatement :
+     *      IterationStatement
+     *      SwitchStatement
+     *
+     * BlockStatement :
+     *      Block
+     *
+     * Block :
+     *      { StatementList opt }
      *
-     * Parse any of the basic statement types.
+     * StatementList :
+     *      StatementListItem
+     *      StatementList StatementListItem
+     *
+     * StatementItem :
+     *      Statement
+     *      Declaration
+     *
+     * Declaration :
+     *     HoistableDeclaration
+     *     ClassDeclaration
+     *     LexicalDeclaration
+     *
+     * HoistableDeclaration :
+     *     FunctionDeclaration
+     *     GeneratorDeclaration
      */
     private void statement() {
-        statement(false, false, false);
+        statement(false, false, false, false);
     }
 
     /**
@@ -879,14 +1105,7 @@
      * @param allowPropertyFunction allow property "get" and "set" functions?
      * @param singleStatement are we in a single statement context?
      */
-    private void statement(final boolean topLevel, final boolean allowPropertyFunction, final boolean singleStatement) {
-        if (type == FUNCTION) {
-            // As per spec (ECMA section 12), function declarations as arbitrary statement
-            // is not "portable". Implementation can issue a warning or disallow the same.
-            functionExpression(true, topLevel);
-            return;
-        }
-
+    private void statement(final boolean topLevel, final boolean allowPropertyFunction, final boolean singleStatement, final boolean labelledStatement) {
         switch (type) {
         case LBRACE:
             block();
@@ -918,9 +1137,6 @@
         case RETURN:
             returnStatement();
             break;
-        case YIELD:
-            yieldStatement();
-            break;
         case WITH:
             withStatement();
             break;
@@ -941,13 +1157,32 @@
         case EOF:
             expect(SEMICOLON);
             break;
+        case FUNCTION:
+            // As per spec (ECMA section 12), function declarations as arbitrary statement
+            // is not "portable". Implementation can issue a warning or disallow the same.
+            if (singleStatement) {
+                // ES6 B.3.2 Labelled Function Declarations
+                // It is a Syntax Error if any strict mode source code matches this rule:
+                // LabelledItem : FunctionDeclaration.
+                if (!labelledStatement || isStrictMode) {
+                    throw error(AbstractParser.message("expected.stmt", "function declaration"), token);
+                }
+            }
+            functionExpression(true, topLevel || labelledStatement);
+            return;
         default:
-            if (useBlockScope() && (type == LET || type == CONST)) {
+            if (useBlockScope() && (type == LET && lookaheadIsLetDeclaration(false) || type == CONST)) {
                 if (singleStatement) {
                     throw error(AbstractParser.message("expected.stmt", type.getName() + " declaration"), token);
                 }
                 variableStatement(type);
                 break;
+            } else if (type == CLASS && isES6()) {
+                if (singleStatement) {
+                    throw error(AbstractParser.message("expected.stmt", "class declaration"), token);
+                }
+                classDeclaration(false);
+                break;
             }
             if (env._const_as_var && type == CONST) {
                 variableStatement(TokenType.VAR);
@@ -963,11 +1198,11 @@
                     final String ident = (String)getValue();
                     final long propertyToken = token;
                     final int propertyLine = line;
-                    if("get".equals(ident)) {
+                    if ("get".equals(ident)) {
                         next();
                         addPropertyFunctionStatement(propertyGetterFunction(propertyToken, propertyLine));
                         return;
-                    } else if("set".equals(ident)) {
+                    } else if ("set".equals(ident)) {
                         next();
                         addPropertyFunctionStatement(propertySetterFunction(propertyToken, propertyLine));
                         return;
@@ -986,6 +1221,267 @@
     }
 
     /**
+     * ClassDeclaration[Yield, Default] :
+     *   class BindingIdentifier[?Yield] ClassTail[?Yield]
+     *   [+Default] class ClassTail[?Yield]
+     */
+    private ClassNode classDeclaration(boolean isDefault) {
+        int classLineNumber = line;
+
+        ClassNode classExpression = classExpression(!isDefault);
+
+        if (!isDefault) {
+            VarNode classVar = new VarNode(classLineNumber, classExpression.getToken(), classExpression.getIdent().getFinish(), classExpression.getIdent(), classExpression, VarNode.IS_CONST);
+            appendStatement(classVar);
+        }
+        return classExpression;
+    }
+
+    /**
+     * ClassExpression[Yield] :
+     *   class BindingIdentifier[?Yield]opt ClassTail[?Yield]
+     */
+    private ClassNode classExpression(boolean isStatement) {
+        assert type == CLASS;
+        int classLineNumber = line;
+        long classToken = token;
+        next();
+
+        IdentNode className = null;
+        if (isStatement || type == IDENT) {
+            className = getIdent();
+        }
+
+        return classTail(classLineNumber, classToken, className);
+    }
+
+    private static final class ClassElementKey {
+        private final boolean isStatic;
+        private final String propertyName;
+
+        private ClassElementKey(boolean isStatic, String propertyName) {
+            this.isStatic = isStatic;
+            this.propertyName = propertyName;
+        }
+
+        @Override
+        public int hashCode() {
+            final int prime = 31;
+            int result = 1;
+            result = prime * result + (isStatic ? 1231 : 1237);
+            result = prime * result + ((propertyName == null) ? 0 : propertyName.hashCode());
+            return result;
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (obj instanceof ClassElementKey) {
+                ClassElementKey other = (ClassElementKey) obj;
+                return this.isStatic == other.isStatic && Objects.equals(this.propertyName, other.propertyName);
+            }
+            return false;
+        }
+    }
+
+    /**
+     * Parse ClassTail and ClassBody.
+     *
+     * ClassTail[Yield] :
+     *   ClassHeritage[?Yield]opt { ClassBody[?Yield]opt }
+     * ClassHeritage[Yield] :
+     *   extends LeftHandSideExpression[?Yield]
+     *
+     * ClassBody[Yield] :
+     *   ClassElementList[?Yield]
+     * ClassElementList[Yield] :
+     *   ClassElement[?Yield]
+     *   ClassElementList[?Yield] ClassElement[?Yield]
+     * ClassElement[Yield] :
+     *   MethodDefinition[?Yield]
+     *   static MethodDefinition[?Yield]
+     *   ;
+     */
+    private ClassNode classTail(final int classLineNumber, final long classToken, final IdentNode className) {
+        final boolean oldStrictMode = isStrictMode;
+        isStrictMode = true;
+        try {
+            Expression classHeritage = null;
+            if (type == EXTENDS) {
+                next();
+                classHeritage = leftHandSideExpression();
+            }
+
+            expect(LBRACE);
+
+            PropertyNode constructor = null;
+            final ArrayList<PropertyNode> classElements = new ArrayList<>();
+            final Map<ClassElementKey, Integer> keyToIndexMap = new HashMap<>();
+            for (;;) {
+                if (type == SEMICOLON) {
+                    next();
+                    continue;
+                }
+                if (type == RBRACE) {
+                    break;
+                }
+                final long classElementToken = token;
+                boolean isStatic = false;
+                if (type == STATIC) {
+                    isStatic = true;
+                    next();
+                }
+                boolean generator = false;
+                if (isES6() && type == MUL) {
+                    generator = true;
+                    next();
+                }
+                final PropertyNode classElement = methodDefinition(isStatic, classHeritage != null, generator);
+                if (classElement.isComputed()) {
+                    classElements.add(classElement);
+                } else if (!classElement.isStatic() && classElement.getKeyName().equals("constructor")) {
+                    if (constructor == null) {
+                        constructor = classElement;
+                    } else {
+                        throw error(AbstractParser.message("multiple.constructors"), classElementToken);
+                    }
+                } else {
+                    // Check for duplicate method definitions and combine accessor methods.
+                    // In ES6, a duplicate is never an error regardless of strict mode (in consequence of computed property names).
+
+                    final ClassElementKey key = new ClassElementKey(classElement.isStatic(), classElement.getKeyName());
+                    final Integer existing = keyToIndexMap.get(key);
+
+                    if (existing == null) {
+                        keyToIndexMap.put(key, classElements.size());
+                        classElements.add(classElement);
+                    } else {
+                        final PropertyNode existingProperty = classElements.get(existing);
+
+                        final Expression   value  = classElement.getValue();
+                        final FunctionNode getter = classElement.getGetter();
+                        final FunctionNode setter = classElement.getSetter();
+
+                        if (value != null || existingProperty.getValue() != null) {
+                            keyToIndexMap.put(key, classElements.size());
+                            classElements.add(classElement);
+                        } else if (getter != null) {
+                            assert existingProperty.getGetter() != null || existingProperty.getSetter() != null;
+                            classElements.set(existing, existingProperty.setGetter(getter));
+                        } else if (setter != null) {
+                            assert existingProperty.getGetter() != null || existingProperty.getSetter() != null;
+                            classElements.set(existing, existingProperty.setSetter(setter));
+                        }
+                    }
+                }
+            }
+
+            final long lastToken = token;
+            expect(RBRACE);
+
+            if (constructor == null) {
+                constructor = createDefaultClassConstructor(classLineNumber, classToken, lastToken, className, classHeritage != null);
+            }
+
+            classElements.trimToSize();
+            return new ClassNode(classLineNumber, classToken, finish, className, classHeritage, constructor, classElements);
+        } finally {
+            isStrictMode = oldStrictMode;
+        }
+    }
+
+    private PropertyNode createDefaultClassConstructor(int classLineNumber, long classToken, long lastToken, IdentNode className, boolean subclass) {
+        final int ctorFinish = finish;
+        final List<Statement> statements;
+        final List<IdentNode> parameters;
+        final long identToken = Token.recast(classToken, TokenType.IDENT);
+        if (subclass) {
+            final IdentNode superIdent = createIdentNode(identToken, ctorFinish, SUPER.getName()).setIsDirectSuper();
+            final IdentNode argsIdent = createIdentNode(identToken, ctorFinish, "args").setIsRestParameter();
+            final Expression spreadArgs = new UnaryNode(Token.recast(classToken, TokenType.SPREAD_ARGUMENT), argsIdent);
+            final CallNode superCall = new CallNode(classLineNumber, classToken, ctorFinish, superIdent, Collections.singletonList(spreadArgs), false);
+            statements = Collections.singletonList(new ExpressionStatement(classLineNumber, classToken, ctorFinish, superCall));
+            parameters = Collections.singletonList(argsIdent);
+        } else {
+            statements = Collections.emptyList();
+            parameters = Collections.emptyList();
+        }
+
+        final Block body = new Block(classToken, ctorFinish, Block.IS_BODY, statements);
+        final IdentNode ctorName = className != null ? className : createIdentNode(identToken, ctorFinish, "constructor");
+        final ParserContextFunctionNode function = createParserContextFunctionNode(ctorName, classToken, FunctionNode.Kind.NORMAL, classLineNumber, parameters);
+        function.setLastToken(lastToken);
+
+        function.setFlag(FunctionNode.ES6_IS_METHOD);
+        function.setFlag(FunctionNode.ES6_IS_CLASS_CONSTRUCTOR);
+        if (subclass) {
+            function.setFlag(FunctionNode.ES6_IS_SUBCLASS_CONSTRUCTOR);
+            function.setFlag(FunctionNode.ES6_HAS_DIRECT_SUPER);
+        }
+        if (className == null) {
+            function.setFlag(FunctionNode.IS_ANONYMOUS);
+        }
+
+        final PropertyNode constructor = new PropertyNode(classToken, ctorFinish, ctorName, createFunctionNode(
+                        function,
+                        classToken,
+                        ctorName,
+                        parameters,
+                        FunctionNode.Kind.NORMAL,
+                        classLineNumber,
+                        body
+                        ), null, null, false, false);
+        return constructor;
+    }
+
+    private PropertyNode methodDefinition(final boolean isStatic, final boolean subclass, final boolean generator) {
+        final long methodToken = token;
+        final int methodLine = line;
+        final boolean computed = type == LBRACKET;
+        final boolean isIdent = type == IDENT;
+        final Expression propertyName = propertyName();
+        int flags = FunctionNode.ES6_IS_METHOD;
+        if (!computed) {
+            final String name = ((PropertyKey)propertyName).getPropertyName();
+            if (!generator && isIdent && type != LPAREN && name.equals("get")) {
+                final PropertyFunction methodDefinition = propertyGetterFunction(methodToken, methodLine, flags);
+                verifyAllowedMethodName(methodDefinition.key, isStatic, methodDefinition.computed, generator, true);
+                return new PropertyNode(methodToken, finish, methodDefinition.key, null, methodDefinition.functionNode, null, isStatic, methodDefinition.computed);
+            } else if (!generator && isIdent && type != LPAREN && name.equals("set")) {
+                final PropertyFunction methodDefinition = propertySetterFunction(methodToken, methodLine, flags);
+                verifyAllowedMethodName(methodDefinition.key, isStatic, methodDefinition.computed, generator, true);
+                return new PropertyNode(methodToken, finish, methodDefinition.key, null, null, methodDefinition.functionNode, isStatic, methodDefinition.computed);
+            } else {
+                if (!isStatic && !generator && name.equals("constructor")) {
+                    flags |= FunctionNode.ES6_IS_CLASS_CONSTRUCTOR;
+                    if (subclass) {
+                        flags |= FunctionNode.ES6_IS_SUBCLASS_CONSTRUCTOR;
+                    }
+                }
+                verifyAllowedMethodName(propertyName, isStatic, computed, generator, false);
+            }
+        }
+        final PropertyFunction methodDefinition = propertyMethodFunction(propertyName, methodToken, methodLine, generator, flags, computed);
+        return new PropertyNode(methodToken, finish, methodDefinition.key, methodDefinition.functionNode, null, null, isStatic, computed);
+    }
+
+    /**
+     * ES6 14.5.1 Static Semantics: Early Errors.
+     */
+    private void verifyAllowedMethodName(final Expression key, final boolean isStatic, final boolean computed, final boolean generator, final boolean accessor) {
+        if (!computed) {
+            if (!isStatic && generator && ((PropertyKey) key).getPropertyName().equals("constructor")) {
+                throw error(AbstractParser.message("generator.constructor"), key.getToken());
+            }
+            if (!isStatic && accessor && ((PropertyKey) key).getPropertyName().equals("constructor")) {
+                throw error(AbstractParser.message("accessor.constructor"), key.getToken());
+            }
+            if (isStatic && ((PropertyKey) key).getPropertyName().equals("prototype")) {
+                throw error(AbstractParser.message("static.prototype.method"), key.getToken());
+            }
+        }
+    }
+
+    /**
      * block :
      *      { StatementList? }
      *
@@ -1008,7 +1504,7 @@
      */
     private void statementList() {
         // Accumulate statements until end of list. */
-loop:
+        loop:
         while (type != EOF) {
             switch (type) {
             case EOF:
@@ -1026,6 +1522,22 @@
     }
 
     /**
+     * Make sure that the identifier name used is allowed.
+     *
+     * @param ident         Identifier that is verified
+     * @param contextString String used in error message to give context to the user
+     */
+    private void verifyIdent(final IdentNode ident, final String contextString) {
+        verifyStrictIdent(ident, contextString);
+        if (isES6()) {
+            final TokenType tokenType = TokenLookup.lookupKeyword(ident.getName().toCharArray(), 0, ident.getName().length());
+            if (tokenType != IDENT && tokenType.getKind() != TokenKind.FUTURESTRICT) {
+                throw error(expectMessage(IDENT));
+            }
+        }
+    }
+
+    /**
      * Make sure that in strict mode, the identifier name used is allowed.
      *
      * @param ident         Identifier that is verified
@@ -1066,15 +1578,16 @@
      * Parse a VAR statement.
      * @param isStatement True if a statement (not used in a FOR.)
      */
-    private List<VarNode> variableStatement(final TokenType varType) {
-        return variableStatement(varType, true, -1);
+    private void variableStatement(final TokenType varType) {
+        variableDeclarationList(varType, true, -1);
     }
 
-    private List<VarNode> variableStatement(final TokenType varType, final boolean isStatement, final int sourceOrder) {
+    private List<Expression> variableDeclarationList(final TokenType varType, final boolean isStatement, final int sourceOrder) {
         // VAR tested in caller.
+        assert varType == VAR || varType == LET || varType == CONST;
         next();
 
-        final List<VarNode> vars = new ArrayList<>();
+        final List<Expression> bindings = new ArrayList<>();
         int varFlags = 0;
         if (varType == LET) {
             varFlags |= VarNode.IS_LET;
@@ -1082,13 +1595,29 @@
             varFlags |= VarNode.IS_CONST;
         }
 
+        Expression missingAssignment = null;
         while (true) {
             // Get starting token.
             final int  varLine  = line;
             final long varToken = token;
             // Get name of var.
-            final IdentNode name = getIdent();
-            verifyStrictIdent(name, "variable name");
+            if (type == YIELD && inGeneratorFunction()) {
+                expect(IDENT);
+            }
+
+            final String contextString = "variable name";
+            Expression binding = bindingIdentifierOrPattern(contextString);
+            final boolean isDestructuring = !(binding instanceof IdentNode);
+            if (isDestructuring) {
+                final int finalVarFlags = varFlags;
+                verifyDestructuringBindingPattern(binding, new Consumer<IdentNode>() {
+                    public void accept(final IdentNode identNode) {
+                        verifyIdent(identNode, contextString);
+                        final VarNode var = new VarNode(varLine, varToken, sourceOrder, identNode.getFinish(), identNode.setIsDeclaredHere(), null, finalVarFlags);
+                        appendStatement(var);
+                    }
+                });
+            }
 
             // Assume no init.
             Expression init = null;
@@ -1098,22 +1627,53 @@
                 next();
 
                 // Get initializer expression. Suppress IN if not statement.
-                defaultNames.push(name);
+                if (!isDestructuring) {
+                    defaultNames.push(binding);
+                }
                 try {
                     init = assignmentExpression(!isStatement);
                 } finally {
-                    defaultNames.pop();
+                    if (!isDestructuring) {
+                        defaultNames.pop();
+                    }
                 }
-            } else if (varType == CONST && isStatement) {
-                throw error(AbstractParser.message("missing.const.assignment", name.getName()));
+            } else if (isStatement) {
+                if (isDestructuring) {
+                    throw error(AbstractParser.message("missing.destructuring.assignment"), token);
+                } else if (varType == CONST) {
+                    throw error(AbstractParser.message("missing.const.assignment", ((IdentNode)binding).getName()));
+                }
+                // else, if we are in a for loop, delay checking until we know the kind of loop
             }
 
-            // Only set declaration flag on lexically scoped let/const as it adds runtime overhead.
-            final IdentNode actualName = varType == LET || varType == CONST ? name.setIsDeclaredHere() : name;
-            // Allocate var node.
-            final VarNode var = new VarNode(varLine, varToken, sourceOrder, finish, actualName, init, varFlags);
-            vars.add(var);
-            appendStatement(var);
+            if (!isDestructuring) {
+                assert init != null || varType != CONST || !isStatement;
+                final IdentNode ident = (IdentNode)binding;
+                if (!isStatement && ident.getName().equals("let")) {
+                    throw error(AbstractParser.message("let.binding.for")); //ES6 13.7.5.1
+                }
+                // Only set declaration flag on lexically scoped let/const as it adds runtime overhead.
+                final IdentNode name = varType == LET || varType == CONST ? ident.setIsDeclaredHere() : ident;
+                binding = name;
+                final VarNode var = new VarNode(varLine, varToken, sourceOrder, finish, name, init, varFlags);
+                appendStatement(var);
+                if (init == null && varType == CONST) {
+                    if (missingAssignment == null) {
+                        missingAssignment = binding;
+                    }
+                }
+            } else {
+                assert init != null || !isStatement;
+                binding = init == null ? binding : verifyAssignment(Token.recast(varToken, ASSIGN), binding, init);
+                if (isStatement) {
+                    appendStatement(new ExpressionStatement(varLine, binding.getToken(), finish, binding));
+                } else if (init == null) {
+                    if (missingAssignment == null) {
+                        missingAssignment = binding;
+                    }
+                }
+            }
+            bindings.add(binding);
 
             if (type != COMMARIGHT) {
                 break;
@@ -1124,9 +1684,128 @@
         // If is a statement then handle end of line.
         if (isStatement) {
             endOfLine();
+        } else {
+            if (type == SEMICOLON) {
+                // late check for missing assignment, now we know it's a for (init; test; modify) loop
+                if (missingAssignment != null) {
+                    if (missingAssignment instanceof IdentNode) {
+                        throw error(AbstractParser.message("missing.const.assignment", ((IdentNode)missingAssignment).getName()));
+                    } else {
+                        throw error(AbstractParser.message("missing.destructuring.assignment"), missingAssignment.getToken());
+                    }
+                }
+            }
         }
 
-        return vars;
+        return bindings;
+    }
+
+    private boolean isBindingIdentifier() {
+        return type == IDENT || isNonStrictModeIdent();
+    }
+
+    private IdentNode bindingIdentifier(final String contextString) {
+        final IdentNode name = getIdent();
+        verifyIdent(name, contextString);
+        return name;
+    }
+
+    private Expression bindingPattern() {
+        if (type == LBRACKET) {
+            return arrayLiteral();
+        } else if (type == LBRACE) {
+            return objectLiteral();
+        } else {
+            throw error(AbstractParser.message("expected.binding"));
+        }
+    }
+
+    private Expression bindingIdentifierOrPattern(final String contextString) {
+        if (isBindingIdentifier() || !isES6()) {
+            return bindingIdentifier(contextString);
+        } else {
+            return bindingPattern();
+        }
+    }
+
+    /**
+     * Verify destructuring variable declaration binding pattern and extract bound variable declarations.
+     */
+    private void verifyDestructuringBindingPattern(final Expression pattern, final Consumer<IdentNode> identifierCallback) {
+        assert pattern instanceof ObjectNode || pattern instanceof LiteralNode.ArrayLiteralNode;
+        pattern.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
+            @Override
+            public boolean enterLiteralNode(final LiteralNode<?> literalNode) {
+                if (literalNode.isArray()) {
+                    boolean restElement = false;
+                    for (final Expression element : literalNode.getElementExpressions()) {
+                        if (restElement) {
+                            throw error(String.format("Unexpected element after rest element"), element.getToken());
+                        }
+                        if (element != null) {
+                            if (element.isTokenType(SPREAD_ARRAY)) {
+                                restElement = true;
+                                if (!(((UnaryNode) element).getExpression() instanceof IdentNode)) {
+                                    throw error(String.format("Expected a valid binding identifier"), element.getToken());
+
+                                }
+                            }
+                            element.accept(this);
+                        }
+                    }
+                    return false;
+                } else {
+                    return enterDefault(literalNode);
+                }
+            }
+
+            @Override
+            public boolean enterObjectNode(final ObjectNode objectNode) {
+                return true;
+            }
+
+            @Override
+            public boolean enterPropertyNode(final PropertyNode propertyNode) {
+                if (propertyNode.getValue() != null) {
+                    propertyNode.getValue().accept(this);
+                    return false;
+                } else {
+                    return enterDefault(propertyNode);
+                }
+            }
+
+            @Override
+            public boolean enterIdentNode(final IdentNode identNode) {
+                identifierCallback.accept(identNode);
+                return false;
+            }
+
+            @Override
+            public boolean enterBinaryNode(final BinaryNode binaryNode) {
+                if (binaryNode.isTokenType(ASSIGN)) {
+                    binaryNode.lhs().accept(this);
+                    // Initializer(rhs) can be any AssignmentExpression
+                    return false;
+                } else {
+                    return enterDefault(binaryNode);
+                }
+            }
+
+            @Override
+            public boolean enterUnaryNode(final UnaryNode unaryNode) {
+                if (unaryNode.isTokenType(SPREAD_ARRAY)) {
+                    // rest element
+                    return true;
+                } else {
+                    return enterDefault(unaryNode);
+                }
+            }
+
+            @Override
+            protected boolean enterDefault(final Node node) {
+                throw error(String.format("unexpected node in BindingPattern: %s", node));
+            }
+        });
     }
 
     /**
@@ -1230,7 +1909,7 @@
         final ParserContextLoopNode forNode = new ParserContextLoopNode();
         lc.push(forNode);
         Block body = null;
-        List<VarNode> vars = null;
+        List<Expression> vars = null;
         Expression init = null;
         JoinPredecessorExpression test = null;
         JoinPredecessorExpression modify = null;
@@ -1254,20 +1933,20 @@
             switch (type) {
             case VAR:
                 // Var declaration captured in for outer block.
-                vars = variableStatement(type, false, forStart);
+                vars = variableDeclarationList(type, false, forStart);
                 break;
             case SEMICOLON:
                 break;
             default:
-                if (useBlockScope() && (type == LET || type == CONST)) {
+                if (useBlockScope() && (type == LET && lookaheadIsLetDeclaration(true) || type == CONST)) {
                     flags |= ForNode.PER_ITERATION_SCOPE;
                     // LET/CONST declaration captured in container block created above.
-                    vars = variableStatement(type, false, forStart);
+                    vars = variableDeclarationList(type, false, forStart);
                     break;
                 }
                 if (env._const_as_var && type == CONST) {
                     // Var declaration captured in for outer block.
-                    vars = variableStatement(TokenType.VAR, false, forStart);
+                    vars = variableDeclarationList(TokenType.VAR, false, forStart);
                     break;
                 }
 
@@ -1309,7 +1988,11 @@
                 if (vars != null) {
                     // for (var i in obj)
                     if (vars.size() == 1) {
-                        init = new IdentNode(vars.get(0).getName());
+                        init = new IdentNode((IdentNode)vars.get(0));
+                        if (init.isTokenType(ASSIGN)) {
+                            throw error(AbstractParser.message("for.in.loop.initializer"), init.getToken());
+                        }
+                        assert init instanceof IdentNode || isDestructuringLhs(init);
                     } else {
                         // for (var i, j in obj) is invalid
                         throw error(AbstractParser.message("many.vars.in.for.in.loop", isForOf ? "of" : "in"), vars.get(1).getToken());
@@ -1351,10 +2034,9 @@
         } finally {
             lc.pop(forNode);
 
-            if (vars != null) {
-                for (final VarNode var : vars) {
-                    appendStatement(var);
-                }
+            for (final Statement var : forNode.getStatements()) {
+                assert var instanceof VarNode;
+                appendStatement(var);
             }
             if (body != null) {
                 appendStatement(new ForNode(forLine, forToken, body.getFinish(), body, (forNode.getFlags() | flags), init, test, modify));
@@ -1371,6 +2053,49 @@
         }
     }
 
+    private boolean checkValidLValue(final Expression init, final String contextString) {
+        if (init instanceof IdentNode) {
+            if (!checkIdentLValue((IdentNode)init)) {
+                return false;
+            }
+            verifyIdent((IdentNode)init, contextString);
+            return true;
+        } else if (init instanceof AccessNode || init instanceof IndexNode) {
+            return true;
+        } else if (isDestructuringLhs(init)) {
+            verifyDestructuringAssignmentPattern(init, contextString);
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    private boolean lookaheadIsLetDeclaration(final boolean ofContextualKeyword) {
+        assert type == LET;
+        for (int i = 1;; i++) {
+            TokenType t = T(k + i);
+            switch (t) {
+            case EOL:
+            case COMMENT:
+                continue;
+            case IDENT:
+                if (ofContextualKeyword && isES6() && "of".equals(getValue(getToken(k + i)))) {
+                    return false;
+                }
+                // fall through
+            case LBRACKET:
+            case LBRACE:
+                return true;
+            default:
+                // accept future strict tokens in non-strict mode (including LET)
+                if (!isStrictMode && t.getKind() == TokenKind.FUTURESTRICT) {
+                    return true;
+                }
+                return false;
+            }
+        }
+    }
+
     /**
      * ...IterationStatement :
      *           ...
@@ -1559,7 +2284,7 @@
      */
     private void returnStatement() {
         // check for return outside function
-        if (lc.getCurrentFunction().getKind() == FunctionNode.Kind.SCRIPT) {
+        if (lc.getCurrentFunction().getKind() == FunctionNode.Kind.SCRIPT || lc.getCurrentFunction().getKind() == FunctionNode.Kind.MODULE) {
             throw error(AbstractParser.message("invalid.return"));
         }
 
@@ -1591,39 +2316,61 @@
     }
 
     /**
-     * YieldStatement :
-     *      yield Expression? ; // [no LineTerminator here]
-     *
-     * JavaScript 1.8
+     * Parse YieldExpression.
      *
-     * Parse YIELD statement.
+     * YieldExpression[In] :
+     *   yield
+     *   yield [no LineTerminator here] AssignmentExpression[?In, Yield]
+     *   yield [no LineTerminator here] * AssignmentExpression[?In, Yield]
      */
-    private void yieldStatement() {
+    private Expression yieldExpression(final boolean noIn) {
+        assert inGeneratorFunction();
         // Capture YIELD token.
-        final int  yieldLine  = line;
-        final long yieldToken = token;
+        long yieldToken = token;
         // YIELD tested in caller.
+        assert type == YIELD;
         nextOrEOL();
 
         Expression expression = null;
 
-        // SEMICOLON or expression.
+        boolean yieldAsterisk = false;
+        if (type == MUL) {
+            yieldAsterisk = true;
+            yieldToken = Token.recast(yieldToken, YIELD_STAR);
+            next();
+        }
+
         switch (type) {
         case RBRACE:
         case SEMICOLON:
         case EOL:
         case EOF:
-            break;
+        case COMMARIGHT:
+        case RPAREN:
+        case RBRACKET:
+        case COLON:
+            if (!yieldAsterisk) {
+                // treat (yield) as (yield void 0)
+                expression = newUndefinedLiteral(yieldToken, finish);
+                if (type == EOL) {
+                    next();
+                }
+                break;
+            } else {
+                // AssignmentExpression required, fall through
+            }
 
         default:
-            expression = expression();
+            expression = assignmentExpression(noIn);
             break;
         }
 
-        endOfLine();
-
         // Construct and add YIELD node.
-        appendStatement(new ReturnNode(yieldLine, yieldToken, finish, expression));
+        return new UnaryNode(yieldToken, expression);
+    }
+
+    private static UnaryNode newUndefinedLiteral(final long token, final int finish) {
+        return new UnaryNode(Token.recast(token, VOID), LiteralNode.newInstance(token, finish, 0));
     }
 
     /**
@@ -1679,11 +2426,15 @@
     private void switchStatement() {
         final int  switchLine  = line;
         final long switchToken = token;
+
+        // Block to capture variables declared inside the switch statement.
+        final ParserContextBlockNode switchBlock = newBlock();
+
         // SWITCH tested in caller.
         next();
 
         // Create and add switch statement.
-        final ParserContextSwitchNode switchNode= new ParserContextSwitchNode();
+        final ParserContextSwitchNode switchNode = new ParserContextSwitchNode();
         lc.push(switchNode);
 
         CaseNode defaultCase = null;
@@ -1727,7 +2478,7 @@
                 expect(COLON);
 
                 // Get CASE body.
-                final Block statements = getBlock(false);
+                final Block statements = getBlock(false); // TODO: List<Statement> statements = caseStatementList();
                 final CaseNode caseNode = new CaseNode(caseToken, finish, caseExpression, statements);
 
                 if (caseExpression == null) {
@@ -1740,9 +2491,11 @@
             next();
         } finally {
             lc.pop(switchNode);
+            restoreBlock(switchBlock);
         }
 
-        appendStatement(new SwitchNode(switchLine, switchToken, finish, expression, cases, defaultCase));
+        final SwitchNode switchStatement = new SwitchNode(switchLine, switchToken, finish, expression, cases, defaultCase);
+        appendStatement(new BlockStatement(switchLine, new Block(switchToken, finish, switchBlock.getFlags() | Block.IS_SYNTHETIC | Block.IS_SWITCH_BLOCK, switchStatement)));
     }
 
     /**
@@ -1769,7 +2522,7 @@
         Block body = null;
         try {
             lc.push(labelNode);
-            body = getStatement();
+            body = getStatement(true);
         } finally {
             assert lc.peek() instanceof ParserContextLabelNode;
             lc.pop(labelNode);
@@ -1935,13 +2688,19 @@
     /**
      * PrimaryExpression :
      *      this
-     *      Identifier
+     *      IdentifierReference
      *      Literal
      *      ArrayLiteral
      *      ObjectLiteral
      *      RegularExpressionLiteral
      *      TemplateLiteral
+     *      CoverParenthesizedExpressionAndArrowParameterList
+     *
+     * CoverParenthesizedExpressionAndArrowParameterList :
      *      ( Expression )
+     *      ( )
+     *      ( ... BindingIdentifier )
+     *      ( Expression , ... BindingIdentifier )
      *
      * Parse primary expression.
      * @return Expression node.
@@ -1956,7 +2715,7 @@
         case THIS:
             final String name = type.getName();
             next();
-            lc.getCurrentFunction().setFlag(FunctionNode.USES_THIS);
+            markThis(lc);
             return new IdentNode(primaryToken, finish, name);
         case IDENT:
             final IdentNode ident = getIdent();
@@ -1997,6 +2756,22 @@
         case LPAREN:
             next();
 
+            if (isES6()) {
+                if (type == RPAREN) {
+                    // ()
+                    nextOrEOL();
+                    expectDontAdvance(ARROW);
+                    return new ExpressionList(primaryToken, finish, Collections.emptyList());
+                } else if (type == ELLIPSIS) {
+                    // (...rest)
+                    final IdentNode restParam = formalParameterList(false).get(0);
+                    expectDontAdvance(RPAREN);
+                    nextOrEOL();
+                    expectDontAdvance(ARROW);
+                    return new ExpressionList(primaryToken, finish, Collections.singletonList(restParam));
+                }
+            }
+
             final Expression expression = expression();
 
             expect(RPAREN);
@@ -2073,8 +2848,9 @@
         final List<Expression> elements = new ArrayList<>();
         // Track elisions.
         boolean elision = true;
-loop:
+        loop:
         while (true) {
+            long spreadToken = 0;
             switch (type) {
             case RBRACKET:
                 next();
@@ -2093,14 +2869,24 @@
 
                 break;
 
+            case ELLIPSIS:
+                if (isES6()) {
+                    spreadToken = token;
+                    next();
+                }
+                // fall through
+
             default:
                 if (!elision) {
                     throw error(AbstractParser.message("expected.comma", type.getNameOrType()));
                 }
+
                 // Add expression element.
-                final Expression expression = assignmentExpression(false);
-
+                Expression expression = assignmentExpression(false);
                 if (expression != null) {
+                    if (spreadToken != 0) {
+                        expression = new UnaryNode(Token.recast(spreadToken, SPREAD_ARRAY), expression);
+                    }
                     elements.add(expression);
                 } else {
                     expect(RBRACKET);
@@ -2141,7 +2927,7 @@
 
         // Create a block for the object literal.
         boolean commaSeen = true;
-loop:
+        loop:
         while (true) {
             switch (type) {
                 case RBRACE:
@@ -2164,6 +2950,12 @@
                     commaSeen = false;
                     // Get and add the next property.
                     final PropertyNode property = propertyAssignment();
+
+                    if (property.isComputed()) {
+                        elements.add(property);
+                        break;
+                    }
+
                     final String key = property.getKeyName();
                     final Integer existing = map.get(key);
 
@@ -2185,36 +2977,23 @@
                     final FunctionNode prevGetter = existingProperty.getGetter();
                     final FunctionNode prevSetter = existingProperty.getSetter();
 
-                    // ECMA 11.1.5 strict mode restrictions
-                    if (isStrictMode && value != null && prevValue != null) {
-                        throw error(AbstractParser.message("property.redefinition", key), property.getToken());
-                    }
-
-                    final boolean isPrevAccessor = prevGetter != null || prevSetter != null;
-                    final boolean isAccessor     = getter != null     || setter != null;
-
-                    // data property redefined as accessor property
-                    if (prevValue != null && isAccessor) {
-                        throw error(AbstractParser.message("property.redefinition", key), property.getToken());
-                    }
-
-                    // accessor property redefined as data
-                    if (isPrevAccessor && value != null) {
-                        throw error(AbstractParser.message("property.redefinition", key), property.getToken());
-                    }
-
-                    if (isAccessor && isPrevAccessor) {
-                        if (getter != null && prevGetter != null ||
-                                setter != null && prevSetter != null) {
-                            throw error(AbstractParser.message("property.redefinition", key), property.getToken());
+                    if (!isES6()) {
+                        checkPropertyRedefinition(property, value, getter, setter, prevValue, prevGetter, prevSetter);
+                    } else {
+                        if (property.getKey() instanceof IdentNode && ((IdentNode)property.getKey()).isProtoPropertyName() &&
+                                        existingProperty.getKey() instanceof IdentNode && ((IdentNode)existingProperty.getKey()).isProtoPropertyName()) {
+                            throw error(AbstractParser.message("multiple.proto.key"), property.getToken());
                         }
                     }
 
-                    if (value != null) {
+                    if (value != null || prevValue != null) {
+                        map.put(key, elements.size());
                         elements.add(property);
                     } else if (getter != null) {
+                        assert prevGetter != null || prevSetter != null;
                         elements.set(existing, existingProperty.setGetter(getter));
                     } else if (setter != null) {
+                        assert prevGetter != null || prevSetter != null;
                         elements.set(existing, existingProperty.setSetter(setter));
                     }
                     break;
@@ -2224,18 +3003,43 @@
         return new ObjectNode(objectToken, finish, elements);
     }
 
+    private void checkPropertyRedefinition(final PropertyNode property, final Expression value, final FunctionNode getter, final FunctionNode setter, final Expression prevValue, final FunctionNode prevGetter, final FunctionNode prevSetter) {
+        // ECMA 11.1.5 strict mode restrictions
+        if (isStrictMode && value != null && prevValue != null) {
+            throw error(AbstractParser.message("property.redefinition", property.getKeyName()), property.getToken());
+        }
+
+        final boolean isPrevAccessor = prevGetter != null || prevSetter != null;
+        final boolean isAccessor     = getter != null     || setter != null;
+
+        // data property redefined as accessor property
+        if (prevValue != null && isAccessor) {
+            throw error(AbstractParser.message("property.redefinition", property.getKeyName()), property.getToken());
+        }
+
+        // accessor property redefined as data
+        if (isPrevAccessor && value != null) {
+            throw error(AbstractParser.message("property.redefinition", property.getKeyName()), property.getToken());
+        }
+
+        if (isAccessor && isPrevAccessor) {
+            if (getter != null && prevGetter != null ||
+                    setter != null && prevSetter != null) {
+                throw error(AbstractParser.message("property.redefinition", property.getKeyName()), property.getToken());
+            }
+        }
+    }
+
     /**
-     * PropertyName :
+     * LiteralPropertyName :
      *      IdentifierName
      *      StringLiteral
      *      NumericLiteral
      *
-     * See 11.1.5
-     *
      * @return PropertyName node
      */
     @SuppressWarnings("fallthrough")
-    private PropertyKey propertyName() {
+    private PropertyKey literalPropertyName() {
         switch (type) {
         case IDENT:
             return getIdent().setIsPropertyName();
@@ -2257,6 +3061,34 @@
     }
 
     /**
+     * ComputedPropertyName :
+     *      AssignmentExpression
+     *
+     * @return PropertyName node
+     */
+    private Expression computedPropertyName() {
+        expect(LBRACKET);
+        Expression expression = assignmentExpression(false);
+        expect(RBRACKET);
+        return expression;
+    }
+
+    /**
+     * PropertyName :
+     *      LiteralPropertyName
+     *      ComputedPropertyName
+     *
+     * @return PropertyName node
+     */
+    private Expression propertyName() {
+        if (type == LBRACKET && isES6()) {
+            return computedPropertyName();
+        } else {
+            return (Expression)literalPropertyName();
+        }
+    }
+
+    /**
      * PropertyAssignment :
      *      PropertyName : AssignmentExpression
      *      get PropertyName ( ) { FunctionBody }
@@ -2280,51 +3112,95 @@
         final long propertyToken = token;
         final int  functionLine  = line;
 
-        PropertyKey propertyName;
-
+        final Expression propertyName;
+        final boolean isIdentifier;
+
+        boolean generator = false;
+        if (type == MUL && isES6()) {
+            generator = true;
+            next();
+        }
+
+        final boolean computed = type == LBRACKET;
         if (type == IDENT) {
             // Get IDENT.
             final String ident = (String)expectValue(IDENT);
 
-            if (type != COLON) {
+            if (type != COLON && (type != LPAREN || !isES6())) {
                 final long getSetToken = propertyToken;
 
                 switch (ident) {
                 case "get":
                     final PropertyFunction getter = propertyGetterFunction(getSetToken, functionLine);
-                    return new PropertyNode(propertyToken, finish, getter.ident, null, getter.functionNode, null);
+                    return new PropertyNode(propertyToken, finish, getter.key, null, getter.functionNode, null, false, getter.computed);
 
                 case "set":
                     final PropertyFunction setter = propertySetterFunction(getSetToken, functionLine);
-                    return new PropertyNode(propertyToken, finish, setter.ident, null, null, setter.functionNode);
+                    return new PropertyNode(propertyToken, finish, setter.key, null, null, setter.functionNode, false, setter.computed);
                 default:
                     break;
                 }
             }
 
-            propertyName = createIdentNode(propertyToken, finish, ident).setIsPropertyName();
+            isIdentifier = true;
+            IdentNode identNode = createIdentNode(propertyToken, finish, ident).setIsPropertyName();
+            if (type == COLON && ident.equals("__proto__")) {
+                identNode = identNode.setIsProtoPropertyName();
+            }
+            propertyName = identNode;
         } else {
+            isIdentifier = isNonStrictModeIdent();
             propertyName = propertyName();
         }
 
-        expect(COLON);
-
-        defaultNames.push(propertyName);
-        try {
-            return new PropertyNode(propertyToken, finish, propertyName, assignmentExpression(false), null, null);
-        } finally {
-            defaultNames.pop();
+        Expression propertyValue;
+
+        if (generator) {
+            expectDontAdvance(LPAREN);
         }
+
+        if (type == LPAREN && isES6()) {
+            propertyValue = propertyMethodFunction(propertyName, propertyToken, functionLine, generator, FunctionNode.ES6_IS_METHOD, computed).functionNode;
+        } else if (isIdentifier && (type == COMMARIGHT || type == RBRACE || type == ASSIGN) && isES6()) {
+            propertyValue = createIdentNode(propertyToken, finish, ((IdentNode) propertyName).getPropertyName());
+            if (type == ASSIGN && isES6()) {
+                // TODO if not destructuring, this is a SyntaxError
+                final long assignToken = token;
+                next();
+                final Expression rhs = assignmentExpression(false);
+                propertyValue = verifyAssignment(assignToken, propertyValue, rhs);
+            }
+        } else {
+            expect(COLON);
+
+            defaultNames.push(propertyName);
+            try {
+                propertyValue = assignmentExpression(false);
+            } finally {
+                defaultNames.pop();
+            }
+        }
+
+        return new PropertyNode(propertyToken, finish, propertyName, propertyValue, null, null, false, computed);
     }
 
     private PropertyFunction propertyGetterFunction(final long getSetToken, final int functionLine) {
-        final PropertyKey getIdent = propertyName();
-        final String getterName = getIdent.getPropertyName();
-        final IdentNode getNameNode = createIdentNode(((Node)getIdent).getToken(), finish, NameCodec.encode("get " + getterName));
+        return propertyGetterFunction(getSetToken, functionLine, FunctionNode.ES6_IS_METHOD);
+    }
+
+    private PropertyFunction propertyGetterFunction(final long getSetToken, final int functionLine, final int flags) {
+        final boolean computed = type == LBRACKET;
+        final Expression propertyName = propertyName();
+        final String getterName = propertyName instanceof PropertyKey ? ((PropertyKey) propertyName).getPropertyName() : getDefaultValidFunctionName(functionLine, false);
+        final IdentNode getNameNode = createIdentNode((propertyName).getToken(), finish, NameCodec.encode("get " + getterName));
         expect(LPAREN);
         expect(RPAREN);
 
         final ParserContextFunctionNode functionNode = createParserContextFunctionNode(getNameNode, getSetToken, FunctionNode.Kind.GETTER, functionLine, Collections.<IdentNode>emptyList());
+        functionNode.setFlag(flags);
+        if (computed) {
+            functionNode.setFlag(FunctionNode.IS_ANONYMOUS);
+        }
         lc.push(functionNode);
 
         Block functionBody;
@@ -2345,20 +3221,25 @@
                 functionLine,
                 functionBody);
 
-        return new PropertyFunction(getIdent, function);
+        return new PropertyFunction(propertyName, function, computed);
     }
 
     private PropertyFunction propertySetterFunction(final long getSetToken, final int functionLine) {
-        final PropertyKey setIdent = propertyName();
-        final String setterName = setIdent.getPropertyName();
-        final IdentNode setNameNode = createIdentNode(((Node)setIdent).getToken(), finish, NameCodec.encode("set " + setterName));
+        return propertySetterFunction(getSetToken, functionLine, FunctionNode.ES6_IS_METHOD);
+    }
+
+    private PropertyFunction propertySetterFunction(final long getSetToken, final int functionLine, final int flags) {
+        final boolean computed = type == LBRACKET;
+        final Expression propertyName = propertyName();
+        final String setterName = propertyName instanceof PropertyKey ? ((PropertyKey) propertyName).getPropertyName() : getDefaultValidFunctionName(functionLine, false);
+        final IdentNode setNameNode = createIdentNode((propertyName).getToken(), finish, NameCodec.encode("set " + setterName));
         expect(LPAREN);
         // be sloppy and allow missing setter parameter even though
         // spec does not permit it!
         final IdentNode argIdent;
-        if (type == IDENT || isNonStrictModeIdent()) {
+        if (isBindingIdentifier()) {
             argIdent = getIdent();
-            verifyStrictIdent(argIdent, "setter argument");
+            verifyIdent(argIdent, "setter argument");
         } else {
             argIdent = null;
         }
@@ -2370,6 +3251,10 @@
 
 
         final ParserContextFunctionNode functionNode = createParserContextFunctionNode(setNameNode, getSetToken, FunctionNode.Kind.SETTER, functionLine, parameters);
+        functionNode.setFlag(flags);
+        if (computed) {
+            functionNode.setFlag(FunctionNode.IS_ANONYMOUS);
+        }
         lc.push(functionNode);
 
         Block functionBody;
@@ -2389,33 +3274,81 @@
                 functionLine,
                 functionBody);
 
-        return new PropertyFunction(setIdent, function);
+        return new PropertyFunction(propertyName, function, computed);
+    }
+
+    private PropertyFunction propertyMethodFunction(Expression key, final long methodToken, final int methodLine, final boolean generator, final int flags, boolean computed) {
+        final String methodName = key instanceof PropertyKey ? ((PropertyKey) key).getPropertyName() : getDefaultValidFunctionName(methodLine, false);
+        final IdentNode methodNameNode = createIdentNode(((Node)key).getToken(), finish, methodName);
+
+        FunctionNode.Kind functionKind = generator ? FunctionNode.Kind.GENERATOR : FunctionNode.Kind.NORMAL;
+        final ParserContextFunctionNode functionNode = createParserContextFunctionNode(methodNameNode, methodToken, functionKind, methodLine, null);
+        functionNode.setFlag(flags);
+        if (computed) {
+            functionNode.setFlag(FunctionNode.IS_ANONYMOUS);
+        }
+        lc.push(functionNode);
+
+        try {
+            final ParserContextBlockNode parameterBlock = newBlock();
+            final List<IdentNode> parameters;
+            try {
+                expect(LPAREN);
+                parameters = formalParameterList(generator);
+                functionNode.setParameters(parameters);
+                expect(RPAREN);
+            } finally {
+                restoreBlock(parameterBlock);
+            }
+
+            Block functionBody = functionBody(functionNode);
+
+            functionBody = maybeWrapBodyInParameterBlock(functionBody, parameterBlock);
+
+            final FunctionNode  function = createFunctionNode(
+                            functionNode,
+                            methodToken,
+                            methodNameNode,
+                            parameters,
+                            functionKind,
+                            methodLine,
+                            functionBody);
+            return new PropertyFunction(key, function, computed);
+        } finally {
+            lc.pop(functionNode);
+        }
     }
 
     private static class PropertyFunction {
-        final PropertyKey ident;
+        final Expression key;
         final FunctionNode functionNode;
-
-        PropertyFunction(final PropertyKey ident, final FunctionNode function) {
-            this.ident = ident;
+        final boolean computed;
+
+        PropertyFunction(final Expression key, final FunctionNode function, final boolean computed) {
+            this.key = key;
             this.functionNode = function;
+            this.computed = computed;
         }
     }
 
     /**
-     * Parse left hand side expression.
-     *
      * LeftHandSideExpression :
      *      NewExpression
      *      CallExpression
      *
      * CallExpression :
      *      MemberExpression Arguments
+     *      SuperCall
      *      CallExpression Arguments
      *      CallExpression [ Expression ]
      *      CallExpression . IdentifierName
-     *      CallExpression TemplateLiteral
+     *
+     * SuperCall :
+     *      super Arguments
      *
+     * See 11.2
+     *
+     * Parse left hand side expression.
      * @return Expression node.
      */
     private Expression leftHandSideExpression() {
@@ -2435,7 +3368,7 @@
             lhs = new CallNode(callLine, callToken, finish, lhs, arguments, false);
         }
 
-loop:
+        loop:
         while (true) {
             // Capture token.
             callLine  = line;
@@ -2479,6 +3412,7 @@
                 // tagged template literal
                 final List<Expression> arguments = templateLiteralArgumentList();
 
+                // Create call node.
                 lhs = new CallNode(callLine, callToken, finish, lhs, arguments, false);
 
                 break;
@@ -2506,6 +3440,20 @@
         // NEW is tested in caller.
         next();
 
+        if (type == PERIOD && isES6()) {
+            next();
+            if (type == IDENT && "target".equals(getValue())) {
+                if (lc.getCurrentFunction().isProgram()) {
+                    throw error(AbstractParser.message("new.target.in.function"), token);
+                }
+                next();
+                markNewTarget(lc);
+                return new IdentNode(newToken, finish, "new.target");
+            } else {
+                throw error(AbstractParser.message("expected.target"), token);
+            }
+        }
+
         // Get function base.
         final int  callLine    = line;
         final Expression constructor = memberExpression();
@@ -2541,21 +3489,33 @@
     }
 
     /**
-     * Parse member expression.
-     *
      * MemberExpression :
      *      PrimaryExpression
-     *      FunctionExpression
+     *        FunctionExpression
+     *        ClassExpression
+     *        GeneratorExpression
      *      MemberExpression [ Expression ]
      *      MemberExpression . IdentifierName
      *      MemberExpression TemplateLiteral
+     *      SuperProperty
+     *      MetaProperty
      *      new MemberExpression Arguments
      *
+     * SuperProperty :
+     *      super [ Expression ]
+     *      super . IdentifierName
+     *
+     * MetaProperty :
+     *      NewTarget
+     *
+     * Parse member expression.
      * @return Expression node.
      */
+    @SuppressWarnings("fallthrough")
     private Expression memberExpression() {
         // Prepare to build operation.
         Expression lhs;
+        boolean isSuper = false;
 
         switch (type) {
         case NEW:
@@ -2568,13 +3528,53 @@
             lhs = functionExpression(false, false);
             break;
 
+        case CLASS:
+            if (isES6()) {
+                lhs = classExpression(false);
+                break;
+            } else {
+                // fall through
+            }
+
+        case SUPER:
+            if (isES6()) {
+                final ParserContextFunctionNode currentFunction = getCurrentNonArrowFunction();
+                if (currentFunction.isMethod()) {
+                    long identToken = Token.recast(token, IDENT);
+                    next();
+                    lhs = createIdentNode(identToken, finish, SUPER.getName());
+
+                    switch (type) {
+                        case LBRACKET:
+                        case PERIOD:
+                            getCurrentNonArrowFunction().setFlag(FunctionNode.ES6_USES_SUPER);
+                            isSuper = true;
+                            break;
+                        case LPAREN:
+                            if (currentFunction.isSubclassConstructor()) {
+                                lhs = ((IdentNode)lhs).setIsDirectSuper();
+                                break;
+                            } else {
+                                // fall through to throw error
+                            }
+                        default:
+                            throw error(AbstractParser.message("invalid.super"), identToken);
+                    }
+                    break;
+                } else {
+                    // fall through
+                }
+            } else {
+                // fall through
+            }
+
         default:
             // Get primary expression.
             lhs = primaryExpression();
             break;
         }
 
-loop:
+        loop:
         while (true) {
             // Capture token.
             final long callToken = token;
@@ -2591,6 +3591,11 @@
                 // Create indexing node.
                 lhs = new IndexNode(callToken, finish, lhs, index);
 
+                if (isSuper) {
+                    isSuper = false;
+                    lhs = ((BaseNode) lhs).setIsSuper();
+                }
+
                 break;
             }
             case PERIOD: {
@@ -2605,6 +3610,11 @@
                 // Create property access node.
                 lhs = new AccessNode(callToken, finish, lhs, property.getName());
 
+                if (isSuper) {
+                    isSuper = false;
+                    lhs = ((BaseNode) lhs).setIsSuper();
+                }
+
                 break;
             }
             case TEMPLATE:
@@ -2632,7 +3642,9 @@
      *
      * ArgumentList :
      *      AssignmentExpression
+     *      ... AssignmentExpression
      *      ArgumentList , AssignmentExpression
+     *      ArgumentList , ... AssignmentExpression
      *
      * See 11.2
      *
@@ -2656,8 +3668,18 @@
                 first = false;
             }
 
+            long spreadToken = 0;
+            if (type == ELLIPSIS && isES6()) {
+                spreadToken = token;
+                next();
+            }
+
             // Get argument expression.
-            nodeList.add(assignmentExpression(false));
+            Expression expression = assignmentExpression(false);
+            if (spreadToken != 0) {
+                expression = new UnaryNode(Token.recast(spreadToken, TokenType.SPREAD_ARGUMENT), expression);
+            }
+            nodeList.add(expression);
         }
 
         expect(RPAREN);
@@ -2697,11 +3719,24 @@
         final long functionToken = token;
         final int  functionLine  = line;
         // FUNCTION is tested in caller.
+        assert type == FUNCTION;
         next();
 
+        boolean generator = false;
+        if (type == MUL && isES6()) {
+            generator = true;
+            next();
+        }
+
         IdentNode name = null;
 
-        if (type == IDENT || isNonStrictModeIdent()) {
+        if (isBindingIdentifier()) {
+            if (type == YIELD && ((!isStatement && generator) || (isStatement && inGeneratorFunction()))) {
+                // 12.1.1 Early SyntaxError if:
+                // GeneratorExpression with BindingIdentifier yield
+                // HoistableDeclaration with BindingIdentifier yield in generator function body
+                expect(IDENT);
+            }
             name = getIdent();
             verifyStrictIdent(name, "function name");
         } else if (isStatement) {
@@ -2723,25 +3758,36 @@
             isAnonymous = true;
         }
 
-        expect(LPAREN);
-        final List<IdentNode> parameters = formalParameterList();
-        expect(RPAREN);
-
-        final ParserContextFunctionNode functionNode = createParserContextFunctionNode(name, functionToken, FunctionNode.Kind.NORMAL, functionLine, parameters);
+        FunctionNode.Kind functionKind = generator ? FunctionNode.Kind.GENERATOR : FunctionNode.Kind.NORMAL;
+        List<IdentNode> parameters = Collections.emptyList();
+        final ParserContextFunctionNode functionNode = createParserContextFunctionNode(name, functionToken, functionKind, functionLine, parameters);
         lc.push(functionNode);
+
         Block functionBody = null;
         // Hide the current default name across function boundaries. E.g. "x3 = function x1() { function() {}}"
         // If we didn't hide the current default name, then the innermost anonymous function would receive "x3".
         hideDefaultName();
-        try{
+        try {
+            final ParserContextBlockNode parameterBlock = newBlock();
+            try {
+                expect(LPAREN);
+                parameters = formalParameterList(generator);
+                functionNode.setParameters(parameters);
+                expect(RPAREN);
+            } finally {
+                restoreBlock(parameterBlock);
+            }
+
             functionBody = functionBody(functionNode);
+
+            functionBody = maybeWrapBodyInParameterBlock(functionBody, parameterBlock);
         } finally {
             defaultNames.pop();
             lc.pop(functionNode);
         }
 
         if (isStatement) {
-            if (topLevel || useBlockScope()) {
+            if (topLevel || useBlockScope() || (!isStrictMode && env._function_statement == ScriptEnvironment.FunctionStatementBehavior.ACCEPT)) {
                 functionNode.setFlag(FunctionNode.IS_DECLARED);
             } else if (isStrictMode) {
                 throw error(JSErrorType.SYNTAX_ERROR, AbstractParser.message("strict.no.func.decl.here"), functionToken);
@@ -2759,45 +3805,14 @@
             functionNode.setFlag(FunctionNode.IS_ANONYMOUS);
         }
 
-        final int arity = parameters.size();
-
-        final boolean strict = functionNode.isStrict();
-        if (arity > 1) {
-            final HashSet<String> parametersSet = new HashSet<>(arity);
-
-            for (int i = arity - 1; i >= 0; i--) {
-                final IdentNode parameter = parameters.get(i);
-                String parameterName = parameter.getName();
-
-                if (isArguments(parameterName)) {
-                    functionNode.setFlag(FunctionNode.DEFINES_ARGUMENTS);
-                }
-
-                if (parametersSet.contains(parameterName)) {
-                    // redefinition of parameter name
-                    if (strict) {
-                        throw error(AbstractParser.message("strict.param.redefinition", parameterName), parameter.getToken());
-                    }
-                    // rename in non-strict mode
-                    parameterName = functionNode.uniqueName(parameterName);
-                    final long parameterToken = parameter.getToken();
-                    parameters.set(i, new IdentNode(parameterToken, Token.descPosition(parameterToken), functionNode.uniqueName(parameterName)));
-                }
-
-                parametersSet.add(parameterName);
-            }
-        } else if (arity == 1) {
-            if (isArguments(parameters.get(0))) {
-                functionNode.setFlag(FunctionNode.DEFINES_ARGUMENTS);
-            }
-        }
+        verifyParameterList(parameters, functionNode);
 
         final FunctionNode function = createFunctionNode(
                 functionNode,
                 functionToken,
                 name,
                 parameters,
-                FunctionNode.Kind.NORMAL,
+                functionKind,
                 functionLine,
                 functionBody);
 
@@ -2822,6 +3837,40 @@
         return function;
     }
 
+    private void verifyParameterList(final List<IdentNode> parameters, final ParserContextFunctionNode functionNode) {
+        final IdentNode duplicateParameter = functionNode.getDuplicateParameterBinding();
+        if (duplicateParameter != null) {
+            if (functionNode.isStrict() || functionNode.getKind() == FunctionNode.Kind.ARROW || !functionNode.isSimpleParameterList()) {
+                throw error(AbstractParser.message("strict.param.redefinition", duplicateParameter.getName()), duplicateParameter.getToken());
+            }
+
+            final int arity = parameters.size();
+            final HashSet<String> parametersSet = new HashSet<>(arity);
+
+            for (int i = arity - 1; i >= 0; i--) {
+                final IdentNode parameter = parameters.get(i);
+                String parameterName = parameter.getName();
+
+                if (parametersSet.contains(parameterName)) {
+                    // redefinition of parameter name, rename in non-strict mode
+                    parameterName = functionNode.uniqueName(parameterName);
+                    final long parameterToken = parameter.getToken();
+                    parameters.set(i, new IdentNode(parameterToken, Token.descPosition(parameterToken), functionNode.uniqueName(parameterName)));
+                }
+                parametersSet.add(parameterName);
+            }
+        }
+    }
+
+    private static Block maybeWrapBodyInParameterBlock(Block functionBody, ParserContextBlockNode parameterBlock) {
+        assert functionBody.isFunctionBody();
+        if (!parameterBlock.getStatements().isEmpty()) {
+            parameterBlock.appendStatement(new BlockStatement(functionBody));
+            return new Block(parameterBlock.getToken(), functionBody.getFinish(), (functionBody.getFlags() | Block.IS_PARAMETER_BLOCK) & ~Block.IS_BODY, parameterBlock.getStatements());
+        }
+        return functionBody;
+    }
+
     private String getDefaultValidFunctionName(final int functionLine, final boolean isStatement) {
         final String defaultFunctionName = getDefaultFunctionName();
         if (isValidIdentifier(defaultFunctionName)) {
@@ -2836,14 +3885,14 @@
     }
 
     private static boolean isValidIdentifier(final String name) {
-        if(name == null || name.isEmpty()) {
+        if (name == null || name.isEmpty()) {
             return false;
         }
-        if(!Character.isJavaIdentifierStart(name.charAt(0))) {
+        if (!Character.isJavaIdentifierStart(name.charAt(0))) {
             return false;
         }
-        for(int i = 1; i < name.length(); ++i) {
-            if(!Character.isJavaIdentifierPart(name.charAt(i))) {
+        for (int i = 1; i < name.length(); ++i) {
+            if (!Character.isJavaIdentifierPart(name.charAt(i))) {
                 return false;
             }
         }
@@ -2851,12 +3900,12 @@
     }
 
     private String getDefaultFunctionName() {
-        if(!defaultNames.isEmpty()) {
+        if (!defaultNames.isEmpty()) {
             final Object nameExpr = defaultNames.peek();
-            if(nameExpr instanceof PropertyKey) {
+            if (nameExpr instanceof PropertyKey) {
                 markDefaultNameUsed();
                 return ((PropertyKey)nameExpr).getPropertyName();
-            } else if(nameExpr instanceof AccessNode) {
+            } else if (nameExpr instanceof AccessNode) {
                 markDefaultNameUsed();
                 return ((AccessNode)nameExpr).getProperty();
             }
@@ -2885,8 +3934,8 @@
      * Parse function parameter list.
      * @return List of parameter nodes.
      */
-    private List<IdentNode> formalParameterList() {
-        return formalParameterList(RPAREN);
+    private List<IdentNode> formalParameterList(final boolean yield) {
+        return formalParameterList(RPAREN, yield);
     }
 
     /**
@@ -2902,7 +3951,7 @@
      * Parse function parameter list.
      * @return List of parameter nodes.
      */
-    private List<IdentNode> formalParameterList(final TokenType endType) {
+    private List<IdentNode> formalParameterList(final TokenType endType, final boolean yield) {
         // Prepare to gather parameters.
         final ArrayList<IdentNode> parameters = new ArrayList<>();
         // Track commas.
@@ -2916,12 +3965,84 @@
                 first = false;
             }
 
-            // Get and add parameter.
-            final IdentNode ident = getIdent();
-
-            // ECMA 13.1 strict mode restrictions
-            verifyStrictIdent(ident, "function parameter");
-
+            boolean restParameter = false;
+            if (type == ELLIPSIS && isES6()) {
+                next();
+                restParameter = true;
+            }
+
+            if (type == YIELD && yield) {
+                expect(IDENT);
+            }
+
+            final long paramToken = token;
+            final int paramLine = line;
+            final String contextString = "function parameter";
+            IdentNode ident;
+            if (isBindingIdentifier() || restParameter || !isES6()) {
+                ident = bindingIdentifier(contextString);
+
+                if (restParameter) {
+                    ident = ident.setIsRestParameter();
+                    // rest parameter must be last
+                    expectDontAdvance(endType);
+                    parameters.add(ident);
+                    break;
+                } else if (type == ASSIGN && isES6()) {
+                    next();
+                    ident = ident.setIsDefaultParameter();
+
+                    if (type == YIELD && yield) {
+                        // error: yield in default expression
+                        expect(IDENT);
+                    }
+
+                    // default parameter
+                    Expression initializer = assignmentExpression(false);
+
+                    ParserContextFunctionNode currentFunction = lc.getCurrentFunction();
+                    if (currentFunction != null) {
+                        // desugar to: param = (param === undefined) ? initializer : param;
+                        // possible alternative: if (param === undefined) param = initializer;
+                        BinaryNode test = new BinaryNode(Token.recast(paramToken, EQ_STRICT), ident, newUndefinedLiteral(paramToken, finish));
+                        TernaryNode value = new TernaryNode(Token.recast(paramToken, TERNARY), test, new JoinPredecessorExpression(initializer), new JoinPredecessorExpression(ident));
+                        BinaryNode assignment = new BinaryNode(Token.recast(paramToken, ASSIGN), ident, value);
+                        lc.getFunctionBody(currentFunction).appendStatement(new ExpressionStatement(paramLine, assignment.getToken(), assignment.getFinish(), assignment));
+                    }
+                }
+
+                ParserContextFunctionNode currentFunction = lc.getCurrentFunction();
+                if (currentFunction != null) {
+                    currentFunction.addParameterBinding(ident);
+                    if (ident.isRestParameter() || ident.isDefaultParameter()) {
+                        currentFunction.setSimpleParameterList(false);
+                    }
+                }
+            } else {
+                final Expression pattern = bindingPattern();
+                // Introduce synthetic temporary parameter to capture the object to be destructured.
+                ident = createIdentNode(paramToken, pattern.getFinish(), String.format("arguments[%d]", parameters.size())).setIsDestructuredParameter();
+                verifyDestructuringParameterBindingPattern(pattern, paramToken, paramLine, contextString);
+
+                Expression value = ident;
+                if (type == ASSIGN) {
+                    next();
+                    ident = ident.setIsDefaultParameter();
+
+                    // binding pattern with initializer. desugar to: (param === undefined) ? initializer : param
+                    Expression initializer = assignmentExpression(false);
+                    // TODO initializer must not contain yield expression if yield=true (i.e. this is generator function's parameter list)
+                    BinaryNode test = new BinaryNode(Token.recast(paramToken, EQ_STRICT), ident, newUndefinedLiteral(paramToken, finish));
+                    value = new TernaryNode(Token.recast(paramToken, TERNARY), test, new JoinPredecessorExpression(initializer), new JoinPredecessorExpression(ident));
+                }
+
+                ParserContextFunctionNode currentFunction = lc.getCurrentFunction();
+                if (currentFunction != null) {
+                    // destructuring assignment
+                    BinaryNode assignment = new BinaryNode(Token.recast(paramToken, ASSIGN), pattern, value);
+                    lc.getFunctionBody(currentFunction).appendStatement(new ExpressionStatement(paramLine, assignment.getToken(), assignment.getFinish(), assignment));
+                }
+            }
             parameters.add(ident);
         }
 
@@ -2929,6 +4050,23 @@
         return parameters;
     }
 
+    private void verifyDestructuringParameterBindingPattern(final Expression pattern, final long paramToken, final int paramLine, final String contextString) {
+        verifyDestructuringBindingPattern(pattern, new Consumer<IdentNode>() {
+            public void accept(IdentNode identNode) {
+                verifyIdent(identNode, contextString);
+
+                ParserContextFunctionNode currentFunction = lc.getCurrentFunction();
+                if (currentFunction != null) {
+                    // declare function-scope variables for destructuring bindings
+                    lc.getFunctionBody(currentFunction).appendStatement(new VarNode(paramLine, Token.recast(paramToken, VAR), pattern.getFinish(), identNode, null));
+                    // detect duplicate bounds names in parameter list
+                    currentFunction.addParameterBinding(identNode);
+                    currentFunction.setSimpleParameterList(false);
+                }
+            }
+        });
+    }
+
     /**
      * FunctionBody :
      *      SourceElements?
@@ -2958,7 +4096,7 @@
             final int functionId = functionNode.getId();
             parseBody = reparsedFunction == null || functionId <= reparsedFunction.getFunctionNodeId();
             // Nashorn extension: expression closures
-            if (!env._no_syntax_extensions && type != LBRACE) {
+            if ((!env._no_syntax_extensions || functionNode.getKind() == FunctionNode.Kind.ARROW) && type != LBRACE) {
                 /*
                  * Example:
                  *
@@ -2967,7 +4105,7 @@
                  */
 
                 // just expression as function body
-                final Expression expr = assignmentExpression(true);
+                final Expression expr = assignmentExpression(false);
                 lastToken = previousToken;
                 functionNode.setLastToken(previousToken);
                 assert lc.getCurrentBlock() == lc.getFunctionBody(functionNode);
@@ -2982,6 +4120,7 @@
                     final ReturnNode returnNode = new ReturnNode(functionNode.getLineNumber(), expr.getToken(), lastFinish, expr);
                     appendStatement(returnNode);
                 }
+                // bodyFinish = finish;
             } else {
                 expectDontAdvance(LBRACE);
                 if (parseBody || !skipFunctionBody(functionNode)) {
@@ -3054,7 +4193,7 @@
                 }
             }
         }
-        functionBody = new Block(bodyToken, bodyFinish, body.getFlags(), body.getStatements());
+        functionBody = new Block(bodyToken, bodyFinish, body.getFlags() | Block.IS_BODY, body.getStatements());
         return functionBody;
     }
 
@@ -3095,8 +4234,7 @@
         // Doesn't really matter, but it's safe to treat it as if there were a semicolon before
         // the RBRACE.
         type = SEMICOLON;
-        k = -1;
-        next();
+        scanFirstToken();
 
         return true;
     }
@@ -3126,11 +4264,11 @@
     }
 
     private void printAST(final FunctionNode functionNode) {
-        if (functionNode.getFlag(FunctionNode.IS_PRINT_AST)) {
+        if (functionNode.getDebugFlag(FunctionNode.DEBUG_PRINT_AST)) {
             env.getErr().println(new ASTWriter(functionNode));
         }
 
-        if (functionNode.getFlag(FunctionNode.IS_PRINT_PARSE)) {
+        if (functionNode.getDebugFlag(FunctionNode.DEBUG_PRINT_PARSE)) {
             env.getErr().println(new PrintVisitor(functionNode, true, false));
         }
     }
@@ -3222,20 +4360,7 @@
                 throw error(AbstractParser.message("expected.lvalue", type.getNameOrType()));
             }
 
-            if (!(lhs instanceof AccessNode ||
-                  lhs instanceof IndexNode ||
-                  lhs instanceof IdentNode)) {
-                return referenceError(lhs, null, env._early_lvalue_error);
-            }
-
-            if (lhs instanceof IdentNode) {
-                if (!checkIdentLValue((IdentNode)lhs)) {
-                    return referenceError(lhs, null, false);
-                }
-                verifyStrictIdent((IdentNode)lhs, "operand for " + opType.getName() + " operator");
-            }
-
-            return incDecExpression(unaryToken, opType, lhs, false);
+            return verifyIncDecExpression(unaryToken, opType, lhs, false);
 
         default:
             break;
@@ -3247,29 +4372,16 @@
             switch (type) {
             case INCPREFIX:
             case DECPREFIX:
+                final long opToken = token;
                 final TokenType opType = type;
                 final Expression lhs = expression;
                 // ++, -- without operand..
                 if (lhs == null) {
                     throw error(AbstractParser.message("expected.lvalue", type.getNameOrType()));
                 }
-
-                if (!(lhs instanceof AccessNode ||
-                   lhs instanceof IndexNode ||
-                   lhs instanceof IdentNode)) {
-                    next();
-                    return referenceError(lhs, null, env._early_lvalue_error);
-                }
-                if (lhs instanceof IdentNode) {
-                    if (!checkIdentLValue((IdentNode)lhs)) {
-                        next();
-                        return referenceError(lhs, null, false);
-                    }
-                    verifyStrictIdent((IdentNode)lhs, "operand for " + opType.getName() + " operator");
-                }
-                expression = incDecExpression(token, type, expression, true);
                 next();
-                break;
+
+                return verifyIncDecExpression(opToken, opType, lhs, true);
             default:
                 break;
             }
@@ -3282,6 +4394,25 @@
         return expression;
     }
 
+    private Expression verifyIncDecExpression(final long unaryToken, final TokenType opType, final Expression lhs, final boolean isPostfix) {
+        assert lhs != null;
+
+        if (!(lhs instanceof AccessNode ||
+              lhs instanceof IndexNode ||
+              lhs instanceof IdentNode)) {
+            return referenceError(lhs, null, env._early_lvalue_error);
+        }
+
+        if (lhs instanceof IdentNode) {
+            if (!checkIdentLValue((IdentNode)lhs)) {
+                return referenceError(lhs, null, false);
+            }
+            verifyIdent((IdentNode)lhs, "operand for " + opType.getName() + " operator");
+        }
+
+        return incDecExpression(unaryToken, opType, lhs, isPostfix);
+    }
+
     /**
      * {@code
      * MultiplicativeExpression :
@@ -3380,7 +4511,42 @@
         // at expression start point!
 
         // Include commas in expression parsing.
-        return expression(unaryExpression(), COMMARIGHT.getPrecedence(), false);
+        return expression(false);
+    }
+
+    private Expression expression(final boolean noIn) {
+        Expression assignmentExpression = assignmentExpression(noIn);
+        while (type == COMMARIGHT) {
+            long commaToken = token;
+            next();
+
+            boolean rhsRestParameter = false;
+            if (type == ELLIPSIS && isES6()) {
+                // (a, b, ...rest) is not a valid expression, unless we're parsing the parameter list of an arrow function (we need to throw the right error).
+                // But since the rest parameter is always last, at least we know that the expression has to end here and be followed by RPAREN and ARROW, so peek ahead.
+                if (isRestParameterEndOfArrowFunctionParameterList()) {
+                    next();
+                    rhsRestParameter = true;
+                }
+            }
+
+            Expression rhs = assignmentExpression(noIn);
+
+            if (rhsRestParameter) {
+                rhs = ((IdentNode)rhs).setIsRestParameter();
+                // Our only valid move is to end Expression here and continue with ArrowFunction.
+                // We've already checked that this is the parameter list of an arrow function (see above).
+                // RPAREN is next, so we'll finish the binary expression and drop out of the loop.
+                assert type == RPAREN;
+            }
+
+            assignmentExpression = new BinaryNode(commaToken, assignmentExpression, rhs);
+        }
+        return assignmentExpression;
+    }
+
+    private Expression expression(final int minPrecedence, final boolean noIn) {
+        return expression(unaryExpression(), minPrecedence, noIn);
     }
 
     private JoinPredecessorExpression joinPredecessorExpression() {
@@ -3448,12 +4614,316 @@
         return lhs;
     }
 
+    /**
+     * AssignmentExpression.
+     *
+     * AssignmentExpression[In, Yield] :
+     *   ConditionalExpression[?In, ?Yield]
+     *   [+Yield] YieldExpression[?In]
+     *   ArrowFunction[?In, ?Yield]
+     *   LeftHandSideExpression[?Yield] = AssignmentExpression[?In, ?Yield]
+     *   LeftHandSideExpression[?Yield] AssignmentOperator AssignmentExpression[?In, ?Yield]
+     */
     protected Expression assignmentExpression(final boolean noIn) {
         // This method is protected so that subclass can get details
         // at assignment expression start point!
 
-        // Exclude commas in expression parsing.
-        return expression(unaryExpression(), ASSIGN.getPrecedence(), noIn);
+        if (type == YIELD && inGeneratorFunction() && isES6()) {
+            return yieldExpression(noIn);
+        }
+
+        final long startToken = token;
+        final int startLine = line;
+        final Expression exprLhs = conditionalExpression(noIn);
+
+        if (type == ARROW && isES6()) {
+            if (checkNoLineTerminator()) {
+                final Expression paramListExpr;
+                if (exprLhs instanceof ExpressionList) {
+                    paramListExpr = (((ExpressionList)exprLhs).getExpressions().isEmpty() ? null : ((ExpressionList)exprLhs).getExpressions().get(0));
+                } else {
+                    paramListExpr = exprLhs;
+                }
+                return arrowFunction(startToken, startLine, paramListExpr);
+            }
+        }
+        assert !(exprLhs instanceof ExpressionList);
+
+        if (isAssignmentOperator(type)) {
+            final boolean isAssign = type == ASSIGN;
+            if (isAssign) {
+                defaultNames.push(exprLhs);
+            }
+            try {
+                final long assignToken = token;
+                next();
+                final Expression exprRhs = assignmentExpression(noIn);
+                return verifyAssignment(assignToken, exprLhs, exprRhs);
+            } finally {
+                if (isAssign) {
+                    defaultNames.pop();
+                }
+            }
+        } else {
+            return exprLhs;
+        }
+    }
+
+    /**
+     * Is type one of {@code = *= /= %= += -= <<= >>= >>>= &= ^= |=}?
+     */
+    private static boolean isAssignmentOperator(TokenType type) {
+        switch (type) {
+        case ASSIGN:
+        case ASSIGN_ADD:
+        case ASSIGN_BIT_AND:
+        case ASSIGN_BIT_OR:
+        case ASSIGN_BIT_XOR:
+        case ASSIGN_DIV:
+        case ASSIGN_MOD:
+        case ASSIGN_MUL:
+        case ASSIGN_SAR:
+        case ASSIGN_SHL:
+        case ASSIGN_SHR:
+        case ASSIGN_SUB:
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * ConditionalExpression.
+     */
+    private Expression conditionalExpression(boolean noIn) {
+        return expression(TERNARY.getPrecedence(), noIn);
+    }
+
+    /**
+     * ArrowFunction.
+     *
+     * @param startToken start token of the ArrowParameters expression
+     * @param functionLine start line of the arrow function
+     * @param paramListExpr ArrowParameters expression or {@code null} for {@code ()} (empty list)
+     */
+    private Expression arrowFunction(final long startToken, final int functionLine, final Expression paramListExpr) {
+        // caller needs to check that there's no LineTerminator between parameter list and arrow
+        assert type != ARROW || checkNoLineTerminator();
+        expect(ARROW);
+
+        final long functionToken = Token.recast(startToken, ARROW);
+        final IdentNode name = new IdentNode(functionToken, Token.descPosition(functionToken), "=>:" + functionLine);
+        final ParserContextFunctionNode functionNode = createParserContextFunctionNode(name, functionToken, FunctionNode.Kind.ARROW, functionLine, null);
+        functionNode.setFlag(FunctionNode.IS_ANONYMOUS);
+
+        lc.push(functionNode);
+        try {
+            ParserContextBlockNode parameterBlock = newBlock();
+            final List<IdentNode> parameters;
+            try {
+                parameters = convertArrowFunctionParameterList(paramListExpr, functionLine);
+                functionNode.setParameters(parameters);
+
+                if (!functionNode.isSimpleParameterList()) {
+                    markEvalInArrowParameterList(parameterBlock);
+                }
+            } finally {
+                restoreBlock(parameterBlock);
+            }
+            Block functionBody = functionBody(functionNode);
+
+            functionBody = maybeWrapBodyInParameterBlock(functionBody, parameterBlock);
+
+            verifyParameterList(parameters, functionNode);
+
+            final FunctionNode function = createFunctionNode(
+                            functionNode,
+                            functionToken,
+                            name,
+                            parameters,
+                            FunctionNode.Kind.ARROW,
+                            functionLine,
+                            functionBody);
+            return function;
+        } finally {
+            lc.pop(functionNode);
+        }
+    }
+
+    private void markEvalInArrowParameterList(final ParserContextBlockNode parameterBlock) {
+        final Iterator<ParserContextFunctionNode> iter = lc.getFunctions();
+        final ParserContextFunctionNode current = iter.next();
+        final ParserContextFunctionNode parent = iter.next();
+
+        if (parent.getFlag(FunctionNode.HAS_EVAL) != 0) {
+            // we might have flagged has-eval in the parent function during parsing the parameter list,
+            // if the parameter list contains eval; must tag arrow function as has-eval.
+            for (final Statement st : parameterBlock.getStatements()) {
+                st.accept(new NodeVisitor<LexicalContext>(new LexicalContext()) {
+                    @Override
+                    public boolean enterCallNode(final CallNode callNode) {
+                        if (callNode.getFunction() instanceof IdentNode && ((IdentNode) callNode.getFunction()).getName().equals("eval")) {
+                            current.setFlag(FunctionNode.HAS_EVAL);
+                        }
+                        return true;
+                    }
+                });
+            }
+            // TODO: function containing the arrow function should not be flagged has-eval
+        }
+    }
+
+    private List<IdentNode> convertArrowFunctionParameterList(final Expression paramListExpr, final int functionLine) {
+        final List<IdentNode> parameters;
+        if (paramListExpr == null) {
+            // empty parameter list, i.e. () =>
+            parameters = Collections.emptyList();
+        } else if (paramListExpr instanceof IdentNode || paramListExpr.isTokenType(ASSIGN) || isDestructuringLhs(paramListExpr)) {
+            parameters = Collections.singletonList(verifyArrowParameter(paramListExpr, 0, functionLine));
+        } else if (paramListExpr instanceof BinaryNode && Token.descType(paramListExpr.getToken()) == COMMARIGHT) {
+            parameters = new ArrayList<>();
+            Expression car = paramListExpr;
+            do {
+                final Expression cdr = ((BinaryNode) car).rhs();
+                parameters.add(0, verifyArrowParameter(cdr, parameters.size(), functionLine));
+                car = ((BinaryNode) car).lhs();
+            } while (car instanceof BinaryNode && Token.descType(car.getToken()) == COMMARIGHT);
+            parameters.add(0, verifyArrowParameter(car, parameters.size(), functionLine));
+        } else {
+            throw error(AbstractParser.message("expected.arrow.parameter"), paramListExpr.getToken());
+        }
+        return parameters;
+    }
+
+    private IdentNode verifyArrowParameter(Expression param, int index, int paramLine) {
+        final String contextString = "function parameter";
+        if (param instanceof IdentNode) {
+            IdentNode ident = (IdentNode)param;
+            verifyStrictIdent(ident, contextString);
+            ParserContextFunctionNode currentFunction = lc.getCurrentFunction();
+            if (currentFunction != null) {
+                currentFunction.addParameterBinding(ident);
+            }
+            return ident;
+        }
+
+        if (param.isTokenType(ASSIGN)) {
+            Expression lhs = ((BinaryNode) param).lhs();
+            long paramToken = lhs.getToken();
+            Expression initializer = ((BinaryNode) param).rhs();
+            if (lhs instanceof IdentNode) {
+                // default parameter
+                IdentNode ident = (IdentNode) lhs;
+
+                ParserContextFunctionNode currentFunction = lc.getCurrentFunction();
+                if (currentFunction != null) {
+                    BinaryNode test = new BinaryNode(Token.recast(paramToken, EQ_STRICT), ident, newUndefinedLiteral(paramToken, finish));
+                    TernaryNode value = new TernaryNode(Token.recast(paramToken, TERNARY), test, new JoinPredecessorExpression(initializer), new JoinPredecessorExpression(ident));
+                    BinaryNode assignment = new BinaryNode(Token.recast(paramToken, ASSIGN), ident, value);
+                    lc.getFunctionBody(currentFunction).appendStatement(new ExpressionStatement(paramLine, assignment.getToken(), assignment.getFinish(), assignment));
+
+                    currentFunction.addParameterBinding(ident);
+                    currentFunction.setSimpleParameterList(false);
+                }
+                return ident;
+            } else if (isDestructuringLhs(lhs)) {
+                // binding pattern with initializer
+                // Introduce synthetic temporary parameter to capture the object to be destructured.
+                IdentNode ident = createIdentNode(paramToken, param.getFinish(), String.format("arguments[%d]", index)).setIsDestructuredParameter().setIsDefaultParameter();
+                verifyDestructuringParameterBindingPattern(param, paramToken, paramLine, contextString);
+
+                ParserContextFunctionNode currentFunction = lc.getCurrentFunction();
+                if (currentFunction != null) {
+                    BinaryNode test = new BinaryNode(Token.recast(paramToken, EQ_STRICT), ident, newUndefinedLiteral(paramToken, finish));
+                    TernaryNode value = new TernaryNode(Token.recast(paramToken, TERNARY), test, new JoinPredecessorExpression(initializer), new JoinPredecessorExpression(ident));
+                    BinaryNode assignment = new BinaryNode(Token.recast(paramToken, ASSIGN), param, value);
+                    lc.getFunctionBody(currentFunction).appendStatement(new ExpressionStatement(paramLine, assignment.getToken(), assignment.getFinish(), assignment));
+                }
+                return ident;
+            }
+        } else if (isDestructuringLhs(param)) {
+            // binding pattern
+            long paramToken = param.getToken();
+
+            // Introduce synthetic temporary parameter to capture the object to be destructured.
+            IdentNode ident = createIdentNode(paramToken, param.getFinish(), String.format("arguments[%d]", index)).setIsDestructuredParameter();
+            verifyDestructuringParameterBindingPattern(param, paramToken, paramLine, contextString);
+
+            ParserContextFunctionNode currentFunction = lc.getCurrentFunction();
+            if (currentFunction != null) {
+                BinaryNode assignment = new BinaryNode(Token.recast(paramToken, ASSIGN), param, ident);
+                lc.getFunctionBody(currentFunction).appendStatement(new ExpressionStatement(paramLine, assignment.getToken(), assignment.getFinish(), assignment));
+            }
+            return ident;
+        }
+        throw error(AbstractParser.message("invalid.arrow.parameter"), param.getToken());
+    }
+
+    private boolean checkNoLineTerminator() {
+        assert type == ARROW;
+        if (last == RPAREN) {
+            return true;
+        } else if (last == IDENT) {
+            return true;
+        }
+        for (int i = k - 1; i >= 0; i--) {
+            TokenType t = T(i);
+            switch (t) {
+            case RPAREN:
+            case IDENT:
+                return true;
+            case EOL:
+                return false;
+            case COMMENT:
+                continue;
+            default:
+                if (t.getKind() == TokenKind.FUTURESTRICT) {
+                    return true;
+                }
+                return false;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Peek ahead to see if what follows after the ellipsis is a rest parameter
+     * at the end of an arrow function parameter list.
+     */
+    private boolean isRestParameterEndOfArrowFunctionParameterList() {
+        assert type == ELLIPSIS;
+        // find IDENT, RPAREN, ARROW, in that order, skipping over EOL (where allowed) and COMMENT
+        int i = 1;
+        for (;;) {
+            TokenType t = T(k + i++);
+            if (t == IDENT) {
+                break;
+            } else if (t == EOL || t == COMMENT) {
+                continue;
+            } else {
+                return false;
+            }
+        }
+        for (;;) {
+            TokenType t = T(k + i++);
+            if (t == RPAREN) {
+                break;
+            } else if (t == EOL || t == COMMENT) {
+                continue;
+            } else {
+                return false;
+            }
+        }
+        for (;;) {
+            TokenType t = T(k + i++);
+            if (t == ARROW) {
+                break;
+            } else if (t == COMMENT) {
+                continue;
+            } else {
+                return false;
+            }
+        }
+        return true;
     }
 
     /**
@@ -3551,6 +5021,380 @@
         cookedStrings.add(LiteralNode.newInstance(stringToken, finish, cookedString));
     }
 
+
+    /**
+     * Parse a module.
+     *
+     * Module :
+     *      ModuleBody?
+     *
+     * ModuleBody :
+     *      ModuleItemList
+     */
+    private FunctionNode module(final String moduleName) {
+        boolean oldStrictMode = isStrictMode;
+        try {
+            isStrictMode = true; // Module code is always strict mode code. (ES6 10.2.1)
+
+            // Make a pseudo-token for the script holding its start and length.
+            int functionStart = Math.min(Token.descPosition(Token.withDelimiter(token)), finish);
+            final long functionToken = Token.toDesc(FUNCTION, functionStart, source.getLength() - functionStart);
+            final int  functionLine  = line;
+
+            final IdentNode ident = new IdentNode(functionToken, Token.descPosition(functionToken), moduleName);
+            final ParserContextFunctionNode script = createParserContextFunctionNode(
+                            ident,
+                            functionToken,
+                            FunctionNode.Kind.MODULE,
+                            functionLine,
+                            Collections.<IdentNode>emptyList());
+            lc.push(script);
+
+            final ParserContextModuleNode module = new ParserContextModuleNode(moduleName);
+            lc.push(module);
+
+            final ParserContextBlockNode body = newBlock();
+
+            functionDeclarations = new ArrayList<>();
+            moduleBody();
+            addFunctionDeclarations(script);
+            functionDeclarations = null;
+
+            restoreBlock(body);
+            body.setFlag(Block.NEEDS_SCOPE);
+            final Block programBody = new Block(functionToken, finish, body.getFlags() | Block.IS_SYNTHETIC | Block.IS_BODY, body.getStatements());
+            lc.pop(module);
+            lc.pop(script);
+            script.setLastToken(token);
+
+            expect(EOF);
+
+            script.setModule(module.createModule());
+            return createFunctionNode(script, functionToken, ident, Collections.<IdentNode>emptyList(), FunctionNode.Kind.MODULE, functionLine, programBody);
+        } finally {
+            isStrictMode = oldStrictMode;
+        }
+    }
+
+    /**
+     * Parse module body.
+     *
+     * ModuleBody :
+     *      ModuleItemList
+     *
+     * ModuleItemList :
+     *      ModuleItem
+     *      ModuleItemList ModuleItem
+     *
+     * ModuleItem :
+     *      ImportDeclaration
+     *      ExportDeclaration
+     *      StatementListItem
+     */
+    private void moduleBody() {
+        loop:
+        while (type != EOF) {
+            switch (type) {
+            case EOF:
+                break loop;
+            case IMPORT:
+                importDeclaration();
+                break;
+            case EXPORT:
+                exportDeclaration();
+                break;
+            default:
+                // StatementListItem
+                statement(true, false, false, false);
+                break;
+            }
+        }
+    }
+
+
+    /**
+     * Parse import declaration.
+     *
+     * ImportDeclaration :
+     *     import ImportClause FromClause ;
+     *     import ModuleSpecifier ;
+     * ImportClause :
+     *     ImportedDefaultBinding
+     *     NameSpaceImport
+     *     NamedImports
+     *     ImportedDefaultBinding , NameSpaceImport
+     *     ImportedDefaultBinding , NamedImports
+     * ImportedDefaultBinding :
+     *     ImportedBinding
+     * ModuleSpecifier :
+     *     StringLiteral
+     * ImportedBinding :
+     *     BindingIdentifier
+     */
+    private void importDeclaration() {
+        expect(IMPORT);
+        final ParserContextModuleNode module = lc.getCurrentModule();
+        if (type == STRING || type == ESCSTRING) {
+            // import ModuleSpecifier ;
+            final String moduleSpecifier = (String) getValue();
+            next();
+            module.addModuleRequest(moduleSpecifier);
+        } else {
+            // import ImportClause FromClause ;
+            List<Module.ImportEntry> importEntries;
+            if (type == MUL) {
+                importEntries = Collections.singletonList(nameSpaceImport());
+            } else if (type == LBRACE) {
+                importEntries = namedImports();
+            } else if (isBindingIdentifier()) {
+                // ImportedDefaultBinding
+                final IdentNode importedDefaultBinding = bindingIdentifier("ImportedBinding");
+                Module.ImportEntry defaultImport = Module.ImportEntry.importDefault(importedDefaultBinding.getName());
+
+                if (type == COMMARIGHT) {
+                    next();
+                    importEntries = new ArrayList<>();
+                    if (type == MUL) {
+                        importEntries.add(nameSpaceImport());
+                    } else if (type == LBRACE) {
+                        importEntries.addAll(namedImports());
+                    } else {
+                        throw error(AbstractParser.message("expected.named.import"));
+                    }
+                } else {
+                    importEntries = Collections.singletonList(defaultImport);
+                }
+            } else {
+                throw error(AbstractParser.message("expected.import"));
+            }
+
+            final String moduleSpecifier = fromClause();
+            module.addModuleRequest(moduleSpecifier);
+            for (int i = 0; i < importEntries.size(); i++) {
+                module.addImportEntry(importEntries.get(i).withFrom(moduleSpecifier));
+            }
+        }
+        expect(SEMICOLON);
+    }
+
+    /**
+     * NameSpaceImport :
+     *     * as ImportedBinding
+     *
+     * @return imported binding identifier
+     */
+    private Module.ImportEntry nameSpaceImport() {
+        assert type == MUL;
+        next();
+        final long asToken = token;
+        final String as = (String) expectValue(IDENT);
+        if (!"as".equals(as)) {
+            throw error(AbstractParser.message("expected.as"), asToken);
+        }
+        final IdentNode localNameSpace = bindingIdentifier("ImportedBinding");
+        return Module.ImportEntry.importStarAsNameSpaceFrom(localNameSpace.getName());
+    }
+
+    /**
+     * NamedImports :
+     *     { }
+     *     { ImportsList }
+     *     { ImportsList , }
+     * ImportsList :
+     *     ImportSpecifier
+     *     ImportsList , ImportSpecifier
+     * ImportSpecifier :
+     *     ImportedBinding
+     *     IdentifierName as ImportedBinding
+     * ImportedBinding :
+     *     BindingIdentifier
+     */
+    private List<Module.ImportEntry> namedImports() {
+        assert type == LBRACE;
+        next();
+        List<Module.ImportEntry> importEntries = new ArrayList<>();
+        while (type != RBRACE) {
+            final boolean bindingIdentifier = isBindingIdentifier();
+            final long nameToken = token;
+            final IdentNode importName = getIdentifierName();
+            if (type == IDENT && "as".equals(getValue())) {
+                next();
+                final IdentNode localName = bindingIdentifier("ImportedBinding");
+                importEntries.add(Module.ImportEntry.importSpecifier(importName.getName(), localName.getName()));
+            } else if (!bindingIdentifier) {
+                throw error(AbstractParser.message("expected.binding.identifier"), nameToken);
+            } else {
+                importEntries.add(Module.ImportEntry.importSpecifier(importName.getName()));
+            }
+            if (type == COMMARIGHT) {
+                next();
+            } else {
+                break;
+            }
+        }
+        expect(RBRACE);
+        return importEntries;
+    }
+
+    /**
+     * FromClause :
+     *     from ModuleSpecifier
+     */
+    private String fromClause() {
+        final long fromToken = token;
+        final String name = (String) expectValue(IDENT);
+        if (!"from".equals(name)) {
+            throw error(AbstractParser.message("expected.from"), fromToken);
+        }
+        if (type == STRING || type == ESCSTRING) {
+            final String moduleSpecifier = (String) getValue();
+            next();
+            return moduleSpecifier;
+        } else {
+            throw error(expectMessage(STRING));
+        }
+    }
+
+    /**
+     * Parse export declaration.
+     *
+     * ExportDeclaration :
+     *     export * FromClause ;
+     *     export ExportClause FromClause ;
+     *     export ExportClause ;
+     *     export VariableStatement
+     *     export Declaration
+     *     export default HoistableDeclaration[Default]
+     *     export default ClassDeclaration[Default]
+     *     export default [lookahead !in {function, class}] AssignmentExpression[In] ;
+     */
+    private void exportDeclaration() {
+        expect(EXPORT);
+        final ParserContextModuleNode module = lc.getCurrentModule();
+        switch (type) {
+            case MUL: {
+                next();
+                final String moduleRequest = fromClause();
+                expect(SEMICOLON);
+                module.addModuleRequest(moduleRequest);
+                module.addStarExportEntry(Module.ExportEntry.exportStarFrom(moduleRequest));
+                break;
+            }
+            case LBRACE: {
+                final List<Module.ExportEntry> exportEntries = exportClause();
+                if (type == IDENT && "from".equals(getValue())) {
+                    final String moduleRequest = fromClause();
+                    module.addModuleRequest(moduleRequest);
+                    for (Module.ExportEntry exportEntry : exportEntries) {
+                        module.addIndirectExportEntry(exportEntry.withFrom(moduleRequest));
+                    }
+                } else {
+                    for (Module.ExportEntry exportEntry : exportEntries) {
+                        module.addLocalExportEntry(exportEntry);
+                    }
+                }
+                expect(SEMICOLON);
+                break;
+            }
+            case DEFAULT:
+                next();
+                final Expression assignmentExpression;
+                IdentNode ident;
+                final int lineNumber = line;
+                final long rhsToken = token;
+                final boolean declaration;
+                switch (type) {
+                    case FUNCTION:
+                        assignmentExpression = functionExpression(false, true);
+                        ident = ((FunctionNode) assignmentExpression).getIdent();
+                        declaration = true;
+                        break;
+                    case CLASS:
+                        assignmentExpression = classDeclaration(true);
+                        ident = ((ClassNode) assignmentExpression).getIdent();
+                        declaration = true;
+                        break;
+                    default:
+                        assignmentExpression = assignmentExpression(false);
+                        ident = null;
+                        declaration = false;
+                        break;
+                }
+                if (ident != null) {
+                    module.addLocalExportEntry(Module.ExportEntry.exportDefault(ident.getName()));
+                } else {
+                    ident = createIdentNode(Token.recast(rhsToken, IDENT), finish, Module.DEFAULT_EXPORT_BINDING_NAME);
+                    lc.appendStatementToCurrentNode(new VarNode(lineNumber, Token.recast(rhsToken, LET), finish, ident, assignmentExpression));
+                    if (!declaration) {
+                        expect(SEMICOLON);
+                    }
+                    module.addLocalExportEntry(Module.ExportEntry.exportDefault());
+                }
+                break;
+            case VAR:
+            case LET:
+            case CONST:
+                final List<Statement> statements = lc.getCurrentBlock().getStatements();
+                final int previousEnd = statements.size();
+                variableStatement(type);
+                for (final Statement statement : statements.subList(previousEnd, statements.size())) {
+                    if (statement instanceof VarNode) {
+                        module.addLocalExportEntry(Module.ExportEntry.exportSpecifier(((VarNode) statement).getName().getName()));
+                    }
+                }
+                break;
+            case CLASS: {
+                final ClassNode classDeclaration = classDeclaration(false);
+                module.addLocalExportEntry(Module.ExportEntry.exportSpecifier(classDeclaration.getIdent().getName()));
+                break;
+            }
+            case FUNCTION: {
+                final FunctionNode functionDeclaration = (FunctionNode) functionExpression(true, true);
+                module.addLocalExportEntry(Module.ExportEntry.exportSpecifier(functionDeclaration.getIdent().getName()));
+                break;
+            }
+            default:
+                throw error(AbstractParser.message("invalid.export"), token);
+        }
+    }
+
+    /**
+     * ExportClause :
+     *     { }
+     *     { ExportsList }
+     *     { ExportsList , }
+     * ExportsList :
+     *     ExportSpecifier
+     *     ExportsList , ExportSpecifier
+     * ExportSpecifier :
+     *     IdentifierName
+     *     IdentifierName as IdentifierName
+     *
+     * @return a list of ExportSpecifiers
+     */
+    private List<Module.ExportEntry> exportClause() {
+        assert type == LBRACE;
+        next();
+        List<Module.ExportEntry> exports = new ArrayList<>();
+        while (type != RBRACE) {
+            final IdentNode localName = getIdentifierName();
+            if (type == IDENT && "as".equals(getValue())) {
+                next();
+                final IdentNode exportName = getIdentifierName();
+                exports.add(Module.ExportEntry.exportSpecifier(exportName.getName(), localName.getName()));
+            } else {
+                exports.add(Module.ExportEntry.exportSpecifier(localName.getName()));
+            }
+            if (type == COMMARIGHT) {
+                next();
+            } else {
+                break;
+            }
+        }
+        expect(RBRACE);
+        return exports;
+    }
+
     @Override
     public String toString() {
         return "'JavaScript Parsing'";
@@ -3564,6 +5408,12 @@
             if (!flaggedCurrentFn) {
                 fn.setFlag(FunctionNode.HAS_EVAL);
                 flaggedCurrentFn = true;
+                if (fn.getKind() == FunctionNode.Kind.ARROW) {
+                    // possible use of this in an eval that's nested in an arrow function, e.g.:
+                    // function fun(){ return (() => eval("this"))(); };
+                    markThis(lc);
+                    markNewTarget(lc);
+                }
             } else {
                 fn.setFlag(FunctionNode.HAS_NESTED_EVAL);
             }
@@ -3583,4 +5433,55 @@
     private void appendStatement(final Statement statement) {
         lc.appendStatementToCurrentNode(statement);
     }
+
+    private static void markSuperCall(final ParserContext lc) {
+        final Iterator<ParserContextFunctionNode> iter = lc.getFunctions();
+        while (iter.hasNext()) {
+            final ParserContextFunctionNode fn = iter.next();
+            if (fn.getKind() != FunctionNode.Kind.ARROW) {
+                assert fn.isSubclassConstructor();
+                fn.setFlag(FunctionNode.ES6_HAS_DIRECT_SUPER);
+                break;
+            }
+        }
+    }
+
+    private ParserContextFunctionNode getCurrentNonArrowFunction() {
+        final Iterator<ParserContextFunctionNode> iter = lc.getFunctions();
+        while (iter.hasNext()) {
+            final ParserContextFunctionNode fn = iter.next();
+            if (fn.getKind() != FunctionNode.Kind.ARROW) {
+                return fn;
+            }
+        }
+        return null;
+    }
+
+    private static void markThis(final ParserContext lc) {
+        final Iterator<ParserContextFunctionNode> iter = lc.getFunctions();
+        while (iter.hasNext()) {
+            final ParserContextFunctionNode fn = iter.next();
+            fn.setFlag(FunctionNode.USES_THIS);
+            if (fn.getKind() != FunctionNode.Kind.ARROW) {
+                break;
+            }
+        }
+    }
+
+    private static void markNewTarget(final ParserContext lc) {
+        final Iterator<ParserContextFunctionNode> iter = lc.getFunctions();
+        while (iter.hasNext()) {
+            final ParserContextFunctionNode fn = iter.next();
+            if (fn.getKind() != FunctionNode.Kind.ARROW) {
+                if (!fn.isProgram()) {
+                    fn.setFlag(FunctionNode.ES6_USES_NEW_TARGET);
+                }
+                break;
+            }
+        }
+    }
+
+    private boolean inGeneratorFunction() {
+        return lc.getCurrentFunction().getKind() == FunctionNode.Kind.GENERATOR;
+    }
 }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/ParserContext.java	Tue May 03 09:48:02 2016 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/ParserContext.java	Tue May 03 12:25:20 2016 -0700
@@ -278,7 +278,12 @@
         return new NodeIterator<>(ParserContextFunctionNode.class);
     }
 
-    private class NodeIterator <T extends ParserContextNode> implements Iterator<T> {
+    public ParserContextModuleNode getCurrentModule() {
+        final Iterator<ParserContextModuleNode> iter = new NodeIterator<>(ParserContextModuleNode.class, getCurrentFunction());
+        return iter.hasNext() ? iter.next() : null;
+    }
+
+    private class NodeIterator<T extends ParserContextNode> implements Iterator<T> {
         private int index;
         private T next;
         private final Class<T> clazz;
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/ParserContextFunctionNode.java	Tue May 03 09:48:02 2016 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/ParserContextFunctionNode.java	Tue May 03 12:25:20 2016 -0700
@@ -24,10 +24,12 @@
  */
 package jdk.nashorn.internal.parser;
 
+import java.util.HashSet;
 import java.util.List;
 import jdk.nashorn.internal.codegen.Namespace;
 import jdk.nashorn.internal.ir.FunctionNode;
 import jdk.nashorn.internal.ir.IdentNode;
+import jdk.nashorn.internal.ir.Module;
 
 /**
  * ParserContextNode that represents a function that is currently being parsed
@@ -46,11 +48,11 @@
     /** Line number for function declaration */
     private final int line;
 
-    /** Function node kind, see {@link FunctionNode#Kind} */
+    /** Function node kind, see {@link FunctionNode.Kind} */
     private final FunctionNode.Kind kind;
 
     /** List of parameter identifiers for function */
-    private final List<IdentNode> parameters;
+    private List<IdentNode> parameters;
 
     /** Token for function start */
     private final long token;
@@ -61,6 +63,14 @@
     /** Opaque node for parser end state, see {@link Parser} */
     private Object endParserState;
 
+    private HashSet<String> parameterBoundNames;
+    private IdentNode duplicateParameterBinding;
+    private boolean simpleParameterList = true;
+
+    private Module module;
+
+    private int debugFlags;
+
     /**
      * @param token The token for the function
      * @param ident External function name
@@ -155,6 +165,10 @@
         return parameters;
     }
 
+    void setParameters(List<IdentNode> parameters) {
+        this.parameters = parameters;
+    }
+
     /**
      * Set last token
      * @param token New last token
@@ -194,4 +208,70 @@
     public int getId() {
         return isProgram() ? -1 : Token.descPosition(token);
     }
+
+    /**
+     * Returns the debug flags for this function.
+     *
+     * @return the debug flags
+     */
+    int getDebugFlags() {
+        return debugFlags;
+    }
+
+    /**
+     * Sets a debug flag for this function.
+     *
+     * @param debugFlag the debug flag
+     */
+    void setDebugFlag(final int debugFlag) {
+        debugFlags |= debugFlag;
+    }
+
+    public boolean isMethod() {
+        return getFlag(FunctionNode.ES6_IS_METHOD) != 0;
+    }
+
+    public boolean isClassConstructor() {
+        return getFlag(FunctionNode.ES6_IS_CLASS_CONSTRUCTOR) != 0;
+    }
+
+    public boolean isSubclassConstructor() {
+        return getFlag(FunctionNode.ES6_IS_SUBCLASS_CONSTRUCTOR) != 0;
+    }
+
+    boolean addParameterBinding(final IdentNode bindingIdentifier) {
+        if (Parser.isArguments(bindingIdentifier)) {
+            setFlag(FunctionNode.DEFINES_ARGUMENTS);
+        }
+
+        if (parameterBoundNames == null) {
+            parameterBoundNames = new HashSet<>();
+        }
+        if (parameterBoundNames.add(bindingIdentifier.getName())) {
+            return true;
+        } else {
+            duplicateParameterBinding = bindingIdentifier;
+            return false;
+        }
+    }
+
+    public IdentNode getDuplicateParameterBinding() {
+        return duplicateParameterBinding;
+    }
+
+    public boolean isSimpleParameterList() {
+        return simpleParameterList;
+    }
+
+    public void setSimpleParameterList(final boolean simpleParameterList) {
+        this.simpleParameterList = simpleParameterList;
+    }
+
+    public Module getModule() {
+        return module;
+    }
+
+    public void setModule(final Module module) {
+        this.module = module;
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/ParserContextModuleNode.java	Tue May 03 12:25:20 2016 -0700
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package jdk.nashorn.internal.parser;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import jdk.nashorn.internal.ir.Module;
+import jdk.nashorn.internal.ir.Module.ExportEntry;
+import jdk.nashorn.internal.ir.Module.ImportEntry;
+
+/**
+ * ParserContextNode that represents a module.
+ */
+class ParserContextModuleNode extends ParserContextBaseNode {
+
+    /** Module name. */
+    private final String name;
+
+    private List<String> requestedModules = new ArrayList<>();
+    private List<ImportEntry> importEntries = new ArrayList<>();
+    private List<ExportEntry> localExportEntries = new ArrayList<>();
+    private List<ExportEntry> indirectExportEntries = new ArrayList<>();
+    private List<ExportEntry> starExportEntries = new ArrayList<>();
+
+    /**
+     * Constructor.
+     *
+     * @param name name of the module
+     */
+    ParserContextModuleNode(final String name) {
+        this.name = name;
+    }
+
+    /**
+     * Returns the name of the module.
+     *
+     * @return name of the module
+     */
+    public String getModuleName() {
+        return name;
+    }
+
+    public void addModuleRequest(final String moduleRequest) {
+        requestedModules.add(moduleRequest);
+    }
+
+    public void addImportEntry(final ImportEntry importEntry) {
+        importEntries.add(importEntry);
+    }
+
+    public void addLocalExportEntry(final ExportEntry exportEntry) {
+        localExportEntries.add(exportEntry);
+    }
+
+    public void addIndirectExportEntry(final ExportEntry exportEntry) {
+        indirectExportEntries.add(exportEntry);
+    }
+
+    public void addStarExportEntry(final ExportEntry exportEntry) {
+        starExportEntries.add(exportEntry);
+    }
+
+    public Module createModule() {
+        return new Module(requestedModules, importEntries, localExportEntries, indirectExportEntries, starExportEntries);
+    }
+}
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/TokenType.java	Tue May 03 09:48:02 2016 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/TokenType.java	Tue May 03 12:25:20 2016 -0700
@@ -82,7 +82,7 @@
     ASSIGN         (BINARY,  "=",     2, false),
     EQ             (BINARY,  "==",    9, true),
     EQ_STRICT      (BINARY,  "===",   9, true),
-    BIND           (BINARY,  "=>",    9, true),
+    ARROW          (BINARY,  "=>",    2, true),
     GT             (BINARY,  ">",    10, true),
     GE             (BINARY,  ">=",   10, true),
     SAR            (BINARY,  ">>",   11, true),
@@ -100,6 +100,7 @@
     OR             (BINARY,  "||",    4, true),
     RBRACE         (BRACKET, "}"),
     BIT_NOT        (UNARY,   "~",     14, false),
+    ELLIPSIS       (UNARY,   "..."),
 
     // ECMA 7.6.1.1 Keywords, 7.6.1.2 Future Reserved Words.
     // All other Java keywords are commented out.
@@ -190,7 +191,10 @@
 
     COMMALEFT      (IR,       null),
     DECPOSTFIX     (IR,       null),
-    INCPOSTFIX     (IR,       null);
+    INCPOSTFIX     (IR,       null),
+    SPREAD_ARGUMENT(IR,       null),
+    SPREAD_ARRAY   (IR,       null),
+    YIELD_STAR     (IR,       null);
 
     /** Next token kind in token lookup table. */
     private TokenType next;
@@ -251,7 +255,6 @@
         return kind == BINARY && (!noIn || this != IN) && precedence != 0;
     }
 
-
     public int getLength() {
         assert name != null : "Token name not set";
         return name.length();
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Context.java	Tue May 03 09:48:02 2016 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Context.java	Tue May 03 12:25:20 2016 -0700
@@ -1403,11 +1403,11 @@
                 return null;
             }
 
-            if (env._print_ast || functionNode.getFlag(FunctionNode.IS_PRINT_AST)) {
+            if (env._print_ast || functionNode.getDebugFlag(FunctionNode.DEBUG_PRINT_AST)) {
                 getErr().println(new ASTWriter(functionNode));
             }
 
-            if (env._print_parse || functionNode.getFlag(FunctionNode.IS_PRINT_PARSE)) {
+            if (env._print_parse || functionNode.getDebugFlag(FunctionNode.DEBUG_PRINT_PARSE)) {
                 getErr().println(new PrintVisitor(functionNode, true, false));
             }
         }
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/doubleconv/DtoaBuffer.java	Tue May 03 09:48:02 2016 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/doubleconv/DtoaBuffer.java	Tue May 03 12:25:20 2016 -0700
@@ -176,6 +176,8 @@
                     buffer.append('0');
                 }
                 buffer.append(chars, 0, length);
+            } else {
+                decimalPoint = 1;
             }
         } else if (decimalPoint >= length) {
             // large integer, add trailing zeroes
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/resources/Messages.properties	Tue May 03 09:48:02 2016 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/resources/Messages.properties	Tue May 03 12:25:20 2016 -0700
@@ -63,6 +63,27 @@
 parser.error.missing.const.assignment=Missing assignment to constant "{0}"
 parser.error.unterminated.template.expression=Expected } after expression in template literal
 
+# ES6 mode error messages
+parser.error.multiple.constructors=Class contains more than one constructor
+parser.error.generator.constructor=Class constructor must not be a generator
+parser.error.accessor.constructor=Class constructor must not be an accessor
+parser.error.static.prototype.method=Static class method must not be named 'prototype'
+parser.error.missing.destructuring.assignment=Missing assignment in destructuring declaration
+parser.error.let.binding.for='let' is not a valid binding name in a for loop
+parser.error.invalid.export=invalid export declaration
+parser.error.expected.binding=expected BindingIdentifier or BindingPattern
+parser.error.multiple.proto.key=property name __proto__ appears more than once in object literal
+parser.error.new.target.in.function=new.target expression is only allowed in functions
+parser.error.expected.target=expected 'target'
+parser.error.invalid.super=invalid use of keyword super
+parser.error.expected.arrow.parameter=expected arrow function parameter list
+parser.error.invalid.arrow.parameter=invalid arrow function parameter
+parser.error.expected.named.import=expected NameSpaceImport or NamedImports
+parser.error.expected.import=expected ImportClause or ModuleSpecifier
+parser.error.expected.as=expected 'as'
+parser.error.expected.binding.identifier=expected BindingIdentifier
+parser.error.expected.from=expected 'from'
+
 # strict mode error messages
 parser.error.strict.no.with="with" statement cannot be used in strict mode
 parser.error.strict.name="{0}" cannot be used as {1} in strict mode
--- a/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/tools/Shell.java	Tue May 03 09:48:02 2016 -0700
+++ b/nashorn/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/tools/Shell.java	Tue May 03 12:25:20 2016 -0700
@@ -438,6 +438,9 @@
                 final File file = new File(fileName);
                 final ScriptFunction script = context.compileScript(sourceFor(fileName, file), global);
                 if (script == null || errors.getNumberOfErrors() != 0) {
+                    if (context.getEnv()._parse_only && !errors.hasErrors()) {
+                        continue; // No error, continue to consume all files in list
+                    }
                     return COMPILATION_ERROR;
                 }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8155025.js	Tue May 03 12:25:20 2016 -0700
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8155025: 0.001.toFixed(2) should return "0.00" not "0"
+ *
+ * @test
+ * @run
+ */
+
+for (var i = 0, zeros=""; i <= 9; i++, zeros += "0") {
+    var n = Number("0." + zeros + "1");
+    for (var j = 1; j <= i + 3; j++) {
+        print(n + ".toFixed(" + j + ")=" + n.toFixed(j));
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8155025.js.EXPECTED	Tue May 03 12:25:20 2016 -0700
@@ -0,0 +1,75 @@
+0.1.toFixed(1)=0.1
+0.1.toFixed(2)=0.10
+0.1.toFixed(3)=0.100
+0.01.toFixed(1)=0.0
+0.01.toFixed(2)=0.01
+0.01.toFixed(3)=0.010
+0.01.toFixed(4)=0.0100
+0.001.toFixed(1)=0.0
+0.001.toFixed(2)=0.00
+0.001.toFixed(3)=0.001
+0.001.toFixed(4)=0.0010
+0.001.toFixed(5)=0.00100
+0.0001.toFixed(1)=0.0
+0.0001.toFixed(2)=0.00
+0.0001.toFixed(3)=0.000
+0.0001.toFixed(4)=0.0001
+0.0001.toFixed(5)=0.00010
+0.0001.toFixed(6)=0.000100
+0.00001.toFixed(1)=0.0
+0.00001.toFixed(2)=0.00
+0.00001.toFixed(3)=0.000
+0.00001.toFixed(4)=0.0000
+0.00001.toFixed(5)=0.00001
+0.00001.toFixed(6)=0.000010
+0.00001.toFixed(7)=0.0000100
+0.000001.toFixed(1)=0.0
+0.000001.toFixed(2)=0.00
+0.000001.toFixed(3)=0.000
+0.000001.toFixed(4)=0.0000
+0.000001.toFixed(5)=0.00000
+0.000001.toFixed(6)=0.000001
+0.000001.toFixed(7)=0.0000010
+0.000001.toFixed(8)=0.00000100
+1e-7.toFixed(1)=0.0
+1e-7.toFixed(2)=0.00
+1e-7.toFixed(3)=0.000
+1e-7.toFixed(4)=0.0000
+1e-7.toFixed(5)=0.00000
+1e-7.toFixed(6)=0.000000
+1e-7.toFixed(7)=0.0000001
+1e-7.toFixed(8)=0.00000010
+1e-7.toFixed(9)=0.000000100
+1e-8.toFixed(1)=0.0
+1e-8.toFixed(2)=0.00
+1e-8.toFixed(3)=0.000
+1e-8.toFixed(4)=0.0000
+1e-8.toFixed(5)=0.00000
+1e-8.toFixed(6)=0.000000
+1e-8.toFixed(7)=0.0000000
+1e-8.toFixed(8)=0.00000001
+1e-8.toFixed(9)=0.000000010
+1e-8.toFixed(10)=0.0000000100
+1e-9.toFixed(1)=0.0
+1e-9.toFixed(2)=0.00
+1e-9.toFixed(3)=0.000
+1e-9.toFixed(4)=0.0000
+1e-9.toFixed(5)=0.00000
+1e-9.toFixed(6)=0.000000
+1e-9.toFixed(7)=0.0000000
+1e-9.toFixed(8)=0.00000000
+1e-9.toFixed(9)=0.000000001
+1e-9.toFixed(10)=0.0000000010
+1e-9.toFixed(11)=0.00000000100
+1e-10.toFixed(1)=0.0
+1e-10.toFixed(2)=0.00
+1e-10.toFixed(3)=0.000
+1e-10.toFixed(4)=0.0000
+1e-10.toFixed(5)=0.00000
+1e-10.toFixed(6)=0.000000
+1e-10.toFixed(7)=0.0000000
+1e-10.toFixed(8)=0.00000000
+1e-10.toFixed(9)=0.000000000
+1e-10.toFixed(10)=0.0000000001
+1e-10.toFixed(11)=0.00000000010
+1e-10.toFixed(12)=0.000000000100
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/es6/parser-es6.js	Tue May 03 12:25:20 2016 -0700
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ * 
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ * 
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ * 
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ * 
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * JDK-8134503: support ES6 parsing in Nashorn
+ *
+ * @test
+ * @option --language=es6
+ * @option --parse-only
+ */
+
+
+[].map(v => v + 1);
+
+class A extends B.C {
+    constructor(a, b) {
+        super(a, b);
+    }
+    someMethod(c) {
+        super.someMethod();
+    }
+    get g() {
+        return this.g;
+    }
+    set s(t) {
+        this.t = t;
+    }
+    static m() {
+        return k;
+    }
+}
+
+var obj = {
+    __proto__: theProtoObj,
+    handler,
+    r() {
+        return super.m();
+    },
+    [ '__' + (() => 'x')() ]: 1,
+    *q (x, y) {
+       yield 1;
+    }
+};
+
+var [a, , b] = [1, 2, 3];
+
+var { x: a, y: { z: b }, w: c } = abc();
+
+var {a, b, c} = abc();
+
+var o = { x, y };
+
+function g({name: x}) {
+  return x;
+}
+
+foo(a, ...b);
+
+var c = [ ...s ];
+
+var [a] = [];
+
+var [a = 1] = [];
+
+
+var f = {
+    [Symbol.iterator]: function*() {
+        var cur = 1;
+        for (;;) {
+            yield cur;
+        }
+    }
+};
+
--- a/nashorn/test/script/basic/yield.js	Tue May 03 09:48:02 2016 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,34 +0,0 @@
-/*
- * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-
-/**
- * Check yield keyword is parsed and yield statement does nothing (yet).
- *
- * @test
- * @run
- */
-
-function func() {
-    yield 2;
-}
--- a/nashorn/test/script/error/NASHORN-154/function_mult_params_in_strict.js.EXPECTED	Tue May 03 09:48:02 2016 -0700
+++ b/nashorn/test/script/error/NASHORN-154/function_mult_params_in_strict.js.EXPECTED	Tue May 03 12:25:20 2016 -0700
@@ -1,3 +1,3 @@
-test/script/error/NASHORN-154/function_mult_params_in_strict.js:38:14 strict mode function cannot have duplicate parameter name "x"
+test/script/error/NASHORN-154/function_mult_params_in_strict.js:38:17 strict mode function cannot have duplicate parameter name "x"
 function func(x, x) {}
-              ^
+                 ^
--- a/nashorn/test/script/nosecurity/parserapi.js.EXPECTED	Tue May 03 09:48:02 2016 -0700
+++ b/nashorn/test/script/nosecurity/parserapi.js.EXPECTED	Tue May 03 12:25:20 2016 -0700
@@ -100,7 +100,7 @@
             "startPosition": "1181",
             "properties": [
               {
-                "endPosition": "1185",
+                "endPosition": "1187",
                 "kind": "PROPERTY",
                 "value": {
                   "endPosition": "1187",
@@ -2386,7 +2386,7 @@
           "startPosition": "1139",
           "properties": [
             {
-              "endPosition": "1143",
+              "endPosition": "1146",
               "kind": "PROPERTY",
               "value": {
                 "endPosition": "1146",
@@ -2403,7 +2403,7 @@
               }
             },
             {
-              "endPosition": "1150",
+              "endPosition": "1152",
               "kind": "PROPERTY",
               "value": {
                 "endPosition": "1152",
@@ -2443,7 +2443,7 @@
           "startPosition": "1160",
           "properties": [
             {
-              "endPosition": "1166",
+              "endPosition": "1169",
               "kind": "PROPERTY",
               "value": {
                 "endPosition": "1169",
@@ -2460,7 +2460,7 @@
               }
             },
             {
-              "endPosition": "1175",
+              "endPosition": "1177",
               "kind": "PROPERTY",
               "value": {
                 "endPosition": "1177",
@@ -2914,7 +2914,7 @@
         "startPosition": "1178",
         "properties": [
           {
-            "endPosition": "1182",
+            "endPosition": "1184",
             "kind": "PROPERTY",
             "value": {
               "endPosition": "1184",
@@ -3395,7 +3395,7 @@
         "startPosition": "1200",
         "properties": [
           {
-            "endPosition": "1206",
+            "endPosition": "1214",
             "kind": "PROPERTY",
             "value": {
               "endPosition": "1214",
@@ -4709,11 +4709,11 @@
 ,
 {
   "fileName": "parsernegativetests/strict_repeatparam.js",
-  "code": "ident (1119, 1)",
-  "columnNumber": "14",
+  "code": "ident (1122, 1)",
+  "columnNumber": "17",
   "kind": "ERROR",
-  "position": "1119",
-  "message": "parsernegativetests/strict_repeatparam.js:31:14 strict mode function cannot have duplicate parameter name \"x\"\nfunction func(x, x) {}\n              ^",
+  "position": "1122",
+  "message": "parsernegativetests/strict_repeatparam.js:31:17 strict mode function cannot have duplicate parameter name \"x\"\nfunction func(x, x) {}\n                 ^",
   "lineNumber": "31"
 }
 ,
--- a/nashorn/test/script/nosecurity/parserapi_strict.js.EXPECTED	Tue May 03 09:48:02 2016 -0700
+++ b/nashorn/test/script/nosecurity/parserapi_strict.js.EXPECTED	Tue May 03 12:25:20 2016 -0700
@@ -6,10 +6,10 @@
 
 with({}) {}
        ^
-repeat_param.js:2:15 strict mode function cannot have duplicate parameter name "x"
+repeat_param.js:2:18 strict mode function cannot have duplicate parameter name "x"
 
 function func(x, x) {}
-               ^
+                  ^
 repeat_prop.js:2:22 Property "foo" already defined
 
 var obj = { foo: 34, foo: 'hello' };
--- a/nashorn/test/script/nosecurity/treeapi/array_literal.js.EXPECTED	Tue May 03 09:48:02 2016 -0700
+++ b/nashorn/test/script/nosecurity/treeapi/array_literal.js.EXPECTED	Tue May 03 12:25:20 2016 -0700
@@ -74,7 +74,7 @@
         "properties": [
           {
             "getter": "null",
-            "endPosition": "74",
+            "endPosition": "76",
             "kind": "PROPERTY",
             "setter": "null",
             "value": {
--- a/nashorn/test/script/nosecurity/treeapi/objectLiteral.js.EXPECTED	Tue May 03 09:48:02 2016 -0700
+++ b/nashorn/test/script/nosecurity/treeapi/objectLiteral.js.EXPECTED	Tue May 03 12:25:20 2016 -0700
@@ -6,7 +6,7 @@
     "properties": [
       {
         "getter": "null",
-        "endPosition": "8",
+        "endPosition": "12",
         "kind": "PROPERTY",
         "setter": "null",
         "value": {
@@ -38,7 +38,7 @@
     "properties": [
       {
         "getter": "null",
-        "endPosition": "34",
+        "endPosition": "37",
         "kind": "PROPERTY",
         "setter": "null",
         "value": {
@@ -57,7 +57,7 @@
       },
       {
         "getter": "null",
-        "endPosition": "41",
+        "endPosition": "43",
         "kind": "PROPERTY",
         "setter": "null",
         "value": {
@@ -83,7 +83,7 @@
     "properties": [
       {
         "getter": "null",
-        "endPosition": "57",
+        "endPosition": "60",
         "kind": "PROPERTY",
         "setter": "null",
         "value": {
@@ -102,7 +102,7 @@
       },
       {
         "getter": "null",
-        "endPosition": "66",
+        "endPosition": "68",
         "kind": "PROPERTY",
         "setter": "null",
         "value": {
--- a/nashorn/test/script/nosecurity/treeapi/property.js.EXPECTED	Tue May 03 09:48:02 2016 -0700
+++ b/nashorn/test/script/nosecurity/treeapi/property.js.EXPECTED	Tue May 03 12:25:20 2016 -0700
@@ -1,7 +1,7 @@
 [
   {
     "getter": "null",
-    "endPosition": "17",
+    "endPosition": "22",
     "kind": "PROPERTY",
     "setter": "null",
     "value": {
@@ -20,7 +20,7 @@
   },
   {
     "getter": "null",
-    "endPosition": "31",
+    "endPosition": "38",
     "kind": "PROPERTY",
     "setter": "null",
     "value": {
@@ -45,7 +45,7 @@
   },
   {
     "getter": "null",
-    "endPosition": "46",
+    "endPosition": "61",
     "kind": "PROPERTY",
     "setter": "null",
     "value": {
@@ -72,7 +72,7 @@
   },
   {
     "getter": "null",
-    "endPosition": "69",
+    "endPosition": "72",
     "kind": "PROPERTY",
     "setter": "null",
     "value": {
--- a/nashorn/test/script/nosecurity/treeapi/throw.js.EXPECTED	Tue May 03 09:48:02 2016 -0700
+++ b/nashorn/test/script/nosecurity/treeapi/throw.js.EXPECTED	Tue May 03 12:25:20 2016 -0700
@@ -80,7 +80,7 @@
       "properties": [
         {
           "getter": "null",
-          "endPosition": "97",
+          "endPosition": "105",
           "kind": "PROPERTY",
           "setter": "null",
           "value": {
--- a/nashorn/test/script/nosecurity/treeapi/with.js.EXPECTED	Tue May 03 09:48:02 2016 -0700
+++ b/nashorn/test/script/nosecurity/treeapi/with.js.EXPECTED	Tue May 03 12:25:20 2016 -0700
@@ -49,7 +49,7 @@
       "properties": [
         {
           "getter": "null",
-          "endPosition": "34",
+          "endPosition": "39",
           "kind": "PROPERTY",
           "setter": "null",
           "value": {
--- a/nashorn/test/src/jdk/nashorn/internal/test/framework/ScriptRunnable.java	Tue May 03 09:48:02 2016 -0700
+++ b/nashorn/test/src/jdk/nashorn/internal/test/framework/ScriptRunnable.java	Tue May 03 12:25:20 2016 -0700
@@ -194,9 +194,9 @@
             pb.redirectError(errorFileHandle);
             final Process process = pb.start();
 
-            process.waitFor();
+            final int exitCode = process.waitFor();
 
-            if (errorFileHandle.length() > 0) {
+            if (exitCode != 0 || errorFileHandle.length() > 0) {
                 if (expectRunFailure) {
                     return;
                 }