changeset 47378:974275a24b74

Merge
author jwilhelm
date Wed, 04 Oct 2017 20:01:19 +0000
parents bf73ca31add9 6feee2a82b0b
children b3fd664e5af2
files src/jdk.jshell/share/classes/jdk/jshell/VarTypePrinter.java test/nashorn/script/currently-failing/JDK-8055034.js test/nashorn/script/currently-failing/JDK-8055034.js.EXPECTED
diffstat 236 files changed, 7742 insertions(+), 2711 deletions(-) [+]
line wrap: on
line diff
--- a/.hgtags	Wed Oct 04 11:52:07 2017 -0700
+++ b/.hgtags	Wed Oct 04 20:01:19 2017 +0000
@@ -449,3 +449,4 @@
 e5357aa85dadacc6562175ff74714fecfb4470cf jdk-10+22
 22850b3a55240253841b9a425ad60a7fcdb22d47 jdk-10+23
 3b201865d5c1f244f555cad58da599c9261286d8 jdk-10+24
+8eb5e3ccee560c28ac9b1df2670adac2b3d36fad jdk-10+25
--- a/bin/jib.sh	Wed Oct 04 11:52:07 2017 -0700
+++ b/bin/jib.sh	Wed Oct 04 20:01:19 2017 +0000
@@ -28,8 +28,8 @@
 mydir="$(dirname "${BASH_SOURCE[0]}")"
 myname="$(basename "${BASH_SOURCE[0]}")"
 
-installed_jib_script=${mydir}/../../.jib/jib
-install_data=${mydir}/../../.jib/.data
+installed_jib_script=${mydir}/../.jib/jib
+install_data=${mydir}/../.jib/.data
 
 setup_url() {
     if [ -f ~/.config/jib/jib.conf ]; then
@@ -42,7 +42,7 @@
     jib_revision="2.0-SNAPSHOT"
     jib_ext="jib.sh.gz"
 
-    closed_script="${mydir}/../../../closed/conf/jib-install.conf"
+    closed_script="${mydir}/../../closed/make/conf/jib-install.conf"
     if [ -f "${closed_script}" ]; then
         source "${closed_script}"
     fi
--- a/doc/nashorn/JavaScriptingProgrammersGuide.html	Wed Oct 04 11:52:07 2017 -0700
+++ b/doc/nashorn/JavaScriptingProgrammersGuide.html	Wed Oct 04 20:01:19 2017 +0000
@@ -127,7 +127,7 @@
 <hr>
 <span><a name="package" id="package"></a></span>
 <h2><span>Scripting Package</span></h2>
-<p><span>The Java Scripting functionality is in the <code><a href="http://docs.oracle.com/javase/6/docs/api/javax/script/package-summary.html">javax.script</a></code>
+<p><span>The Java Scripting functionality is in the <code><a href="http://docs.oracle.com/javase/9/docs/api/javax/script/package-summary.html">javax.script</a></code>
 package. This is a relatively small, simple API. The starting point
 of the scripting API is the <code>ScriptEngineManager</code> class.
 A ScriptEngineManager object can discover script engines through
--- a/make/BuildNashorn.gmk	Wed Oct 04 11:52:07 2017 -0700
+++ b/make/BuildNashorn.gmk	Wed Oct 04 20:01:19 2017 +0000
@@ -41,7 +41,7 @@
 $(eval $(call SetupJavaCompiler, GENERATE_NEWBYTECODE_DEBUG, \
     JVM := $(JAVA_JAVAC), \
     JAVAC := $(NEW_JAVAC), \
-    FLAGS := -g -source 9 -target 9 --upgrade-module-path "$(JDK_OUTPUTDIR)/modules/" \
+    FLAGS := -g -source 10 -target 10 --upgrade-module-path "$(JDK_OUTPUTDIR)/modules/" \
          --system none --module-source-path $(call GetModuleSrcPath), \
     SERVER_DIR := $(SJAVAC_SERVER_DIR), \
     SERVER_JVM := $(SJAVAC_SERVER_JAVA)))
--- a/make/InitSupport.gmk	Wed Oct 04 11:52:07 2017 -0700
+++ b/make/InitSupport.gmk	Wed Oct 04 20:01:19 2017 +0000
@@ -36,7 +36,7 @@
 
   # Include the corresponding closed file, if present.
   # Normal hook mechanism cannot be used since we have no SPEC.
-  -include $(topdir)/closed/make/InitSupport.gmk
+  -include $(topdir)/../closed/make/InitSupport.gmk
 
   ##############################################################################
   # Helper functions for the initial part of Init.gmk, before the spec file is
--- a/make/autoconf/flags.m4	Wed Oct 04 11:52:07 2017 -0700
+++ b/make/autoconf/flags.m4	Wed Oct 04 20:01:19 2017 +0000
@@ -1311,6 +1311,7 @@
   $2LDFLAGS_JDKLIB="${$2LDFLAGS_JDK}"
 
   $2LDFLAGS_JDKLIB="${$2LDFLAGS_JDKLIB} ${SHARED_LIBRARY_FLAGS}"
+  $2LDFLAGS_JDKLIB="${$2LDFLAGS_JDKLIB} ${LDFLAGS_NO_EXEC_STACK}"
   if test "x$TOOLCHAIN_TYPE" = xmicrosoft; then
     $2JAVA_BASE_LDFLAGS="${$2JAVA_BASE_LDFLAGS} \
         -libpath:${OUTPUTDIR}/support/modules_libs/java.base"
@@ -1388,6 +1389,7 @@
   AC_SUBST($2JDKEXE_LIBS)
   AC_SUBST($2LDFLAGS_CXX_JDK)
   AC_SUBST($2LDFLAGS_HASH_STYLE)
+  AC_SUBST($2LDFLAGS_NO_EXEC_STACK)
 
   AC_SUBST($2JVM_CFLAGS)
   AC_SUBST($2JVM_LDFLAGS)
--- a/make/autoconf/generated-configure.sh	Wed Oct 04 11:52:07 2017 -0700
+++ b/make/autoconf/generated-configure.sh	Wed Oct 04 20:01:19 2017 +0000
@@ -723,6 +723,7 @@
 OPENJDK_BUILD_JVM_ASFLAGS
 OPENJDK_BUILD_JVM_LDFLAGS
 OPENJDK_BUILD_JVM_CFLAGS
+OPENJDK_BUILD_LDFLAGS_NO_EXEC_STACK
 OPENJDK_BUILD_LDFLAGS_HASH_STYLE
 OPENJDK_BUILD_LDFLAGS_CXX_JDK
 OPENJDK_BUILD_JDKEXE_LIBS
@@ -738,6 +739,7 @@
 JVM_ASFLAGS
 JVM_LDFLAGS
 JVM_CFLAGS
+LDFLAGS_NO_EXEC_STACK
 LDFLAGS_HASH_STYLE
 LDFLAGS_CXX_JDK
 JDKEXE_LIBS
@@ -5115,7 +5117,7 @@
 #CUSTOM_AUTOCONF_INCLUDE
 
 # Do not change or remove the following line, it is needed for consistency checks:
-DATE_WHEN_GENERATED=1506333008
+DATE_WHEN_GENERATED=1506397140
 
 ###############################################################################
 #
@@ -52024,6 +52026,7 @@
   LDFLAGS_JDKLIB="${LDFLAGS_JDK}"
 
   LDFLAGS_JDKLIB="${LDFLAGS_JDKLIB} ${SHARED_LIBRARY_FLAGS}"
+  LDFLAGS_JDKLIB="${LDFLAGS_JDKLIB} ${LDFLAGS_NO_EXEC_STACK}"
   if test "x$TOOLCHAIN_TYPE" = xmicrosoft; then
     JAVA_BASE_LDFLAGS="${JAVA_BASE_LDFLAGS} \
         -libpath:${OUTPUTDIR}/support/modules_libs/java.base"
@@ -52109,6 +52112,7 @@
 
 
 
+
   # Special extras...
   if test "x$TOOLCHAIN_TYPE" = xsolstudio; then
     if test "x$OPENJDK_BUILD_CPU_ARCH" = "xsparc"; then
@@ -52903,6 +52907,7 @@
   OPENJDK_BUILD_LDFLAGS_JDKLIB="${OPENJDK_BUILD_LDFLAGS_JDK}"
 
   OPENJDK_BUILD_LDFLAGS_JDKLIB="${OPENJDK_BUILD_LDFLAGS_JDKLIB} ${SHARED_LIBRARY_FLAGS}"
+  OPENJDK_BUILD_LDFLAGS_JDKLIB="${OPENJDK_BUILD_LDFLAGS_JDKLIB} ${LDFLAGS_NO_EXEC_STACK}"
   if test "x$TOOLCHAIN_TYPE" = xmicrosoft; then
     OPENJDK_BUILD_JAVA_BASE_LDFLAGS="${OPENJDK_BUILD_JAVA_BASE_LDFLAGS} \
         -libpath:${OUTPUTDIR}/support/modules_libs/java.base"
@@ -52988,6 +52993,7 @@
 
 
 
+
   # Tests are only ever compiled for TARGET
   # Flags for compiling test libraries
   CFLAGS_TESTLIB="$COMMON_CCXXFLAGS_JDK $CFLAGS_JDK $PICFLAG $CFLAGS_JDKLIB_EXTRA"
--- a/make/autoconf/spec.gmk.in	Wed Oct 04 11:52:07 2017 -0700
+++ b/make/autoconf/spec.gmk.in	Wed Oct 04 20:01:19 2017 +0000
@@ -387,6 +387,7 @@
 CXXFLAGS_JDKEXE:=@CXXFLAGS_JDKEXE@
 
 LDFLAGS_HASH_STYLE := @LDFLAGS_HASH_STYLE@
+LDFLAGS_NO_EXEC_STACK := @LDFLAGS_NO_EXEC_STACK@
 
 JVM_CFLAGS := @JVM_CFLAGS@
 JVM_CFLAGS_SYMBOLS := @JVM_CFLAGS_SYMBOLS@
--- a/make/common/Modules.gmk	Wed Oct 04 11:52:07 2017 -0700
+++ b/make/common/Modules.gmk	Wed Oct 04 20:01:19 2017 +0000
@@ -58,7 +58,6 @@
     java.rmi \
     java.security.sasl \
     java.xml \
-    jdk.httpserver \
     jdk.internal.vm.ci \
     jdk.management \
     jdk.management.agent \
@@ -112,6 +111,7 @@
     jdk.crypto.cryptoki \
     jdk.crypto.ec \
     jdk.dynalink \
+    jdk.httpserver \
     jdk.incubator.httpclient \
     jdk.internal.vm.compiler.management \
     jdk.jsobject \
--- a/make/conf/jib-profiles.js	Wed Oct 04 11:52:07 2017 -0700
+++ b/make/conf/jib-profiles.js	Wed Oct 04 20:01:19 2017 +0000
@@ -900,6 +900,45 @@
             }
         },
 
+        "windows-x64-open": {
+            artifacts: {
+                jdk: {
+                    local: "bundles/\\(jdk.*bin.tar.gz\\)",
+                    remote: [
+                        "bundles/openjdk/GPL/windows-x64/jdk-" + data.version
+                            + "_windows-x64_bin.tar.gz",
+                        "bundles/openjdk/GPL/windows-x64/\\1"
+                    ],
+                    subdir: "jdk-" + data.version
+                },
+                jre: {
+                    local: "bundles/\\(jre.*bin.tar.gz\\)",
+                    remote: "bundles/openjdk/GPL/windows-x64/\\1"
+                },
+                test: {
+                    local: "bundles/\\(jdk.*bin-tests.tar.gz\\)",
+                    remote: [
+                        "bundles/openjdk/GPL/windows-x64/jdk-" + data.version
+                            + "_windows-x64_bin-tests.tar.gz",
+                        "bundles/openjdk/GPL/windows-x64/\\1"
+                    ]
+                },
+                jdk_symbols: {
+                    local: "bundles/\\(jdk.*bin-symbols.tar.gz\\)",
+                    remote: [
+                        "bundles/openjdk/GPL/windows-x64/jdk-" + data.version
+                            + "_windows-x64_bin-symbols.tar.gz",
+                        "bundles/openjdk/GPL/windows-x64/\\1"
+                    ],
+                    subdir: "jdk-" + data.version
+                },
+                jre_symbols: {
+                    local: "bundles/\\(jre.*bin-symbols.tar.gz\\)",
+                    remote: "bundles/openjdk/GPL/windows-x64/\\1",
+                }
+            }
+        },
+
         "linux-x86-open-debug": {
             artifacts: {
                 jdk: {
@@ -929,9 +968,10 @@
     profiles["linux-x86-ri-debug"] = clone(profiles["linux-x86-open-debug"]);
     profiles["macosx-x64-ri"] = clone(profiles["macosx-x64-open"]);
     profiles["windows-x86-ri"] = clone(profiles["windows-x86-open"]);
+    profiles["windows-x64-ri"] = clone(profiles["windows-x64-open"]);
 
     // Generate artifacts for ri profiles
-    [ "linux-x64-ri", "linux-x86-ri", "linux-x86-ri-debug", "macosx-x64-ri", "windows-x86-ri" ]
+    [ "linux-x64-ri", "linux-x86-ri", "linux-x86-ri-debug", "macosx-x64-ri", "windows-x86-ri", "windows-x64-ri" ]
         .forEach(function (name) {
             // Rewrite all remote dirs to "bundles/openjdk/BCL/..."
             for (artifactName in profiles[name].artifacts) {
@@ -947,6 +987,11 @@
             configure_args: "--with-freetype-license="
                 + input.get("freetype", "install_path")
                 + "/freetype-2.7.1-v120-x86/freetype.md"
+        },
+        "windows-x64-ri": {
+            configure_args: "--with-freetype-license="
+                + input.get("freetype", "install_path")
+                + "/freetype-2.7.1-v120-x64/freetype.md"
         }
     };
     profiles = concatObjects(profiles, profilesRiFreetype);
--- a/make/hotspot/lib/CompileLibjsig.gmk	Wed Oct 04 11:52:07 2017 -0700
+++ b/make/hotspot/lib/CompileLibjsig.gmk	Wed Oct 04 20:01:19 2017 +0000
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2013, 2017, 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
@@ -36,7 +36,7 @@
   ifeq ($(STATIC_BUILD), false)
     ifeq ($(OPENJDK_TARGET_OS), linux)
       LIBJSIG_CFLAGS := -fPIC -D_GNU_SOURCE -D_REENTRANT $(EXTRA_CFLAGS)
-      LIBJSIG_LDFLAGS := $(LDFLAGS_HASH_STYLE) $(EXTRA_CFLAGS)
+      LIBJSIG_LDFLAGS := $(LDFLAGS_HASH_STYLE) ${LDFLAGS_NO_EXEC_STACK} $(EXTRA_CFLAGS)
       LIBJSIG_LIBS := $(LIBDL)
 
       # NOTE: The old build compiled this library without -soname.
--- a/make/langtools/src/classes/build/tools/symbolgenerator/TransitiveDependencies.java	Wed Oct 04 11:52:07 2017 -0700
+++ b/make/langtools/src/classes/build/tools/symbolgenerator/TransitiveDependencies.java	Wed Oct 04 20:01:19 2017 +0000
@@ -57,8 +57,8 @@
         }
 
         JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
-        List<String> options = Arrays.asList("-source", "9",
-                                             "-target", "9",
+        List<String> options = Arrays.asList("-source", "10",
+                                             "-target", "10",
                                              "-proc:only",
                                              "--system", "none",
                                              "--module-source-path", args[0],
--- a/make/nashorn/build.xml	Wed Oct 04 11:52:07 2017 -0700
+++ b/make/nashorn/build.xml	Wed Oct 04 20:01:19 2017 +0000
@@ -174,8 +174,6 @@
   <target name="compile" depends="prepare" description="Compiles nashorn">
     <javac srcdir="${dynalink.module.src.dir}"
            destdir="${dynalink.module.classes.dir}"
-           source="${javac.source}"
-           target="${javac.target}"
            debug="${javac.debug}"
            encoding="${javac.encoding}"
            includeantruntime="false" fork="true">
@@ -190,8 +188,6 @@
     </delete>
     <javac srcdir="${nashorn.module.src.dir}"
            destdir="${nashorn.module.classes.dir}"
-           source="${javac.source}"
-           target="${javac.target}"
            debug="${javac.debug}"
            encoding="${javac.encoding}"
            includeantruntime="false" fork="true">
@@ -207,8 +203,6 @@
     </delete>
     <javac srcdir="${nashorn.shell.module.src.dir}"
            destdir="${nashorn.shell.module.classes.dir}"
-           source="${javac.source}"
-           target="${javac.target}"
            debug="${javac.debug}"
            encoding="${javac.encoding}"
            includeantruntime="false" fork="true">
@@ -342,8 +336,6 @@
     <javac srcdir="${test.src.dir}"
            destdir="${build.test.classes.dir}"
            classpath="${javac.test.classpath}"
-           source="${javac.source}"
-           target="${javac.target}"
            debug="${javac.debug}"
            encoding="${javac.encoding}"
            includeantruntime="false" fork="true">
@@ -351,7 +343,7 @@
         <compilerarg value="-Xlint:unchecked"/>
         <compilerarg value="-Xlint:deprecation"/>
         <compilerarg value="-Xdiags:verbose"/>
-        <compilerarg line="${test.module.imports}"/>
+        <compilerarg line="${test.module.imports.compile.time}"/>
     </javac>
 
     <copy todir="${build.test.classes.dir}/META-INF/services">
--- a/make/nashorn/buildtools/nasgen/project.properties	Wed Oct 04 11:52:07 2017 -0700
+++ b/make/nashorn/buildtools/nasgen/project.properties	Wed Oct 04 20:01:19 2017 +0000
@@ -24,8 +24,6 @@
 
 # source and target levels
 build.compiler=modern
-javac.source=1.7
-javac.target=1.7
 
 # This directory is removed when the project is cleaned:
 nasgen.build.dir=../../../../build/nashorn/nasgen
--- a/make/nashorn/buildtools/nashorntask/project.properties	Wed Oct 04 11:52:07 2017 -0700
+++ b/make/nashorn/buildtools/nashorntask/project.properties	Wed Oct 04 20:01:19 2017 +0000
@@ -24,8 +24,6 @@
 
 # source and target levels
 build.compiler=modern
-javac.source=1.8
-javac.target=1.8
 
 # This directory is removed when the project is cleaned:
 nashorntask.build.dir=../../../../build/nashorn/nashorntask
--- a/make/nashorn/project.properties	Wed Oct 04 11:52:07 2017 -0700
+++ b/make/nashorn/project.properties	Wed Oct 04 20:01:19 2017 +0000
@@ -32,8 +32,6 @@
 
 # source and target levels
 build.compiler=modern
-javac.source=1.9
-javac.target=1.9
 
 javadoc.option=\
     -tag "implSpec:a:Implementation Requirements:" \
@@ -146,7 +144,7 @@
     ${file.reference.bsh.jar}${path.separator}\
     ${file.reference.snakeyaml.jar}
 
-test.module.imports=\
+test.module.imports.compile.time=\
     --add-exports jdk.scripting.nashorn/jdk.nashorn.internal.ir=ALL-UNNAMED \
     --add-exports jdk.scripting.nashorn/jdk.nashorn.internal.codegen=ALL-UNNAMED \
     --add-exports jdk.scripting.nashorn/jdk.nashorn.internal.parser=ALL-UNNAMED \
@@ -159,7 +157,10 @@
     --add-exports jdk.scripting.nashorn/jdk.nashorn.internal.runtime.regexp=ALL-UNNAMED \
     --add-exports jdk.scripting.nashorn/jdk.nashorn.internal.runtime.regexp.joni=ALL-UNNAMED \
     --add-exports jdk.scripting.nashorn/jdk.nashorn.tools=ALL-UNNAMED \
-    --add-exports java.base/jdk.internal.org.objectweb.asm=ALL-UNNAMED \
+    --add-exports java.base/jdk.internal.org.objectweb.asm=ALL-UNNAMED
+
+test.module.imports.runtime=\
+    ${test.module.imports.compile.time} \
     --add-opens jdk.scripting.nashorn/jdk.nashorn.internal.runtime=ALL-UNNAMED \
     --add-opens jdk.scripting.nashorn/jdk.nashorn.internal.runtime.doubleconv=ALL-UNNAMED
 
@@ -359,7 +360,7 @@
 
 run.test.jvmargs.common=\
   -server \
-  ${test.module.imports} \
+  ${test.module.imports.runtime} \
   ${run.test.jvmargs.external} \
   --add-modules jdk.scripting.nashorn.shell \
   ${nashorn.override.option} \
--- a/src/hotspot/share/prims/whitebox.cpp	Wed Oct 04 11:52:07 2017 -0700
+++ b/src/hotspot/share/prims/whitebox.cpp	Wed Oct 04 20:01:19 2017 +0000
@@ -73,6 +73,9 @@
 #include "utilities/nativeCallStack.hpp"
 #endif // INCLUDE_NMT
 
+#ifdef LINUX
+#include "utilities/elfFile.hpp"
+#endif
 
 #define SIZE_T_MAX_VALUE ((size_t) -1)
 
@@ -1823,6 +1826,20 @@
   DirectivesStack::pop(count);
 WB_END
 
+// Checks that the library libfile has the noexecstack bit set.
+WB_ENTRY(jboolean, WB_CheckLibSpecifiesNoexecstack(JNIEnv* env, jobject o, jstring libfile))
+  jboolean ret = false;
+#ifdef LINUX
+  // Can't be in VM when we call JNI.
+  ThreadToNativeFromVM ttnfv(thread);
+  const char* lf = env->GetStringUTFChars(libfile, NULL);
+  CHECK_JNI_EXCEPTION_(env, 0);
+  ret = (jboolean) ElfFile::specifies_noexecstack(lf);
+  env->ReleaseStringUTFChars(libfile, lf);
+#endif
+  return ret;
+WB_END
+
 #define CC (char*)
 
 static JNINativeMethod methods[] = {
@@ -2027,6 +2044,8 @@
                                                       (void*)&WB_GetConcurrentGCPhases},
   {CC"requestConcurrentGCPhase0", CC"(Ljava/lang/String;)Z",
                                                       (void*)&WB_RequestConcurrentGCPhase},
+  {CC"checkLibSpecifiesNoexecstack", CC"(Ljava/lang/String;)Z",
+                                                      (void*)&WB_CheckLibSpecifiesNoexecstack},
 };
 
 #undef CC
--- a/src/java.base/share/classes/java/lang/ClassLoader.java	Wed Oct 04 11:52:07 2017 -0700
+++ b/src/java.base/share/classes/java/lang/ClassLoader.java	Wed Oct 04 20:01:19 2017 +0000
@@ -2160,10 +2160,12 @@
      *          if a package of the given {@code name} is already
      *          defined by this class loader
      *
+     *
      * @since  1.2
      * @revised 9
      * @spec JPMS
      *
+     * @jvms 5.3 Run-time package
      * @see <a href="{@docRoot}/../specs/jar/jar.html#sealing">
      *      The JAR File Specification: Package Sealing</a>
      */
@@ -2186,17 +2188,19 @@
     }
 
     /**
-     * Returns a {@code Package} of the given <a href="#name">name</a> that has been
-     * defined by this class loader.
+     * Returns a {@code Package} of the given <a href="#name">name</a> that
+     * has been defined by this class loader.
      *
      * @param  name The <a href="#name">package name</a>
      *
-     * @return The {@code Package} of the given name defined by this class loader,
-     *         or {@code null} if not found
+     * @return The {@code Package} of the given name that has been defined
+     *         by this class loader, or {@code null} if not found
      *
      * @throws  NullPointerException
      *          if {@code name} is {@code null}.
      *
+     * @jvms 5.3 Run-time package
+     *
      * @since  9
      * @spec JPMS
      */
@@ -2211,14 +2215,18 @@
     }
 
     /**
-     * Returns all of the {@code Package}s defined by this class loader.
-     * The returned array has no duplicated {@code Package}s of the same name.
+     * Returns all of the {@code Package}s that have been defined by
+     * this class loader.  The returned array has no duplicated {@code Package}s
+     * of the same name.
      *
      * @apiNote This method returns an array rather than a {@code Set} or {@code Stream}
      *          for consistency with the existing {@link #getPackages} method.
      *
-     * @return The array of {@code Package} objects defined by this class loader;
-     *         or an zero length array if no package has been defined by this class loader.
+     * @return The array of {@code Package} objects that have been defined by
+     *         this class loader; or an zero length array if no package has been
+     *         defined by this class loader.
+     *
+     * @jvms 5.3 Run-time package
      *
      * @since  9
      * @spec JPMS
@@ -2244,7 +2252,7 @@
      * @param  name
      *         The <a href="#name">package name</a>
      *
-     * @return The {@code Package} corresponding to the given name defined by
+     * @return The {@code Package} of the given name that has been defined by
      *         this class loader or its ancestors, or {@code null} if not found.
      *
      * @throws  NullPointerException
@@ -2263,6 +2271,8 @@
      * {@link ClassLoader#getDefinedPackage} method which returns
      * a {@code Package} for the specified class loader.
      *
+     * @see ClassLoader#getDefinedPackage(String)
+     *
      * @since  1.2
      * @revised 9
      * @spec JPMS
@@ -2281,10 +2291,10 @@
     }
 
     /**
-     * Returns all of the {@code Package}s defined by this class loader
-     * and its ancestors.  The returned array may contain more than one
-     * {@code Package} object of the same package name, each defined by
-     * a different class loader in the class loader hierarchy.
+     * Returns all of the {@code Package}s that have been defined by
+     * this class loader and its ancestors.  The returned array may contain
+     * more than one {@code Package} object of the same package name, each
+     * defined by a different class loader in the class loader hierarchy.
      *
      * @apiNote The {@link #getPlatformClassLoader() platform class loader}
      * may delegate to the application class loader. In other words,
@@ -2294,8 +2304,10 @@
      * when invoked on the platform class loader, this method will not
      * return any packages defined to the application class loader.
      *
-     * @return  The array of {@code Package} objects defined by this
-     *          class loader and its ancestors
+     * @return  The array of {@code Package} objects that have been defined by
+     *          this class loader and its ancestors
+     *
+     * @see ClassLoader#getDefinedPackages()
      *
      * @since  1.2
      * @revised 9
--- a/src/java.base/share/classes/java/lang/StackFrameInfo.java	Wed Oct 04 11:52:07 2017 -0700
+++ b/src/java.base/share/classes/java/lang/StackFrameInfo.java	Wed Oct 04 20:01:19 2017 +0000
@@ -29,6 +29,7 @@
 
 import static java.lang.StackWalker.Option.*;
 import java.lang.StackWalker.StackFrame;
+import java.lang.invoke.MethodType;
 
 class StackFrameInfo implements StackFrame {
     private final static JavaLangInvokeAccess JLIA =
@@ -79,6 +80,17 @@
     }
 
     @Override
+    public MethodType getMethodType() {
+        walker.ensureAccessEnabled(RETAIN_CLASS_REFERENCE);
+        return JLIA.getMethodType(memberName);
+    }
+
+    @Override
+    public String getDescriptor() {
+        return JLIA.getMethodDescriptor(memberName);
+    }
+
+    @Override
     public int getByteCodeIndex() {
         // bci not available for native methods
         if (isNativeMethod())
--- a/src/java.base/share/classes/java/lang/StackWalker.java	Wed Oct 04 11:52:07 2017 -0700
+++ b/src/java.base/share/classes/java/lang/StackWalker.java	Wed Oct 04 20:01:19 2017 +0000
@@ -26,10 +26,12 @@
 
 import jdk.internal.reflect.CallerSensitive;
 
-import java.util.*;
+import java.lang.invoke.MethodType;
+import java.util.EnumSet;
+import java.util.Objects;
+import java.util.Set;
 import java.util.function.Consumer;
 import java.util.function.Function;
-import java.util.function.Predicate;
 import java.util.stream.Stream;
 
 /**
@@ -96,7 +98,7 @@
      * @since 9
      * @jvms 2.6
      */
-    public static interface StackFrame {
+    public interface StackFrame {
         /**
          * Gets the <a href="ClassLoader.html#name">binary name</a>
          * of the declaring class of the method represented by this stack frame.
@@ -128,6 +130,47 @@
         public Class<?> getDeclaringClass();
 
         /**
+         * Returns the {@link MethodType} representing the parameter types and
+         * the return type for the method represented by this stack frame.
+         *
+         * @implSpec
+         * The default implementation throws {@code UnsupportedOperationException}.
+         *
+         * @return the {@code MethodType} for this stack frame
+         *
+         * @throws UnsupportedOperationException if this {@code StackWalker}
+         *         is not configured with {@link Option#RETAIN_CLASS_REFERENCE
+         *         Option.RETAIN_CLASS_REFERENCE}.
+         *
+         * @since 10
+         */
+        public default MethodType getMethodType() {
+            throw new UnsupportedOperationException();
+        }
+
+        /**
+         * Returns the <i>descriptor</i> of the method represented by
+         * this stack frame as defined by
+         * <cite>The Java Virtual Machine Specification</cite>.
+         *
+         * @implSpec
+         * The default implementation throws {@code UnsupportedOperationException}.
+         *
+         * @return the descriptor of the method represented by
+         *         this stack frame
+         *
+         * @see MethodType#fromMethodDescriptorString(String, ClassLoader)
+         * @see MethodType#toMethodDescriptorString()
+         * @jvms 4.3.3 Method Descriptor
+         *
+         * @since 10
+         */
+        public default String getDescriptor() {
+            throw new UnsupportedOperationException();
+        }
+
+
+        /**
          * Returns the index to the code array of the {@code Code} attribute
          * containing the execution point represented by this stack frame.
          * The code array gives the actual bytes of Java Virtual Machine code
--- a/src/java.base/share/classes/java/lang/invoke/DelegatingMethodHandle.java	Wed Oct 04 11:52:07 2017 -0700
+++ b/src/java.base/share/classes/java/lang/invoke/DelegatingMethodHandle.java	Wed Oct 04 20:01:19 2017 +0000
@@ -28,6 +28,7 @@
 import java.util.Arrays;
 import static java.lang.invoke.LambdaForm.*;
 import static java.lang.invoke.LambdaForm.Kind.*;
+import static java.lang.invoke.MethodHandleNatives.Constants.REF_invokeVirtual;
 import static java.lang.invoke.MethodHandleStatics.*;
 
 /**
@@ -158,8 +159,11 @@
     static final NamedFunction NF_getTarget;
     static {
         try {
-            NF_getTarget = new NamedFunction(DelegatingMethodHandle.class
-                                             .getDeclaredMethod("getTarget"));
+            MemberName member = new MemberName(DelegatingMethodHandle.class, "getTarget",
+                    MethodType.methodType(MethodHandle.class), REF_invokeVirtual);
+            NF_getTarget = new NamedFunction(
+                    MemberName.getFactory()
+                            .resolveOrFail(REF_invokeVirtual, member, DelegatingMethodHandle.class, NoSuchMethodException.class));
         } catch (ReflectiveOperationException ex) {
             throw newInternalError(ex);
         }
--- a/src/java.base/share/classes/java/lang/invoke/DirectMethodHandle.java	Wed Oct 04 11:52:07 2017 -0700
+++ b/src/java.base/share/classes/java/lang/invoke/DirectMethodHandle.java	Wed Oct 04 20:01:19 2017 +0000
@@ -753,42 +753,38 @@
         return nf;
     }
 
+    private static final MethodType OBJ_OBJ_TYPE = MethodType.methodType(Object.class, Object.class);
+
+    private static final MethodType LONG_OBJ_TYPE = MethodType.methodType(long.class, Object.class);
+
     private static NamedFunction createFunction(byte func) {
         try {
             switch (func) {
                 case NF_internalMemberName:
-                    return new NamedFunction(DirectMethodHandle.class
-                            .getDeclaredMethod("internalMemberName", Object.class));
+                    return getNamedFunction("internalMemberName", OBJ_OBJ_TYPE);
                 case NF_internalMemberNameEnsureInit:
-                    return new NamedFunction(DirectMethodHandle.class
-                            .getDeclaredMethod("internalMemberNameEnsureInit", Object.class));
+                    return getNamedFunction("internalMemberNameEnsureInit", OBJ_OBJ_TYPE);
                 case NF_ensureInitialized:
-                    return new NamedFunction(DirectMethodHandle.class
-                            .getDeclaredMethod("ensureInitialized", Object.class));
+                    return getNamedFunction("ensureInitialized", MethodType.methodType(void.class, Object.class));
                 case NF_fieldOffset:
-                    return new NamedFunction(DirectMethodHandle.class
-                            .getDeclaredMethod("fieldOffset", Object.class));
+                    return getNamedFunction("fieldOffset", LONG_OBJ_TYPE);
                 case NF_checkBase:
-                    return new NamedFunction(DirectMethodHandle.class
-                            .getDeclaredMethod("checkBase", Object.class));
+                    return getNamedFunction("checkBase", OBJ_OBJ_TYPE);
                 case NF_staticBase:
-                    return new NamedFunction(DirectMethodHandle.class
-                            .getDeclaredMethod("staticBase", Object.class));
+                    return getNamedFunction("staticBase", OBJ_OBJ_TYPE);
                 case NF_staticOffset:
-                    return new NamedFunction(DirectMethodHandle.class
-                            .getDeclaredMethod("staticOffset", Object.class));
+                    return getNamedFunction("staticOffset", LONG_OBJ_TYPE);
                 case NF_checkCast:
-                    return new NamedFunction(DirectMethodHandle.class
-                            .getDeclaredMethod("checkCast", Object.class, Object.class));
+                    return getNamedFunction("checkCast", MethodType.methodType(Object.class, Object.class, Object.class));
                 case NF_allocateInstance:
-                    return new NamedFunction(DirectMethodHandle.class
-                            .getDeclaredMethod("allocateInstance", Object.class));
+                    return getNamedFunction("allocateInstance", OBJ_OBJ_TYPE);
                 case NF_constructorMethod:
-                    return new NamedFunction(DirectMethodHandle.class
-                            .getDeclaredMethod("constructorMethod", Object.class));
+                    return getNamedFunction("constructorMethod", OBJ_OBJ_TYPE);
                 case NF_UNSAFE:
-                    return new NamedFunction(new MemberName(MethodHandleStatics.class
-                            .getDeclaredField("UNSAFE")));
+                    MemberName member = new MemberName(MethodHandleStatics.class, "UNSAFE", Unsafe.class, REF_getField);
+                    return new NamedFunction(
+                            MemberName.getFactory()
+                                    .resolveOrFail(REF_getField, member, DirectMethodHandle.class, NoSuchMethodException.class));
                 default:
                     throw newInternalError("Unknown function: " + func);
             }
@@ -797,6 +793,15 @@
         }
     }
 
+    private static NamedFunction getNamedFunction(String name, MethodType type)
+        throws ReflectiveOperationException
+    {
+        MemberName member = new MemberName(DirectMethodHandle.class, name, type, REF_invokeStatic);
+        return new NamedFunction(
+            MemberName.getFactory()
+                .resolveOrFail(REF_invokeStatic, member, DirectMethodHandle.class, NoSuchMethodException.class));
+    }
+
     static {
         // The Holder class will contain pre-generated DirectMethodHandles resolved
         // speculatively using MemberName.getFactory().resolveOrNull. However, that
--- a/src/java.base/share/classes/java/lang/invoke/Invokers.java	Wed Oct 04 11:52:07 2017 -0700
+++ b/src/java.base/share/classes/java/lang/invoke/Invokers.java	Wed Oct 04 20:01:19 2017 +0000
@@ -611,23 +611,17 @@
         try {
             switch (func) {
                 case NF_checkExactType:
-                    return new NamedFunction(Invokers.class
-                        .getDeclaredMethod("checkExactType", MethodHandle.class,  MethodType.class));
+                    return getNamedFunction("checkExactType", MethodType.methodType(void.class, MethodHandle.class, MethodType.class));
                 case NF_checkGenericType:
-                    return new NamedFunction(Invokers.class
-                        .getDeclaredMethod("checkGenericType", MethodHandle.class,  MethodType.class));
+                    return getNamedFunction("checkGenericType", MethodType.methodType(MethodHandle.class, MethodHandle.class, MethodType.class));
                 case NF_getCallSiteTarget:
-                    return new NamedFunction(Invokers.class
-                        .getDeclaredMethod("getCallSiteTarget", CallSite.class));
+                    return getNamedFunction("getCallSiteTarget", MethodType.methodType(MethodHandle.class, CallSite.class));
                 case NF_checkCustomized:
-                    return new NamedFunction(Invokers.class
-                        .getDeclaredMethod("checkCustomized", MethodHandle.class));
+                    return getNamedFunction("checkCustomized", MethodType.methodType(void.class, MethodHandle.class));
                 case NF_checkVarHandleGenericType:
-                    return new NamedFunction(Invokers.class
-                        .getDeclaredMethod("checkVarHandleGenericType", VarHandle.class, VarHandle.AccessDescriptor.class));
+                    return getNamedFunction("checkVarHandleGenericType", MethodType.methodType(MethodHandle.class, VarHandle.class, VarHandle.AccessDescriptor.class));
                 case NF_checkVarHandleExactType:
-                    return new NamedFunction(Invokers.class
-                        .getDeclaredMethod("checkVarHandleExactType", VarHandle.class, VarHandle.AccessDescriptor.class));
+                    return getNamedFunction("checkVarHandleExactType", MethodType.methodType(MethodHandle.class, VarHandle.class, VarHandle.AccessDescriptor.class));
                 default:
                     throw newInternalError("Unknown function: " + func);
             }
@@ -636,6 +630,15 @@
         }
     }
 
+    private static NamedFunction getNamedFunction(String name, MethodType type)
+        throws ReflectiveOperationException
+    {
+        MemberName member = new MemberName(Invokers.class, name, type, REF_invokeStatic);
+        return new NamedFunction(
+                MemberName.getFactory()
+                        .resolveOrFail(REF_invokeStatic, member, Invokers.class, NoSuchMethodException.class));
+    }
+
     private static class Lazy {
         private static final MethodHandle MH_asSpreader;
 
--- a/src/java.base/share/classes/java/lang/invoke/MemberName.java	Wed Oct 04 11:52:07 2017 -0700
+++ b/src/java.base/share/classes/java/lang/invoke/MemberName.java	Wed Oct 04 20:01:19 2017 +0000
@@ -162,6 +162,29 @@
         return (MethodType) type;
     }
 
+    /** Return the descriptor of this member, which
+     *  must be a method or constructor.
+     */
+    String getMethodDescriptor() {
+        if (type == null) {
+            expandFromVM();
+            if (type == null) {
+                return null;
+            }
+        }
+        if (!isInvocable()) {
+            throw newIllegalArgumentException("not invocable, no method type");
+        }
+
+        // Get a snapshot of type which doesn't get changed by racing threads.
+        final Object type = this.type;
+        if (type instanceof String) {
+            return (String) type;
+        } else {
+            return getMethodType().toMethodDescriptorString();
+        }
+    }
+
     /** Return the actual type under which this method or constructor must be invoked.
      *  For non-static methods or constructors, this is the type with a leading parameter,
      *  a reference to declaring class.  For static methods, it is the same as the declared type.
--- a/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java	Wed Oct 04 11:52:07 2017 -0700
+++ b/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java	Wed Oct 04 20:01:19 2017 +0000
@@ -1786,6 +1786,18 @@
             }
 
             @Override
+            public MethodType getMethodType(Object mname) {
+                MemberName memberName = (MemberName)mname;
+                return memberName.getMethodType();
+            }
+
+            @Override
+            public String getMethodDescriptor(Object mname) {
+                MemberName memberName = (MemberName)mname;
+                return memberName.getMethodDescriptor();
+            }
+
+            @Override
             public boolean isNative(Object mname) {
                 MemberName memberName = (MemberName)mname;
                 return memberName.isNative();
--- a/src/java.base/share/classes/java/util/ArrayDeque.java	Wed Oct 04 11:52:07 2017 -0700
+++ b/src/java.base/share/classes/java/util/ArrayDeque.java	Wed Oct 04 20:01:19 2017 +0000
@@ -211,7 +211,7 @@
     }
 
     /**
-     * Increments i, mod modulus.
+     * Circularly increments i, mod modulus.
      * Precondition and postcondition: 0 <= i < modulus.
      */
     static final int inc(int i, int modulus) {
@@ -220,7 +220,7 @@
     }
 
     /**
-     * Decrements i, mod modulus.
+     * Circularly decrements i, mod modulus.
      * Precondition and postcondition: 0 <= i < modulus.
      */
     static final int dec(int i, int modulus) {
@@ -233,7 +233,7 @@
      * Precondition: 0 <= i < modulus, 0 <= distance <= modulus.
      * @return index 0 <= i < modulus
      */
-    static final int add(int i, int distance, int modulus) {
+    static final int inc(int i, int distance, int modulus) {
         if ((i += distance) - modulus >= 0) i -= modulus;
         return i;
     }
@@ -825,7 +825,7 @@
             final int i, n;
             return ((n = sub(getFence(), i = cursor, es.length) >> 1) <= 0)
                 ? null
-                : new DeqSpliterator(i, cursor = add(i, n, es.length));
+                : new DeqSpliterator(i, cursor = inc(i, n, es.length));
         }
 
         public void forEachRemaining(Consumer<? super E> action) {
--- a/src/java.base/share/classes/java/util/HashMap.java	Wed Oct 04 11:52:07 2017 -0700
+++ b/src/java.base/share/classes/java/util/HashMap.java	Wed Oct 04 20:01:19 2017 +0000
@@ -490,7 +490,7 @@
     }
 
     /**
-     * Implements Map.putAll and Map constructor
+     * Implements Map.putAll and Map constructor.
      *
      * @param m the map
      * @param evict false when initially constructing this map, else
@@ -557,7 +557,7 @@
     }
 
     /**
-     * Implements Map.get and related methods
+     * Implements Map.get and related methods.
      *
      * @param hash hash for key
      * @param key the key
@@ -612,7 +612,7 @@
     }
 
     /**
-     * Implements Map.put and related methods
+     * Implements Map.put and related methods.
      *
      * @param hash hash for key
      * @param key the key
@@ -700,7 +700,7 @@
         }
         threshold = newThr;
         @SuppressWarnings({"rawtypes","unchecked"})
-            Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];
+        Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];
         table = newTab;
         if (oldTab != null) {
             for (int j = 0; j < oldCap; ++j) {
@@ -800,7 +800,7 @@
     }
 
     /**
-     * Implements Map.remove and related methods
+     * Implements Map.remove and related methods.
      *
      * @param hash hash for key
      * @param key the key
@@ -875,7 +875,7 @@
     public boolean containsValue(Object value) {
         Node<K,V>[] tab; V v;
         if ((tab = table) != null && size > 0) {
-            for (Node<K, V> e : tab) {
+            for (Node<K,V> e : tab) {
                 for (; e != null; e = e.next) {
                     if ((v = e.value) == value ||
                         (value != null && value.equals(v)))
@@ -927,7 +927,7 @@
                 throw new NullPointerException();
             if (size > 0 && (tab = table) != null) {
                 int mc = modCount;
-                for (Node<K, V> e : tab) {
+                for (Node<K,V> e : tab) {
                     for (; e != null; e = e.next)
                         action.accept(e.key);
                 }
@@ -975,7 +975,7 @@
                 throw new NullPointerException();
             if (size > 0 && (tab = table) != null) {
                 int mc = modCount;
-                for (Node<K, V> e : tab) {
+                for (Node<K,V> e : tab) {
                     for (; e != null; e = e.next)
                         action.accept(e.value);
                 }
@@ -1038,7 +1038,7 @@
                 throw new NullPointerException();
             if (size > 0 && (tab = table) != null) {
                 int mc = modCount;
-                for (Node<K, V> e : tab) {
+                for (Node<K,V> e : tab) {
                     for (; e != null; e = e.next)
                         action.accept(e);
                 }
@@ -1335,7 +1335,7 @@
             throw new NullPointerException();
         if (size > 0 && (tab = table) != null) {
             int mc = modCount;
-            for (Node<K, V> e : tab) {
+            for (Node<K,V> e : tab) {
                 for (; e != null; e = e.next)
                     action.accept(e.key, e.value);
             }
@@ -1351,7 +1351,7 @@
             throw new NullPointerException();
         if (size > 0 && (tab = table) != null) {
             int mc = modCount;
-            for (Node<K, V> e : tab) {
+            for (Node<K,V> e : tab) {
                 for (; e != null; e = e.next) {
                     e.value = function.apply(e.key, e.value);
                 }
@@ -1394,9 +1394,10 @@
     }
 
     /**
-     * Save the state of the {@code HashMap} instance to a stream (i.e.,
-     * serialize it).
+     * Saves this map to a stream (that is, serializes it).
      *
+     * @param s the stream
+     * @throws IOException if an I/O error occurs
      * @serialData The <i>capacity</i> of the HashMap (the length of the
      *             bucket array) is emitted (int), followed by the
      *             <i>size</i> (an int, the number of key-value
@@ -1415,8 +1416,11 @@
     }
 
     /**
-     * Reconstitute the {@code HashMap} instance from a stream (i.e.,
-     * deserialize it).
+     * Reconstitutes this map from a stream (that is, deserializes it).
+     * @param s the stream
+     * @throws ClassNotFoundException if the class of a serialized object
+     *         could not be found
+     * @throws IOException if an I/O error occurs
      */
     private void readObject(java.io.ObjectInputStream s)
         throws IOException, ClassNotFoundException {
@@ -1445,7 +1449,7 @@
             threshold = ((cap < MAXIMUM_CAPACITY && ft < MAXIMUM_CAPACITY) ?
                          (int)ft : Integer.MAX_VALUE);
             @SuppressWarnings({"rawtypes","unchecked"})
-                Node<K,V>[] tab = (Node<K,V>[])new Node[cap];
+            Node<K,V>[] tab = (Node<K,V>[])new Node[cap];
             table = tab;
 
             // Read the keys and values, and put the mappings in the HashMap
@@ -1830,7 +1834,7 @@
     void internalWriteEntries(java.io.ObjectOutputStream s) throws IOException {
         Node<K,V>[] tab;
         if (size > 0 && (tab = table) != null) {
-            for (Node<K, V> e : tab) {
+            for (Node<K,V> e : tab) {
                 for (; e != null; e = e.next) {
                     s.writeObject(e.key);
                     s.writeObject(e.value);
@@ -1951,7 +1955,6 @@
 
         /**
          * Forms tree of the nodes linked from this node.
-         * @return root of tree
          */
         final void treeify(Node<K,V>[] tab) {
             TreeNode<K,V> root = null;
@@ -2089,8 +2092,11 @@
                 return;
             if (root.parent != null)
                 root = root.root();
-            if (root == null || root.right == null ||
-                (rl = root.left) == null || rl.left == null) {
+            if (root == null
+                || (movable
+                    && (root.right == null
+                        || (rl = root.left) == null
+                        || rl.left == null))) {
                 tab[index] = first.untreeify(map);  // too small
                 return;
             }
@@ -2319,7 +2325,7 @@
 
         static <K,V> TreeNode<K,V> balanceDeletion(TreeNode<K,V> root,
                                                    TreeNode<K,V> x) {
-            for (TreeNode<K,V> xp, xpl, xpr;;)  {
+            for (TreeNode<K,V> xp, xpl, xpr;;) {
                 if (x == null || x == root)
                     return root;
                 else if ((xp = x.parent) == null) {
--- a/src/java.base/share/classes/java/util/concurrent/CompletableFuture.java	Wed Oct 04 11:52:07 2017 -0700
+++ b/src/java.base/share/classes/java/util/concurrent/CompletableFuture.java	Wed Oct 04 20:01:19 2017 +0000
@@ -2490,13 +2490,13 @@
         for (Completion p = stack; p != null; p = p.next)
             ++count;
         return super.toString() +
-            ((r == null) ?
-             ((count == 0) ?
-              "[Not completed]" :
-              "[Not completed, " + count + " dependents]") :
-             (((r instanceof AltResult) && ((AltResult)r).ex != null) ?
-              "[Completed exceptionally]" :
-              "[Completed normally]"));
+            ((r == null)
+             ? ((count == 0)
+                ? "[Not completed]"
+                : "[Not completed, " + count + " dependents]")
+             : (((r instanceof AltResult) && ((AltResult)r).ex != null)
+                ? "[Completed exceptionally: " + ((AltResult)r).ex + "]"
+                : "[Completed normally]"));
     }
 
     // jdk9 additions
--- a/src/java.base/share/classes/java/util/concurrent/ConcurrentHashMap.java	Wed Oct 04 11:52:07 2017 -0700
+++ b/src/java.base/share/classes/java/util/concurrent/ConcurrentHashMap.java	Wed Oct 04 20:01:19 2017 +0000
@@ -1394,8 +1394,8 @@
     }
 
     /**
-     * Saves the state of the {@code ConcurrentHashMap} instance to a
-     * stream (i.e., serializes it).
+     * Saves this map to a stream (that is, serializes it).
+     *
      * @param s the stream
      * @throws java.io.IOException if an I/O error occurs
      * @serialData
@@ -1439,7 +1439,7 @@
     }
 
     /**
-     * Reconstitutes the instance from a stream (that is, deserializes it).
+     * Reconstitutes this map from a stream (that is, deserializes it).
      * @param s the stream
      * @throws ClassNotFoundException if the class of a serialized object
      *         could not be found
--- a/src/java.base/share/classes/java/util/concurrent/ConcurrentSkipListMap.java	Wed Oct 04 11:52:07 2017 -0700
+++ b/src/java.base/share/classes/java/util/concurrent/ConcurrentSkipListMap.java	Wed Oct 04 20:01:19 2017 +0000
@@ -58,6 +58,7 @@
 import java.util.function.Consumer;
 import java.util.function.Function;
 import java.util.function.Predicate;
+import java.util.concurrent.atomic.LongAdder;
 
 /**
  * A scalable concurrent {@link ConcurrentNavigableMap} implementation.
@@ -86,12 +87,7 @@
  * associated map using {@code put}, {@code putIfAbsent}, or
  * {@code replace}, depending on exactly which effect you need.)
  *
- * <p>Beware that, unlike in most collections, the {@code size}
- * method is <em>not</em> a constant-time operation. Because of the
- * asynchronous nature of these maps, determining the current number
- * of elements requires a traversal of the elements, and so may report
- * inaccurate results if this collection is modified during traversal.
- * Additionally, the bulk operations {@code putAll}, {@code equals},
+ * <p>Beware that bulk operations {@code putAll}, {@code equals},
  * {@code toArray}, {@code containsValue}, and {@code clear} are
  * <em>not</em> guaranteed to be performed atomically. For example, an
  * iterator operating concurrently with a {@code putAll} operation
@@ -158,42 +154,35 @@
      * be slow and space-intensive using AtomicMarkedReference), nodes
      * use direct CAS'able next pointers.  On deletion, instead of
      * marking a pointer, they splice in another node that can be
-     * thought of as standing for a marked pointer (indicating this by
-     * using otherwise impossible field values).  Using plain nodes
-     * acts roughly like "boxed" implementations of marked pointers,
-     * but uses new nodes only when nodes are deleted, not for every
-     * link.  This requires less space and supports faster
-     * traversal. Even if marked references were better supported by
-     * JVMs, traversal using this technique might still be faster
-     * because any search need only read ahead one more node than
-     * otherwise required (to check for trailing marker) rather than
-     * unmasking mark bits or whatever on each read.
+     * thought of as standing for a marked pointer (see method
+     * unlinkNode).  Using plain nodes acts roughly like "boxed"
+     * implementations of marked pointers, but uses new nodes only
+     * when nodes are deleted, not for every link.  This requires less
+     * space and supports faster traversal. Even if marked references
+     * were better supported by JVMs, traversal using this technique
+     * might still be faster because any search need only read ahead
+     * one more node than otherwise required (to check for trailing
+     * marker) rather than unmasking mark bits or whatever on each
+     * read.
      *
      * This approach maintains the essential property needed in the HM
      * algorithm of changing the next-pointer of a deleted node so
      * that any other CAS of it will fail, but implements the idea by
-     * changing the pointer to point to a different node, not by
-     * marking it.  While it would be possible to further squeeze
-     * space by defining marker nodes not to have key/value fields, it
-     * isn't worth the extra type-testing overhead.  The deletion
-     * markers are rarely encountered during traversal and are
-     * normally quickly garbage collected. (Note that this technique
-     * would not work well in systems without garbage collection.)
+     * changing the pointer to point to a different node (with
+     * otherwise illegal null fields), not by marking it.  While it
+     * would be possible to further squeeze space by defining marker
+     * nodes not to have key/value fields, it isn't worth the extra
+     * type-testing overhead.  The deletion markers are rarely
+     * encountered during traversal, are easily detected via null
+     * checks that are needed anyway, and are normally quickly garbage
+     * collected. (Note that this technique would not work well in
+     * systems without garbage collection.)
      *
      * In addition to using deletion markers, the lists also use
      * nullness of value fields to indicate deletion, in a style
      * similar to typical lazy-deletion schemes.  If a node's value is
      * null, then it is considered logically deleted and ignored even
-     * though it is still reachable. This maintains proper control of
-     * concurrent replace vs delete operations -- an attempted replace
-     * must fail if a delete beat it by nulling field, and a delete
-     * must return the last non-null value held in the field. (Note:
-     * Null, rather than some special marker, is used for value fields
-     * here because it just so happens to mesh with the Map API
-     * requirement that method get returns null if there is no
-     * mapping, which allows nodes to remain concurrently readable
-     * even when deleted. Using any other marker value here would be
-     * messy at best.)
+     * though it is still reachable.
      *
      * Here's the sequence of events for a deletion of node n with
      * predecessor b and successor f, initially:
@@ -203,9 +192,8 @@
      *        +------+       +------+      +------+
      *
      * 1. CAS n's value field from non-null to null.
-     *    From this point on, no public operations encountering
-     *    the node consider this mapping to exist. However, other
-     *    ongoing insertions and deletions might still modify
+     *    Traversals encountering a node with null value ignore it.
+     *    However, ongoing insertions and deletions might still modify
      *    n's next pointer.
      *
      * 2. CAS n's next pointer to point to a new marker node.
@@ -228,12 +216,7 @@
      * thread noticed during a traversal a node with null value and
      * helped out by marking and/or unlinking.  This helping-out
      * ensures that no thread can become stuck waiting for progress of
-     * the deleting thread.  The use of marker nodes slightly
-     * complicates helping-out code because traversals must track
-     * consistent reads of up to four nodes (b, n, marker, f), not
-     * just (b, n, f), although the next field of a marker is
-     * immutable, and once a next field is CAS'ed to point to a
-     * marker, it never again changes, so this requires less care.
+     * the deleting thread.
      *
      * Skip lists add indexing to this scheme, so that the base-level
      * traversals start close to the locations being found, inserted
@@ -243,113 +226,101 @@
      * b) that are not (structurally) deleted, otherwise retrying
      * after processing the deletion.
      *
-     * Index levels are maintained as lists with volatile next fields,
-     * using CAS to link and unlink.  Races are allowed in index-list
-     * operations that can (rarely) fail to link in a new index node
-     * or delete one. (We can't do this of course for data nodes.)
-     * However, even when this happens, the index lists remain sorted,
-     * so correctly serve as indices.  This can impact performance,
-     * but since skip lists are probabilistic anyway, the net result
-     * is that under contention, the effective "p" value may be lower
-     * than its nominal value. And race windows are kept small enough
-     * that in practice these failures are rare, even under a lot of
-     * contention.
+     * Index levels are maintained using CAS to link and unlink
+     * successors ("right" fields).  Races are allowed in index-list
+     * operations that can (rarely) fail to link in a new index node.
+     * (We can't do this of course for data nodes.)  However, even
+     * when this happens, the index lists correctly guide search.
+     * This can impact performance, but since skip lists are
+     * probabilistic anyway, the net result is that under contention,
+     * the effective "p" value may be lower than its nominal value.
      *
-     * The fact that retries (for both base and index lists) are
-     * relatively cheap due to indexing allows some minor
-     * simplifications of retry logic. Traversal restarts are
-     * performed after most "helping-out" CASes. This isn't always
-     * strictly necessary, but the implicit backoffs tend to help
-     * reduce other downstream failed CAS's enough to outweigh restart
-     * cost.  This worsens the worst case, but seems to improve even
-     * highly contended cases.
-     *
-     * Unlike most skip-list implementations, index insertion and
-     * deletion here require a separate traversal pass occurring after
-     * the base-level action, to add or remove index nodes.  This adds
-     * to single-threaded overhead, but improves contended
-     * multithreaded performance by narrowing interference windows,
-     * and allows deletion to ensure that all index nodes will be made
-     * unreachable upon return from a public remove operation, thus
-     * avoiding unwanted garbage retention. This is more important
-     * here than in some other data structures because we cannot null
-     * out node fields referencing user keys since they might still be
-     * read by other ongoing traversals.
+     * Index insertion and deletion sometimes require a separate
+     * traversal pass occurring after the base-level action, to add or
+     * remove index nodes.  This adds to single-threaded overhead, but
+     * improves contended multithreaded performance by narrowing
+     * interference windows, and allows deletion to ensure that all
+     * index nodes will be made unreachable upon return from a public
+     * remove operation, thus avoiding unwanted garbage retention.
      *
      * Indexing uses skip list parameters that maintain good search
      * performance while using sparser-than-usual indices: The
-     * hardwired parameters k=1, p=0.5 (see method doPut) mean
-     * that about one-quarter of the nodes have indices. Of those that
-     * do, half have one level, a quarter have two, and so on (see
-     * Pugh's Skip List Cookbook, sec 3.4).  The expected total space
-     * requirement for a map is slightly less than for the current
-     * implementation of java.util.TreeMap.
+     * hardwired parameters k=1, p=0.5 (see method doPut) mean that
+     * about one-quarter of the nodes have indices. Of those that do,
+     * half have one level, a quarter have two, and so on (see Pugh's
+     * Skip List Cookbook, sec 3.4), up to a maximum of 62 levels
+     * (appropriate for up to 2^63 elements).  The expected total
+     * space requirement for a map is slightly less than for the
+     * current implementation of java.util.TreeMap.
      *
      * Changing the level of the index (i.e, the height of the
-     * tree-like structure) also uses CAS. The head index has initial
-     * level/height of one. Creation of an index with height greater
-     * than the current level adds a level to the head index by
-     * CAS'ing on a new top-most head. To maintain good performance
-     * after a lot of removals, deletion methods heuristically try to
-     * reduce the height if the topmost levels appear to be empty.
-     * This may encounter races in which it possible (but rare) to
-     * reduce and "lose" a level just as it is about to contain an
-     * index (that will then never be encountered). This does no
-     * structural harm, and in practice appears to be a better option
-     * than allowing unrestrained growth of levels.
+     * tree-like structure) also uses CAS.  Creation of an index with
+     * height greater than the current level adds a level to the head
+     * index by CAS'ing on a new top-most head. To maintain good
+     * performance after a lot of removals, deletion methods
+     * heuristically try to reduce the height if the topmost levels
+     * appear to be empty.  This may encounter races in which it is
+     * possible (but rare) to reduce and "lose" a level just as it is
+     * about to contain an index (that will then never be
+     * encountered). This does no structural harm, and in practice
+     * appears to be a better option than allowing unrestrained growth
+     * of levels.
      *
-     * The code for all this is more verbose than you'd like. Most
-     * operations entail locating an element (or position to insert an
-     * element). The code to do this can't be nicely factored out
-     * because subsequent uses require a snapshot of predecessor
-     * and/or successor and/or value fields which can't be returned
-     * all at once, at least not without creating yet another object
-     * to hold them -- creating such little objects is an especially
-     * bad idea for basic internal search operations because it adds
-     * to GC overhead.  (This is one of the few times I've wished Java
-     * had macros.) Instead, some traversal code is interleaved within
-     * insertion and removal operations.  The control logic to handle
-     * all the retry conditions is sometimes twisty. Most search is
-     * broken into 2 parts. findPredecessor() searches index nodes
-     * only, returning a base-level predecessor of the key. findNode()
-     * finishes out the base-level search. Even with this factoring,
-     * there is a fair amount of near-duplication of code to handle
-     * variants.
+     * This class provides concurrent-reader-style memory consistency,
+     * ensuring that read-only methods report status and/or values no
+     * staler than those holding at method entry. This is done by
+     * performing all publication and structural updates using
+     * (volatile) CAS, placing an acquireFence in a few access
+     * methods, and ensuring that linked objects are transitively
+     * acquired via dependent reads (normally once) unless performing
+     * a volatile-mode CAS operation (that also acts as an acquire and
+     * release).  This form of fence-hoisting is similar to RCU and
+     * related techniques (see McKenney's online book
+     * https://www.kernel.org/pub/linux/kernel/people/paulmck/perfbook/perfbook.html)
+     * It minimizes overhead that may otherwise occur when using so
+     * many volatile-mode reads. Using explicit acquireFences is
+     * logistically easier than targeting particular fields to be read
+     * in acquire mode: fences are just hoisted up as far as possible,
+     * to the entry points or loop headers of a few methods. A
+     * potential disadvantage is that these few remaining fences are
+     * not easily optimized away by compilers under exclusively
+     * single-thread use.  It requires some care to avoid volatile
+     * mode reads of other fields. (Note that the memory semantics of
+     * a reference dependently read in plain mode exactly once are
+     * equivalent to those for atomic opaque mode.)  Iterators and
+     * other traversals encounter each node and value exactly once.
+     * Other operations locate an element (or position to insert an
+     * element) via a sequence of dereferences. This search is broken
+     * into two parts. Method findPredecessor (and its specialized
+     * embeddings) searches index nodes only, returning a base-level
+     * predecessor of the key. Callers carry out the base-level
+     * search, restarting if encountering a marker preventing link
+     * modification.  In some cases, it is possible to encounter a
+     * node multiple times while descending levels. For mutative
+     * operations, the reported value is validated using CAS (else
+     * retrying), preserving linearizability with respect to each
+     * other. Others may return any (non-null) value holding in the
+     * course of the method call.  (Search-based methods also include
+     * some useless-looking explicit null checks designed to allow
+     * more fields to be nulled out upon removal, to reduce floating
+     * garbage, but which is not currently done, pending discovery of
+     * a way to do this with less impact on other operations.)
      *
      * To produce random values without interference across threads,
      * we use within-JDK thread local random support (via the
      * "secondary seed", to avoid interference with user-level
      * ThreadLocalRandom.)
      *
-     * A previous version of this class wrapped non-comparable keys
-     * with their comparators to emulate Comparables when using
-     * comparators vs Comparables.  However, JVMs now appear to better
-     * handle infusing comparator-vs-comparable choice into search
-     * loops. Static method cpr(comparator, x, y) is used for all
-     * comparisons, which works well as long as the comparator
-     * argument is set up outside of loops (thus sometimes passed as
-     * an argument to internal methods) to avoid field re-reads.
-     *
      * For explanation of algorithms sharing at least a couple of
      * features with this one, see Mikhail Fomitchev's thesis
      * (http://www.cs.yorku.ca/~mikhail/), Keir Fraser's thesis
      * (http://www.cl.cam.ac.uk/users/kaf24/), and Hakan Sundell's
      * thesis (http://www.cs.chalmers.se/~phs/).
      *
-     * Given the use of tree-like index nodes, you might wonder why
-     * this doesn't use some kind of search tree instead, which would
-     * support somewhat faster search operations. The reason is that
-     * there are no known efficient lock-free insertion and deletion
-     * algorithms for search trees. The immutability of the "down"
-     * links of index nodes (as opposed to mutable "left" fields in
-     * true trees) makes this tractable using only CAS operations.
-     *
      * Notation guide for local variables
-     * Node:         b, n, f    for  predecessor, node, successor
+     * Node:         b, n, f, p for  predecessor, node, successor, aux
      * Index:        q, r, d    for index node, right, down.
-     *               t          for another index node
      * Head:         h
-     * Levels:       j
      * Keys:         k, key
      * Values:       v, value
      * Comparisons:  c
@@ -358,16 +329,6 @@
     private static final long serialVersionUID = -8627078645895051609L;
 
     /**
-     * Special value used to identify base-level header.
-     */
-    static final Object BASE_HEADER = new Object();
-
-    /**
-     * The topmost head index of the skiplist.
-     */
-    private transient volatile HeadIndex<K,V> head;
-
-    /**
      * The comparator used to maintain order in this map, or null if
      * using natural ordering.  (Non-private to simplify access in
      * nested classes.)
@@ -375,311 +336,152 @@
      */
     final Comparator<? super K> comparator;
 
+    /** Lazily initialized topmost index of the skiplist. */
+    private transient Index<K,V> head;
+    /** Lazily initialized element count */
+    private transient LongAdder adder;
     /** Lazily initialized key set */
     private transient KeySet<K,V> keySet;
     /** Lazily initialized values collection */
     private transient Values<K,V> values;
     /** Lazily initialized entry set */
     private transient EntrySet<K,V> entrySet;
-    /** Lazily initialized descending key set */
+    /** Lazily initialized descending map */
     private transient SubMap<K,V> descendingMap;
 
     /**
-     * Initializes or resets state. Needed by constructors, clone,
-     * clear, readObject. and ConcurrentSkipListSet.clone.
-     * (Note that comparator must be separately initialized.)
-     */
-    private void initialize() {
-        keySet = null;
-        entrySet = null;
-        values = null;
-        descendingMap = null;
-        head = new HeadIndex<K,V>(new Node<K,V>(null, BASE_HEADER, null),
-                                  null, null, 1);
-    }
-
-    /**
-     * compareAndSet head node.
-     */
-    private boolean casHead(HeadIndex<K,V> cmp, HeadIndex<K,V> val) {
-        return HEAD.compareAndSet(this, cmp, val);
-    }
-
-    /* ---------------- Nodes -------------- */
-
-    /**
      * Nodes hold keys and values, and are singly linked in sorted
      * order, possibly with some intervening marker nodes. The list is
-     * headed by a dummy node accessible as head.node. The value field
-     * is declared only as Object because it takes special non-V
-     * values for marker and header nodes.
+     * headed by a header node accessible as head.node. Headers and
+     * marker nodes have null keys. The val field (but currently not
+     * the key field) is nulled out upon deletion.
      */
     static final class Node<K,V> {
-        final K key;
-        volatile Object value;
-        volatile Node<K,V> next;
-
-        /**
-         * Creates a new regular node.
-         */
-        Node(K key, Object value, Node<K,V> next) {
+        final K key; // currently, never detached
+        V val;
+        Node<K,V> next;
+        Node(K key, V value, Node<K,V> next) {
             this.key = key;
-            this.value = value;
+            this.val = value;
             this.next = next;
         }
-
-        /**
-         * Creates a new marker node. A marker is distinguished by
-         * having its value field point to itself.  Marker nodes also
-         * have null keys, a fact that is exploited in a few places,
-         * but this doesn't distinguish markers from the base-level
-         * header node (head.node), which also has a null key.
-         */
-        Node(Node<K,V> next) {
-            this.key = null;
-            this.value = this;
-            this.next = next;
-        }
-
-        /**
-         * compareAndSet value field.
-         */
-        boolean casValue(Object cmp, Object val) {
-            return VALUE.compareAndSet(this, cmp, val);
-        }
-
-        /**
-         * compareAndSet next field.
-         */
-        boolean casNext(Node<K,V> cmp, Node<K,V> val) {
-            return NEXT.compareAndSet(this, cmp, val);
-        }
-
-        /**
-         * Returns true if this node is a marker. This method isn't
-         * actually called in any current code checking for markers
-         * because callers will have already read value field and need
-         * to use that read (not another done here) and so directly
-         * test if value points to node.
-         *
-         * @return true if this node is a marker node
-         */
-        boolean isMarker() {
-            return value == this;
-        }
-
-        /**
-         * Returns true if this node is the header of base-level list.
-         * @return true if this node is header node
-         */
-        boolean isBaseHeader() {
-            return value == BASE_HEADER;
-        }
-
-        /**
-         * Tries to append a deletion marker to this node.
-         * @param f the assumed current successor of this node
-         * @return true if successful
-         */
-        boolean appendMarker(Node<K,V> f) {
-            return casNext(f, new Node<K,V>(f));
-        }
-
-        /**
-         * Helps out a deletion by appending marker or unlinking from
-         * predecessor. This is called during traversals when value
-         * field seen to be null.
-         * @param b predecessor
-         * @param f successor
-         */
-        void helpDelete(Node<K,V> b, Node<K,V> f) {
-            /*
-             * Rechecking links and then doing only one of the
-             * help-out stages per call tends to minimize CAS
-             * interference among helping threads.
-             */
-            if (f == next && this == b.next) {
-                if (f == null || f.value != f) // not already marked
-                    casNext(f, new Node<K,V>(f));
-                else
-                    b.casNext(this, f.next);
-            }
-        }
-
-        /**
-         * Returns value if this node contains a valid key-value pair,
-         * else null.
-         * @return this node's value if it isn't a marker or header or
-         * is deleted, else null
-         */
-        V getValidValue() {
-            Object v = value;
-            if (v == this || v == BASE_HEADER)
-                return null;
-            @SuppressWarnings("unchecked") V vv = (V)v;
-            return vv;
-        }
-
-        /**
-         * Creates and returns a new SimpleImmutableEntry holding current
-         * mapping if this node holds a valid value, else null.
-         * @return new entry or null
-         */
-        AbstractMap.SimpleImmutableEntry<K,V> createSnapshot() {
-            Object v = value;
-            if (v == null || v == this || v == BASE_HEADER)
-                return null;
-            @SuppressWarnings("unchecked") V vv = (V)v;
-            return new AbstractMap.SimpleImmutableEntry<K,V>(key, vv);
-        }
-
-        // VarHandle mechanics
-        private static final VarHandle VALUE;
-        private static final VarHandle NEXT;
-        static {
-            try {
-                MethodHandles.Lookup l = MethodHandles.lookup();
-                VALUE = l.findVarHandle(Node.class, "value", Object.class);
-                NEXT = l.findVarHandle(Node.class, "next", Node.class);
-            } catch (ReflectiveOperationException e) {
-                    throw new Error(e);
-            }
-        }
     }
 
-    /* ---------------- Indexing -------------- */
-
     /**
-     * Index nodes represent the levels of the skip list.  Note that
-     * even though both Nodes and Indexes have forward-pointing
-     * fields, they have different types and are handled in different
-     * ways, that can't nicely be captured by placing field in a
-     * shared abstract class.
+     * Index nodes represent the levels of the skip list.
      */
-    static class Index<K,V> {
-        final Node<K,V> node;
+    static final class Index<K,V> {
+        final Node<K,V> node;  // currently, never detached
         final Index<K,V> down;
-        volatile Index<K,V> right;
-
-        /**
-         * Creates index node with given values.
-         */
+        Index<K,V> right;
         Index(Node<K,V> node, Index<K,V> down, Index<K,V> right) {
             this.node = node;
             this.down = down;
             this.right = right;
         }
-
-        /**
-         * compareAndSet right field.
-         */
-        final boolean casRight(Index<K,V> cmp, Index<K,V> val) {
-            return RIGHT.compareAndSet(this, cmp, val);
-        }
-
-        /**
-         * Returns true if the node this indexes has been deleted.
-         * @return true if indexed node is known to be deleted
-         */
-        final boolean indexesDeletedNode() {
-            return node.value == null;
-        }
-
-        /**
-         * Tries to CAS newSucc as successor.  To minimize races with
-         * unlink that may lose this index node, if the node being
-         * indexed is known to be deleted, it doesn't try to link in.
-         * @param succ the expected current successor
-         * @param newSucc the new successor
-         * @return true if successful
-         */
-        final boolean link(Index<K,V> succ, Index<K,V> newSucc) {
-            Node<K,V> n = node;
-            newSucc.right = succ;
-            return n.value != null && casRight(succ, newSucc);
-        }
-
-        /**
-         * Tries to CAS right field to skip over apparent successor
-         * succ.  Fails (forcing a retraversal by caller) if this node
-         * is known to be deleted.
-         * @param succ the expected current successor
-         * @return true if successful
-         */
-        final boolean unlink(Index<K,V> succ) {
-            return node.value != null && casRight(succ, succ.right);
-        }
-
-        // VarHandle mechanics
-        private static final VarHandle RIGHT;
-        static {
-            try {
-                MethodHandles.Lookup l = MethodHandles.lookup();
-                RIGHT = l.findVarHandle(Index.class, "right", Index.class);
-            } catch (ReflectiveOperationException e) {
-                throw new Error(e);
-            }
-        }
     }
 
-    /* ---------------- Head nodes -------------- */
-
-    /**
-     * Nodes heading each level keep track of their level.
-     */
-    static final class HeadIndex<K,V> extends Index<K,V> {
-        final int level;
-        HeadIndex(Node<K,V> node, Index<K,V> down, Index<K,V> right, int level) {
-            super(node, down, right);
-            this.level = level;
-        }
-    }
-
-    /* ---------------- Comparison utilities -------------- */
+    /* ----------------  Utilities -------------- */
 
     /**
      * Compares using comparator or natural ordering if null.
      * Called only by methods that have performed required type checks.
      */
     @SuppressWarnings({"unchecked", "rawtypes"})
-    static final int cpr(Comparator c, Object x, Object y) {
+    static int cpr(Comparator c, Object x, Object y) {
         return (c != null) ? c.compare(x, y) : ((Comparable)x).compareTo(y);
     }
 
+    /**
+     * Returns the header for base node list, or null if uninitialized
+     */
+    final Node<K,V> baseHead() {
+        Index<K,V> h;
+        VarHandle.acquireFence();
+        return ((h = head) == null) ? null : h.node;
+    }
+
+    /**
+     * Tries to unlink deleted node n from predecessor b (if both
+     * exist), by first splicing in a marker if not already present.
+     * Upon return, node n is sure to be unlinked from b, possibly
+     * via the actions of some other thread.
+     *
+     * @param b if nonnull, predecessor
+     * @param n if nonnull, node known to be deleted
+     */
+    static <K,V> void unlinkNode(Node<K,V> b, Node<K,V> n) {
+        if (b != null && n != null) {
+            Node<K,V> f, p;
+            for (;;) {
+                if ((f = n.next) != null && f.key == null) {
+                    p = f.next;               // already marked
+                    break;
+                }
+                else if (NEXT.compareAndSet(n, f,
+                                            new Node<K,V>(null, null, f))) {
+                    p = f;                    // add marker
+                    break;
+                }
+            }
+            NEXT.compareAndSet(b, n, p);
+        }
+    }
+
+    /**
+     * Adds to element count, initializing adder if necessary
+     *
+     * @param c count to add
+     */
+    private void addCount(long c) {
+        LongAdder a;
+        do {} while ((a = adder) == null &&
+                     !ADDER.compareAndSet(this, null, a = new LongAdder()));
+        a.add(c);
+    }
+
+    /**
+     * Returns element count, initializing adder if necessary.
+     */
+    final long getAdderCount() {
+        LongAdder a; long c;
+        do {} while ((a = adder) == null &&
+                     !ADDER.compareAndSet(this, null, a = new LongAdder()));
+        return ((c = a.sum()) <= 0L) ? 0L : c; // ignore transient negatives
+    }
+
     /* ---------------- Traversal -------------- */
 
     /**
-     * Returns a base-level node with key strictly less than given key,
-     * or the base-level header if there is no such node.  Also
-     * unlinks indexes to deleted nodes found along the way.  Callers
-     * rely on this side-effect of clearing indices to deleted nodes.
-     * @param key the key
-     * @return a predecessor of key
+     * Returns an index node with key strictly less than given key.
+     * Also unlinks indexes to deleted nodes found along the way.
+     * Callers rely on this side-effect of clearing indices to deleted
+     * nodes.
+     *
+     * @param key if nonnull the key
+     * @return a predecessor node of key, or null if uninitialized or null key
      */
     private Node<K,V> findPredecessor(Object key, Comparator<? super K> cmp) {
-        if (key == null)
-            throw new NullPointerException(); // don't postpone errors
-        for (;;) {
-            for (Index<K,V> q = head, r = q.right, d;;) {
-                if (r != null) {
-                    Node<K,V> n = r.node;
-                    K k = n.key;
-                    if (n.value == null) {
-                        if (!q.unlink(r))
-                            break;           // restart
-                        r = q.right;         // reread r
-                        continue;
-                    }
-                    if (cpr(cmp, key, k) > 0) {
+        Index<K,V> q;
+        VarHandle.acquireFence();
+        if ((q = head) == null || key == null)
+            return null;
+        else {
+            for (Index<K,V> r, d;;) {
+                while ((r = q.right) != null) {
+                    Node<K,V> p; K k;
+                    if ((p = r.node) == null || (k = p.key) == null ||
+                        p.val == null)  // unlink index to deleted node
+                        RIGHT.compareAndSet(q, r, r.right);
+                    else if (cpr(cmp, key, k) > 0)
                         q = r;
-                        r = r.right;
-                        continue;
-                    }
+                    else
+                        break;
                 }
-                if ((d = q.down) == null)
+                if ((d = q.down) != null)
+                    q = d;
+                else
                     return q.node;
-                q = d;
-                r = d.right;
             }
         }
     }
@@ -689,41 +491,11 @@
      * deleted nodes seen along the way.  Repeatedly traverses at
      * base-level looking for key starting at predecessor returned
      * from findPredecessor, processing base-level deletions as
-     * encountered. Some callers rely on this side-effect of clearing
-     * deleted nodes.
-     *
-     * Restarts occur, at traversal step centered on node n, if:
-     *
-     *   (1) After reading n's next field, n is no longer assumed
-     *       predecessor b's current successor, which means that
-     *       we don't have a consistent 3-node snapshot and so cannot
-     *       unlink any subsequent deleted nodes encountered.
-     *
-     *   (2) n's value field is null, indicating n is deleted, in
-     *       which case we help out an ongoing structural deletion
-     *       before retrying.  Even though there are cases where such
-     *       unlinking doesn't require restart, they aren't sorted out
-     *       here because doing so would not usually outweigh cost of
-     *       restarting.
-     *
-     *   (3) n is a marker or n's predecessor's value field is null,
-     *       indicating (among other possibilities) that
-     *       findPredecessor returned a deleted node. We can't unlink
-     *       the node because we don't know its predecessor, so rely
-     *       on another call to findPredecessor to notice and return
-     *       some earlier predecessor, which it will do. This check is
-     *       only strictly needed at beginning of loop, (and the
-     *       b.value check isn't strictly needed at all) but is done
-     *       each iteration to help avoid contention with other
-     *       threads by callers that will fail to be able to change
-     *       links, and so will retry anyway.
-     *
-     * The traversal loops in doPut, doRemove, and findNear all
-     * include the same three kinds of checks. And specialized
-     * versions appear in findFirst, and findLast and their variants.
-     * They can't easily share code because each uses the reads of
-     * fields held in locals occurring in the orders they were
-     * performed.
+     * encountered. Restarts occur, at traversal step encountering
+     * node n, if n's key field is null, indicating it is a marker, so
+     * its predecessor is deleted before continuing, which we help do
+     * by re-finding a valid predecessor.  The traversal loops in
+     * doPut, doRemove, and findNear all include the same checks.
      *
      * @param key the key
      * @return node holding key, or null if no such
@@ -732,67 +504,81 @@
         if (key == null)
             throw new NullPointerException(); // don't postpone errors
         Comparator<? super K> cmp = comparator;
-        outer: for (;;) {
-            for (Node<K,V> b = findPredecessor(key, cmp), n = b.next;;) {
-                Object v; int c;
-                if (n == null)
+        Node<K,V> b;
+        outer: while ((b = findPredecessor(key, cmp)) != null) {
+            for (;;) {
+                Node<K,V> n; K k; V v; int c;
+                if ((n = b.next) == null)
+                    break outer;               // empty
+                else if ((k = n.key) == null)
+                    break;                     // b is deleted
+                else if ((v = n.val) == null)
+                    unlinkNode(b, n);          // n is deleted
+                else if ((c = cpr(cmp, key, k)) > 0)
+                    b = n;
+                else if (c == 0)
+                    return n;
+                else
                     break outer;
-                Node<K,V> f = n.next;
-                if (n != b.next)                // inconsistent read
-                    break;
-                if ((v = n.value) == null) {    // n is deleted
-                    n.helpDelete(b, f);
-                    break;
-                }
-                if (b.value == null || v == n)  // b is deleted
-                    break;
-                if ((c = cpr(cmp, key, n.key)) == 0)
-                    return n;
-                if (c < 0)
-                    break outer;
-                b = n;
-                n = f;
             }
         }
         return null;
     }
 
     /**
-     * Gets value for key. Almost the same as findNode, but returns
-     * the found value (to avoid retries during re-reads)
+     * Gets value for key. Same idea as findNode, except skips over
+     * deletions and markers, and returns first encountered value to
+     * avoid possibly inconsistent rereads.
      *
      * @param key the key
      * @return the value, or null if absent
      */
     private V doGet(Object key) {
+        Index<K,V> q;
+        VarHandle.acquireFence();
         if (key == null)
             throw new NullPointerException();
         Comparator<? super K> cmp = comparator;
-        outer: for (;;) {
-            for (Node<K,V> b = findPredecessor(key, cmp), n = b.next;;) {
-                Object v; int c;
-                if (n == null)
-                    break outer;
-                Node<K,V> f = n.next;
-                if (n != b.next)                // inconsistent read
-                    break;
-                if ((v = n.value) == null) {    // n is deleted
-                    n.helpDelete(b, f);
+        V result = null;
+        if ((q = head) != null) {
+            outer: for (Index<K,V> r, d;;) {
+                while ((r = q.right) != null) {
+                    Node<K,V> p; K k; V v; int c;
+                    if ((p = r.node) == null || (k = p.key) == null ||
+                        (v = p.val) == null)
+                        RIGHT.compareAndSet(q, r, r.right);
+                    else if ((c = cpr(cmp, key, k)) > 0)
+                        q = r;
+                    else if (c == 0) {
+                        result = v;
+                        break outer;
+                    }
+                    else
+                        break;
+                }
+                if ((d = q.down) != null)
+                    q = d;
+                else {
+                    Node<K,V> b, n;
+                    if ((b = q.node) != null) {
+                        while ((n = b.next) != null) {
+                            V v; int c;
+                            K k = n.key;
+                            if ((v = n.val) == null || k == null ||
+                                (c = cpr(cmp, key, k)) > 0)
+                                b = n;
+                            else {
+                                if (c == 0)
+                                    result = v;
+                                break;
+                            }
+                        }
+                    }
                     break;
                 }
-                if (b.value == null || v == n)  // b is deleted
-                    break;
-                if ((c = cpr(cmp, key, n.key)) == 0) {
-                    @SuppressWarnings("unchecked") V vv = (V)v;
-                    return vv;
-                }
-                if (c < 0)
-                    break outer;
-                b = n;
-                n = f;
             }
         }
-        return null;
+        return result;
     }
 
     /* ---------------- Insertion -------------- */
@@ -800,129 +586,160 @@
     /**
      * Main insertion method.  Adds element if not present, or
      * replaces value if present and onlyIfAbsent is false.
+     *
      * @param key the key
      * @param value the value that must be associated with key
      * @param onlyIfAbsent if should not insert if already present
      * @return the old value, or null if newly inserted
      */
     private V doPut(K key, V value, boolean onlyIfAbsent) {
-        Node<K,V> z;             // added node
         if (key == null)
             throw new NullPointerException();
         Comparator<? super K> cmp = comparator;
-        outer: for (;;) {
-            for (Node<K,V> b = findPredecessor(key, cmp), n = b.next;;) {
-                if (n != null) {
-                    Object v; int c;
-                    Node<K,V> f = n.next;
-                    if (n != b.next)               // inconsistent read
-                        break;
-                    if ((v = n.value) == null) {   // n is deleted
-                        n.helpDelete(b, f);
-                        break;
+        for (;;) {
+            Index<K,V> h; Node<K,V> b;
+            VarHandle.acquireFence();
+            int levels = 0;                    // number of levels descended
+            if ((h = head) == null) {          // try to initialize
+                Node<K,V> base = new Node<K,V>(null, null, null);
+                h = new Index<K,V>(base, null, null);
+                b = (HEAD.compareAndSet(this, null, h)) ? base : null;
+            }
+            else {
+                for (Index<K,V> q = h, r, d;;) { // count while descending
+                    while ((r = q.right) != null) {
+                        Node<K,V> p; K k;
+                        if ((p = r.node) == null || (k = p.key) == null ||
+                            p.val == null)
+                            RIGHT.compareAndSet(q, r, r.right);
+                        else if (cpr(cmp, key, k) > 0)
+                            q = r;
+                        else
+                            break;
                     }
-                    if (b.value == null || v == n) // b is deleted
-                        break;
-                    if ((c = cpr(cmp, key, n.key)) > 0) {
-                        b = n;
-                        n = f;
-                        continue;
+                    if ((d = q.down) != null) {
+                        ++levels;
+                        q = d;
                     }
-                    if (c == 0) {
-                        if (onlyIfAbsent || n.casValue(v, value)) {
-                            @SuppressWarnings("unchecked") V vv = (V)v;
-                            return vv;
-                        }
-                        break; // restart if lost race to replace value
-                    }
-                    // else c < 0; fall through
-                } else if (b == head.node) {
-                    // map is empty, so type check key now
-                    cpr(cmp, key, key);
-                }
-
-                z = new Node<K,V>(key, value, n);
-                if (!b.casNext(n, z))
-                    break;         // restart if lost race to append to b
-                break outer;
-            }
-        }
-
-        int rnd = ThreadLocalRandom.nextSecondarySeed();
-        if ((rnd & 0x80000001) == 0) { // test highest and lowest bits
-            int level = 1, max;
-            while (((rnd >>>= 1) & 1) != 0)
-                ++level;
-            Index<K,V> idx = null;
-            HeadIndex<K,V> h = head;
-            if (level <= (max = h.level)) {
-                for (int i = 1; i <= level; ++i)
-                    idx = new Index<K,V>(z, idx, null);
-            }
-            else { // try to grow by one level
-                level = max + 1; // hold in array and later pick the one to use
-                @SuppressWarnings("unchecked")Index<K,V>[] idxs =
-                    (Index<K,V>[])new Index<?,?>[level+1];
-                for (int i = 1; i <= level; ++i)
-                    idxs[i] = idx = new Index<K,V>(z, idx, null);
-                for (;;) {
-                    h = head;
-                    int oldLevel = h.level;
-                    if (level <= oldLevel) // lost race to add level
-                        break;
-                    HeadIndex<K,V> newh = h;
-                    Node<K,V> oldbase = h.node;
-                    for (int j = oldLevel+1; j <= level; ++j)
-                        newh = new HeadIndex<K,V>(oldbase, newh, idxs[j], j);
-                    if (casHead(h, newh)) {
-                        h = newh;
-                        idx = idxs[level = oldLevel];
+                    else {
+                        b = q.node;
                         break;
                     }
                 }
             }
-            // find insertion points and splice in
-            splice: for (int insertionLevel = level;;) {
-                int j = h.level;
-                for (Index<K,V> q = h, r = q.right, t = idx;;) {
-                    if (q == null || t == null)
-                        break splice;
-                    if (r != null) {
-                        Node<K,V> n = r.node;
-                        // compare before deletion check avoids needing recheck
-                        int c = cpr(cmp, key, n.key);
-                        if (n.value == null) {
-                            if (!q.unlink(r))
+            if (b != null) {
+                Node<K,V> z = null;              // new node, if inserted
+                for (;;) {                       // find insertion point
+                    Node<K,V> n, p; K k; V v; int c;
+                    if ((n = b.next) == null) {
+                        if (b.key == null)       // if empty, type check key now
+                            cpr(cmp, key, key);
+                        c = -1;
+                    }
+                    else if ((k = n.key) == null)
+                        break;                   // can't append; restart
+                    else if ((v = n.val) == null) {
+                        unlinkNode(b, n);
+                        c = 1;
+                    }
+                    else if ((c = cpr(cmp, key, k)) > 0)
+                        b = n;
+                    else if (c == 0 &&
+                             (onlyIfAbsent || VAL.compareAndSet(n, v, value)))
+                        return v;
+
+                    if (c < 0 &&
+                        NEXT.compareAndSet(b, n,
+                                           p = new Node<K,V>(key, value, n))) {
+                        z = p;
+                        break;
+                    }
+                }
+
+                if (z != null) {
+                    int lr = ThreadLocalRandom.nextSecondarySeed();
+                    if ((lr & 0x3) == 0) {       // add indices with 1/4 prob
+                        int hr = ThreadLocalRandom.nextSecondarySeed();
+                        long rnd = ((long)hr << 32) | ((long)lr & 0xffffffffL);
+                        int skips = levels;      // levels to descend before add
+                        Index<K,V> x = null;
+                        for (;;) {               // create at most 62 indices
+                            x = new Index<K,V>(z, x, null);
+                            if (rnd >= 0L || --skips < 0)
                                 break;
-                            r = q.right;
-                            continue;
+                            else
+                                rnd <<= 1;
                         }
-                        if (c > 0) {
-                            q = r;
-                            r = r.right;
-                            continue;
+                        if (addIndices(h, skips, x, cmp) && skips < 0 &&
+                            head == h) {         // try to add new level
+                            Index<K,V> hx = new Index<K,V>(z, x, null);
+                            Index<K,V> nh = new Index<K,V>(h.node, h, hx);
+                            HEAD.compareAndSet(this, h, nh);
                         }
+                        if (z.val == null)       // deleted while adding indices
+                            findPredecessor(key, cmp); // clean
                     }
-
-                    if (j == insertionLevel) {
-                        if (!q.link(r, t))
-                            break; // restart
-                        if (t.node.value == null) {
-                            findNode(key);
-                            break splice;
-                        }
-                        if (--insertionLevel == 0)
-                            break splice;
-                    }
-
-                    if (--j >= insertionLevel && j < level)
-                        t = t.down;
-                    q = q.down;
-                    r = q.right;
+                    addCount(1L);
+                    return null;
                 }
             }
         }
-        return null;
+    }
+
+    /**
+     * Add indices after an insertion. Descends iteratively to the
+     * highest level of insertion, then recursively, to chain index
+     * nodes to lower ones. Returns null on (staleness) failure,
+     * disabling higher-level insertions. Recursion depths are
+     * exponentially less probable.
+     *
+     * @param q starting index for current level
+     * @param skips levels to skip before inserting
+     * @param x index for this insertion
+     * @param cmp comparator
+     */
+    static <K,V> boolean addIndices(Index<K,V> q, int skips, Index<K,V> x,
+                                    Comparator<? super K> cmp) {
+        Node<K,V> z; K key;
+        if (x != null && (z = x.node) != null && (key = z.key) != null &&
+            q != null) {                            // hoist checks
+            boolean retrying = false;
+            for (;;) {                              // find splice point
+                Index<K,V> r, d; int c;
+                if ((r = q.right) != null) {
+                    Node<K,V> p; K k;
+                    if ((p = r.node) == null || (k = p.key) == null ||
+                        p.val == null) {
+                        RIGHT.compareAndSet(q, r, r.right);
+                        c = 0;
+                    }
+                    else if ((c = cpr(cmp, key, k)) > 0)
+                        q = r;
+                    else if (c == 0)
+                        break;                      // stale
+                }
+                else
+                    c = -1;
+
+                if (c < 0) {
+                    if ((d = q.down) != null && skips > 0) {
+                        --skips;
+                        q = d;
+                    }
+                    else if (d != null && !retrying &&
+                             !addIndices(d, 0, x.down, cmp))
+                        break;
+                    else {
+                        x.right = r;
+                        if (RIGHT.compareAndSet(q, r, x))
+                            return true;
+                        else
+                            retrying = true;         // re-find splice point
+                    }
+                }
+            }
+        }
+        return false;
     }
 
     /* ---------------- Deletion -------------- */
@@ -932,15 +749,6 @@
      * deletion marker, unlinks predecessor, removes associated index
      * nodes, and possibly reduces head index level.
      *
-     * Index nodes are cleared out simply by calling findPredecessor.
-     * which unlinks indexes to deleted nodes found along path to key,
-     * which will include the indexes to this node.  This is done
-     * unconditionally. We can't check beforehand whether there are
-     * index nodes because it might be the case that some or all
-     * indexes hadn't been inserted yet for this node during initial
-     * search for it, and we'd like to ensure lack of garbage
-     * retention, so must call to be sure.
-     *
      * @param key the key
      * @param value if non-null, the value that must be
      * associated with key
@@ -950,43 +758,36 @@
         if (key == null)
             throw new NullPointerException();
         Comparator<? super K> cmp = comparator;
-        outer: for (;;) {
-            for (Node<K,V> b = findPredecessor(key, cmp), n = b.next;;) {
-                Object v; int c;
-                if (n == null)
+        V result = null;
+        Node<K,V> b;
+        outer: while ((b = findPredecessor(key, cmp)) != null &&
+                      result == null) {
+            for (;;) {
+                Node<K,V> n; K k; V v; int c;
+                if ((n = b.next) == null)
                     break outer;
-                Node<K,V> f = n.next;
-                if (n != b.next)                    // inconsistent read
+                else if ((k = n.key) == null)
                     break;
-                if ((v = n.value) == null) {        // n is deleted
-                    n.helpDelete(b, f);
-                    break;
+                else if ((v = n.val) == null)
+                    unlinkNode(b, n);
+                else if ((c = cpr(cmp, key, k)) > 0)
+                    b = n;
+                else if (c < 0)
+                    break outer;
+                else if (value != null && !value.equals(v))
+                    break outer;
+                else if (VAL.compareAndSet(n, v, null)) {
+                    result = v;
+                    unlinkNode(b, n);
+                    break; // loop to clean up
                 }
-                if (b.value == null || v == n)      // b is deleted
-                    break;
-                if ((c = cpr(cmp, key, n.key)) < 0)
-                    break outer;
-                if (c > 0) {
-                    b = n;
-                    n = f;
-                    continue;
-                }
-                if (value != null && !value.equals(v))
-                    break outer;
-                if (!n.casValue(v, null))
-                    break;
-                if (!n.appendMarker(f) || !b.casNext(n, f))
-                    findNode(key);                  // retry via findNode
-                else {
-                    findPredecessor(key, cmp);      // clean index
-                    if (head.right == null)
-                        tryReduceLevel();
-                }
-                @SuppressWarnings("unchecked") V vv = (V)v;
-                return vv;
             }
         }
-        return null;
+        if (result != null) {
+            tryReduceLevel();
+            addCount(-1L);
+        }
+        return result;
     }
 
     /**
@@ -1010,77 +811,132 @@
      * reduction.
      */
     private void tryReduceLevel() {
-        HeadIndex<K,V> h = head;
-        HeadIndex<K,V> d;
-        HeadIndex<K,V> e;
-        if (h.level > 3 &&
-            (d = (HeadIndex<K,V>)h.down) != null &&
-            (e = (HeadIndex<K,V>)d.down) != null &&
-            e.right == null &&
-            d.right == null &&
-            h.right == null &&
-            casHead(h, d) && // try to set
-            h.right != null) // recheck
-            casHead(d, h);   // try to backout
+        Index<K,V> h, d, e;
+        if ((h = head) != null && h.right == null &&
+            (d = h.down) != null && d.right == null &&
+            (e = d.down) != null && e.right == null &&
+            HEAD.compareAndSet(this, h, d) &&
+            h.right != null)   // recheck
+            HEAD.compareAndSet(this, d, h);  // try to backout
     }
 
     /* ---------------- Finding and removing first element -------------- */
 
     /**
-     * Specialized variant of findNode to get first valid node.
+     * Gets first valid node, unlinking deleted nodes if encountered.
      * @return first node or null if empty
      */
     final Node<K,V> findFirst() {
-        for (Node<K,V> b, n;;) {
-            if ((n = (b = head.node).next) == null)
-                return null;
-            if (n.value != null)
-                return n;
-            n.helpDelete(b, n.next);
+        Node<K,V> b, n;
+        if ((b = baseHead()) != null) {
+            while ((n = b.next) != null) {
+                if (n.val == null)
+                    unlinkNode(b, n);
+                else
+                    return n;
+            }
         }
+        return null;
+    }
+
+    /**
+     * Entry snapshot version of findFirst
+     */
+    final AbstractMap.SimpleImmutableEntry<K,V> findFirstEntry() {
+        Node<K,V> b, n; V v;
+        if ((b = baseHead()) != null) {
+            while ((n = b.next) != null) {
+                if ((v = n.val) == null)
+                    unlinkNode(b, n);
+                else
+                    return new AbstractMap.SimpleImmutableEntry<K,V>(n.key, v);
+            }
+        }
+        return null;
     }
 
     /**
      * Removes first entry; returns its snapshot.
      * @return null if empty, else snapshot of first entry
      */
-    private Map.Entry<K,V> doRemoveFirstEntry() {
-        for (Node<K,V> b, n;;) {
-            if ((n = (b = head.node).next) == null)
-                return null;
-            Node<K,V> f = n.next;
-            if (n != b.next)
-                continue;
-            Object v = n.value;
-            if (v == null) {
-                n.helpDelete(b, f);
-                continue;
+    private AbstractMap.SimpleImmutableEntry<K,V> doRemoveFirstEntry() {
+        Node<K,V> b, n; V v;
+        if ((b = baseHead()) != null) {
+            while ((n = b.next) != null) {
+                if ((v = n.val) == null || VAL.compareAndSet(n, v, null)) {
+                    K k = n.key;
+                    unlinkNode(b, n);
+                    if (v != null) {
+                        tryReduceLevel();
+                        findPredecessor(k, comparator); // clean index
+                        addCount(-1L);
+                        return new AbstractMap.SimpleImmutableEntry<K,V>(k, v);
+                    }
+                }
             }
-            if (!n.casValue(v, null))
-                continue;
-            if (!n.appendMarker(f) || !b.casNext(n, f))
-                findFirst(); // retry
-            clearIndexToFirst();
-            @SuppressWarnings("unchecked") V vv = (V)v;
-            return new AbstractMap.SimpleImmutableEntry<K,V>(n.key, vv);
         }
+        return null;
+    }
+
+    /* ---------------- Finding and removing last element -------------- */
+
+    /**
+     * Specialized version of find to get last valid node.
+     * @return last node or null if empty
+     */
+    final Node<K,V> findLast() {
+        outer: for (;;) {
+            Index<K,V> q; Node<K,V> b;
+            VarHandle.acquireFence();
+            if ((q = head) == null)
+                break;
+            for (Index<K,V> r, d;;) {
+                while ((r = q.right) != null) {
+                    Node<K,V> p;
+                    if ((p = r.node) == null || p.val == null)
+                        RIGHT.compareAndSet(q, r, r.right);
+                    else
+                        q = r;
+                }
+                if ((d = q.down) != null)
+                    q = d;
+                else {
+                    b = q.node;
+                    break;
+                }
+            }
+            if (b != null) {
+                for (;;) {
+                    Node<K,V> n;
+                    if ((n = b.next) == null) {
+                        if (b.key == null) // empty
+                            break outer;
+                        else
+                            return b;
+                    }
+                    else if (n.key == null)
+                        break;
+                    else if (n.val == null)
+                        unlinkNode(b, n);
+                    else
+                        b = n;
+                }
+            }
+        }
+        return null;
     }
 
     /**
-     * Clears out index nodes associated with deleted first entry.
+     * Entry version of findLast
+     * @return Entry for last node or null if empty
      */
-    private void clearIndexToFirst() {
+    final AbstractMap.SimpleImmutableEntry<K,V> findLastEntry() {
         for (;;) {
-            for (Index<K,V> q = head;;) {
-                Index<K,V> r = q.right;
-                if (r != null && r.indexesDeletedNode() && !q.unlink(r))
-                    break;
-                if ((q = q.down) == null) {
-                    if (head.right == null)
-                        tryReduceLevel();
-                    return;
-                }
-            }
+            Node<K,V> n; V v;
+            if ((n = findLast()) == null)
+                return null;
+            if ((v = n.val) != null)
+                return new AbstractMap.SimpleImmutableEntry<K,V>(n.key, v);
         }
     }
 
@@ -1090,121 +946,54 @@
      * @return null if empty, else snapshot of last entry
      */
     private Map.Entry<K,V> doRemoveLastEntry() {
-        for (;;) {
-            Node<K,V> b = findPredecessorOfLast();
-            Node<K,V> n = b.next;
-            if (n == null) {
-                if (b.isBaseHeader())               // empty
-                    return null;
-                else
-                    continue; // all b's successors are deleted; retry
-            }
+        outer: for (;;) {
+            Index<K,V> q; Node<K,V> b;
+            VarHandle.acquireFence();
+            if ((q = head) == null)
+                break;
             for (;;) {
-                Node<K,V> f = n.next;
-                if (n != b.next)                    // inconsistent read
-                    break;
-                Object v = n.value;
-                if (v == null) {                    // n is deleted
-                    n.helpDelete(b, f);
-                    break;
-                }
-                if (b.value == null || v == n)      // b is deleted
-                    break;
-                if (f != null) {
-                    b = n;
-                    n = f;
-                    continue;
-                }
-                if (!n.casValue(v, null))
-                    break;
-                K key = n.key;
-                if (!n.appendMarker(f) || !b.casNext(n, f))
-                    findNode(key);                  // retry via findNode
-                else {                              // clean index
-                    findPredecessor(key, comparator);
-                    if (head.right == null)
-                        tryReduceLevel();
-                }
-                @SuppressWarnings("unchecked") V vv = (V)v;
-                return new AbstractMap.SimpleImmutableEntry<K,V>(key, vv);
-            }
-        }
-    }
-
-    /* ---------------- Finding and removing last element -------------- */
-
-    /**
-     * Specialized version of find to get last valid node.
-     * @return last node or null if empty
-     */
-    final Node<K,V> findLast() {
-        /*
-         * findPredecessor can't be used to traverse index level
-         * because this doesn't use comparisons.  So traversals of
-         * both levels are folded together.
-         */
-        Index<K,V> q = head;
-        for (;;) {
-            Index<K,V> d, r;
-            if ((r = q.right) != null) {
-                if (r.indexesDeletedNode()) {
-                    q.unlink(r);
-                    q = head; // restart
-                }
-                else
-                    q = r;
-            } else if ((d = q.down) != null) {
-                q = d;
-            } else {
-                for (Node<K,V> b = q.node, n = b.next;;) {
-                    if (n == null)
-                        return b.isBaseHeader() ? null : b;
-                    Node<K,V> f = n.next;            // inconsistent read
-                    if (n != b.next)
+                Index<K,V> d, r; Node<K,V> p;
+                while ((r = q.right) != null) {
+                    if ((p = r.node) == null || p.val == null)
+                        RIGHT.compareAndSet(q, r, r.right);
+                    else if (p.next != null)
+                        q = r;  // continue only if a successor
+                    else
                         break;
-                    Object v = n.value;
-                    if (v == null) {                 // n is deleted
-                        n.helpDelete(b, f);
-                        break;
-                    }
-                    if (b.value == null || v == n)      // b is deleted
-                        break;
-                    b = n;
-                    n = f;
-                }
-                q = head; // restart
-            }
-        }
-    }
-
-    /**
-     * Specialized variant of findPredecessor to get predecessor of last
-     * valid node.  Needed when removing the last entry.  It is possible
-     * that all successors of returned node will have been deleted upon
-     * return, in which case this method can be retried.
-     * @return likely predecessor of last node
-     */
-    private Node<K,V> findPredecessorOfLast() {
-        for (;;) {
-            for (Index<K,V> q = head;;) {
-                Index<K,V> d, r;
-                if ((r = q.right) != null) {
-                    if (r.indexesDeletedNode()) {
-                        q.unlink(r);
-                        break;    // must restart
-                    }
-                    // proceed as far across as possible without overshooting
-                    if (r.node.next != null) {
-                        q = r;
-                        continue;
-                    }
                 }
                 if ((d = q.down) != null)
                     q = d;
-                else
-                    return q.node;
+                else {
+                    b = q.node;
+                    break;
+                }
+            }
+            if (b != null) {
+                for (;;) {
+                    Node<K,V> n; K k; V v;
+                    if ((n = b.next) == null) {
+                        if (b.key == null) // empty
+                            break outer;
+                        else
+                            break; // retry
+                    }
+                    else if ((k = n.key) == null)
+                        break;
+                    else if ((v = n.val) == null)
+                        unlinkNode(b, n);
+                    else if (n.next != null)
+                        b = n;
+                    else if (VAL.compareAndSet(n, v, null)) {
+                        unlinkNode(b, n);
+                        tryReduceLevel();
+                        findPredecessor(k, comparator); // clean index
+                        addCount(-1L);
+                        return new AbstractMap.SimpleImmutableEntry<K,V>(k, v);
+                    }
+                }
             }
         }
+        return null;
     }
 
     /* ---------------- Relational operations -------------- */
@@ -1224,47 +1013,52 @@
     final Node<K,V> findNear(K key, int rel, Comparator<? super K> cmp) {
         if (key == null)
             throw new NullPointerException();
-        for (;;) {
-            for (Node<K,V> b = findPredecessor(key, cmp), n = b.next;;) {
-                Object v;
-                if (n == null)
-                    return ((rel & LT) == 0 || b.isBaseHeader()) ? null : b;
-                Node<K,V> f = n.next;
-                if (n != b.next)                  // inconsistent read
+        Node<K,V> result;
+        outer: for (Node<K,V> b;;) {
+            if ((b = findPredecessor(key, cmp)) == null) {
+                result = null;
+                break;                   // empty
+            }
+            for (;;) {
+                Node<K,V> n; K k; int c;
+                if ((n = b.next) == null) {
+                    result = ((rel & LT) != 0 && b.key != null) ? b : null;
+                    break outer;
+                }
+                else if ((k = n.key) == null)
                     break;
-                if ((v = n.value) == null) {      // n is deleted
-                    n.helpDelete(b, f);
-                    break;
+                else if (n.val == null)
+                    unlinkNode(b, n);
+                else if (((c = cpr(cmp, key, k)) == 0 && (rel & EQ) != 0) ||
+                         (c < 0 && (rel & LT) == 0)) {
+                    result = n;
+                    break outer;
                 }
-                if (b.value == null || v == n)      // b is deleted
-                    break;
-                int c = cpr(cmp, key, n.key);
-                if ((c == 0 && (rel & EQ) != 0) ||
-                    (c <  0 && (rel & LT) == 0))
-                    return n;
-                if ( c <= 0 && (rel & LT) != 0)
-                    return b.isBaseHeader() ? null : b;
-                b = n;
-                n = f;
+                else if (c <= 0 && (rel & LT) != 0) {
+                    result = (b.key != null) ? b : null;
+                    break outer;
+                }
+                else
+                    b = n;
             }
         }
+        return result;
     }
 
     /**
-     * Returns SimpleImmutableEntry for results of findNear.
+     * Variant of findNear returning SimpleImmutableEntry
      * @param key the key
      * @param rel the relation -- OR'ed combination of EQ, LT, GT
      * @return Entry fitting relation, or null if no such
      */
-    final AbstractMap.SimpleImmutableEntry<K,V> getNear(K key, int rel) {
-        Comparator<? super K> cmp = comparator;
+    final AbstractMap.SimpleImmutableEntry<K,V> findNearEntry(K key, int rel,
+                                                              Comparator<? super K> cmp) {
         for (;;) {
-            Node<K,V> n = findNear(key, rel, cmp);
-            if (n == null)
+            Node<K,V> n; V v;
+            if ((n = findNear(key, rel, cmp)) == null)
                 return null;
-            AbstractMap.SimpleImmutableEntry<K,V> e = n.createSnapshot();
-            if (e != null)
-                return e;
+            if ((v = n.val) != null)
+                return new AbstractMap.SimpleImmutableEntry<K,V>(n.key, v);
         }
     }
 
@@ -1276,7 +1070,6 @@
      */
     public ConcurrentSkipListMap() {
         this.comparator = null;
-        initialize();
     }
 
     /**
@@ -1289,7 +1082,6 @@
      */
     public ConcurrentSkipListMap(Comparator<? super K> comparator) {
         this.comparator = comparator;
-        initialize();
     }
 
     /**
@@ -1305,7 +1097,6 @@
      */
     public ConcurrentSkipListMap(Map<? extends K, ? extends V> m) {
         this.comparator = null;
-        initialize();
         putAll(m);
     }
 
@@ -1320,8 +1111,7 @@
      */
     public ConcurrentSkipListMap(SortedMap<K, ? extends V> m) {
         this.comparator = m.comparator();
-        initialize();
-        buildFromSorted(m);
+        buildFromSorted(m); // initializes transients
     }
 
     /**
@@ -1335,7 +1125,10 @@
             @SuppressWarnings("unchecked")
             ConcurrentSkipListMap<K,V> clone =
                 (ConcurrentSkipListMap<K,V>) super.clone();
-            clone.initialize();
+            clone.keySet = null;
+            clone.entrySet = null;
+            clone.values = null;
+            clone.descendingMap = null;
             clone.buildFromSorted(this);
             return clone;
         } catch (CloneNotSupportedException e) {
@@ -1351,58 +1144,49 @@
     private void buildFromSorted(SortedMap<K, ? extends V> map) {
         if (map == null)
             throw new NullPointerException();
-
-        HeadIndex<K,V> h = head;
-        Node<K,V> basepred = h.node;
-
-        // Track the current rightmost node at each level. Uses an
-        // ArrayList to avoid committing to initial or maximum level.
-        ArrayList<Index<K,V>> preds = new ArrayList<>();
-
-        // initialize
-        for (int i = 0; i <= h.level; ++i)
-            preds.add(null);
-        Index<K,V> q = h;
-        for (int i = h.level; i > 0; --i) {
-            preds.set(i, q);
-            q = q.down;
-        }
-
         Iterator<? extends Map.Entry<? extends K, ? extends V>> it =
             map.entrySet().iterator();
+
+        /*
+         * Add equally spaced indices at log intervals, using the bits
+         * of count during insertion. The maximum possible resulting
+         * level is less than the number of bits in a long (64). The
+         * preds array tracks the current rightmost node at each
+         * level.
+         */
+        @SuppressWarnings("unchecked")
+        Index<K,V>[] preds = (Index<K,V>[])new Index<?,?>[64];
+        Node<K,V> bp = new Node<K,V>(null, null, null);
+        Index<K,V> h = preds[0] = new Index<K,V>(bp, null, null);
+        long count = 0;
+
         while (it.hasNext()) {
             Map.Entry<? extends K, ? extends V> e = it.next();
-            int rnd = ThreadLocalRandom.current().nextInt();
-            int j = 0;
-            if ((rnd & 0x80000001) == 0) {
-                do {
-                    ++j;
-                } while (((rnd >>>= 1) & 1) != 0);
-                if (j > h.level) j = h.level + 1;
-            }
             K k = e.getKey();
             V v = e.getValue();
             if (k == null || v == null)
                 throw new NullPointerException();
             Node<K,V> z = new Node<K,V>(k, v, null);
-            basepred.next = z;
-            basepred = z;
-            if (j > 0) {
-                Index<K,V> idx = null;
-                for (int i = 1; i <= j; ++i) {
+            bp = bp.next = z;
+            if ((++count & 3L) == 0L) {
+                long m = count >>> 2;
+                int i = 0;
+                Index<K,V> idx = null, q;
+                do {
                     idx = new Index<K,V>(z, idx, null);
-                    if (i > h.level)
-                        h = new HeadIndex<K,V>(h.node, h, idx, i);
-
-                    if (i < preds.size()) {
-                        preds.get(i).right = idx;
-                        preds.set(i, idx);
-                    } else
-                        preds.add(idx);
-                }
+                    if ((q = preds[i]) == null)
+                        preds[i] = h = new Index<K,V>(h.node, h, idx);
+                    else
+                        preds[i] = q.right = idx;
+                } while (++i < preds.length && ((m >>>= 1) & 1L) != 0L);
             }
         }
-        head = h;
+        if (count != 0L) {
+            VarHandle.releaseFence(); // emulate volatile stores
+            addCount(count);
+            head = h;
+            VarHandle.fullFence();
+        }
     }
 
     /* ---------------- Serialization -------------- */
@@ -1424,11 +1208,14 @@
         s.defaultWriteObject();
 
         // Write out keys and values (alternating)
-        for (Node<K,V> n = findFirst(); n != null; n = n.next) {
-            V v = n.getValidValue();
-            if (v != null) {
-                s.writeObject(n.key);
-                s.writeObject(v);
+        Node<K,V> b, n; V v;
+        if ((b = baseHead()) != null) {
+            while ((n = b.next) != null) {
+                if ((v = n.val) != null) {
+                    s.writeObject(n.key);
+                    s.writeObject(v);
+                }
+                b = n;
             }
         }
         s.writeObject(null);
@@ -1446,64 +1233,47 @@
         throws java.io.IOException, ClassNotFoundException {
         // Read in the Comparator and any hidden stuff
         s.defaultReadObject();
-        // Reset transients
-        initialize();
 
-        /*
-         * This is nearly identical to buildFromSorted, but is
-         * distinct because readObject calls can't be nicely adapted
-         * as the kind of iterator needed by buildFromSorted. (They
-         * can be, but doing so requires type cheats and/or creation
-         * of adapter classes.) It is simpler to just adapt the code.
-         */
-
-        HeadIndex<K,V> h = head;
-        Node<K,V> basepred = h.node;
-        ArrayList<Index<K,V>> preds = new ArrayList<>();
-        for (int i = 0; i <= h.level; ++i)
-            preds.add(null);
-        Index<K,V> q = h;
-        for (int i = h.level; i > 0; --i) {
-            preds.set(i, q);
-            q = q.down;
-        }
+        // Same idea as buildFromSorted
+        @SuppressWarnings("unchecked")
+        Index<K,V>[] preds = (Index<K,V>[])new Index<?,?>[64];
+        Node<K,V> bp = new Node<K,V>(null, null, null);
+        Index<K,V> h = preds[0] = new Index<K,V>(bp, null, null);
+        Comparator<? super K> cmp = comparator;
+        K prevKey = null;
+        long count = 0;
 
         for (;;) {
-            Object k = s.readObject();
+            K k = (K)s.readObject();
             if (k == null)
                 break;
-            Object v = s.readObject();
+            V v = (V)s.readObject();
             if (v == null)
                 throw new NullPointerException();
-            K key = (K) k;
-            V val = (V) v;
-            int rnd = ThreadLocalRandom.current().nextInt();
-            int j = 0;
-            if ((rnd & 0x80000001) == 0) {
+            if (prevKey != null && cpr(cmp, prevKey, k) > 0)
+                throw new IllegalStateException("out of order");
+            prevKey = k;
+            Node<K,V> z = new Node<K,V>(k, v, null);
+            bp = bp.next = z;
+            if ((++count & 3L) == 0L) {
+                long m = count >>> 2;
+                int i = 0;
+                Index<K,V> idx = null, q;
                 do {
-                    ++j;
-                } while (((rnd >>>= 1) & 1) != 0);
-                if (j > h.level) j = h.level + 1;
-            }
-            Node<K,V> z = new Node<K,V>(key, val, null);
-            basepred.next = z;
-            basepred = z;
-            if (j > 0) {
-                Index<K,V> idx = null;
-                for (int i = 1; i <= j; ++i) {
                     idx = new Index<K,V>(z, idx, null);
-                    if (i > h.level)
-                        h = new HeadIndex<K,V>(h.node, h, idx, i);
-
-                    if (i < preds.size()) {
-                        preds.get(i).right = idx;
-                        preds.set(i, idx);
-                    } else
-                        preds.add(idx);
-                }
+                    if ((q = preds[i]) == null)
+                        preds[i] = h = new Index<K,V>(h.node, h, idx);
+                    else
+                        preds[i] = q.right = idx;
+                } while (++i < preds.length && ((m >>>= 1) & 1L) != 0L);
             }
         }
-        head = h;
+        if (count != 0L) {
+            VarHandle.releaseFence();
+            addCount(count);
+            head = h;
+            VarHandle.fullFence();
+        }
     }
 
     /* ------ Map API methods ------ */
@@ -1604,42 +1374,30 @@
     public boolean containsValue(Object value) {
         if (value == null)
             throw new NullPointerException();
-        for (Node<K,V> n = findFirst(); n != null; n = n.next) {
-            V v = n.getValidValue();
-            if (v != null && value.equals(v))
-                return true;
+        Node<K,V> b, n; V v;
+        if ((b = baseHead()) != null) {
+            while ((n = b.next) != null) {
+                if ((v = n.val) != null && value.equals(v))
+                    return true;
+                else
+                    b = n;
+            }
         }
         return false;
     }
 
     /**
-     * Returns the number of key-value mappings in this map.  If this map
-     * contains more than {@code Integer.MAX_VALUE} elements, it
-     * returns {@code Integer.MAX_VALUE}.
-     *
-     * <p>Beware that, unlike in most collections, this method is
-     * <em>NOT</em> a constant-time operation. Because of the
-     * asynchronous nature of these maps, determining the current
-     * number of elements requires traversing them all to count them.
-     * Additionally, it is possible for the size to change during
-     * execution of this method, in which case the returned result
-     * will be inaccurate. Thus, this method is typically not very
-     * useful in concurrent applications.
-     *
-     * @return the number of elements in this map
+     * {@inheritDoc}
      */
     public int size() {
-        long count = 0;
-        for (Node<K,V> n = findFirst(); n != null; n = n.next) {
-            if (n.getValidValue() != null)
-                ++count;
-        }
-        return (count >= Integer.MAX_VALUE) ? Integer.MAX_VALUE : (int) count;
+        long c;
+        return ((baseHead() == null) ? 0 :
+                ((c = getAdderCount()) >= Integer.MAX_VALUE) ?
+                Integer.MAX_VALUE : (int) c);
     }
 
     /**
-     * Returns {@code true} if this map contains no key-value mappings.
-     * @return {@code true} if this map contains no key-value mappings
+     * {@inheritDoc}
      */
     public boolean isEmpty() {
         return findFirst() == null;
@@ -1649,23 +1407,32 @@
      * Removes all of the mappings from this map.
      */
     public void clear() {
-        for (;;) {
-            Node<K,V> b, n;
-            HeadIndex<K,V> h = head, d = (HeadIndex<K,V>)h.down;
-            if (d != null)
-                casHead(h, d);            // remove levels
-            else if ((b = h.node) != null && (n = b.next) != null) {
-                Node<K,V> f = n.next;     // remove values
-                if (n == b.next) {
-                    Object v = n.value;
-                    if (v == null)
-                        n.helpDelete(b, f);
-                    else if (n.casValue(v, null) && n.appendMarker(f))
-                        b.casNext(n, f);
+        Index<K,V> h, r, d; Node<K,V> b;
+        VarHandle.acquireFence();
+        while ((h = head) != null) {
+            if ((r = h.right) != null)        // remove indices
+                RIGHT.compareAndSet(h, r, null);
+            else if ((d = h.down) != null)    // remove levels
+                HEAD.compareAndSet(this, h, d);
+            else {
+                long count = 0L;
+                if ((b = h.node) != null) {    // remove nodes
+                    Node<K,V> n; V v;
+                    while ((n = b.next) != null) {
+                        if ((v = n.val) != null &&
+                            VAL.compareAndSet(n, v, null)) {
+                            --count;
+                            v = null;
+                        }
+                        if (v == null)
+                            unlinkNode(b, n);
+                    }
                 }
+                if (count != 0L)
+                    addCount(count);
+                else
+                    break;
             }
-            else
-                break;
         }
     }
 
@@ -1712,16 +1479,15 @@
                               BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
         if (key == null || remappingFunction == null)
             throw new NullPointerException();
-        Node<K,V> n; Object v;
+        Node<K,V> n; V v;
         while ((n = findNode(key)) != null) {
-            if ((v = n.value) != null) {
-                @SuppressWarnings("unchecked") V vv = (V) v;
-                V r = remappingFunction.apply(key, vv);
+            if ((v = n.val) != null) {
+                V r = remappingFunction.apply(key, v);
                 if (r != null) {
-                    if (n.casValue(vv, r))
+                    if (VAL.compareAndSet(n, v, r))
                         return r;
                 }
-                else if (doRemove(key, vv) != null)
+                else if (doRemove(key, v) != null)
                     break;
             }
         }
@@ -1746,20 +1512,19 @@
         if (key == null || remappingFunction == null)
             throw new NullPointerException();
         for (;;) {
-            Node<K,V> n; Object v; V r;
+            Node<K,V> n; V v; V r;
             if ((n = findNode(key)) == null) {
                 if ((r = remappingFunction.apply(key, null)) == null)
                     break;
                 if (doPut(key, r, true) == null)
                     return r;
             }
-            else if ((v = n.value) != null) {
-                @SuppressWarnings("unchecked") V vv = (V) v;
-                if ((r = remappingFunction.apply(key, vv)) != null) {
-                    if (n.casValue(vv, r))
+            else if ((v = n.val) != null) {
+                if ((r = remappingFunction.apply(key, v)) != null) {
+                    if (VAL.compareAndSet(n, v, r))
                         return r;
                 }
-                else if (doRemove(key, vv) != null)
+                else if (doRemove(key, v) != null)
                     break;
             }
         }
@@ -1786,18 +1551,17 @@
         if (key == null || value == null || remappingFunction == null)
             throw new NullPointerException();
         for (;;) {
-            Node<K,V> n; Object v; V r;
+            Node<K,V> n; V v; V r;
             if ((n = findNode(key)) == null) {
                 if (doPut(key, value, true) == null)
                     return value;
             }
-            else if ((v = n.value) != null) {
-                @SuppressWarnings("unchecked") V vv = (V) v;
-                if ((r = remappingFunction.apply(vv, value)) != null) {
-                    if (n.casValue(vv, r))
+            else if ((v = n.val) != null) {
+                if ((r = remappingFunction.apply(v, value)) != null) {
+                    if (VAL.compareAndSet(n, v, r))
                         return r;
                 }
-                else if (doRemove(key, vv) != null)
+                else if (doRemove(key, v) != null)
                     return null;
             }
         }
@@ -1946,16 +1710,60 @@
             return false;
         Map<?,?> m = (Map<?,?>) o;
         try {
-            for (Map.Entry<K,V> e : this.entrySet())
-                if (! e.getValue().equals(m.get(e.getKey())))
-                    return false;
-            for (Map.Entry<?,?> e : m.entrySet()) {
-                Object k = e.getKey();
-                Object v = e.getValue();
-                if (k == null || v == null || !v.equals(get(k)))
-                    return false;
+            Comparator<? super K> cmp = comparator;
+            @SuppressWarnings("unchecked")
+            Iterator<Map.Entry<?,?>> it =
+                (Iterator<Map.Entry<?,?>>)m.entrySet().iterator();
+            if (m instanceof SortedMap &&
+                ((SortedMap<?,?>)m).comparator() == cmp) {
+                Node<K,V> b, n;
+                if ((b = baseHead()) != null) {
+                    while ((n = b.next) != null) {
+                        K k; V v;
+                        if ((v = n.val) != null && (k = n.key) != null) {
+                            if (!it.hasNext())
+                                return false;
+                            Map.Entry<?,?> e = it.next();
+                            Object mk = e.getKey();
+                            Object mv = e.getValue();
+                            if (mk == null || mv == null)
+                                return false;
+                            try {
+                                if (cpr(cmp, k, mk) != 0)
+                                    return false;
+                            } catch (ClassCastException cce) {
+                                return false;
+                            }
+                            if (!mv.equals(v))
+                                return false;
+                        }
+                        b = n;
+                    }
+                }
+                return !it.hasNext();
             }
-            return true;
+            else {
+                while (it.hasNext()) {
+                    V v;
+                    Map.Entry<?,?> e = it.next();
+                    Object mk = e.getKey();
+                    Object mv = e.getValue();
+                    if (mk == null || mv == null ||
+                        (v = get(mk)) == null || !v.equals(mv))
+                        return false;
+                }
+                Node<K,V> b, n;
+                if ((b = baseHead()) != null) {
+                    K k; V v; Object mv;
+                    while ((n = b.next) != null) {
+                        if ((v = n.val) != null && (k = n.key) != null &&
+                            ((mv = m.get(k)) == null || !mv.equals(v)))
+                            return false;
+                        b = n;
+                    }
+                }
+                return true;
+            }
         } catch (ClassCastException unused) {
             return false;
         } catch (NullPointerException unused) {
@@ -2004,13 +1812,13 @@
         if (key == null || oldValue == null || newValue == null)
             throw new NullPointerException();
         for (;;) {
-            Node<K,V> n; Object v;
+            Node<K,V> n; V v;
             if ((n = findNode(key)) == null)
                 return false;
-            if ((v = n.value) != null) {
+            if ((v = n.val) != null) {
                 if (!oldValue.equals(v))
                     return false;
-                if (n.casValue(v, newValue))
+                if (VAL.compareAndSet(n, v, newValue))
                     return true;
             }
         }
@@ -2029,13 +1837,11 @@
         if (key == null || value == null)
             throw new NullPointerException();
         for (;;) {
-            Node<K,V> n; Object v;
+            Node<K,V> n; V v;
             if ((n = findNode(key)) == null)
                 return null;
-            if ((v = n.value) != null && n.casValue(v, value)) {
-                @SuppressWarnings("unchecked") V vv = (V)v;
-                return vv;
-            }
+            if ((v = n.val) != null && VAL.compareAndSet(n, v, value))
+                return v;
         }
     }
 
@@ -2145,7 +1951,7 @@
      * @throws NullPointerException if the specified key is null
      */
     public Map.Entry<K,V> lowerEntry(K key) {
-        return getNear(key, LT);
+        return findNearEntry(key, LT, comparator);
     }
 
     /**
@@ -2168,7 +1974,7 @@
      * @throws NullPointerException if the specified key is null
      */
     public Map.Entry<K,V> floorEntry(K key) {
-        return getNear(key, LT|EQ);
+        return findNearEntry(key, LT|EQ, comparator);
     }
 
     /**
@@ -2191,7 +1997,7 @@
      * @throws NullPointerException if the specified key is null
      */
     public Map.Entry<K,V> ceilingEntry(K key) {
-        return getNear(key, GT|EQ);
+        return findNearEntry(key, GT|EQ, comparator);
     }
 
     /**
@@ -2214,7 +2020,7 @@
      * @throws NullPointerException if the specified key is null
      */
     public Map.Entry<K,V> higherEntry(K key) {
-        return getNear(key, GT);
+        return findNearEntry(key, GT, comparator);
     }
 
     /**
@@ -2234,14 +2040,7 @@
      * the {@code Entry.setValue} method.
      */
     public Map.Entry<K,V> firstEntry() {
-        for (;;) {
-            Node<K,V> n = findFirst();
-            if (n == null)
-                return null;
-            AbstractMap.SimpleImmutableEntry<K,V> e = n.createSnapshot();
-            if (e != null)
-                return e;
-        }
+        return findFirstEntry();
     }
 
     /**
@@ -2251,14 +2050,7 @@
      * the {@code Entry.setValue} method.
      */
     public Map.Entry<K,V> lastEntry() {
-        for (;;) {
-            Node<K,V> n = findLast();
-            if (n == null)
-                return null;
-            AbstractMap.SimpleImmutableEntry<K,V> e = n.createSnapshot();
-            if (e != null)
-                return e;
-        }
+        return findLastEntry();
     }
 
     /**
@@ -2281,11 +2073,10 @@
         return doRemoveLastEntry();
     }
 
-
     /* ---------------- Iterators -------------- */
 
     /**
-     * Base of iterator classes:
+     * Base of iterator classes
      */
     abstract class Iter<T> implements Iterator<T> {
         /** the last node returned by next() */
@@ -2297,14 +2088,7 @@
 
         /** Initializes ascending iterator for entire range. */
         Iter() {
-            while ((next = findFirst()) != null) {
-                Object x = next.value;
-                if (x != null && x != next) {
-                    @SuppressWarnings("unchecked") V vv = (V)x;
-                    nextValue = vv;
-                    break;
-                }
-            }
+            advance(baseHead());
         }
 
         public final boolean hasNext() {
@@ -2312,54 +2096,58 @@
         }
 
         /** Advances next to higher entry. */
-        final void advance() {
-            if (next == null)
-                throw new NoSuchElementException();
-            lastReturned = next;
-            while ((next = next.next) != null) {
-                Object x = next.value;
-                if (x != null && x != next) {
-                    @SuppressWarnings("unchecked") V vv = (V)x;
-                    nextValue = vv;
-                    break;
-                }
+        final void advance(Node<K,V> b) {
+            Node<K,V> n = null;
+            V v = null;
+            if ((lastReturned = b) != null) {
+                while ((n = b.next) != null && (v = n.val) == null)
+                    b = n;
             }
+            nextValue = v;
+            next = n;
         }
 
-        public void remove() {
-            Node<K,V> l = lastReturned;
-            if (l == null)
+        public final void remove() {
+            Node<K,V> n; K k;
+            if ((n = lastReturned) == null || (k = n.key) == null)
                 throw new IllegalStateException();
             // It would not be worth all of the overhead to directly
             // unlink from here. Using remove is fast enough.
-            ConcurrentSkipListMap.this.remove(l.key);
+            ConcurrentSkipListMap.this.remove(k);
             lastReturned = null;
         }
-
     }
 
     final class ValueIterator extends Iter<V> {
         public V next() {
-            V v = nextValue;
-            advance();
+            V v;
+            if ((v = nextValue) == null)
+                throw new NoSuchElementException();
+            advance(next);
             return v;
         }
     }
 
     final class KeyIterator extends Iter<K> {
         public K next() {
-            Node<K,V> n = next;
-            advance();
-            return n.key;
+            Node<K,V> n;
+            if ((n = next) == null)
+                throw new NoSuchElementException();
+            K k = n.key;
+            advance(n);
+            return k;
         }
     }
 
     final class EntryIterator extends Iter<Map.Entry<K,V>> {
         public Map.Entry<K,V> next() {
-            Node<K,V> n = next;
+            Node<K,V> n;
+            if ((n = next) == null)
+                throw new NoSuchElementException();
+            K k = n.key;
             V v = nextValue;
-            advance();
-            return new AbstractMap.SimpleImmutableEntry<K,V>(n.key, v);
+            advance(n);
+            return new AbstractMap.SimpleImmutableEntry<K,V>(k, v);
         }
     }
 
@@ -2725,38 +2513,34 @@
         Map.Entry<K,V> lowestEntry() {
             Comparator<? super K> cmp = m.comparator;
             for (;;) {
-                ConcurrentSkipListMap.Node<K,V> n = loNode(cmp);
-                if (!isBeforeEnd(n, cmp))
+                ConcurrentSkipListMap.Node<K,V> n; V v;
+                if ((n = loNode(cmp)) == null || !isBeforeEnd(n, cmp))
                     return null;
-                Map.Entry<K,V> e = n.createSnapshot();
-                if (e != null)
-                    return e;
+                else if ((v = n.val) != null)
+                    return new AbstractMap.SimpleImmutableEntry<K,V>(n.key, v);
             }
         }
 
         Map.Entry<K,V> highestEntry() {
             Comparator<? super K> cmp = m.comparator;
             for (;;) {
-                ConcurrentSkipListMap.Node<K,V> n = hiNode(cmp);
-                if (n == null || !inBounds(n.key, cmp))
+                ConcurrentSkipListMap.Node<K,V> n; V v;
+                if ((n = hiNode(cmp)) == null || !inBounds(n.key, cmp))
                     return null;
-                Map.Entry<K,V> e = n.createSnapshot();
-                if (e != null)
-                    return e;
+                else if ((v = n.val) != null)
+                    return new AbstractMap.SimpleImmutableEntry<K,V>(n.key, v);
             }
         }
 
         Map.Entry<K,V> removeLowest() {
             Comparator<? super K> cmp = m.comparator;
             for (;;) {
-                Node<K,V> n = loNode(cmp);
-                if (n == null)
+                ConcurrentSkipListMap.Node<K,V> n; K k; V v;
+                if ((n = loNode(cmp)) == null)
                     return null;
-                K k = n.key;
-                if (!inBounds(k, cmp))
+                else if (!inBounds((k = n.key), cmp))
                     return null;
-                V v = m.doRemove(k, null);
-                if (v != null)
+                else if ((v = m.doRemove(k, null)) != null)
                     return new AbstractMap.SimpleImmutableEntry<K,V>(k, v);
             }
         }
@@ -2764,20 +2548,18 @@
         Map.Entry<K,V> removeHighest() {
             Comparator<? super K> cmp = m.comparator;
             for (;;) {
-                Node<K,V> n = hiNode(cmp);
-                if (n == null)
+                ConcurrentSkipListMap.Node<K,V> n; K k; V v;
+                if ((n = hiNode(cmp)) == null)
                     return null;
-                K k = n.key;
-                if (!inBounds(k, cmp))
+                else if (!inBounds((k = n.key), cmp))
                     return null;
-                V v = m.doRemove(k, null);
-                if (v != null)
+                else if ((v = m.doRemove(k, null)) != null)
                     return new AbstractMap.SimpleImmutableEntry<K,V>(k, v);
             }
         }
 
         /**
-         * Submap version of ConcurrentSkipListMap.getNearEntry.
+         * Submap version of ConcurrentSkipListMap.findNearEntry.
          */
         Map.Entry<K,V> getNearEntry(K key, int rel) {
             Comparator<? super K> cmp = m.comparator;
@@ -2791,15 +2573,12 @@
                 return ((rel & LT) != 0) ? null : lowestEntry();
             if (tooHigh(key, cmp))
                 return ((rel & LT) != 0) ? highestEntry() : null;
-            for (;;) {
-                Node<K,V> n = m.findNear(key, rel, cmp);
-                if (n == null || !inBounds(n.key, cmp))
-                    return null;
-                K k = n.key;
-                V v = n.getValidValue();
-                if (v != null)
-                    return new AbstractMap.SimpleImmutableEntry<K,V>(k, v);
-            }
+            AbstractMap.SimpleImmutableEntry<K,V> e =
+                m.findNearEntry(key, rel, cmp);
+            if (e == null || !inBounds(e.getKey(), cmp))
+                return null;
+            else
+                return e;
         }
 
         // Almost the same as getNearEntry, except for keys
@@ -2834,10 +2613,8 @@
                 Node<K,V> n = m.findNear(key, rel, cmp);
                 if (n == null || !inBounds(n.key, cmp))
                     return null;
-                K k = n.key;
-                V v = n.getValidValue();
-                if (v != null)
-                    return k;
+                if (n.val != null)
+                    return n.key;
             }
         }
 
@@ -2868,7 +2645,7 @@
             for (ConcurrentSkipListMap.Node<K,V> n = loNode(cmp);
                  isBeforeEnd(n, cmp);
                  n = n.next) {
-                if (n.getValidValue() != null)
+                if (n.val != null)
                     ++count;
             }
             return count >= Integer.MAX_VALUE ? Integer.MAX_VALUE : (int)count;
@@ -2886,7 +2663,7 @@
             for (ConcurrentSkipListMap.Node<K,V> n = loNode(cmp);
                  isBeforeEnd(n, cmp);
                  n = n.next) {
-                V v = n.getValidValue();
+                V v = n.val;
                 if (v != null && value.equals(v))
                     return true;
             }
@@ -2898,7 +2675,7 @@
             for (ConcurrentSkipListMap.Node<K,V> n = loNode(cmp);
                  isBeforeEnd(n, cmp);
                  n = n.next) {
-                if (n.getValidValue() != null)
+                if (n.val != null)
                     m.remove(n.key);
             }
         }
@@ -3112,19 +2889,18 @@
             V nextValue;
 
             SubMapIter() {
+                VarHandle.acquireFence();
                 Comparator<? super K> cmp = m.comparator;
                 for (;;) {
                     next = isDescending ? hiNode(cmp) : loNode(cmp);
                     if (next == null)
                         break;
-                    Object x = next.value;
-                    if (x != null && x != next) {
+                    V x = next.val;
+                    if (x != null) {
                         if (! inBounds(next.key, cmp))
                             next = null;
-                        else {
-                            @SuppressWarnings("unchecked") V vv = (V)x;
-                            nextValue = vv;
-                        }
+                        else
+                            nextValue = x;
                         break;
                     }
                 }
@@ -3150,14 +2926,12 @@
                     next = next.next;
                     if (next == null)
                         break;
-                    Object x = next.value;
-                    if (x != null && x != next) {
+                    V x = next.val;
+                    if (x != null) {
                         if (tooHigh(next.key, cmp))
                             next = null;
-                        else {
-                            @SuppressWarnings("unchecked") V vv = (V)x;
-                            nextValue = vv;
-                        }
+                        else
+                            nextValue = x;
                         break;
                     }
                 }
@@ -3169,14 +2943,12 @@
                     next = m.findNear(lastReturned.key, LT, cmp);
                     if (next == null)
                         break;
-                    Object x = next.value;
-                    if (x != null && x != next) {
+                    V x = next.val;
+                    if (x != null) {
                         if (tooLow(next.key, cmp))
                             next = null;
-                        else {
-                            @SuppressWarnings("unchecked") V vv = (V)x;
-                            nextValue = vv;
-                        }
+                        else
+                            nextValue = x;
                         break;
                     }
                 }
@@ -3256,22 +3028,28 @@
 
     public void forEach(BiConsumer<? super K, ? super V> action) {
         if (action == null) throw new NullPointerException();
-        V v;
-        for (Node<K,V> n = findFirst(); n != null; n = n.next) {
-            if ((v = n.getValidValue()) != null)
-                action.accept(n.key, v);
+        Node<K,V> b, n; V v;
+        if ((b = baseHead()) != null) {
+            while ((n = b.next) != null) {
+                if ((v = n.val) != null)
+                    action.accept(n.key, v);
+                b = n;
+            }
         }
     }
 
     public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
         if (function == null) throw new NullPointerException();
-        V v;
-        for (Node<K,V> n = findFirst(); n != null; n = n.next) {
-            while ((v = n.getValidValue()) != null) {
-                V r = function.apply(n.key, v);
-                if (r == null) throw new NullPointerException();
-                if (n.casValue(v, r))
-                    break;
+        Node<K,V> b, n; V v;
+        if ((b = baseHead()) != null) {
+            while ((n = b.next) != null) {
+                while ((v = n.val) != null) {
+                    V r = function.apply(n.key, v);
+                    if (r == null) throw new NullPointerException();
+                    if (VAL.compareAndSet(n, v, r))
+                        break;
+                }
+                b = n;
             }
         }
     }
@@ -3282,13 +3060,16 @@
     boolean removeEntryIf(Predicate<? super Entry<K,V>> function) {
         if (function == null) throw new NullPointerException();
         boolean removed = false;
-        for (Node<K,V> n = findFirst(); n != null; n = n.next) {
-            V v;
-            if ((v = n.getValidValue()) != null) {
-                K k = n.key;
-                Map.Entry<K,V> e = new AbstractMap.SimpleImmutableEntry<>(k, v);
-                if (function.test(e) && remove(k, v))
-                    removed = true;
+        Node<K,V> b, n; V v;
+        if ((b = baseHead()) != null) {
+            while ((n = b.next) != null) {
+                if ((v = n.val) != null) {
+                    K k = n.key;
+                    Map.Entry<K,V> e = new AbstractMap.SimpleImmutableEntry<>(k, v);
+                    if (function.test(e) && remove(k, v))
+                        removed = true;
+                }
+                b = n;
             }
         }
         return removed;
@@ -3300,12 +3081,12 @@
     boolean removeValueIf(Predicate<? super V> function) {
         if (function == null) throw new NullPointerException();
         boolean removed = false;
-        for (Node<K,V> n = findFirst(); n != null; n = n.next) {
-            V v;
-            if ((v = n.getValidValue()) != null) {
-                K k = n.key;
-                if (function.test(v) && remove(k, v))
+        Node<K,V> b, n; V v;
+        if ((b = baseHead()) != null) {
+            while ((n = b.next) != null) {
+                if ((v = n.val) != null && function.test(v) && remove(n.key, v))
                     removed = true;
+                b = n;
             }
         }
         return removed;
@@ -3323,30 +3104,27 @@
      * off, or the end of row is encountered. Control of the number of
      * splits relies on some statistical estimation: The expected
      * remaining number of elements of a skip list when advancing
-     * either across or down decreases by about 25%. To make this
-     * observation useful, we need to know initial size, which we
-     * don't. But we can just use Integer.MAX_VALUE so that we
-     * don't prematurely zero out while splitting.
+     * either across or down decreases by about 25%.
      */
     abstract static class CSLMSpliterator<K,V> {
         final Comparator<? super K> comparator;
         final K fence;     // exclusive upper bound for keys, or null if to end
         Index<K,V> row;    // the level to split out
         Node<K,V> current; // current traversal node; initialize at origin
-        int est;           // pseudo-size estimate
+        long est;          // size estimate
         CSLMSpliterator(Comparator<? super K> comparator, Index<K,V> row,
-                        Node<K,V> origin, K fence, int est) {
+                        Node<K,V> origin, K fence, long est) {
             this.comparator = comparator; this.row = row;
             this.current = origin; this.fence = fence; this.est = est;
         }
 
-        public final long estimateSize() { return (long)est; }
+        public final long estimateSize() { return est; }
     }
 
     static final class KeySpliterator<K,V> extends CSLMSpliterator<K,V>
         implements Spliterator<K> {
         KeySpliterator(Comparator<? super K> comparator, Index<K,V> row,
-                       Node<K,V> origin, K fence, int est) {
+                       Node<K,V> origin, K fence, long est) {
             super(comparator, row, origin, fence, est);
         }
 
@@ -3358,7 +3136,7 @@
                 for (Index<K,V> q = row; q != null; q = row = q.down) {
                     Index<K,V> s; Node<K,V> b, n; K sk;
                     if ((s = q.right) != null && (b = s.node) != null &&
-                        (n = b.next) != null && n.value != null &&
+                        (n = b.next) != null && n.val != null &&
                         (sk = n.key) != null && cpr(cmp, sk, ek) > 0 &&
                         (f == null || cpr(cmp, sk, f) < 0)) {
                         current = n;
@@ -3379,10 +3157,10 @@
             Node<K,V> e = current;
             current = null;
             for (; e != null; e = e.next) {
-                K k; Object v;
+                K k;
                 if ((k = e.key) != null && f != null && cpr(cmp, f, k) <= 0)
                     break;
-                if ((v = e.value) != null && v != e)
+                if (e.val != null)
                     action.accept(k);
             }
         }
@@ -3393,12 +3171,12 @@
             K f = fence;
             Node<K,V> e = current;
             for (; e != null; e = e.next) {
-                K k; Object v;
+                K k;
                 if ((k = e.key) != null && f != null && cpr(cmp, f, k) <= 0) {
                     e = null;
                     break;
                 }
-                if ((v = e.value) != null && v != e) {
+                if (e.val != null) {
                     current = e.next;
                     action.accept(k);
                     return true;
@@ -3420,21 +3198,23 @@
     }
     // factory method for KeySpliterator
     final KeySpliterator<K,V> keySpliterator() {
-        Comparator<? super K> cmp = comparator;
-        for (;;) { // ensure h corresponds to origin p
-            HeadIndex<K,V> h; Node<K,V> p;
-            Node<K,V> b = (h = head).node;
-            if ((p = b.next) == null || p.value != null)
-                return new KeySpliterator<K,V>(cmp, h, p, null, (p == null) ?
-                                               0 : Integer.MAX_VALUE);
-            p.helpDelete(b, p.next);
+        Index<K,V> h; Node<K,V> n; long est;
+        VarHandle.acquireFence();
+        if ((h = head) == null) {
+            n = null;
+            est = 0L;
         }
+        else {
+            n = h.node;
+            est = getAdderCount();
+        }
+        return new KeySpliterator<K,V>(comparator, h, n, null, est);
     }
 
     static final class ValueSpliterator<K,V> extends CSLMSpliterator<K,V>
         implements Spliterator<V> {
         ValueSpliterator(Comparator<? super K> comparator, Index<K,V> row,
-                       Node<K,V> origin, K fence, int est) {
+                       Node<K,V> origin, K fence, long est) {
             super(comparator, row, origin, fence, est);
         }
 
@@ -3446,7 +3226,7 @@
                 for (Index<K,V> q = row; q != null; q = row = q.down) {
                     Index<K,V> s; Node<K,V> b, n; K sk;
                     if ((s = q.right) != null && (b = s.node) != null &&
-                        (n = b.next) != null && n.value != null &&
+                        (n = b.next) != null && n.val != null &&
                         (sk = n.key) != null && cpr(cmp, sk, ek) > 0 &&
                         (f == null || cpr(cmp, sk, f) < 0)) {
                         current = n;
@@ -3467,13 +3247,11 @@
             Node<K,V> e = current;
             current = null;
             for (; e != null; e = e.next) {
-                K k; Object v;
+                K k; V v;
                 if ((k = e.key) != null && f != null && cpr(cmp, f, k) <= 0)
                     break;
-                if ((v = e.value) != null && v != e) {
-                    @SuppressWarnings("unchecked") V vv = (V)v;
-                    action.accept(vv);
-                }
+                if ((v = e.val) != null)
+                    action.accept(v);
             }
         }
 
@@ -3483,15 +3261,14 @@
             K f = fence;
             Node<K,V> e = current;
             for (; e != null; e = e.next) {
-                K k; Object v;
+                K k; V v;
                 if ((k = e.key) != null && f != null && cpr(cmp, f, k) <= 0) {
                     e = null;
                     break;
                 }
-                if ((v = e.value) != null && v != e) {
+                if ((v = e.val) != null) {
                     current = e.next;
-                    @SuppressWarnings("unchecked") V vv = (V)v;
-                    action.accept(vv);
+                    action.accept(v);
                     return true;
                 }
             }
@@ -3507,21 +3284,23 @@
 
     // Almost the same as keySpliterator()
     final ValueSpliterator<K,V> valueSpliterator() {
-        Comparator<? super K> cmp = comparator;
-        for (;;) {
-            HeadIndex<K,V> h; Node<K,V> p;
-            Node<K,V> b = (h = head).node;
-            if ((p = b.next) == null || p.value != null)
-                return new ValueSpliterator<K,V>(cmp, h, p, null, (p == null) ?
-                                                 0 : Integer.MAX_VALUE);
-            p.helpDelete(b, p.next);
+        Index<K,V> h; Node<K,V> n; long est;
+        VarHandle.acquireFence();
+        if ((h = head) == null) {
+            n = null;
+            est = 0L;
         }
+        else {
+            n = h.node;
+            est = getAdderCount();
+        }
+        return new ValueSpliterator<K,V>(comparator, h, n, null, est);
     }
 
     static final class EntrySpliterator<K,V> extends CSLMSpliterator<K,V>
         implements Spliterator<Map.Entry<K,V>> {
         EntrySpliterator(Comparator<? super K> comparator, Index<K,V> row,
-                         Node<K,V> origin, K fence, int est) {
+                         Node<K,V> origin, K fence, long est) {
             super(comparator, row, origin, fence, est);
         }
 
@@ -3533,7 +3312,7 @@
                 for (Index<K,V> q = row; q != null; q = row = q.down) {
                     Index<K,V> s; Node<K,V> b, n; K sk;
                     if ((s = q.right) != null && (b = s.node) != null &&
-                        (n = b.next) != null && n.value != null &&
+                        (n = b.next) != null && n.val != null &&
                         (sk = n.key) != null && cpr(cmp, sk, ek) > 0 &&
                         (f == null || cpr(cmp, sk, f) < 0)) {
                         current = n;
@@ -3554,13 +3333,12 @@
             Node<K,V> e = current;
             current = null;
             for (; e != null; e = e.next) {
-                K k; Object v;
+                K k; V v;
                 if ((k = e.key) != null && f != null && cpr(cmp, f, k) <= 0)
                     break;
-                if ((v = e.value) != null && v != e) {
-                    @SuppressWarnings("unchecked") V vv = (V)v;
+                if ((v = e.val) != null) {
                     action.accept
-                        (new AbstractMap.SimpleImmutableEntry<K,V>(k, vv));
+                        (new AbstractMap.SimpleImmutableEntry<K,V>(k, v));
                 }
             }
         }
@@ -3571,16 +3349,15 @@
             K f = fence;
             Node<K,V> e = current;
             for (; e != null; e = e.next) {
-                K k; Object v;
+                K k; V v;
                 if ((k = e.key) != null && f != null && cpr(cmp, f, k) <= 0) {
                     e = null;
                     break;
                 }
-                if ((v = e.value) != null && v != e) {
+                if ((v = e.val) != null) {
                     current = e.next;
-                    @SuppressWarnings("unchecked") V vv = (V)v;
                     action.accept
-                        (new AbstractMap.SimpleImmutableEntry<K,V>(k, vv));
+                        (new AbstractMap.SimpleImmutableEntry<K,V>(k, v));
                     return true;
                 }
             }
@@ -3611,24 +3388,35 @@
 
     // Almost the same as keySpliterator()
     final EntrySpliterator<K,V> entrySpliterator() {
-        Comparator<? super K> cmp = comparator;
-        for (;;) { // almost same as key version
-            HeadIndex<K,V> h; Node<K,V> p;
-            Node<K,V> b = (h = head).node;
-            if ((p = b.next) == null || p.value != null)
-                return new EntrySpliterator<K,V>(cmp, h, p, null, (p == null) ?
-                                                 0 : Integer.MAX_VALUE);
-            p.helpDelete(b, p.next);
+        Index<K,V> h; Node<K,V> n; long est;
+        VarHandle.acquireFence();
+        if ((h = head) == null) {
+            n = null;
+            est = 0L;
         }
+        else {
+            n = h.node;
+            est = getAdderCount();
+        }
+        return new EntrySpliterator<K,V>(comparator, h, n, null, est);
     }
 
     // VarHandle mechanics
     private static final VarHandle HEAD;
+    private static final VarHandle ADDER;
+    private static final VarHandle NEXT;
+    private static final VarHandle VAL;
+    private static final VarHandle RIGHT;
     static {
         try {
             MethodHandles.Lookup l = MethodHandles.lookup();
             HEAD = l.findVarHandle(ConcurrentSkipListMap.class, "head",
-                                   HeadIndex.class);
+                                   Index.class);
+            ADDER = l.findVarHandle(ConcurrentSkipListMap.class, "adder",
+                                    LongAdder.class);
+            NEXT = l.findVarHandle(Node.class, "next", Node.class);
+            VAL = l.findVarHandle(Node.class, "val", Object.class);
+            RIGHT = l.findVarHandle(Index.class, "right", Index.class);
         } catch (ReflectiveOperationException e) {
             throw new Error(e);
         }
--- a/src/java.base/share/classes/java/util/concurrent/ExecutorCompletionService.java	Wed Oct 04 11:52:07 2017 -0700
+++ b/src/java.base/share/classes/java/util/concurrent/ExecutorCompletionService.java	Wed Oct 04 20:01:19 2017 +0000
@@ -174,6 +174,10 @@
         this.completionQueue = completionQueue;
     }
 
+    /**
+     * @throws RejectedExecutionException {@inheritDoc}
+     * @throws NullPointerException       {@inheritDoc}
+     */
     public Future<V> submit(Callable<V> task) {
         if (task == null) throw new NullPointerException();
         RunnableFuture<V> f = newTaskFor(task);
@@ -181,6 +185,10 @@
         return f;
     }
 
+    /**
+     * @throws RejectedExecutionException {@inheritDoc}
+     * @throws NullPointerException       {@inheritDoc}
+     */
     public Future<V> submit(Runnable task, V result) {
         if (task == null) throw new NullPointerException();
         RunnableFuture<V> f = newTaskFor(task, result);
--- a/src/java.base/share/classes/java/util/concurrent/Executors.java	Wed Oct 04 11:52:07 2017 -0700
+++ b/src/java.base/share/classes/java/util/concurrent/Executors.java	Wed Oct 04 20:01:19 2017 +0000
@@ -514,6 +514,9 @@
             task.run();
             return result;
         }
+        public String toString() {
+            return super.toString() + "[Wrapped task = " + task + "]";
+        }
     }
 
     /**
@@ -540,6 +543,10 @@
                 throw e.getException();
             }
         }
+
+        public String toString() {
+            return super.toString() + "[Wrapped task = " + task + "]";
+        }
     }
 
     /**
@@ -592,6 +599,10 @@
                 throw e.getException();
             }
         }
+
+        public String toString() {
+            return super.toString() + "[Wrapped task = " + task + "]";
+        }
     }
 
     /**
--- a/src/java.base/share/classes/java/util/concurrent/ForkJoinTask.java	Wed Oct 04 11:52:07 2017 -0700
+++ b/src/java.base/share/classes/java/util/concurrent/ForkJoinTask.java	Wed Oct 04 20:01:19 2017 +0000
@@ -1375,6 +1375,9 @@
         public final void setRawResult(T v) { result = v; }
         public final boolean exec() { runnable.run(); return true; }
         public final void run() { invoke(); }
+        public String toString() {
+            return super.toString() + "[Wrapped task = " + runnable + "]";
+        }
         private static final long serialVersionUID = 5232453952276885070L;
     }
 
@@ -1392,6 +1395,9 @@
         public final void setRawResult(Void v) { }
         public final boolean exec() { runnable.run(); return true; }
         public final void run() { invoke(); }
+        public String toString() {
+            return super.toString() + "[Wrapped task = " + runnable + "]";
+        }
         private static final long serialVersionUID = 5232453952276885070L;
     }
 
@@ -1437,6 +1443,9 @@
             }
         }
         public final void run() { invoke(); }
+        public String toString() {
+            return super.toString() + "[Wrapped task = " + callable + "]";
+        }
         private static final long serialVersionUID = 2838392045355241008L;
     }
 
--- a/src/java.base/share/classes/java/util/concurrent/FutureTask.java	Wed Oct 04 11:52:07 2017 -0700
+++ b/src/java.base/share/classes/java/util/concurrent/FutureTask.java	Wed Oct 04 20:01:19 2017 +0000
@@ -480,6 +480,41 @@
         }
     }
 
+    /**
+     * Returns a string representation of this FutureTask.
+     *
+     * @implSpec
+     * The default implementation returns a string identifying this
+     * FutureTask, as well as its completion state.  The state, in
+     * brackets, contains one of the strings {@code "Completed Normally"},
+     * {@code "Completed Exceptionally"}, {@code "Cancelled"}, or {@code
+     * "Not completed"}.
+     *
+     * @return a string representation of this FutureTask
+     */
+    public String toString() {
+        final String status;
+        switch (state) {
+        case NORMAL:
+            status = "[Completed normally]";
+            break;
+        case EXCEPTIONAL:
+            status = "[Completed exceptionally: " + outcome + "]";
+            break;
+        case CANCELLED:
+        case INTERRUPTING:
+        case INTERRUPTED:
+            status = "[Cancelled]";
+            break;
+        default:
+            final Callable<?> callable = this.callable;
+            status = (callable == null)
+                ? "[Not completed]"
+                : "[Not completed, task = " + callable + "]";
+        }
+        return super.toString() + status;
+    }
+
     // VarHandle mechanics
     private static final VarHandle STATE;
     private static final VarHandle RUNNER;
--- a/src/java.base/share/classes/java/util/concurrent/ThreadPoolExecutor.java	Wed Oct 04 11:52:07 2017 -0700
+++ b/src/java.base/share/classes/java/util/concurrent/ThreadPoolExecutor.java	Wed Oct 04 20:01:19 2017 +0000
@@ -383,7 +383,7 @@
      */
     private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
     private static final int COUNT_BITS = Integer.SIZE - 3;
-    private static final int CAPACITY   = (1 << COUNT_BITS) - 1;
+    private static final int COUNT_MASK = (1 << COUNT_BITS) - 1;
 
     // runState is stored in the high-order bits
     private static final int RUNNING    = -1 << COUNT_BITS;
@@ -393,8 +393,8 @@
     private static final int TERMINATED =  3 << COUNT_BITS;
 
     // Packing and unpacking ctl
-    private static int runStateOf(int c)     { return c & ~CAPACITY; }
-    private static int workerCountOf(int c)  { return c & CAPACITY; }
+    private static int runStateOf(int c)     { return c & ~COUNT_MASK; }
+    private static int workerCountOf(int c)  { return c & COUNT_MASK; }
     private static int ctlOf(int rs, int wc) { return rs | wc; }
 
     /*
@@ -434,7 +434,7 @@
      * decrements are performed within getTask.
      */
     private void decrementWorkerCount() {
-        do {} while (! compareAndDecrementWorkerCount(ctl.get()));
+        ctl.addAndGet(-1);
     }
 
     /**
@@ -538,12 +538,17 @@
      * Core pool size is the minimum number of workers to keep alive
      * (and not allow to time out etc) unless allowCoreThreadTimeOut
      * is set, in which case the minimum is zero.
+     *
+     * Since the worker count is actually stored in COUNT_BITS bits,
+     * the effective limit is {@code corePoolSize & COUNT_MASK}.
      */
     private volatile int corePoolSize;
 
     /**
-     * Maximum pool size. Note that the actual maximum is internally
-     * bounded by CAPACITY.
+     * Maximum pool size.
+     *
+     * Since the worker count is actually stored in COUNT_BITS bits,
+     * the effective limit is {@code maximumPoolSize & COUNT_MASK}.
      */
     private volatile int maximumPoolSize;
 
@@ -705,7 +710,7 @@
             int c = ctl.get();
             if (isRunning(c) ||
                 runStateAtLeast(c, TIDYING) ||
-                (runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty()))
+                (runStateLessThan(c, STOP) && ! workQueue.isEmpty()))
                 return;
             if (workerCountOf(c) != 0) { // Eligible to terminate
                 interruptIdleWorkers(ONLY_ONE);
@@ -744,17 +749,12 @@
      * specially.
      */
     private void checkShutdownAccess() {
+        // assert mainLock.isHeldByCurrentThread();
         SecurityManager security = System.getSecurityManager();
         if (security != null) {
             security.checkPermission(shutdownPerm);
-            final ReentrantLock mainLock = this.mainLock;
-            mainLock.lock();
-            try {
-                for (Worker w : workers)
-                    security.checkAccess(w.thread);
-            } finally {
-                mainLock.unlock();
-            }
+            for (Worker w : workers)
+                security.checkAccess(w.thread);
         }
     }
 
@@ -763,14 +763,9 @@
      * (in which case some threads may remain uninterrupted).
      */
     private void interruptWorkers() {
-        final ReentrantLock mainLock = this.mainLock;
-        mainLock.lock();
-        try {
-            for (Worker w : workers)
-                w.interruptIfStarted();
-        } finally {
-            mainLock.unlock();
-        }
+        // assert mainLock.isHeldByCurrentThread();
+        for (Worker w : workers)
+            w.interruptIfStarted();
     }
 
     /**
@@ -896,26 +891,22 @@
      */
     private boolean addWorker(Runnable firstTask, boolean core) {
         retry:
-        for (;;) {
-            int c = ctl.get();
-            int rs = runStateOf(c);
-
+        for (int c = ctl.get();;) {
             // Check if queue empty only if necessary.
-            if (rs >= SHUTDOWN &&
-                ! (rs == SHUTDOWN &&
-                   firstTask == null &&
-                   ! workQueue.isEmpty()))
+            if (runStateAtLeast(c, SHUTDOWN)
+                && (runStateAtLeast(c, STOP)
+                    || firstTask != null
+                    || workQueue.isEmpty()))
                 return false;
 
             for (;;) {
-                int wc = workerCountOf(c);
-                if (wc >= CAPACITY ||
-                    wc >= (core ? corePoolSize : maximumPoolSize))
+                if (workerCountOf(c)
+                    >= ((core ? corePoolSize : maximumPoolSize) & COUNT_MASK))
                     return false;
                 if (compareAndIncrementWorkerCount(c))
                     break retry;
                 c = ctl.get();  // Re-read ctl
-                if (runStateOf(c) != rs)
+                if (runStateAtLeast(c, SHUTDOWN))
                     continue retry;
                 // else CAS failed due to workerCount change; retry inner loop
             }
@@ -934,10 +925,10 @@
                     // Recheck while holding lock.
                     // Back out on ThreadFactory failure or if
                     // shut down before lock acquired.
-                    int rs = runStateOf(ctl.get());
+                    int c = ctl.get();
 
-                    if (rs < SHUTDOWN ||
-                        (rs == SHUTDOWN && firstTask == null)) {
+                    if (isRunning(c) ||
+                        (runStateLessThan(c, STOP) && firstTask == null)) {
                         if (t.isAlive()) // precheck that t is startable
                             throw new IllegalThreadStateException();
                         workers.add(w);
@@ -1044,10 +1035,10 @@
 
         for (;;) {
             int c = ctl.get();
-            int rs = runStateOf(c);
 
             // Check if queue empty only if necessary.
-            if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
+            if (runStateAtLeast(c, SHUTDOWN)
+                && (runStateAtLeast(c, STOP) || workQueue.isEmpty())) {
                 decrementWorkerCount();
                 return null;
             }
@@ -1140,17 +1131,12 @@
                     wt.interrupt();
                 try {
                     beforeExecute(wt, task);
-                    Throwable thrown = null;
                     try {
                         task.run();
-                    } catch (RuntimeException x) {
-                        thrown = x; throw x;
-                    } catch (Error x) {
-                        thrown = x; throw x;
-                    } catch (Throwable x) {
-                        thrown = x; throw new Error(x);
-                    } finally {
-                        afterExecute(task, thrown);
+                        afterExecute(task, null);
+                    } catch (Throwable ex) {
+                        afterExecute(task, ex);
+                        throw ex;
                     }
                 } finally {
                     task = null;
@@ -1331,7 +1317,7 @@
      *
      * If the task cannot be submitted for execution, either because this
      * executor has been shutdown or because its capacity has been reached,
-     * the task is handled by the current {@code RejectedExecutionHandler}.
+     * the task is handled by the current {@link RejectedExecutionHandler}.
      *
      * @param command the task to execute
      * @throws RejectedExecutionException at discretion of
@@ -1438,7 +1424,7 @@
     }
 
     public boolean isShutdown() {
-        return ! isRunning(ctl.get());
+        return runStateAtLeast(ctl.get(), SHUTDOWN);
     }
 
     /** Used by ScheduledThreadPoolExecutor. */
@@ -1459,7 +1445,7 @@
      */
     public boolean isTerminating() {
         int c = ctl.get();
-        return ! isRunning(c) && runStateLessThan(c, TERMINATED);
+        return runStateAtLeast(c, SHUTDOWN) && runStateLessThan(c, TERMINATED);
     }
 
     public boolean isTerminated() {
@@ -1472,7 +1458,7 @@
         final ReentrantLock mainLock = this.mainLock;
         mainLock.lock();
         try {
-            while (!runStateAtLeast(ctl.get(), TERMINATED)) {
+            while (runStateLessThan(ctl.get(), TERMINATED)) {
                 if (nanos <= 0L)
                     return false;
                 nanos = termination.awaitNanos(nanos);
@@ -1951,7 +1937,7 @@
         }
         int c = ctl.get();
         String runState =
-            runStateLessThan(c, SHUTDOWN) ? "Running" :
+            isRunning(c) ? "Running" :
             runStateAtLeast(c, TERMINATED) ? "Terminated" :
             "Shutting down";
         return super.toString() +
--- a/src/java.base/share/classes/java/util/concurrent/TimeUnit.java	Wed Oct 04 11:52:07 2017 -0700
+++ b/src/java.base/share/classes/java/util/concurrent/TimeUnit.java	Wed Oct 04 20:01:19 2017 +0000
@@ -342,11 +342,13 @@
      * using:
      *
      * <pre> {@code
-     * public synchronized Object poll(long timeout, TimeUnit unit)
+     * public E poll(long timeout, TimeUnit unit)
      *     throws InterruptedException {
-     *   while (empty) {
-     *     unit.timedWait(this, timeout);
-     *     ...
+     *   synchronized (lock) {
+     *     while (isEmpty()) {
+     *       unit.timedWait(lock, timeout);
+     *       ...
+     *     }
      *   }
      * }}</pre>
      *
--- a/src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java	Wed Oct 04 11:52:07 2017 -0700
+++ b/src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java	Wed Oct 04 20:01:19 2017 +0000
@@ -67,11 +67,11 @@
     private static final long serialVersionUID = 7373984972572414692L;
 
     /*
-      To keep sources in sync, the remainder of this source file is
-      exactly cloned from AbstractQueuedSynchronizer, replacing class
-      name and changing ints related with sync state to longs. Please
-      keep it that way.
-    */
+     * To keep sources in sync, the remainder of this source file is
+     * exactly cloned from AbstractQueuedSynchronizer, replacing class
+     * name and changing ints related with sync state to longs. Please
+     * keep it that way.
+     */
 
     /**
      * Creates a new {@code AbstractQueuedLongSynchronizer} instance
@@ -725,8 +725,7 @@
     /**
      * Returns {@code true} if synchronization is held exclusively with
      * respect to the current (calling) thread.  This method is invoked
-     * upon each call to a non-waiting {@link ConditionObject} method.
-     * (Waiting methods instead invoke {@link #release}.)
+     * upon each call to a {@link ConditionObject} method.
      *
      * <p>The default implementation throws {@link
      * UnsupportedOperationException}. This method is invoked
@@ -1366,9 +1365,8 @@
     }
 
     /**
-     * Condition implementation for a {@link
-     * AbstractQueuedLongSynchronizer} serving as the basis of a {@link
-     * Lock} implementation.
+     * Condition implementation for a {@link AbstractQueuedLongSynchronizer}
+     * serving as the basis of a {@link Lock} implementation.
      *
      * <p>Method documentation for this class describes mechanics,
      * not behavioral specifications from the point of view of Lock
@@ -1401,6 +1399,8 @@
          * @return its new wait node
          */
         private Node addConditionWaiter() {
+            if (!isHeldExclusively())
+                throw new IllegalMonitorStateException();
             Node t = lastWaiter;
             // If lastWaiter is cancelled, clean out.
             if (t != null && t.waitStatus != Node.CONDITION) {
--- a/src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedSynchronizer.java	Wed Oct 04 11:52:07 2017 -0700
+++ b/src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedSynchronizer.java	Wed Oct 04 20:01:19 2017 +0000
@@ -194,19 +194,13 @@
  * represent the locked state. While a non-reentrant lock
  * does not strictly require recording of the current owner
  * thread, this class does so anyway to make usage easier to monitor.
- * It also supports conditions and exposes
- * one of the instrumentation methods:
+ * It also supports conditions and exposes some instrumentation methods:
  *
  * <pre> {@code
  * class Mutex implements Lock, java.io.Serializable {
  *
  *   // Our internal helper class
  *   private static class Sync extends AbstractQueuedSynchronizer {
- *     // Reports whether in locked state
- *     protected boolean isHeldExclusively() {
- *       return getState() == 1;
- *     }
- *
  *     // Acquires the lock if state is zero
  *     public boolean tryAcquire(int acquires) {
  *       assert acquires == 1; // Otherwise unused
@@ -220,14 +214,27 @@
  *     // Releases the lock by setting state to zero
  *     protected boolean tryRelease(int releases) {
  *       assert releases == 1; // Otherwise unused
- *       if (getState() == 0) throw new IllegalMonitorStateException();
+ *       if (!isHeldExclusively())
+ *         throw new IllegalMonitorStateException();
  *       setExclusiveOwnerThread(null);
  *       setState(0);
  *       return true;
  *     }
  *
+ *     // Reports whether in locked state
+ *     public boolean isLocked() {
+ *       return getState() != 0;
+ *     }
+ *
+ *     public boolean isHeldExclusively() {
+ *       // a data race, but safe due to out-of-thin-air guarantees
+ *       return getExclusiveOwnerThread() == Thread.currentThread();
+ *     }
+ *
  *     // Provides a Condition
- *     Condition newCondition() { return new ConditionObject(); }
+ *     public Condition newCondition() {
+ *       return new ConditionObject();
+ *     }
  *
  *     // Deserializes properly
  *     private void readObject(ObjectInputStream s)
@@ -240,12 +247,17 @@
  *   // The sync object does all the hard work. We just forward to it.
  *   private final Sync sync = new Sync();
  *
- *   public void lock()                { sync.acquire(1); }
- *   public boolean tryLock()          { return sync.tryAcquire(1); }
- *   public void unlock()              { sync.release(1); }
- *   public Condition newCondition()   { return sync.newCondition(); }
- *   public boolean isLocked()         { return sync.isHeldExclusively(); }
- *   public boolean hasQueuedThreads() { return sync.hasQueuedThreads(); }
+ *   public void lock()              { sync.acquire(1); }
+ *   public boolean tryLock()        { return sync.tryAcquire(1); }
+ *   public void unlock()            { sync.release(1); }
+ *   public Condition newCondition() { return sync.newCondition(); }
+ *   public boolean isLocked()       { return sync.isLocked(); }
+ *   public boolean isHeldByCurrentThread() {
+ *     return sync.isHeldExclusively();
+ *   }
+ *   public boolean hasQueuedThreads() {
+ *     return sync.hasQueuedThreads();
+ *   }
  *   public void lockInterruptibly() throws InterruptedException {
  *     sync.acquireInterruptibly(1);
  *   }
@@ -1193,8 +1205,7 @@
     /**
      * Returns {@code true} if synchronization is held exclusively with
      * respect to the current (calling) thread.  This method is invoked
-     * upon each call to a non-waiting {@link ConditionObject} method.
-     * (Waiting methods instead invoke {@link #release}.)
+     * upon each call to a {@link ConditionObject} method.
      *
      * <p>The default implementation throws {@link
      * UnsupportedOperationException}. This method is invoked
@@ -1834,9 +1845,8 @@
     }
 
     /**
-     * Condition implementation for a {@link
-     * AbstractQueuedSynchronizer} serving as the basis of a {@link
-     * Lock} implementation.
+     * Condition implementation for a {@link AbstractQueuedSynchronizer}
+     * serving as the basis of a {@link Lock} implementation.
      *
      * <p>Method documentation for this class describes mechanics,
      * not behavioral specifications from the point of view of Lock
@@ -1867,6 +1877,8 @@
          * @return its new wait node
          */
         private Node addConditionWaiter() {
+            if (!isHeldExclusively())
+                throw new IllegalMonitorStateException();
             Node t = lastWaiter;
             // If lastWaiter is cancelled, clean out.
             if (t != null && t.waitStatus != Node.CONDITION) {
--- a/src/java.base/share/classes/java/util/concurrent/locks/Condition.java	Wed Oct 04 11:52:07 2017 -0700
+++ b/src/java.base/share/classes/java/util/concurrent/locks/Condition.java	Wed Oct 04 20:01:19 2017 +0000
@@ -73,7 +73,7 @@
  * available in the buffer. This can be achieved using two
  * {@link Condition} instances.
  * <pre>
- * class BoundedBuffer {
+ * class BoundedBuffer&lt;E&gt; {
  *   <b>final Lock lock = new ReentrantLock();</b>
  *   final Condition notFull  = <b>lock.newCondition(); </b>
  *   final Condition notEmpty = <b>lock.newCondition(); </b>
@@ -81,7 +81,7 @@
  *   final Object[] items = new Object[100];
  *   int putptr, takeptr, count;
  *
- *   public void put(Object x) throws InterruptedException {
+ *   public void put(E x) throws InterruptedException {
  *     <b>lock.lock();
  *     try {</b>
  *       while (count == items.length)
@@ -95,12 +95,12 @@
  *     }</b>
  *   }
  *
- *   public Object take() throws InterruptedException {
+ *   public E take() throws InterruptedException {
  *     <b>lock.lock();
  *     try {</b>
  *       while (count == 0)
  *         <b>notEmpty.await();</b>
- *       Object x = items[takeptr];
+ *       E x = (E) items[takeptr];
  *       if (++takeptr == items.length) takeptr = 0;
  *       --count;
  *       <b>notFull.signal();</b>
@@ -310,7 +310,8 @@
      * the following form:
      *
      * <pre> {@code
-     * boolean aMethod(long timeout, TimeUnit unit) {
+     * boolean aMethod(long timeout, TimeUnit unit)
+     *     throws InterruptedException {
      *   long nanos = unit.toNanos(timeout);
      *   lock.lock();
      *   try {
@@ -320,6 +321,7 @@
      *       nanos = theCondition.awaitNanos(nanos);
      *     }
      *     // ...
+     *     return true;
      *   } finally {
      *     lock.unlock();
      *   }
@@ -410,7 +412,8 @@
      * <p>The return value indicates whether the deadline has elapsed,
      * which can be used as follows:
      * <pre> {@code
-     * boolean aMethod(Date deadline) {
+     * boolean aMethod(Date deadline)
+     *     throws InterruptedException {
      *   boolean stillWaiting = true;
      *   lock.lock();
      *   try {
@@ -420,6 +423,7 @@
      *       stillWaiting = theCondition.awaitUntil(deadline);
      *     }
      *     // ...
+     *     return true;
      *   } finally {
      *     lock.unlock();
      *   }
--- a/src/java.base/share/classes/java/util/concurrent/locks/StampedLock.java	Wed Oct 04 11:52:07 2017 -0700
+++ b/src/java.base/share/classes/java/util/concurrent/locks/StampedLock.java	Wed Oct 04 20:01:19 2017 +0000
@@ -151,18 +151,20 @@
  *   }
  *
  *   double distanceFromOrigin() { // A read-only method
+ *     double currentX, currentY;
  *     long stamp = sl.tryOptimisticRead();
- *     double currentX = x, currentY = y;
- *     if (!sl.validate(stamp)) {
- *       stamp = sl.readLock();
+ *     do {
+ *       if (stamp == 0L)
+ *         stamp = sl.readLock();
  *       try {
+ *         // possibly racy reads
  *         currentX = x;
  *         currentY = y;
  *       } finally {
- *         sl.unlockRead(stamp);
+ *         stamp = sl.tryConvertToOptimisticRead(stamp);
  *       }
- *     }
- *     return Math.sqrt(currentX * currentX + currentY * currentY);
+ *     } while (stamp == 0);
+ *     return Math.hypot(currentX, currentY);
  *   }
  *
  *   void moveIfAtOrigin(double newX, double newY) { // upgrade
--- a/src/java.base/share/classes/jdk/internal/misc/JavaLangInvokeAccess.java	Wed Oct 04 11:52:07 2017 -0700
+++ b/src/java.base/share/classes/jdk/internal/misc/JavaLangInvokeAccess.java	Wed Oct 04 20:01:19 2017 +0000
@@ -40,6 +40,18 @@
     String getName(Object mname);
 
     /**
+     * Returns the {@code MethodType} for the given MemberName.
+     * Used by {@see StackFrameInfo}.
+     */
+    MethodType getMethodType(Object mname);
+
+    /**
+     * Returns the descriptor for the given MemberName.
+     * Used by {@see StackFrameInfo}.
+     */
+    String getMethodDescriptor(Object mname);
+
+    /**
      * Returns {@code true} if the given MemberName is a native method. Used by
      * {@see StackFrameInfo}.
      */
--- a/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java	Wed Oct 04 11:52:07 2017 -0700
+++ b/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java	Wed Oct 04 20:01:19 2017 +0000
@@ -1802,7 +1802,12 @@
                 try {
                     readRecord(true);
                 } catch (SocketTimeoutException e) {
-                    // if time out, ignore the exception and continue
+                    if ((debug != null) && Debug.isOn("ssl")) {
+                        System.out.println(
+                            Thread.currentThread().getName() +
+                            ", received Exception: " + e);
+                    }
+                    fatal((byte)(-1), "Did not receive close_notify from peer", e);
                 }
             }
         } catch (IOException e) {
--- a/src/java.base/share/classes/sun/security/util/ManifestDigester.java	Wed Oct 04 11:52:07 2017 -0700
+++ b/src/java.base/share/classes/sun/security/util/ManifestDigester.java	Wed Oct 04 20:01:19 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2017, 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,6 +28,7 @@
 import java.security.*;
 import java.util.HashMap;
 import java.io.ByteArrayOutputStream;
+import static java.nio.charset.StandardCharsets.UTF_8;
 
 /**
  * This class is used to compute digests on sections of the Manifest.
@@ -112,8 +113,6 @@
         rawBytes = bytes;
         entries = new HashMap<>();
 
-        ByteArrayOutputStream baos = new ByteArrayOutputStream();
-
         Position pos = new Position();
 
         if (!findSection(0, pos))
@@ -131,50 +130,41 @@
 
             if (len > 6) {
                 if (isNameAttr(bytes, start)) {
-                    StringBuilder nameBuf = new StringBuilder(sectionLen);
+                    ByteArrayOutputStream nameBuf = new ByteArrayOutputStream();
+                    nameBuf.write(bytes, start+6, len-6);
 
-                    try {
-                        nameBuf.append(
-                            new String(bytes, start+6, len-6, "UTF8"));
+                    int i = start + len;
+                    if ((i-start) < sectionLen) {
+                        if (bytes[i] == '\r') {
+                            i += 2;
+                        } else {
+                            i += 1;
+                        }
+                    }
 
-                        int i = start + len;
-                        if ((i-start) < sectionLen) {
-                            if (bytes[i] == '\r') {
-                                i += 2;
-                            } else {
-                                i += 1;
-                            }
+                    while ((i-start) < sectionLen) {
+                        if (bytes[i++] == ' ') {
+                            // name is wrapped
+                            int wrapStart = i;
+                            while (((i-start) < sectionLen)
+                                    && (bytes[i++] != '\n'));
+                            if (bytes[i-1] != '\n')
+                                return; // XXX: exception?
+                            int wrapLen;
+                            if (bytes[i-2] == '\r')
+                                wrapLen = i-wrapStart-2;
+                            else
+                                wrapLen = i-wrapStart-1;
+
+                            nameBuf.write(bytes, wrapStart, wrapLen);
+                        } else {
+                            break;
                         }
+                    }
 
-                        while ((i-start) < sectionLen) {
-                            if (bytes[i++] == ' ') {
-                                // name is wrapped
-                                int wrapStart = i;
-                                while (((i-start) < sectionLen)
-                                        && (bytes[i++] != '\n'));
-                                    if (bytes[i-1] != '\n')
-                                        return; // XXX: exception?
-                                    int wrapLen;
-                                    if (bytes[i-2] == '\r')
-                                        wrapLen = i-wrapStart-2;
-                                    else
-                                        wrapLen = i-wrapStart-1;
-
-                            nameBuf.append(new String(bytes, wrapStart,
-                                                      wrapLen, "UTF8"));
-                            } else {
-                                break;
-                            }
-                        }
-
-                        entries.put(nameBuf.toString(),
-                            new Entry(start, sectionLen, sectionLenWithBlank,
+                    entries.put(new String(nameBuf.toByteArray(), UTF_8),
+                        new Entry(start, sectionLen, sectionLenWithBlank,
                                 rawBytes));
-
-                    } catch (java.io.UnsupportedEncodingException uee) {
-                        throw new IllegalStateException(
-                            "UTF8 not available on platform");
-                    }
                 }
             }
             start = pos.startOfNext;
--- a/src/java.base/share/lib/security/default.policy	Wed Oct 04 11:52:07 2017 -0700
+++ b/src/java.base/share/lib/security/default.policy	Wed Oct 04 20:01:19 2017 +0000
@@ -142,6 +142,10 @@
     permission java.security.AllPermission;
 };
 
+grant codeBase "jrt:/jdk.httpserver" {
+    permission java.security.AllPermission;
+};
+
 grant codeBase "jrt:/jdk.internal.le" {
     permission java.security.AllPermission;
 };
--- a/src/java.base/unix/native/libnet/PlainSocketImpl.c	Wed Oct 04 11:52:07 2017 -0700
+++ b/src/java.base/unix/native/libnet/PlainSocketImpl.c	Wed Oct 04 20:01:19 2017 +0000
@@ -679,14 +679,16 @@
         }
 
         /* ECONNABORTED or EWOULDBLOCK error so adjust timeout if there is one. */
-        currNanoTime = JVM_NanoTime(env, 0);
-        nanoTimeout -= (currNanoTime - prevNanoTime);
-        if (nanoTimeout < NET_NSEC_PER_MSEC) {
-            JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
-                    "Accept timed out");
-            return;
+        if (nanoTimeout >= NET_NSEC_PER_MSEC) {
+            currNanoTime = JVM_NanoTime(env, 0);
+            nanoTimeout -= (currNanoTime - prevNanoTime);
+            if (nanoTimeout < NET_NSEC_PER_MSEC) {
+                JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
+                        "Accept timed out");
+                return;
+            }
+            prevNanoTime = currNanoTime;
         }
-        prevNanoTime = currNanoTime;
     }
 
     if (newfd < 0) {
--- a/src/java.base/windows/native/libjava/io_util_md.c	Wed Oct 04 11:52:07 2017 -0700
+++ b/src/java.base/windows/native/libjava/io_util_md.c	Wed Oct 04 20:01:19 2017 +0000
@@ -550,10 +550,10 @@
 fileDescriptorClose(JNIEnv *env, jobject this)
 {
     FD fd = (*env)->GetLongField(env, this, IO_handle_fdID);
+    HANDLE h = (HANDLE)fd;
     if ((*env)->ExceptionOccurred(env)) {
         return;
     }
-    HANDLE h = (HANDLE)fd;
 
     if (h == INVALID_HANDLE_VALUE) {
         return;
--- a/src/java.compiler/share/classes/javax/lang/model/SourceVersion.java	Wed Oct 04 11:52:07 2017 -0700
+++ b/src/java.compiler/share/classes/javax/lang/model/SourceVersion.java	Wed Oct 04 20:01:19 2017 +0000
@@ -216,8 +216,9 @@
      * Character#isJavaIdentifierStart(int)} returns {@code true},
      * followed only by characters for which {@link
      * Character#isJavaIdentifierPart(int)} returns {@code true}.
-     * This pattern matches regular identifiers, keywords, and the
-     * literals {@code "true"}, {@code "false"}, and {@code "null"}.
+     * This pattern matches regular identifiers, keywords, restricted
+     * keywords, and the literals {@code "true"}, {@code "false"}, and
+     * {@code "null"}.
      * The method returns {@code false} for all other strings.
      *
      * @param name the string to check
@@ -251,10 +252,13 @@
      * qualified name in the latest source version.  Unlike {@link
      * #isIdentifier isIdentifier}, this method returns {@code false}
      * for keywords, boolean literals, and the null literal.
+     * This method returns {@code true} for <i>restricted
+     * keywords</i>.
      *
      * @param name the string to check
      * @return {@code true} if this string is a
      * syntactically valid name, {@code false} otherwise.
+     * @jls 3.9 Keywords
      * @jls 6.2 Names and Identifiers
      */
     public static boolean isName(CharSequence name) {
@@ -266,11 +270,14 @@
      * qualified name in the given source version.  Unlike {@link
      * #isIdentifier isIdentifier}, this method returns {@code false}
      * for keywords, boolean literals, and the null literal.
+     * This method returns {@code true} for <i>restricted
+     * keywords</i>.
      *
      * @param name the string to check
      * @param version the version to use
      * @return {@code true} if this string is a
      * syntactically valid name, {@code false} otherwise.
+     * @jls 3.9 Keywords
      * @jls 6.2 Names and Identifiers
      * @since 9
      */
@@ -287,6 +294,8 @@
     /**
      * Returns whether or not {@code s} is a keyword, boolean literal,
      * or null literal in the latest source version.
+     * This method returns {@code false} for <i>restricted
+     * keywords</i>.
      *
      * @param s the string to check
      * @return {@code true} if {@code s} is a keyword, or boolean
@@ -302,6 +311,8 @@
     /**
      * Returns whether or not {@code s} is a keyword, boolean literal,
      * or null literal in the given source version.
+     * This method returns {@code false} for <i>restricted
+     * keywords</i>.
      *
      * @param s the string to check
      * @param version the version to use
--- a/src/java.compiler/share/classes/javax/lang/model/element/ModuleElement.java	Wed Oct 04 11:52:07 2017 -0700
+++ b/src/java.compiler/share/classes/javax/lang/model/element/ModuleElement.java	Wed Oct 04 20:01:19 2017 +0000
@@ -87,7 +87,7 @@
      *
      * @return {@code true} if this is an open module and {@code
      * false} otherwise
-     */ // TODO: add @jls to unnamed module section
+     */
     boolean isOpen();
 
     /**
@@ -96,7 +96,9 @@
      *
      * @return {@code true} if this is an unnamed module and {@code
      * false} otherwise
-     */ // TODO: add @jls to unnamed module section
+     *
+     * @jls 7.7.5 Unnamed Modules
+     */
     boolean isUnnamed();
 
     /**
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Kinds.java	Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Kinds.java	Wed Oct 04 20:01:19 2017 +0000
@@ -71,6 +71,7 @@
         HIDDEN(Category.RESOLUTION_TARGET),                            // not overloaded   non-target
         STATICERR(Category.RESOLUTION_TARGET),                         // overloaded?      target
         MISSING_ENCL(Category.RESOLUTION),                             // not overloaded   non-target
+        BAD_VAR(Category.RESOLUTION),                                  // not overloaded   non-target
         ABSENT_VAR(Category.RESOLUTION_TARGET, KindName.VAR),          // not overloaded   non-target
         WRONG_MTHS(Category.RESOLUTION_TARGET, KindName.METHOD),       // overloaded       target
         WRONG_MTH(Category.RESOLUTION_TARGET, KindName.METHOD),        // not overloaded   target
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Source.java	Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Source.java	Wed Oct 04 20:01:19 2017 +0000
@@ -227,6 +227,7 @@
         return compareTo(JDK1_8) <= 0;
     }
     public boolean allowPrivateInterfaceMethods() { return compareTo(JDK1_9) >= 0; }
+    public boolean allowLocalVariableTypeInference() { return compareTo(JDK1_10) >= 0; }
     public static SourceVersion toSourceVersion(Source source) {
         switch(source) {
         case JDK1_2:
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Type.java	Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Type.java	Wed Oct 04 20:01:19 2017 +0000
@@ -1616,6 +1616,7 @@
 
         public TypeVar(Name name, Symbol owner, Type lower) {
             super(null, TypeMetadata.EMPTY);
+            Assert.checkNonNull(lower);
             tsym = new TypeVariableSymbol(0, name, this, owner);
             this.bound = null;
             this.lower = lower;
@@ -1628,6 +1629,7 @@
         public TypeVar(TypeSymbol tsym, Type bound, Type lower,
                        TypeMetadata metadata) {
             super(tsym, metadata);
+            Assert.checkNonNull(lower);
             this.bound = bound;
             this.lower = lower;
         }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeAnnotations.java	Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeAnnotations.java	Wed Oct 04 20:01:19 2017 +0000
@@ -1247,7 +1247,9 @@
                 final TypeAnnotationPosition pos =
                     TypeAnnotationPosition.localVariable(currentLambda,
                                                          tree.pos);
-                separateAnnotationsKinds(tree.vartype, tree.sym.type, tree.sym, pos);
+                if (!tree.isImplicitlyTyped()) {
+                    separateAnnotationsKinds(tree.vartype, tree.sym.type, tree.sym, pos);
+                }
             } else if (tree.sym.getKind() == ElementKind.EXCEPTION_PARAMETER) {
                 final TypeAnnotationPosition pos =
                     TypeAnnotationPosition.exceptionParameter(currentLambda,
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java	Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java	Wed Oct 04 20:01:19 2017 +0000
@@ -190,6 +190,245 @@
     }
     // </editor-fold>
 
+    // <editor-fold defaultstate="collapsed" desc="projections">
+
+    /**
+     * A projection kind. See {@link TypeProjection}
+     */
+    enum ProjectionKind {
+        UPWARDS() {
+            @Override
+            ProjectionKind complement() {
+                return DOWNWARDS;
+            }
+        },
+        DOWNWARDS() {
+            @Override
+            ProjectionKind complement() {
+                return UPWARDS;
+            }
+        };
+
+        abstract ProjectionKind complement();
+    }
+
+    /**
+     * This visitor performs upwards and downwards projections on types.
+     *
+     * A projection is defined as a function that takes a type T, a set of type variables V and that
+     * produces another type S.
+     *
+     * An upwards projection maps a type T into a type S such that (i) T has no variables in V,
+     * and (ii) S is an upper bound of T.
+     *
+     * A downwards projection maps a type T into a type S such that (i) T has no variables in V,
+     * and (ii) S is a lower bound of T.
+     *
+     * Note that projections are only allowed to touch variables in V. Theferore it is possible for
+     * a projection to leave its input type unchanged if it does not contain any variables in V.
+     *
+     * Moreover, note that while an upwards projection is always defined (every type as an upper bound),
+     * a downwards projection is not always defined.
+     *
+     * Examples:
+     *
+     * {@code upwards(List<#CAP1>, [#CAP1]) = List<? extends String>, where #CAP1 <: String }
+     * {@code downwards(List<#CAP2>, [#CAP2]) = List<? super String>, where #CAP2 :> String }
+     * {@code upwards(List<#CAP1>, [#CAP2]) = List<#CAP1> }
+     * {@code downwards(List<#CAP1>, [#CAP1]) = not defined }
+     */
+    class TypeProjection extends StructuralTypeMapping<ProjectionKind> {
+
+        List<Type> vars;
+        Set<Type> seen = new HashSet<>();
+
+        public TypeProjection(List<Type> vars) {
+            this.vars = vars;
+        }
+
+        @Override
+        public Type visitClassType(ClassType t, ProjectionKind pkind) {
+            if (t.isCompound()) {
+                List<Type> components = directSupertypes(t);
+                List<Type> components1 = components.map(c -> c.map(this, pkind));
+                if (components == components1) return t;
+                else return makeIntersectionType(components1);
+            } else {
+                Type outer = t.getEnclosingType();
+                Type outer1 = visit(outer, pkind);
+                List<Type> typarams = t.getTypeArguments();
+                List<Type> typarams1 = typarams.map(ta -> mapTypeArgument(ta, pkind));
+                if (typarams1.stream().anyMatch(ta -> ta.hasTag(BOT))) {
+                    //not defined
+                    return syms.botType;
+                }
+                if (outer1 == outer && typarams1 == typarams) return t;
+                else return new ClassType(outer1, typarams1, t.tsym, t.getMetadata()) {
+                    @Override
+                    protected boolean needsStripping() {
+                        return true;
+                    }
+                };
+            }
+        }
+
+        protected Type makeWildcard(Type upper, Type lower) {
+            BoundKind bk;
+            Type bound;
+            if (upper.hasTag(BOT)) {
+                upper = syms.objectType;
+            }
+            boolean isUpperObject = isSameType(upper, syms.objectType);
+            if (!lower.hasTag(BOT) && isUpperObject) {
+                bound = lower;
+                bk = SUPER;
+            } else {
+                bound = upper;
+                bk = isUpperObject ? UNBOUND : EXTENDS;
+            }
+            return new WildcardType(bound, bk, syms.boundClass);
+        }
+
+        @Override
+        public Type visitTypeVar(TypeVar t, ProjectionKind pkind) {
+            if (vars.contains(t)) {
+                try {
+                    if (seen.add(t)) {
+                        final Type bound;
+                        switch (pkind) {
+                            case UPWARDS:
+                                bound = t.getUpperBound();
+                                break;
+                            case DOWNWARDS:
+                                bound = (t.getLowerBound() == null) ?
+                                        syms.botType :
+                                        t.getLowerBound();
+                                break;
+                            default:
+                                Assert.error();
+                                return null;
+                        }
+                        return bound.map(this, pkind);
+                    } else {
+                        //cycle
+                        return syms.objectType;
+                    }
+                } finally {
+                    seen.remove(t);
+                }
+            } else {
+                return t;
+            }
+        }
+
+        @Override
+        public Type visitWildcardType(WildcardType wt, ProjectionKind pkind) {
+            switch (pkind) {
+                case UPWARDS:
+                    return wt.isExtendsBound() ?
+                            wt.type.map(this, pkind) :
+                            syms.objectType;
+                case DOWNWARDS:
+                    return wt.isSuperBound() ?
+                            wt.type.map(this, pkind) :
+                            syms.botType;
+                default:
+                    Assert.error();
+                    return null;
+            }
+        }
+
+        private Type mapTypeArgument(Type t, ProjectionKind pkind) {
+            if (!t.containsAny(vars)) {
+                return t;
+            } else if (!t.hasTag(WILDCARD) && pkind == ProjectionKind.DOWNWARDS) {
+                //not defined
+                return syms.botType;
+            } else {
+                Type upper = t.map(this, pkind);
+                Type lower = t.map(this, pkind.complement());
+                return makeWildcard(upper, lower);
+            }
+        }
+    }
+
+    /**
+     * Computes an upward projection of given type, and vars. See {@link TypeProjection}.
+     *
+     * @param t the type to be projected
+     * @param vars the set of type variables to be mapped
+     * @return the type obtained as result of the projection
+     */
+    public Type upward(Type t, List<Type> vars) {
+        return t.map(new TypeProjection(vars), ProjectionKind.UPWARDS);
+    }
+
+    /**
+     * Computes the set of captured variables mentioned in a given type. See {@link CaptureScanner}.
+     * This routine is typically used to computed the input set of variables to be used during
+     * an upwards projection (see {@link Types#upward(Type, List)}).
+     *
+     * @param t the type where occurrences of captured variables have to be found
+     * @return the set of captured variables found in t
+     */
+    public List<Type> captures(Type t) {
+        CaptureScanner cs = new CaptureScanner();
+        Set<Type> captures = new HashSet<>();
+        cs.visit(t, captures);
+        return List.from(captures);
+    }
+
+    /**
+     * This visitor scans a type recursively looking for occurrences of captured type variables.
+     */
+    class CaptureScanner extends SimpleVisitor<Void, Set<Type>> {
+
+        @Override
+        public Void visitType(Type t, Set<Type> types) {
+            return null;
+        }
+
+        @Override
+        public Void visitClassType(ClassType t, Set<Type> seen) {
+            if (t.isCompound()) {
+                directSupertypes(t).forEach(s -> visit(s, seen));
+            } else {
+                t.allparams().forEach(ta -> visit(ta, seen));
+            }
+            return null;
+        }
+
+        @Override
+        public Void visitArrayType(ArrayType t, Set<Type> seen) {
+            return visit(t.elemtype, seen);
+        }
+
+        @Override
+        public Void visitWildcardType(WildcardType t, Set<Type> seen) {
+            visit(t.type, seen);
+            return null;
+        }
+
+        @Override
+        public Void visitTypeVar(TypeVar t, Set<Type> seen) {
+            if ((t.tsym.flags() & Flags.SYNTHETIC) != 0 && seen.add(t)) {
+                visit(t.getUpperBound(), seen);
+            }
+            return null;
+        }
+
+        @Override
+        public Void visitCapturedType(CapturedType t, Set<Type> seen) {
+            if (seen.add(t)) {
+                visit(t.getUpperBound(), seen);
+                visit(t.getLowerBound(), seen);
+            }
+            return null;
+        }
+    }
+
+    // </editor-fold>
+
     // <editor-fold defaultstate="collapsed" desc="isUnbounded">
     /**
      * Checks that all the arguments to a class are unbounded
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Analyzer.java	Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Analyzer.java	Wed Oct 04 20:01:19 2017 +0000
@@ -83,6 +83,7 @@
 import static com.sun.tools.javac.code.Flags.GENERATEDCONSTR;
 import static com.sun.tools.javac.code.TypeTag.CLASS;
 import static com.sun.tools.javac.tree.JCTree.Tag.APPLY;
+import static com.sun.tools.javac.tree.JCTree.Tag.FOREACHLOOP;
 import static com.sun.tools.javac.tree.JCTree.Tag.LABELLED;
 import static com.sun.tools.javac.tree.JCTree.Tag.METHODDEF;
 import static com.sun.tools.javac.tree.JCTree.Tag.NEWCLASS;
@@ -139,7 +140,8 @@
     enum AnalyzerMode {
         DIAMOND("diamond", Source::allowDiamond),
         LAMBDA("lambda", Source::allowLambda),
-        METHOD("method", Source::allowGraphInference);
+        METHOD("method", Source::allowGraphInference),
+        LOCAL("local", Source::allowLocalVariableTypeInference);
 
         final String opt;
         final Predicate<Source> sourceFilter;
@@ -341,11 +343,91 @@
         }
     }
 
+    /**
+     * Base class for local variable inference analyzers.
+     */
+    abstract class RedundantLocalVarTypeAnalyzerBase<X extends JCStatement> extends StatementAnalyzer<X, X> {
+
+        RedundantLocalVarTypeAnalyzerBase(JCTree.Tag tag) {
+            super(AnalyzerMode.LOCAL, tag);
+        }
+
+        /**
+         * Map a variable tree into a new declaration using implicit type.
+         */
+        JCVariableDecl mapVar(JCVariableDecl oldTree, JCVariableDecl newTree){
+            newTree.vartype = null;
+            return newTree;
+        }
+
+        /**
+         * Analyze results of local variable inference.
+         */
+        void processVar(JCVariableDecl oldTree, JCVariableDecl newTree, boolean hasErrors){
+            if (!hasErrors) {
+                if (types.isSameType(oldTree.type, newTree.type)) {
+                    log.warning(oldTree, Warnings.LocalRedundantType);
+                }
+            }
+        }
+    }
+
+    /**
+     * This analyzer checks if a local variable declaration has redundant type.
+     */
+    class RedundantLocalVarTypeAnalyzer extends RedundantLocalVarTypeAnalyzerBase<JCVariableDecl> {
+
+        RedundantLocalVarTypeAnalyzer() {
+            super(VARDEF);
+        }
+
+        boolean match(JCVariableDecl tree){
+            return tree.sym.owner.kind == Kind.MTH &&
+                    tree.init != null && !tree.isImplicitlyTyped() &&
+                    attr.canInferLocalVarType(tree) == null;
+        }
+        @Override
+        JCVariableDecl map(JCVariableDecl oldTree, JCVariableDecl newTree){
+            return mapVar(oldTree, newTree);
+        }
+        @Override
+        void process(JCVariableDecl oldTree, JCVariableDecl newTree, boolean hasErrors){
+            processVar(oldTree, newTree, hasErrors);
+        }
+    }
+
+    /**
+     * This analyzer checks if a for each variable declaration has redundant type.
+     */
+    class RedundantLocalVarTypeAnalyzerForEach extends RedundantLocalVarTypeAnalyzerBase<JCEnhancedForLoop> {
+
+        RedundantLocalVarTypeAnalyzerForEach() {
+            super(FOREACHLOOP);
+        }
+
+        @Override
+        boolean match(JCEnhancedForLoop tree){
+            return !tree.var.isImplicitlyTyped();
+        }
+        @Override
+        JCEnhancedForLoop map(JCEnhancedForLoop oldTree, JCEnhancedForLoop newTree){
+            newTree.var = mapVar(oldTree.var, newTree.var);
+            newTree.body = make.Block(0, List.nil()); //ignore body for analysis purpose
+            return newTree;
+        }
+        @Override
+        void process(JCEnhancedForLoop oldTree, JCEnhancedForLoop newTree, boolean hasErrors){
+            processVar(oldTree.var, newTree.var, hasErrors);
+        }
+    }
+
     @SuppressWarnings({"unchecked", "rawtypes"})
     StatementAnalyzer<JCTree, JCTree>[] analyzers = new StatementAnalyzer[] {
             new DiamondInitializer(),
             new LambdaAnalyzer(),
-            new RedundantTypeArgAnalyzer()
+            new RedundantTypeArgAnalyzer(),
+            new RedundantLocalVarTypeAnalyzer(),
+            new RedundantLocalVarTypeAnalyzerForEach()
     };
 
     /**
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Annotate.java	Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Annotate.java	Wed Oct 04 20:01:19 2017 +0000
@@ -28,9 +28,11 @@
 import com.sun.tools.javac.code.*;
 import com.sun.tools.javac.code.Attribute.Compound;
 import com.sun.tools.javac.code.Attribute.TypeCompound;
+import com.sun.tools.javac.code.Kinds.KindSelector;
 import com.sun.tools.javac.code.Scope.WriteableScope;
 import com.sun.tools.javac.code.Symbol.*;
 import com.sun.tools.javac.code.TypeMetadata.Entry.Kind;
+import com.sun.tools.javac.comp.Check.CheckContext;
 import com.sun.tools.javac.resources.CompilerProperties.Errors;
 import com.sun.tools.javac.tree.JCTree;
 import com.sun.tools.javac.tree.JCTree.*;
@@ -602,7 +604,7 @@
     }
 
     private Attribute getAnnotationEnumValue(Type expectedElementType, JCExpression tree, Env<AttrContext> env) {
-        Type result = attr.attribExpr(tree, env, expectedElementType);
+        Type result = attr.attribTree(tree, env, annotationValueInfo(expectedElementType));
         Symbol sym = TreeInfo.symbol(tree);
         if (sym == null ||
                 TreeInfo.nonstaticSelect(tree) ||
@@ -616,7 +618,7 @@
     }
 
     private Attribute getAnnotationClassValue(Type expectedElementType, JCExpression tree, Env<AttrContext> env) {
-        Type result = attr.attribExpr(tree, env, expectedElementType);
+        Type result = attr.attribTree(tree, env, annotationValueInfo(expectedElementType));
         if (result.isErroneous()) {
             // Does it look like an unresolved class literal?
             if (TreeInfo.name(tree) == names._class &&
@@ -642,7 +644,7 @@
     }
 
     private Attribute getAnnotationPrimitiveValue(Type expectedElementType, JCExpression tree, Env<AttrContext> env) {
-        Type result = attr.attribExpr(tree, env, expectedElementType);
+        Type result = attr.attribTree(tree, env, annotationValueInfo(expectedElementType));
         if (result.isErroneous())
             return new Attribute.Error(result.getOriginalType());
         if (result.constValue() == null) {
@@ -653,6 +655,22 @@
         return new Attribute.Constant(expectedElementType, result.constValue());
     }
 
+    private Attr.ResultInfo annotationValueInfo(Type pt) {
+        return attr.unknownExprInfo.dup(pt, new AnnotationValueContext(attr.unknownExprInfo.checkContext));
+    }
+
+    class AnnotationValueContext extends Check.NestedCheckContext {
+        AnnotationValueContext(CheckContext enclosingContext) {
+            super(enclosingContext);
+        }
+
+        @Override
+        public boolean compatible(Type found, Type req, Warner warn) {
+            //handle non-final implicitly-typed vars (will be rejected later on)
+            return found.hasTag(TypeTag.NONE) || super.compatible(found, req, warn);
+        }
+    }
+
     private Attribute getAnnotationArrayValue(Type expectedElementType, JCExpression tree, Env<AttrContext> env) {
         // Special case, implicit array
         if (!tree.hasTag(NEWARRAY)) {
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java	Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java	Wed Oct 04 20:01:19 2017 +0000
@@ -36,7 +36,6 @@
 import com.sun.source.tree.TreeVisitor;
 import com.sun.source.util.SimpleTreeVisitor;
 import com.sun.tools.javac.code.*;
-import com.sun.tools.javac.code.Directive.RequiresFlag;
 import com.sun.tools.javac.code.Lint.LintCategory;
 import com.sun.tools.javac.code.Scope.WriteableScope;
 import com.sun.tools.javac.code.Symbol.*;
@@ -46,7 +45,6 @@
 import com.sun.tools.javac.comp.ArgumentAttr.LocalCacheContext;
 import com.sun.tools.javac.comp.Check.CheckContext;
 import com.sun.tools.javac.comp.DeferredAttr.AttrMode;
-import com.sun.tools.javac.comp.Infer.FreeTypeListener;
 import com.sun.tools.javac.jvm.*;
 import static com.sun.tools.javac.resources.CompilerProperties.Fragments.Diamond;
 import static com.sun.tools.javac.resources.CompilerProperties.Fragments.DiamondInvalidArg;
@@ -830,6 +828,10 @@
         final JavaFileObject prevSource = log.useSource(env.toplevel.sourcefile);
         try {
             Type itype = attribExpr(variable.init, env, type);
+            if (variable.isImplicitlyTyped()) {
+                //fixup local variable type
+                type = variable.type = variable.sym.type = chk.checkLocalVarType(variable, itype.baseType(), variable.name);
+            }
             if (itype.constValue() != null) {
                 return coerce(itype, type).constValue();
             } else {
@@ -1108,6 +1110,21 @@
                 // parameters have already been entered
                 env.info.scope.enter(tree.sym);
             } else {
+                if (tree.isImplicitlyTyped() && (tree.getModifiers().flags & PARAMETER) == 0) {
+                    if (tree.init == null) {
+                        //cannot use 'var' without initializer
+                        log.error(tree, Errors.CantInferLocalVarType(tree.name, Fragments.LocalMissingInit));
+                        tree.vartype = make.Erroneous();
+                    } else {
+                        Fragment msg = canInferLocalVarType(tree);
+                        if (msg != null) {
+                            //cannot use 'var' with initializer which require an explicit target
+                            //(e.g. lambda, method reference, array initializer).
+                            log.error(tree, Errors.CantInferLocalVarType(tree.name, msg));
+                            tree.vartype = make.Erroneous();
+                        }
+                    }
+                }
                 try {
                     annotate.blockAnnotations();
                     memberEnter.memberEnter(tree, env);
@@ -1131,7 +1148,7 @@
         boolean isImplicitLambdaParameter = env.tree.hasTag(LAMBDA) &&
                 ((JCLambda)env.tree).paramKind == JCLambda.ParameterKind.IMPLICIT &&
                 (tree.sym.flags() & PARAMETER) != 0;
-        chk.validate(tree.vartype, env, !isImplicitLambdaParameter);
+        chk.validate(tree.vartype, env, !isImplicitLambdaParameter && !tree.isImplicitlyTyped());
 
         try {
             v.getConstValue(); // ensure compile-time constant initializer is evaluated
@@ -1152,6 +1169,10 @@
                     // marking the variable as undefined.
                     initEnv.info.enclVar = v;
                     attribExpr(tree.init, initEnv, v.type);
+                    if (tree.isImplicitlyTyped()) {
+                        //fixup local variable type
+                        v.type = chk.checkLocalVarType(tree, tree.init.type.baseType(), tree.name);
+                    }
                 }
             }
             result = tree.type = v.type;
@@ -1161,6 +1182,71 @@
         }
     }
 
+    Fragment canInferLocalVarType(JCVariableDecl tree) {
+        LocalInitScanner lis = new LocalInitScanner();
+        lis.scan(tree.init);
+        return lis.badInferenceMsg;
+    }
+
+    static class LocalInitScanner extends TreeScanner {
+        Fragment badInferenceMsg = null;
+        boolean needsTarget = true;
+
+        @Override
+        public void visitNewArray(JCNewArray tree) {
+            if (tree.elemtype == null && needsTarget) {
+                badInferenceMsg = Fragments.LocalArrayMissingTarget;
+            }
+        }
+
+        @Override
+        public void visitLambda(JCLambda tree) {
+            if (needsTarget) {
+                badInferenceMsg = Fragments.LocalLambdaMissingTarget;
+            }
+        }
+
+        @Override
+        public void visitTypeCast(JCTypeCast tree) {
+            boolean prevNeedsTarget = needsTarget;
+            try {
+                needsTarget = false;
+                super.visitTypeCast(tree);
+            } finally {
+                needsTarget = prevNeedsTarget;
+            }
+        }
+
+        @Override
+        public void visitReference(JCMemberReference tree) {
+            if (needsTarget) {
+                badInferenceMsg = Fragments.LocalMrefMissingTarget;
+            }
+        }
+
+        @Override
+        public void visitNewClass(JCNewClass tree) {
+            boolean prevNeedsTarget = needsTarget;
+            try {
+                needsTarget = false;
+                super.visitNewClass(tree);
+            } finally {
+                needsTarget = prevNeedsTarget;
+            }
+        }
+
+        @Override
+        public void visitApply(JCMethodInvocation tree) {
+            boolean prevNeedsTarget = needsTarget;
+            try {
+                needsTarget = false;
+                super.visitApply(tree);
+            } finally {
+                needsTarget = prevNeedsTarget;
+            }
+        }
+    }
+
     public void visitSkip(JCSkip tree) {
         result = null;
     }
@@ -1243,7 +1329,6 @@
             //attributing the for-each expression; we mimick this by attributing
             //the for-each expression first (against original scope).
             Type exprType = types.cvarUpperBound(attribExpr(tree.expr, loopEnv));
-            attribStat(tree.var, loopEnv);
             chk.checkNonVoid(tree.pos(), exprType);
             Type elemtype = types.elemtype(exprType); // perhaps expr is an array?
             if (elemtype == null) {
@@ -1261,6 +1346,15 @@
                         : types.wildUpperBound(iterableParams.head);
                 }
             }
+            if (tree.var.isImplicitlyTyped()) {
+                Type inferredType = chk.checkLocalVarType(tree.var, elemtype, tree.var.name);
+                if (inferredType.isErroneous()) {
+                    tree.var.vartype = make.at(tree.var.vartype).Erroneous();
+                } else {
+                    tree.var.vartype = make.at(tree.var.vartype).Type(inferredType);
+                }
+            }
+            attribStat(tree.var, loopEnv);
             chk.checkType(tree.expr.pos(), elemtype, tree.var.sym.type);
             loopEnv.tree = tree; // before, we were not in loop!
             attribStat(tree.body, loopEnv);
@@ -2379,7 +2473,8 @@
             if (pt().hasTag(ARRAY)) {
                 elemtype = types.elemtype(pt());
             } else {
-                if (!pt().hasTag(ERROR)) {
+                if (!pt().hasTag(ERROR) &&
+                        (env.info.enclVar == null || !env.info.enclVar.type.isErroneous())) {
                     log.error(tree.pos(),
                               Errors.IllegalInitializerForType(pt()));
                 }
@@ -2404,7 +2499,7 @@
     @Override
     public void visitLambda(final JCLambda that) {
         if (pt().isErroneous() || (pt().hasTag(NONE) && pt() != Type.recoveryType)) {
-            if (pt().hasTag(NONE)) {
+            if (pt().hasTag(NONE) && (env.info.enclVar == null || !env.info.enclVar.type.isErroneous())) {
                 //lambda only allowed in assignment or method invocation/cast context
                 log.error(that.pos(), Errors.UnexpectedLambda);
             }
@@ -2837,7 +2932,7 @@
     @Override
     public void visitReference(final JCMemberReference that) {
         if (pt().isErroneous() || (pt().hasTag(NONE) && pt() != Type.recoveryType)) {
-            if (pt().hasTag(NONE)) {
+            if (pt().hasTag(NONE) && (env.info.enclVar == null || !env.info.enclVar.type.isErroneous())) {
                 //method reference only allowed in assignment or method invocation/cast context
                 log.error(that.pos(), Errors.UnexpectedMref);
             }
@@ -3811,6 +3906,14 @@
                 break;
             case VAR:
                 VarSymbol v = (VarSymbol)sym;
+
+                if (env.info.enclVar != null
+                        && v.type.hasTag(NONE)) {
+                    //self reference to implicitly typed variable declaration
+                    log.error(TreeInfo.positionFor(v, env.enclClass), Errors.CantInferLocalVarType(v.name, Fragments.LocalSelfRef));
+                    return v.type = types.createErrorType(v.type);
+                }
+
                 // Test (4): if symbol is an instance field of a raw type,
                 // which is being assigned to, issue an unchecked warning if
                 // its type changes under erasure.
@@ -4135,6 +4238,9 @@
     public void visitTypeArray(JCArrayTypeTree tree) {
         Type etype = attribType(tree.elemtype, env);
         Type type = new ArrayType(etype, syms.arrayClass);
+        if (etype.isErroneous()) {
+            type = types.createErrorType(type);
+        }
         result = check(tree, type, KindSelector.TYP, resultInfo);
     }
 
@@ -4776,7 +4882,7 @@
         }
         public void visitVarDef(final JCVariableDecl tree) {
             //System.err.println("validateTypeAnnotations.visitVarDef " + tree);
-            if (tree.sym != null && tree.sym.type != null)
+            if (tree.sym != null && tree.sym.type != null && !tree.isImplicitlyTyped())
                 validateAnnotatedType(tree.vartype, tree.sym.type);
             scan(tree.mods);
             scan(tree.vartype);
@@ -4904,17 +5010,16 @@
                     repeat = false;
                 } else if (enclTr.hasTag(JCTree.Tag.WILDCARD)) {
                     JCWildcard wc = (JCWildcard) enclTr;
-                    if (wc.getKind() == JCTree.Kind.EXTENDS_WILDCARD) {
-                        validateAnnotatedType(wc.getBound(), ((WildcardType)enclTy).getExtendsBound());
-                    } else if (wc.getKind() == JCTree.Kind.SUPER_WILDCARD) {
-                        validateAnnotatedType(wc.getBound(), ((WildcardType)enclTy).getSuperBound());
+                    if (wc.getKind() == JCTree.Kind.EXTENDS_WILDCARD ||
+                            wc.getKind() == JCTree.Kind.SUPER_WILDCARD) {
+                        validateAnnotatedType(wc.getBound(), wc.getBound().type);
                     } else {
                         // Nothing to do for UNBOUND
                     }
                     repeat = false;
                 } else if (enclTr.hasTag(TYPEARRAY)) {
                     JCArrayTypeTree art = (JCArrayTypeTree) enclTr;
-                    validateAnnotatedType(art.getType(), ((ArrayType)enclTy).getComponentType());
+                    validateAnnotatedType(art.getType(), art.elemtype.type);
                     repeat = false;
                 } else if (enclTr.hasTag(TYPEUNION)) {
                     JCTypeUnion ut = (JCTypeUnion) enclTr;
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java	Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java	Wed Oct 04 20:01:19 2017 +0000
@@ -843,26 +843,30 @@
     List<Type> checkDiamondDenotable(ClassType t) {
         ListBuffer<Type> buf = new ListBuffer<>();
         for (Type arg : t.allparams()) {
-            if (!diamondTypeChecker.visit(arg, null)) {
+            if (!checkDenotable(arg)) {
                 buf.append(arg);
             }
         }
         return buf.toList();
     }
+
+    boolean checkDenotable(Type t) {
+        return denotableChecker.visit(t, null);
+    }
         // where
 
         /** diamondTypeChecker: A type visitor that descends down the given type looking for non-denotable
          *  types. The visit methods return false as soon as a non-denotable type is encountered and true
          *  otherwise.
          */
-        private static final Types.SimpleVisitor<Boolean, Void> diamondTypeChecker = new Types.SimpleVisitor<Boolean, Void>() {
+        private static final Types.SimpleVisitor<Boolean, Void> denotableChecker = new Types.SimpleVisitor<Boolean, Void>() {
             @Override
             public Boolean visitType(Type t, Void s) {
                 return true;
             }
             @Override
             public Boolean visitClassType(ClassType t, Void s) {
-                if (t.isCompound()) {
+                if (t.isUnion() || t.isIntersection()) {
                     return false;
                 }
                 for (Type targ : t.allparams()) {
@@ -878,7 +882,7 @@
                 /* Any type variable mentioned in the inferred type must have been declared as a type parameter
                   (i.e cannot have been produced by inference (18.4))
                 */
-                return t.tsym.owner.type.getTypeArguments().contains(t);
+                return (t.tsym.flags() & SYNTHETIC) == 0;
             }
 
             @Override
@@ -941,6 +945,17 @@
                                   (allowPrivateSafeVarargs ? PRIVATE : 0) )) != 0);
         }
 
+    Type checkLocalVarType(DiagnosticPosition pos, Type t, Name name) {
+        //upward project the initializer type
+        t = types.upward(t, types.captures(t));
+        //check that resulting type is not the null type
+        if (t.hasTag(BOT)) {
+            log.error(pos, Errors.CantInferLocalVarType(name, Fragments.LocalCantInferNull));
+            return types.createErrorType(t);
+        }
+        return t;
+    }
+
     Type checkMethod(final Type mtype,
             final Symbol sym,
             final Env<AttrContext> env,
@@ -3159,7 +3174,10 @@
                 if (s.kind == PCK)
                     return true;
             } else if (target == names.TYPE_USE) {
-                if (s.kind == TYP || s.kind == VAR ||
+                if (s.kind == VAR && s.owner.kind == MTH && s.type.hasTag(NONE)) {
+                    //cannot type annotate implictly typed locals
+                    return false;
+                } else if (s.kind == TYP || s.kind == VAR ||
                         (s.kind == MTH && !s.isConstructor() &&
                                 !s.type.getReturnType().hasTag(VOID)) ||
                         (s.kind == MTH && s.isConstructor())) {
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Infer.java	Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Infer.java	Wed Oct 04 20:01:19 2017 +0000
@@ -529,7 +529,7 @@
             List<Type> upperBounds = uv.getBounds(InferenceBound.UPPER);
             if (Type.containsAny(upperBounds, vars)) {
                 TypeSymbol fresh_tvar = new TypeVariableSymbol(Flags.SYNTHETIC, uv.qtype.tsym.name, null, uv.qtype.tsym.owner);
-                fresh_tvar.type = new TypeVar(fresh_tvar, types.makeIntersectionType(uv.getBounds(InferenceBound.UPPER)), null);
+                fresh_tvar.type = new TypeVar(fresh_tvar, types.makeIntersectionType(uv.getBounds(InferenceBound.UPPER)), syms.botType);
                 todo.append(uv);
                 uv.setInst(fresh_tvar.type);
             } else if (upperBounds.nonEmpty()) {
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/MemberEnter.java	Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/MemberEnter.java	Wed Oct 04 20:01:19 2017 +0000
@@ -259,7 +259,7 @@
         try {
             if (TreeInfo.isEnumInit(tree)) {
                 attr.attribIdentAsEnumType(localEnv, (JCIdent)tree.vartype);
-            } else {
+            } else if (!tree.isImplicitlyTyped()) {
                 attr.attribType(tree.vartype, localEnv);
                 if (TreeInfo.isReceiverParam(tree))
                     checkReceiver(tree, localEnv);
@@ -279,8 +279,8 @@
             tree.vartype.type = atype.makeVarargs();
         }
         WriteableScope enclScope = enter.enterScope(env);
-        VarSymbol v =
-            new VarSymbol(0, tree.name, tree.vartype.type, enclScope.owner);
+        Type vartype = tree.isImplicitlyTyped() ? Type.noType : tree.vartype.type;
+        VarSymbol v = new VarSymbol(0, tree.name, vartype, enclScope.owner);
         v.flags_field = chk.checkFlags(tree.pos(), tree.mods.flags, v, tree);
         tree.sym = v;
         if (tree.init != null) {
@@ -298,7 +298,9 @@
         }
 
         annotate.annotateLater(tree.mods.annotations, localEnv, v, tree.pos());
-        annotate.queueScanTreeAndTypeAnnotate(tree.vartype, localEnv, v, tree.pos());
+        if (!tree.isImplicitlyTyped()) {
+            annotate.queueScanTreeAndTypeAnnotate(tree.vartype, localEnv, v, tree.pos());
+        }
 
         v.pos = tree.pos;
     }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java	Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java	Wed Oct 04 20:01:19 2017 +0000
@@ -59,6 +59,7 @@
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.LinkedHashMap;
+import java.util.LinkedList;
 import java.util.Map;
 import java.util.Set;
 import java.util.function.BiFunction;
@@ -105,6 +106,7 @@
     public final boolean allowModules;
     public final boolean checkVarargsAccessAfterResolution;
     private final boolean compactMethodDiags;
+    private final boolean allowLocalVariableTypeInference;
     final EnumSet<VerboseResolutionMode> verboseResolutionMode;
 
     WriteableScope polymorphicSignatureScope;
@@ -116,7 +118,7 @@
         varNotFound = new SymbolNotFoundError(ABSENT_VAR);
         methodNotFound = new SymbolNotFoundError(ABSENT_MTH);
         typeNotFound = new SymbolNotFoundError(ABSENT_TYP);
-        referenceNotFound = new ReferenceLookupResult(methodNotFound, null);
+        referenceNotFound = ReferenceLookupResult.error(methodNotFound);
 
         names = Names.instance(context);
         log = Log.instance(context);
@@ -136,6 +138,7 @@
         Target target = Target.instance(context);
         allowMethodHandles = target.hasMethodHandles();
         allowFunctionalInterfaceMostSpecific = source.allowFunctionalInterfaceMostSpecific();
+        allowLocalVariableTypeInference = source.allowLocalVariableTypeInference();
         checkVarargsAccessAfterResolution =
                 source.allowPostApplicabilityVarargsAccessCheck();
         polymorphicSignatureScope = WriteableScope.create(syms.noSymbol);
@@ -2325,6 +2328,10 @@
      *                   (a subset of VAL, TYP, PCK).
      */
     Symbol findIdent(Env<AttrContext> env, Name name, KindSelector kind) {
+        return checkVarType(findIdentInternal(env, name, kind), name);
+    }
+
+    Symbol findIdentInternal(Env<AttrContext> env, Name name, KindSelector kind) {
         Symbol bestSoFar = typeNotFound;
         Symbol sym;
 
@@ -2354,6 +2361,11 @@
      */
     Symbol findIdentInPackage(Env<AttrContext> env, TypeSymbol pck,
                               Name name, KindSelector kind) {
+        return checkVarType(findIdentInPackageInternal(env, pck, name, kind), name);
+    }
+
+    Symbol findIdentInPackageInternal(Env<AttrContext> env, TypeSymbol pck,
+                              Name name, KindSelector kind) {
         Name fullname = TypeSymbol.formFullName(name, pck);
         Symbol bestSoFar = typeNotFound;
         if (kind.contains(KindSelector.TYP)) {
@@ -2383,6 +2395,11 @@
      */
     Symbol findIdentInType(Env<AttrContext> env, Type site,
                            Name name, KindSelector kind) {
+        return checkVarType(findIdentInTypeInternal(env, site, name, kind), name);
+    }
+
+    Symbol findIdentInTypeInternal(Env<AttrContext> env, Type site,
+                           Name name, KindSelector kind) {
         Symbol bestSoFar = typeNotFound;
         Symbol sym;
         if (kind.contains(KindSelector.VAL)) {
@@ -2399,6 +2416,14 @@
         return bestSoFar;
     }
 
+    private Symbol checkVarType(Symbol bestSoFar, Name name) {
+        if (allowLocalVariableTypeInference && name.equals(names.var) &&
+                (bestSoFar.kind == TYP || bestSoFar.kind == ABSENT_TYP)) {
+            bestSoFar = new BadVarTypeError();
+        }
+        return bestSoFar;
+    }
+
 /* ***************************************************************************
  *  Access checking
  *  The following methods convert ResolveErrors to ErrorSymbols, issuing
@@ -2944,10 +2969,10 @@
 
         //merge results
         Pair<Symbol, ReferenceLookupHelper> res;
-        Symbol bestSym = referenceChooser.result(boundRes, unboundRes);
-        res = new Pair<>(bestSym,
-                bestSym == unboundSym ? unboundLookupHelper : boundLookupHelper);
-        env.info.pendingResolutionPhase = bestSym == unboundSym ?
+        ReferenceLookupResult bestRes = referenceChooser.result(boundRes, unboundRes);
+        res = new Pair<>(bestRes.sym,
+                bestRes == unboundRes ? unboundLookupHelper : boundLookupHelper);
+        env.info.pendingResolutionPhase = bestRes == unboundRes ?
                 unboundEnv.info.pendingResolutionPhase :
                 boundEnv.info.pendingResolutionPhase;
 
@@ -3003,11 +3028,15 @@
         Symbol sym;
 
         ReferenceLookupResult(Symbol sym, MethodResolutionContext resolutionContext) {
-            this.staticKind = staticKind(sym, resolutionContext);
+            this(sym, staticKind(sym, resolutionContext));
+        }
+
+        private ReferenceLookupResult(Symbol sym, StaticKind staticKind) {
+            this.staticKind = staticKind;
             this.sym = sym;
         }
 
-        private StaticKind staticKind(Symbol sym, MethodResolutionContext resolutionContext) {
+        private static StaticKind staticKind(Symbol sym, MethodResolutionContext resolutionContext) {
             switch (sym.kind) {
                 case MTH:
                 case AMBIGUOUS:
@@ -3056,6 +3085,10 @@
                     return false;
             }
         }
+
+        static ReferenceLookupResult error(Symbol sym) {
+            return new ReferenceLookupResult(sym, StaticKind.UNDEFINED);
+        }
     }
 
     /**
@@ -3068,7 +3101,7 @@
          * Generate a result from a pair of lookup result objects. This method delegates to the
          * appropriate result generation routine.
          */
-        Symbol result(ReferenceLookupResult boundRes, ReferenceLookupResult unboundRes) {
+        ReferenceLookupResult result(ReferenceLookupResult boundRes, ReferenceLookupResult unboundRes) {
             return unboundRes != referenceNotFound ?
                     unboundResult(boundRes, unboundRes) :
                     boundResult(boundRes);
@@ -3077,12 +3110,12 @@
         /**
          * Generate a symbol from a given bound lookup result.
          */
-        abstract Symbol boundResult(ReferenceLookupResult boundRes);
+        abstract ReferenceLookupResult boundResult(ReferenceLookupResult boundRes);
 
         /**
          * Generate a symbol from a pair of bound/unbound lookup results.
          */
-        abstract Symbol unboundResult(ReferenceLookupResult boundRes, ReferenceLookupResult unboundRes);
+        abstract ReferenceLookupResult unboundResult(ReferenceLookupResult boundRes, ReferenceLookupResult unboundRes);
     }
 
     /**
@@ -3092,37 +3125,38 @@
     ReferenceChooser basicReferenceChooser = new ReferenceChooser() {
 
         @Override
-        Symbol boundResult(ReferenceLookupResult boundRes) {
+        ReferenceLookupResult boundResult(ReferenceLookupResult boundRes) {
             return !boundRes.isSuccess() || boundRes.hasKind(StaticKind.NON_STATIC) ?
-                    boundRes.sym : //the search produces a non-static method
-                    new BadMethodReferenceError(boundRes.sym, false);
+                    boundRes : //the search produces a non-static method
+                    ReferenceLookupResult.error(new BadMethodReferenceError(boundRes.sym, false));
         }
 
         @Override
-        Symbol unboundResult(ReferenceLookupResult boundRes, ReferenceLookupResult unboundRes) {
+        ReferenceLookupResult unboundResult(ReferenceLookupResult boundRes, ReferenceLookupResult unboundRes) {
             if (boundRes.hasKind(StaticKind.STATIC) &&
                     (!unboundRes.isSuccess() || unboundRes.hasKind(StaticKind.STATIC))) {
                 //the first search produces a static method and no non-static method is applicable
                 //during the second search
-                return boundRes.sym;
+                return boundRes;
             } else if (unboundRes.hasKind(StaticKind.NON_STATIC) &&
                     (!boundRes.isSuccess() || boundRes.hasKind(StaticKind.NON_STATIC))) {
                 //the second search produces a non-static method and no static method is applicable
                 //during the first search
-                return unboundRes.sym;
+                return unboundRes;
             } else if (boundRes.isSuccess() && unboundRes.isSuccess()) {
                 //both searches produce some result; ambiguity (error recovery)
-                return ambiguityError(boundRes.sym, unboundRes.sym);
+                return ReferenceLookupResult.error(ambiguityError(boundRes.sym, unboundRes.sym));
             } else if (boundRes.isSuccess() || unboundRes.isSuccess()) {
                 //Both searches failed to produce a result with correct staticness (i.e. first search
                 //produces an non-static method). Alternatively, a given search produced a result
                 //with the right staticness, but the other search has applicable methods with wrong
                 //staticness (error recovery)
-                return new BadMethodReferenceError(boundRes.isSuccess() ? boundRes.sym : unboundRes.sym, true);
+                return ReferenceLookupResult.error(new BadMethodReferenceError(boundRes.isSuccess() ?
+                        boundRes.sym : unboundRes.sym, true));
             } else {
                 //both searches fail to produce a result - pick 'better' error using heuristics (error recovery)
                 return (boundRes.canIgnore() && !unboundRes.canIgnore()) ?
-                        unboundRes.sym : boundRes.sym;
+                        unboundRes : boundRes;
             }
         }
     };
@@ -3134,28 +3168,29 @@
     ReferenceChooser structuralReferenceChooser = new ReferenceChooser() {
 
         @Override
-        Symbol boundResult(ReferenceLookupResult boundRes) {
+        ReferenceLookupResult boundResult(ReferenceLookupResult boundRes) {
             return (!boundRes.isSuccess() || !boundRes.hasKind(StaticKind.STATIC)) ?
-                    boundRes.sym : //the search has at least one applicable non-static method
-                    new BadMethodReferenceError(boundRes.sym, false);
+                    boundRes : //the search has at least one applicable non-static method
+                    ReferenceLookupResult.error(new BadMethodReferenceError(boundRes.sym, false));
         }
 
         @Override
-        Symbol unboundResult(ReferenceLookupResult boundRes, ReferenceLookupResult unboundRes) {
+        ReferenceLookupResult unboundResult(ReferenceLookupResult boundRes, ReferenceLookupResult unboundRes) {
             if (boundRes.isSuccess() && !boundRes.hasKind(StaticKind.NON_STATIC)) {
                 //the first serach has at least one applicable static method
-                return boundRes.sym;
+                return boundRes;
             } else if (unboundRes.isSuccess() && !unboundRes.hasKind(StaticKind.STATIC)) {
                 //the second search has at least one applicable non-static method
-                return unboundRes.sym;
+                return unboundRes;
             } else if (boundRes.isSuccess() || unboundRes.isSuccess()) {
                 //either the first search produces a non-static method, or second search produces
                 //a non-static method (error recovery)
-                return new BadMethodReferenceError(boundRes.isSuccess() ? boundRes.sym : unboundRes.sym, true);
+                return ReferenceLookupResult.error(new BadMethodReferenceError(boundRes.isSuccess() ?
+                        boundRes.sym : unboundRes.sym, true));
             } else {
                 //both searches fail to produce a result - pick 'better' error using heuristics (error recovery)
                 return (boundRes.canIgnore() && !unboundRes.canIgnore()) ?
-                        unboundRes.sym : boundRes.sym;
+                        unboundRes : boundRes;
             }
         }
     };
@@ -3774,6 +3809,17 @@
         }
     }
 
+    class BadVarTypeError extends ResolveError {
+        BadVarTypeError() {
+            super(Kind.BAD_VAR, "bad var use");
+        }
+
+        @Override
+        JCDiagnostic getDiagnostic(DiagnosticType dkind, DiagnosticPosition pos, Symbol location, Type site, Name name, List<Type> argtypes, List<Type> typeargtypes) {
+            return diags.create(dkind, log.currentSource(), pos, "illegal.ref.to.var.type", name);
+        }
+    }
+
     /**
      * InvalidSymbolError error class indicating that a symbol matching a
      * given name does not exists in a given site.
@@ -3995,14 +4041,35 @@
         }
         //where
             private Map<Symbol, JCDiagnostic> mapCandidates() {
-                Map<Symbol, JCDiagnostic> candidates = new LinkedHashMap<>();
+                MostSpecificMap candidates = new MostSpecificMap();
                 for (Candidate c : resolveContext.candidates) {
                     if (c.isApplicable()) continue;
-                    candidates.put(c.sym, c.details);
+                    candidates.put(c);
                 }
                 return candidates;
             }
 
+            @SuppressWarnings("serial")
+            private class MostSpecificMap extends LinkedHashMap<Symbol, JCDiagnostic> {
+                private void put(Candidate c) {
+                    ListBuffer<Symbol> overridden = new ListBuffer<>();
+                    for (Symbol s : keySet()) {
+                        if (s == c.sym) {
+                            continue;
+                        }
+                        if (c.sym.overrides(s, (TypeSymbol)s.owner, types, false)) {
+                            overridden.add(s);
+                        } else if (s.overrides(c.sym, (TypeSymbol)c.sym.owner, types, false)) {
+                            return;
+                        }
+                    }
+                    for (Symbol s : overridden) {
+                        remove(s);
+                    }
+                    put(c.sym, c.details);
+                }
+            }
+
             Map<Symbol, JCDiagnostic> filterCandidates(Map<Symbol, JCDiagnostic> candidatesMap) {
                 Map<Symbol, JCDiagnostic> candidates = new LinkedHashMap<>();
                 for (Map.Entry<Symbol, JCDiagnostic> _entry : candidatesMap.entrySet()) {
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java	Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java	Wed Oct 04 20:01:19 2017 +0000
@@ -179,6 +179,7 @@
         this.allowAnnotationsAfterTypeParams = source.allowAnnotationsAfterTypeParams();
         this.allowUnderscoreIdentifier = source.allowUnderscoreIdentifier();
         this.allowPrivateInterfaceMethods = source.allowPrivateInterfaceMethods();
+        this.allowLocalVariableTypeInference = source.allowLocalVariableTypeInference();
         this.keepDocComments = keepDocComments;
         this.parseModuleInfo = parseModuleInfo;
         docComments = newDocCommentTable(keepDocComments, fac);
@@ -270,11 +271,14 @@
      */
     boolean allowThisIdent;
 
+    /** Switch: is local variable inference allowed?
+     */
+    boolean allowLocalVariableTypeInference;
+
     /** The type of the method receiver, as specified by a first "this" parameter.
      */
     JCVariableDecl receiverParam;
 
-
     /** When terms are parsed, the mode determines which is expected:
      *     mode = EXPR        : an expression
      *     mode = TYPE        : a type
@@ -808,12 +812,16 @@
      * parsing annotations.
      */
     public JCExpression parseType() {
+        return parseType(false);
+    }
+
+    public JCExpression parseType(boolean allowVar) {
         List<JCAnnotation> annotations = typeAnnotationsOpt();
-        return parseType(annotations);
+        return parseType(allowVar, annotations);
     }
 
-    public JCExpression parseType(List<JCAnnotation> annotations) {
-        JCExpression result = unannotatedType();
+    public JCExpression parseType(boolean allowVar, List<JCAnnotation> annotations) {
+        JCExpression result = unannotatedType(allowVar);
 
         if (annotations.nonEmpty()) {
             result = insertAnnotationsToMostInner(result, annotations, false);
@@ -822,10 +830,18 @@
         return result;
     }
 
-    public JCExpression unannotatedType() {
-        return term(TYPE);
+    public JCExpression unannotatedType(boolean allowVar) {
+        JCExpression result = term(TYPE);
+
+        if (!allowVar && isRestrictedLocalVarTypeName(result)) {
+            syntaxError(result.pos, "var.not.allowed.here");
+        }
+
+        return result;
     }
 
+
+
     protected JCExpression term(int newmode) {
         int prevmode = mode;
         mode = newmode;
@@ -1152,11 +1168,11 @@
                        accept(LPAREN);
                        mode = TYPE;
                        int pos1 = pos;
-                       List<JCExpression> targets = List.of(t = term3());
+                       List<JCExpression> targets = List.of(t = parseType());
                        while (token.kind == AMP) {
                            checkIntersectionTypesInCast();
                            accept(AMP);
-                           targets = targets.prepend(term3());
+                           targets = targets.prepend(parseType());
                        }
                        if (targets.length() > 1) {
                            t = toP(F.at(pos1).TypeIntersection(targets.reverse()));
@@ -1912,7 +1928,7 @@
      */
     JCExpression typeArgument() {
         List<JCAnnotation> annotations = typeAnnotationsOpt();
-        if (token.kind != QUES) return parseType(annotations);
+        if (token.kind != QUES) return parseType(false, annotations);
         int pos = token.pos;
         nextToken();
         JCExpression result;
@@ -2425,13 +2441,8 @@
                 token.kind == ENUM) {
                 return List.of(classOrInterfaceOrEnumDeclaration(mods, dc));
             } else {
-                JCExpression t = parseType();
-                ListBuffer<JCStatement> stats =
-                        variableDeclarators(mods, t, new ListBuffer<JCStatement>());
-                // A "LocalVariableDeclarationStatement" subsumes the terminating semicolon
-                accept(SEMI);
-                storeEnd(stats.last(), S.prevToken().endPos);
-                return stats.toList();
+                JCExpression t = parseType(true);
+                return localVariableDeclarations(mods, t);
             }
         }
         case ABSTRACT: case STRICTFP: {
@@ -2458,12 +2469,7 @@
                 pos = token.pos;
                 JCModifiers mods = F.at(Position.NOPOS).Modifiers(0);
                 F.at(pos);
-                ListBuffer<JCStatement> stats =
-                        variableDeclarators(mods, t, new ListBuffer<JCStatement>());
-                // A "LocalVariableDeclarationStatement" subsumes the terminating semicolon
-                accept(SEMI);
-                storeEnd(stats.last(), S.prevToken().endPos);
-                return stats.toList();
+                return localVariableDeclarations(mods, t);
             } else {
                 // This Exec is an "ExpressionStatement"; it subsumes the terminating semicolon
                 t = checkExprStat(t);
@@ -2473,6 +2479,15 @@
             }
         }
     }
+    //where
+        private List<JCStatement> localVariableDeclarations(JCModifiers mods, JCExpression type) {
+            ListBuffer<JCStatement> stats =
+                    variableDeclarators(mods, type, new ListBuffer<>(), true);
+            // A "LocalVariableDeclarationStatement" subsumes the terminating semicolon
+            accept(SEMI);
+            storeEnd(stats.last(), S.prevToken().endPos);
+            return stats.toList();
+        }
 
     /** Statement =
      *       Block
@@ -2766,11 +2781,11 @@
         ListBuffer<JCStatement> stats = new ListBuffer<>();
         int pos = token.pos;
         if (token.kind == FINAL || token.kind == MONKEYS_AT) {
-            return variableDeclarators(optFinal(0), parseType(), stats).toList();
+            return variableDeclarators(optFinal(0), parseType(true), stats, true).toList();
         } else {
             JCExpression t = term(EXPR | TYPE);
             if ((lastmode & TYPE) != 0 && LAX_IDENTIFIER.accepts(token.kind)) {
-                return variableDeclarators(modifiersOpt(), t, stats).toList();
+                return variableDeclarators(modifiersOpt(), t, stats, true).toList();
             } else if ((lastmode & TYPE) != 0 && token.kind == COLON) {
                 error(pos, "bad.initializer", "for-loop");
                 return List.of((JCStatement)F.at(pos).VarDef(null, null, t, null));
@@ -2989,9 +3004,10 @@
      */
     public <T extends ListBuffer<? super JCVariableDecl>> T variableDeclarators(JCModifiers mods,
                                                                          JCExpression type,
-                                                                         T vdefs)
+                                                                         T vdefs,
+                                                                         boolean localDecl)
     {
-        return variableDeclaratorsRest(token.pos, mods, type, ident(), false, null, vdefs);
+        return variableDeclaratorsRest(token.pos, mods, type, ident(), false, null, vdefs, localDecl);
     }
 
     /** VariableDeclaratorsRest = VariableDeclaratorRest { "," VariableDeclarator }
@@ -3006,14 +3022,20 @@
                                                                      Name name,
                                                                      boolean reqInit,
                                                                      Comment dc,
-                                                                     T vdefs)
+                                                                     T vdefs,
+                                                                     boolean localDecl)
     {
-        vdefs.append(variableDeclaratorRest(pos, mods, type, name, reqInit, dc));
+        JCVariableDecl head = variableDeclaratorRest(pos, mods, type, name, reqInit, dc, localDecl);
+        boolean implicit = allowLocalVariableTypeInference && head.vartype == null;
+        vdefs.append(head);
         while (token.kind == COMMA) {
+            if (implicit) {
+                reportSyntaxError(pos, "var.not.allowed.compound");
+            }
             // All but last of multiple declarators subsume a comma
             storeEnd((JCTree)vdefs.last(), token.endPos);
             nextToken();
-            vdefs.append(variableDeclarator(mods, type, reqInit, dc));
+            vdefs.append(variableDeclarator(mods, type, reqInit, dc, localDecl));
         }
         return vdefs;
     }
@@ -3021,8 +3043,8 @@
     /** VariableDeclarator = Ident VariableDeclaratorRest
      *  ConstantDeclarator = Ident ConstantDeclaratorRest
      */
-    JCVariableDecl variableDeclarator(JCModifiers mods, JCExpression type, boolean reqInit, Comment dc) {
-        return variableDeclaratorRest(token.pos, mods, type, ident(), reqInit, dc);
+    JCVariableDecl variableDeclarator(JCModifiers mods, JCExpression type, boolean reqInit, Comment dc, boolean localDecl) {
+        return variableDeclaratorRest(token.pos, mods, type, ident(), reqInit, dc, localDecl);
     }
 
     /** VariableDeclaratorRest = BracketsOpt ["=" VariableInitializer]
@@ -3032,7 +3054,7 @@
      *  @param dc       The documentation comment for the variable declarations, or null.
      */
     JCVariableDecl variableDeclaratorRest(int pos, JCModifiers mods, JCExpression type, Name name,
-                                  boolean reqInit, Comment dc) {
+                                  boolean reqInit, Comment dc, boolean localDecl) {
         type = bracketsOpt(type);
         JCExpression init = null;
         if (token.kind == EQ) {
@@ -3040,12 +3062,40 @@
             init = variableInitializer();
         }
         else if (reqInit) syntaxError(token.pos, "expected", EQ);
+        JCTree elemType = TreeInfo.innermostType(type, true);
+        if (allowLocalVariableTypeInference && elemType.hasTag(IDENT)) {
+            Name typeName = ((JCIdent)elemType).name;
+            if (isRestrictedLocalVarTypeName(typeName)) {
+                if (type.hasTag(TYPEARRAY)) {
+                    //error - 'var' and arrays
+                    reportSyntaxError(pos, "var.not.allowed.array");
+                } else {
+                    //implicit type
+                    type = null;
+                }
+            }
+        }
         JCVariableDecl result =
             toP(F.at(pos).VarDef(mods, name, type, init));
         attach(result, dc);
         return result;
     }
 
+    boolean isRestrictedLocalVarTypeName(JCExpression e) {
+        switch (e.getTag()) {
+            case IDENT:
+                return isRestrictedLocalVarTypeName(((JCIdent)e).name);
+            case TYPEARRAY:
+                return isRestrictedLocalVarTypeName(((JCArrayTypeTree)e).elemtype);
+            default:
+                return false;
+        }
+    }
+
+    boolean isRestrictedLocalVarTypeName(Name name) {
+        return allowLocalVariableTypeInference && name == names.var;
+    }
+
     /** VariableDeclaratorId = Ident BracketsOpt
      */
     JCVariableDecl variableDeclaratorId(JCModifiers mods, JCExpression type) {
@@ -3111,13 +3161,13 @@
         int startPos = token.pos;
         if (token.kind == FINAL || token.kind == MONKEYS_AT) {
             JCModifiers mods = optFinal(Flags.FINAL);
-            JCExpression t = parseType();
-            return variableDeclaratorRest(token.pos, mods, t, ident(), true, null);
+            JCExpression t = parseType(true);
+            return variableDeclaratorRest(token.pos, mods, t, ident(), true, null, true);
         }
         JCExpression t = term(EXPR | TYPE);
         if ((lastmode & TYPE) != 0 && LAX_IDENTIFIER.accepts(token.kind)) {
             JCModifiers mods = toP(F.at(startPos).Modifiers(Flags.FINAL));
-            return variableDeclaratorRest(token.pos, mods, t, ident(), true, null);
+            return variableDeclaratorRest(token.pos, mods, t, ident(), true, null, true);
         } else {
             checkVariableInTryWithResources(startPos);
             if (!t.hasTag(IDENT) && !t.hasTag(SELECT)) {
@@ -3397,7 +3447,7 @@
     protected JCClassDecl classDeclaration(JCModifiers mods, Comment dc) {
         int pos = token.pos;
         accept(CLASS);
-        Name name = ident();
+        Name name = typeName();
 
         List<JCTypeParameter> typarams = typeParametersOpt();
 
@@ -3418,6 +3468,15 @@
         return result;
     }
 
+    Name typeName() {
+        int pos = token.pos;
+        Name name = ident();
+        if (isRestrictedLocalVarTypeName(name)) {
+            reportSyntaxError(pos, "var.not.allowed", name);
+        }
+        return name;
+    }
+
     /** InterfaceDeclaration = INTERFACE Ident TypeParametersOpt
      *                         [EXTENDS TypeList] InterfaceBody
      *  @param mods    The modifiers starting the interface declaration
@@ -3426,7 +3485,8 @@
     protected JCClassDecl interfaceDeclaration(JCModifiers mods, Comment dc) {
         int pos = token.pos;
         accept(INTERFACE);
-        Name name = ident();
+
+        Name name = typeName();
 
         List<JCTypeParameter> typarams = typeParametersOpt();
 
@@ -3449,7 +3509,8 @@
     protected JCClassDecl enumDeclaration(JCModifiers mods, Comment dc) {
         int pos = token.pos;
         accept(ENUM);
-        Name name = ident();
+
+        Name name = typeName();
 
         List<JCExpression> implementing = List.nil();
         if (token.kind == IMPLEMENTS) {
@@ -3647,7 +3708,7 @@
                     nextToken();
                 } else {
                     // method returns types are un-annotated types
-                    type = unannotatedType();
+                    type = unannotatedType(false);
                 }
                 if (token.kind == LPAREN && !isInterface && type.hasTag(IDENT)) {
                     if (isInterface || tk.name() != className)
@@ -3667,7 +3728,7 @@
                     } else if (!isVoid && typarams.isEmpty()) {
                         List<JCTree> defs =
                             variableDeclaratorsRest(pos, mods, type, name, isInterface, dc,
-                                                    new ListBuffer<JCTree>()).toList();
+                                                    new ListBuffer<JCTree>(), false).toList();
                         accept(SEMI);
                         storeEnd(defs.last(), S.prevToken().endPos);
                         return defs;
@@ -3809,7 +3870,7 @@
     JCTypeParameter typeParameter() {
         int pos = token.pos;
         List<JCAnnotation> annos = typeAnnotationsOpt();
-        Name name = ident();
+        Name name = typeName();
         ListBuffer<JCExpression> bounds = new ListBuffer<>();
         if (token.kind == EXTENDS) {
             nextToken();
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties	Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties	Wed Oct 04 20:01:19 2017 +0000
@@ -1190,6 +1190,47 @@
 compiler.err.undef.label=\
     undefined label: {0}
 
+# 0: name (type)
+compiler.err.illegal.ref.to.var.type=\
+    illegal reference to restricted type ''{0}''
+
+# 0: token
+compiler.err.var.not.allowed=\
+    ''{0}'' not allowed here\n\
+    as of release 10, ''{0}'' is a restricted local variable type and cannot be used for type declarations
+
+# 0: name (variable), 1: message segment
+compiler.err.cant.infer.local.var.type=\
+    cannot infer type for local variable {0}\n\
+    ({1})
+
+compiler.err.var.not.allowed.here=\
+    ''var'' is not allowed here
+
+compiler.err.var.not.allowed.array=\
+    ''var'' is not allowed as an element type of an array
+
+compiler.err.var.not.allowed.compound=\
+    ''var'' is not allowed in a compound declaration
+
+compiler.misc.local.cant.infer.null=\
+    variable initializer is ''null''
+
+compiler.misc.local.missing.init=\
+    cannot use ''var'' on variable without initializer
+
+compiler.misc.local.lambda.missing.target=\
+    lambda expression needs an explicit target-type
+
+compiler.misc.local.mref.missing.target=\
+    method reference needs an explicit target-type
+
+compiler.misc.local.array.missing.target=\
+    array initializer needs an explicit target-type
+
+compiler.misc.local.self.ref=\
+    cannot use ''var'' on self-referencing variable
+
 # 0: message segment, 1: unused
 compiler.err.cant.apply.diamond=\
     cannot infer type arguments for {0}
@@ -1873,6 +1914,9 @@
 compiler.warn.diamond.redundant.args=\
     Redundant type arguments in new expression (use diamond operator instead).
 
+compiler.warn.local.redundant.type=\
+    Redundant type for local variable (replace explicit type with ''var'').
+
 compiler.warn.potential.lambda.found=\
     This anonymous inner class creation can be turned into a lambda expression.
 
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java	Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/JCTree.java	Wed Oct 04 20:01:19 2017 +0000
@@ -946,6 +946,10 @@
             }
         }
 
+        public boolean isImplicitlyTyped() {
+            return vartype == null;
+        }
+
         @Override
         public void accept(Visitor v) { v.visitVarDef(this); }
 
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/Pretty.java	Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/Pretty.java	Wed Oct 04 20:01:19 2017 +0000
@@ -1359,7 +1359,7 @@
 
     // Prints the inner element type of a nested array
     private void printBaseElementType(JCTree tree) throws IOException {
-        printExpr(TreeInfo.innermostType(tree));
+        printExpr(TreeInfo.innermostType(tree, false));
     }
 
     // prints the brackets of a nested array in reverse order
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeInfo.java	Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeInfo.java	Wed Oct 04 20:01:19 2017 +0000
@@ -1136,7 +1136,7 @@
      * For an array that contains an annotated type, return that annotated type.
      * TODO: currently only used by Pretty. Describe behavior better.
      */
-    public static JCTree innermostType(JCTree type) {
+    public static JCTree innermostType(JCTree type, boolean skipAnnos) {
         JCTree lastAnnotatedType = null;
         JCTree cur = type;
         loop: while (true) {
@@ -1157,7 +1157,7 @@
                 break loop;
             }
         }
-        if (lastAnnotatedType!=null) {
+        if (!skipAnnos && lastAnnotatedType!=null) {
             return lastAnnotatedType;
         } else {
             return cur;
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Names.java	Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Names.java	Wed Oct 04 20:01:19 2017 +0000
@@ -63,6 +63,7 @@
     public final Name _default;
     public final Name _super;
     public final Name _this;
+    public final Name var;
     public final Name exports;
     public final Name opens;
     public final Name module;
@@ -224,6 +225,7 @@
         _default = fromString("default");
         _super = fromString("super");
         _this = fromString("this");
+        var = fromString("var");
         exports = fromString("exports");
         opens = fromString("opens");
         module = fromString("module");
--- a/src/jdk.compiler/share/classes/module-info.java	Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.compiler/share/classes/module-info.java	Wed Oct 04 20:01:19 2017 +0000
@@ -106,7 +106,8 @@
     exports com.sun.tools.javac.jvm to
         jdk.javadoc;
     exports com.sun.tools.javac.main to
-        jdk.javadoc;
+        jdk.javadoc,
+        jdk.jshell;
     exports com.sun.tools.javac.model to
         jdk.javadoc;
     exports com.sun.tools.javac.parser to
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractExecutableMemberWriter.java	Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractExecutableMemberWriter.java	Wed Oct 04 20:01:19 2017 +0000
@@ -39,6 +39,7 @@
 import javax.lang.model.type.TypeVariable;
 import javax.lang.model.util.SimpleTypeVisitor9;
 
+import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder;
 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
 import jdk.javadoc.internal.doclets.toolkit.Content;
@@ -98,15 +99,19 @@
      */
     @Override
     protected Content getDeprecatedLink(Element member) {
-        StringBuilder sb = new StringBuilder();
-        sb.append(utils.getFullyQualifiedName(member));
+        Content deprecatedLinkContent = new ContentBuilder();
+        deprecatedLinkContent.addContent(utils.getFullyQualifiedName(member));
         if (!utils.isConstructor(member)) {
-            sb.append(".");
-            sb.append(member.getSimpleName());
+            deprecatedLinkContent.addContent(".");
+            deprecatedLinkContent.addContent(member.getSimpleName());
         }
-        sb.append(utils.flatSignature((ExecutableElement) member));
+        String signature = utils.flatSignature((ExecutableElement) member);
+        if (signature.length() > 2) {
+            deprecatedLinkContent.addContent(Contents.ZERO_WIDTH_SPACE);
+        }
+        deprecatedLinkContent.addContent(signature);
 
-        return writer.getDocLink(MEMBER, member, sb);
+        return writer.getDocLink(MEMBER, utils.getEnclosingTypeElement(member), member, deprecatedLinkContent);
     }
 
     /**
@@ -199,55 +204,61 @@
      */
     protected void addParameters(ExecutableElement member,
             boolean includeAnnotations, Content htmltree, int indentSize) {
-        htmltree.addContent(Contents.ZERO_WIDTH_SPACE);
-        htmltree.addContent("(");
+        Content paramTree = new ContentBuilder();
         String sep = "";
         List<? extends VariableElement> parameters = member.getParameters();
         CharSequence indent = makeSpace(indentSize + 1);
         TypeMirror rcvrType = member.getReceiverType();
         if (includeAnnotations && rcvrType != null && utils.isAnnotated(rcvrType)) {
             List<? extends AnnotationMirror> annotationMirrors = rcvrType.getAnnotationMirrors();
-            addReceiverAnnotations(member, rcvrType, annotationMirrors, htmltree);
+            addReceiverAnnotations(member, rcvrType, annotationMirrors, paramTree);
             sep = "," + DocletConstants.NL + indent;
         }
         int paramstart;
         for (paramstart = 0; paramstart < parameters.size(); paramstart++) {
-            htmltree.addContent(sep);
+            paramTree.addContent(sep);
             VariableElement param = parameters.get(paramstart);
 
             if (param.getKind() != ElementKind.INSTANCE_INIT) {
                 if (includeAnnotations) {
                     boolean foundAnnotations =
                             writer.addAnnotationInfo(indent.length(),
-                            member, param, htmltree);
+                            member, param, paramTree);
                     if (foundAnnotations) {
-                        htmltree.addContent(DocletConstants.NL);
-                        htmltree.addContent(indent);
+                        paramTree.addContent(DocletConstants.NL);
+                        paramTree.addContent(indent);
                     }
                 }
                 addParam(member, param,
-                    (paramstart == parameters.size() - 1) && member.isVarArgs(), htmltree);
+                    (paramstart == parameters.size() - 1) && member.isVarArgs(), paramTree);
                 break;
             }
         }
 
         for (int i = paramstart + 1; i < parameters.size(); i++) {
-            htmltree.addContent(",");
-            htmltree.addContent(DocletConstants.NL);
-            htmltree.addContent(indent);
+            paramTree.addContent(",");
+            paramTree.addContent(DocletConstants.NL);
+            paramTree.addContent(indent);
             if (includeAnnotations) {
                 boolean foundAnnotations =
                         writer.addAnnotationInfo(indent.length(), member, parameters.get(i),
-                        htmltree);
+                        paramTree);
                 if (foundAnnotations) {
-                    htmltree.addContent(DocletConstants.NL);
-                    htmltree.addContent(indent);
+                    paramTree.addContent(DocletConstants.NL);
+                    paramTree.addContent(indent);
                 }
             }
             addParam(member, parameters.get(i), (i == parameters.size() - 1) && member.isVarArgs(),
-                    htmltree);
+                    paramTree);
         }
-        htmltree.addContent(")");
+        if (paramTree.isEmpty()) {
+            htmltree.addContent("()");
+        } else {
+            htmltree.addContent(Contents.ZERO_WIDTH_SPACE);
+            htmltree.addContent("(");
+            htmltree.addContent(paramTree);
+            paramTree.addContent(")");
+        }
     }
 
     /**
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractIndexWriter.java	Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractIndexWriter.java	Wed Oct 04 20:01:19 2017 +0000
@@ -364,7 +364,7 @@
         List<? extends DocTree> tags;
         Content span = HtmlTree.SPAN(HtmlStyle.deprecatedLabel, getDeprecatedPhrase(element));
         HtmlTree div = new HtmlTree(HtmlTag.DIV);
-        div.addStyle(HtmlStyle.block);
+        div.addStyle(HtmlStyle.deprecationBlock);
         if (utils.isDeprecated(element)) {
             div.addContent(span);
             tags = utils.getBlockTags(element, DocTree.Kind.DEPRECATED);
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractMemberWriter.java	Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractMemberWriter.java	Wed Oct 04 20:01:19 2017 +0000
@@ -355,7 +355,7 @@
             writer.getTagletWriterInstance(false));
         if (!output.isEmpty()) {
             Content deprecatedContent = output;
-            Content div = HtmlTree.DIV(HtmlStyle.block, deprecatedContent);
+            Content div = HtmlTree.DIV(HtmlStyle.deprecationBlock, deprecatedContent);
             contentTree.addContent(div);
         }
     }
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AnnotationTypeWriterImpl.java	Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AnnotationTypeWriterImpl.java	Wed Oct 04 20:01:19 2017 +0000
@@ -278,7 +278,8 @@
      */
     @Override
     public void addAnnotationTypeSignature(String modifiers, Content annotationInfoTree) {
-        annotationInfoTree.addContent(new HtmlTree(HtmlTag.BR));
+        Content hr = new HtmlTree(HtmlTag.HR);
+        annotationInfoTree.addContent(hr);
         Content pre = new HtmlTree(HtmlTag.PRE);
         addAnnotationInfo(annotationType, pre);
         pre.addContent(modifiers);
@@ -324,18 +325,15 @@
      */
     @Override
     public void addAnnotationTypeDeprecationInfo(Content annotationInfoTree) {
-        Content hr = new HtmlTree(HtmlTag.HR);
-        annotationInfoTree.addContent(hr);
         List<? extends DocTree> deprs = utils.getBlockTags(annotationType, DocTree.Kind.DEPRECATED);
         if (utils.isDeprecated(annotationType)) {
             CommentHelper ch = utils.getCommentHelper(annotationType);
             Content deprLabel = HtmlTree.SPAN(HtmlStyle.deprecatedLabel, getDeprecatedPhrase(annotationType));
-            Content div = HtmlTree.DIV(HtmlStyle.block, deprLabel);
+            Content div = HtmlTree.DIV(HtmlStyle.deprecationBlock, deprLabel);
             if (!deprs.isEmpty()) {
 
                 List<? extends DocTree> commentTags = ch.getDescription(configuration, deprs.get(0));
                 if (!commentTags.isEmpty()) {
-                    div.addContent(Contents.SPACE);
                     addInlineDeprecatedComment(annotationType, deprs.get(0), div);
                 }
             }
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassWriterImpl.java	Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassWriterImpl.java	Wed Oct 04 20:01:19 2017 +0000
@@ -293,7 +293,8 @@
      */
     @Override
     public void addClassSignature(String modifiers, Content classInfoTree) {
-        classInfoTree.addContent(new HtmlTree(HtmlTag.BR));
+        Content hr = new HtmlTree(HtmlTag.HR);
+        classInfoTree.addContent(hr);
         Content pre = new HtmlTree(HtmlTag.PRE);
         addAnnotationInfo(typeElement, pre);
         pre.addContent(modifiers);
@@ -606,18 +607,15 @@
      */
     @Override
     public void addClassDeprecationInfo(Content classInfoTree) {
-        Content hr = new HtmlTree(HtmlTag.HR);
-        classInfoTree.addContent(hr);
         List<? extends DocTree> deprs = utils.getBlockTags(typeElement, DocTree.Kind.DEPRECATED);
         if (utils.isDeprecated(typeElement)) {
             Content deprLabel = HtmlTree.SPAN(HtmlStyle.deprecatedLabel, getDeprecatedPhrase(typeElement));
-            Content div = HtmlTree.DIV(HtmlStyle.block, deprLabel);
+            Content div = HtmlTree.DIV(HtmlStyle.deprecationBlock, deprLabel);
             if (!deprs.isEmpty()) {
                 CommentHelper ch = utils.getCommentHelper(typeElement);
                 DocTree dt = deprs.get(0);
                 List<? extends DocTree> commentTags = ch.getBody(configuration, dt);
                 if (!commentTags.isEmpty()) {
-                    div.addContent(Contents.SPACE);
                     addInlineDeprecatedComment(typeElement, deprs.get(0), div);
                 }
             }
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/DeprecatedListWriter.java	Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/DeprecatedListWriter.java	Wed Oct 04 20:01:19 2017 +0000
@@ -100,33 +100,33 @@
     private String getHeadingKey(DeprElementKind kind) {
         switch (kind) {
             case REMOVAL:
-                return "doclet.Deprecated_For_Removal";
+                return "doclet.For_Removal";
             case MODULE:
-                return "doclet.Deprecated_Modules";
+                return "doclet.Modules";
             case PACKAGE:
-                return "doclet.Deprecated_Packages";
+                return "doclet.Packages";
             case INTERFACE:
-                return "doclet.Deprecated_Interfaces";
+                return "doclet.Interfaces";
             case CLASS:
-                return "doclet.Deprecated_Classes";
+                return "doclet.Classes";
             case ENUM:
-                return "doclet.Deprecated_Enums";
+                return "doclet.Enums";
             case EXCEPTION:
-                return "doclet.Deprecated_Exceptions";
+                return "doclet.Exceptions";
             case ERROR:
-                return "doclet.Deprecated_Errors";
+                return "doclet.Errors";
             case ANNOTATION_TYPE:
-                return "doclet.Deprecated_Annotation_Types";
+                return "doclet.Annotation_Types";
             case FIELD:
-                return "doclet.Deprecated_Fields";
+                return "doclet.Fields";
             case METHOD:
-                return "doclet.Deprecated_Methods";
+                return "doclet.Methods";
             case CONSTRUCTOR:
-                return "doclet.Deprecated_Constructors";
+                return "doclet.Constructors";
             case ENUM_CONSTANT:
-                return "doclet.Deprecated_Enum_Constants";
+                return "doclet.Enum_Constants";
             case ANNOTATION_TYPE_MEMBER:
-                return "doclet.Deprecated_Annotation_Type_Members";
+                return "doclet.Annotation_Type_Members";
             default:
                 throw new AssertionError("unknown kind: " + kind);
         }
@@ -135,33 +135,33 @@
     private String getSummaryKey(DeprElementKind kind) {
         switch (kind) {
             case REMOVAL:
-                return "doclet.deprecated_for_removal";
+                return "doclet.for_removal";
             case MODULE:
-                return "doclet.deprecated_modules";
+                return "doclet.modules";
             case PACKAGE:
-                return "doclet.deprecated_packages";
+                return "doclet.packages";
             case INTERFACE:
-                return "doclet.deprecated_interfaces";
+                return "doclet.interfaces";
             case CLASS:
-                return "doclet.deprecated_classes";
+                return "doclet.classes";
             case ENUM:
-                return "doclet.deprecated_enums";
+                return "doclet.enums";
             case EXCEPTION:
-                return "doclet.deprecated_exceptions";
+                return "doclet.exceptions";
             case ERROR:
-                return "doclet.deprecated_errors";
+                return "doclet.errors";
             case ANNOTATION_TYPE:
-                return "doclet.deprecated_annotation_types";
+                return "doclet.annotation_types";
             case FIELD:
-                return "doclet.deprecated_fields";
+                return "doclet.fields";
             case METHOD:
-                return "doclet.deprecated_methods";
+                return "doclet.methods";
             case CONSTRUCTOR:
-                return "doclet.deprecated_constructors";
+                return "doclet.constructors";
             case ENUM_CONSTANT:
-                return "doclet.deprecated_enum_constants";
+                return "doclet.enum_constants";
             case ANNOTATION_TYPE_MEMBER:
-                return "doclet.deprecated_annotation_type_members";
+                return "doclet.annotation_type_members";
             default:
                 throw new AssertionError("unknown kind: " + kind);
         }
@@ -473,6 +473,6 @@
             default:
                 writer = new AnnotationTypeOptionalMemberWriterImpl(this, null);
         }
-        return HtmlTree.TH_ROW_SCOPE(HtmlStyle.colFirst, writer.getDeprecatedLink(e));
+        return HtmlTree.TH_ROW_SCOPE(HtmlStyle.colDeprecatedItemName, writer.getDeprecatedLink(e));
     }
 }
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java	Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java	Wed Oct 04 20:01:19 2017 +0000
@@ -1715,8 +1715,7 @@
         Content div;
         Content result = commentTagsToContent(null, element, tags, first);
         if (depr) {
-            Content italic = HtmlTree.SPAN(HtmlStyle.deprecationComment, result);
-            div = HtmlTree.DIV(HtmlStyle.block, italic);
+            div = HtmlTree.DIV(HtmlStyle.deprecationComment, result);
             htmltree.addContent(div);
         }
         else {
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ModuleWriterImpl.java	Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ModuleWriterImpl.java	Wed Oct 04 20:01:19 2017 +0000
@@ -929,7 +929,7 @@
         if (utils.isDeprecated(mdle)) {
             CommentHelper ch = utils.getCommentHelper(mdle);
             HtmlTree deprDiv = new HtmlTree(HtmlTag.DIV);
-            deprDiv.addStyle(HtmlStyle.deprecatedContent);
+            deprDiv.addStyle(HtmlStyle.deprecationBlock);
             Content deprPhrase = HtmlTree.SPAN(HtmlStyle.deprecatedLabel, getDeprecatedPhrase(mdle));
             deprDiv.addContent(deprPhrase);
             if (!deprs.isEmpty()) {
@@ -1064,7 +1064,7 @@
         if (utils.isDeprecated(pkg)) {
             deprs = utils.getDeprecatedTrees(pkg);
             HtmlTree deprDiv = new HtmlTree(HtmlTag.DIV);
-            deprDiv.addStyle(HtmlStyle.deprecatedContent);
+            deprDiv.addStyle(HtmlStyle.deprecationBlock);
             Content deprPhrase = HtmlTree.SPAN(HtmlStyle.deprecatedLabel, getDeprecatedPhrase(pkg));
             deprDiv.addContent(deprPhrase);
             if (!deprs.isEmpty()) {
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageWriterImpl.java	Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageWriterImpl.java	Wed Oct 04 20:01:19 2017 +0000
@@ -171,7 +171,7 @@
         if (utils.isDeprecated(packageElement)) {
             CommentHelper ch = utils.getCommentHelper(packageElement);
             HtmlTree deprDiv = new HtmlTree(HtmlTag.DIV);
-            deprDiv.addStyle(HtmlStyle.deprecatedContent);
+            deprDiv.addStyle(HtmlStyle.deprecationBlock);
             Content deprPhrase = HtmlTree.SPAN(HtmlStyle.deprecatedLabel, getDeprecatedPhrase(packageElement));
             deprDiv.addContent(deprPhrase);
             if (!deprs.isEmpty()) {
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SubWriterHolderWriter.java	Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SubWriterHolderWriter.java	Wed Oct 04 20:01:19 2017 +0000
@@ -189,9 +189,8 @@
         if (utils.isDeprecated(member)) {
             Content deprLabel = HtmlTree.SPAN(HtmlStyle.deprecatedLabel, getDeprecatedPhrase(member));
             div = HtmlTree.DIV(HtmlStyle.block, deprLabel);
-            div.addContent(Contents.SPACE);
             if (!deprs.isEmpty()) {
-                addInlineDeprecatedComment(member, deprs.get(0), div);
+                addSummaryDeprecatedComment(member, deprs.get(0), div);
             }
             tdSummary.addContent(div);
             return;
@@ -200,7 +199,6 @@
             if (te != null &&  utils.isTypeElement(te) && utils.isDeprecated(te)) {
                 Content deprLabel = HtmlTree.SPAN(HtmlStyle.deprecatedLabel, getDeprecatedPhrase(te));
                 div = HtmlTree.DIV(HtmlStyle.block, deprLabel);
-                div.addContent(Contents.SPACE);
                 tdSummary.addContent(div);
             }
         }
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/TagletWriterImpl.java	Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/TagletWriterImpl.java	Wed Oct 04 20:01:19 2017 +0000
@@ -179,7 +179,6 @@
             if (utils.isDeprecated(element)) {
                 result.addContent(HtmlTree.SPAN(HtmlStyle.deprecatedLabel,
                         htmlWriter.getDeprecatedPhrase(element)));
-                result.addContent(RawHtml.nbsp);
                 if (!deprs.isEmpty()) {
                     List<? extends DocTree> commentTags = ch.getDescription(configuration, deprs.get(0));
                     if (!commentTags.isEmpty()) {
@@ -191,19 +190,17 @@
             if (utils.isDeprecated(element)) {
                 result.addContent(HtmlTree.SPAN(HtmlStyle.deprecatedLabel,
                         htmlWriter.getDeprecatedPhrase(element)));
-                result.addContent(RawHtml.nbsp);
                 if (!deprs.isEmpty()) {
                     List<? extends DocTree> bodyTags = ch.getBody(configuration, deprs.get(0));
                     Content body = commentTagsToOutput(null, element, bodyTags, false);
                     if (!body.isEmpty())
-                        result.addContent(HtmlTree.SPAN(HtmlStyle.deprecationComment, body));
+                        result.addContent(HtmlTree.DIV(HtmlStyle.deprecationComment, body));
                 }
             } else {
                 Element ee = utils.getEnclosingTypeElement(element);
                 if (utils.isDeprecated(ee)) {
                     result.addContent(HtmlTree.SPAN(HtmlStyle.deprecatedLabel,
                         htmlWriter.getDeprecatedPhrase(ee)));
-                    result.addContent(RawHtml.nbsp);
                 }
             }
         }
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlStyle.java	Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlStyle.java	Wed Oct 04 20:01:19 2017 +0000
@@ -47,15 +47,16 @@
     circle,
     classUseContainer,
     colConstructorName,
+    colDeprecatedItemName,
     colFirst,
     colLast,
     colSecond,
     constantsSummary,
     constantValuesContainer,
     contentContainer,
-    deprecatedContent,
     deprecatedLabel,
     deprecatedSummary,
+    deprecationBlock,
     deprecationComment,
     description,
     descfrmTypeLabel,
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard.properties	Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard.properties	Wed Oct 04 20:01:19 2017 +0000
@@ -74,34 +74,12 @@
 doclet.see.class_or_package_not_accessible=Tag {0}: reference not accessible: {1}
 doclet.tag.invalid_usage=invalid usage of tag {0}
 doclet.Deprecated_API=Deprecated API
-doclet.Deprecated_For_Removal=Deprecated For Removal
-doclet.Deprecated_Modules=Deprecated Modules
-doclet.Deprecated_Packages=Deprecated Packages
-doclet.Deprecated_Classes=Deprecated Classes
-doclet.Deprecated_Enums=Deprecated Enums
-doclet.Deprecated_Interfaces=Deprecated Interfaces
-doclet.Deprecated_Exceptions=Deprecated Exceptions
-doclet.Deprecated_Annotation_Types=Deprecated Annotation Types
-doclet.Deprecated_Errors=Deprecated Errors
-doclet.Deprecated_Fields=Deprecated Fields
-doclet.Deprecated_Constructors=Deprecated Constructors
-doclet.Deprecated_Methods=Deprecated Methods
-doclet.Deprecated_Enum_Constants=Deprecated Enum Constants
-doclet.Deprecated_Annotation_Type_Members=Deprecated Annotation Type Elements
-doclet.deprecated_for_removal=deprecated for removal
-doclet.deprecated_modules=deprecated modules
-doclet.deprecated_packages=deprecated packages
-doclet.deprecated_classes=deprecated classes
-doclet.deprecated_enums=deprecated enums
-doclet.deprecated_interfaces=deprecated interfaces
-doclet.deprecated_exceptions=deprecated exceptions
-doclet.deprecated_annotation_types=deprecated annotation types
-doclet.deprecated_errors=deprecated errors
-doclet.deprecated_fields=deprecated fields
-doclet.deprecated_constructors=deprecated constructors
-doclet.deprecated_methods=deprecated methods
-doclet.deprecated_enum_constants=deprecated enum constants
-doclet.deprecated_annotation_type_members=deprecated annotation type elements
+doclet.For_Removal=For Removal
+doclet.Annotation_Types=Annotation Types
+doclet.Annotation_Type_Members=Annotation Type Elements
+doclet.for_removal=for removal
+doclet.annotation_types=annotation types
+doclet.annotation_type_members=annotation type elements
 doclet.Generated_Docs_Untitled=Generated Documentation (Untitled)
 doclet.Other_Packages=Other Packages
 doclet.Description=Description
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/AnnotationTypeBuilder.java	Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/AnnotationTypeBuilder.java	Wed Oct 04 20:01:19 2017 +0000
@@ -147,8 +147,8 @@
             throws DocletException {
         Content annotationInfoTree = writer.getAnnotationInfoTreeHeader();
 
+        buildAnnotationTypeSignature(annotationInfoTree);
         buildDeprecationInfo(annotationInfoTree);
-        buildAnnotationTypeSignature(annotationInfoTree);
         buildAnnotationTypeDescription(annotationInfoTree);
         buildAnnotationTypeTagInfo(annotationInfoTree);
 
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/ClassBuilder.java	Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/ClassBuilder.java	Wed Oct 04 20:01:19 2017 +0000
@@ -175,8 +175,8 @@
         buildInterfaceUsageInfo(classInfoTree);
         buildNestedClassInfo(classInfoTree);
         buildFunctionalInterfaceInfo(classInfoTree);
+        buildClassSignature(classInfoTree);
         buildDeprecationInfo(classInfoTree);
-        buildClassSignature(classInfoTree);
         buildClassDescription(classInfoTree);
         buildClassTagInfo(classInfoTree);
 
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/stylesheet.css	Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/resources/stylesheet.css	Wed Oct 04 20:01:19 2017 +0000
@@ -531,14 +531,16 @@
     text-align:left;
     padding:0px 0px 12px 10px;
 }
-th.colFirst, th.colSecond, th.colLast, th.colConstructorName, .useSummary th, .constantsSummary th, .packagesSummary th,
-td.colFirst, td.colSecond, td.colLast, .useSummary td, .constantsSummary td {
+th.colFirst, th.colSecond, th.colLast, th.colConstructorName, th.colDeprecatedItemName, .useSummary th,
+.constantsSummary th, .packagesSummary th, td.colFirst, td.colSecond, td.colLast, .useSummary td,
+.constantsSummary td {
     vertical-align:top;
     padding-right:0px;
     padding-top:8px;
     padding-bottom:3px;
 }
-th.colFirst, th.colSecond, th.colLast, th.colConstructorName, .constantsSummary th, .packagesSummary th {
+th.colFirst, th.colSecond, th.colLast, th.colConstructorName, th.colDeprecatedItemName, .constantsSummary th,
+.packagesSummary th {
     background:#dee3e9;
     text-align:left;
     padding:8px 3px 3px 7px;
@@ -547,7 +549,7 @@
     white-space:nowrap;
     font-size:13px;
 }
-td.colSecond, th.colSecond, td.colLast, th.colConstructorName, th.colLast {
+td.colSecond, th.colSecond, td.colLast, th.colConstructorName, th.colDeprecatedItemName, th.colLast {
     font-size:13px;
 }
 .constantsSummary th, .packagesSummary th {
@@ -576,6 +578,7 @@
 th.colFirst a:link, th.colFirst a:visited,
 th.colSecond a:link, th.colSecond a:visited,
 th.colConstructorName a:link, th.colConstructorName a:visited,
+th.colDeprecatedItemName a:link, th.colDeprecatedItemName a:visited, 
 .constantValuesContainer td a:link, .constantValuesContainer td a:visited {
     font-weight:bold;
 }
@@ -645,8 +648,19 @@
 .deprecationComment, .emphasizedPhrase, .interfaceName {
     font-style:italic;
 }
+.deprecationBlock {
+    font-size:14px;
+    font-family:'DejaVu Serif', Georgia, "Times New Roman", Times, serif;
+    border-style:solid;
+    border-width:thin;
+    border-radius:10px;
+    padding:10px;
+    margin-bottom:10px;
+    margin-right:10px;
+    display:inline-block;
+}
 
-div.block div.block span.deprecationComment, div.block div.block span.emphasizedPhrase,
+div.block div.deprecationComment, div.block div.block span.emphasizedPhrase,
 div.block div.block span.interfaceName {
     font-style:normal;
 }
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/DeprecatedAPIListBuilder.java	Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/DeprecatedAPIListBuilder.java	Wed Oct 04 20:01:19 2017 +0000
@@ -78,7 +78,7 @@
         deprecatedMap = new EnumMap<>(DeprElementKind.class);
         for (DeprElementKind kind : DeprElementKind.values()) {
             deprecatedMap.put(kind,
-                    new TreeSet<>(utils.makeGeneralPurposeComparator()));
+                    new TreeSet<>(utils.makeDeprecatedComparator()));
         }
         buildDeprecatedAPIInfo();
     }
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Utils.java	Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Utils.java	Wed Oct 04 20:01:19 2017 +0000
@@ -1733,6 +1733,25 @@
         return packageComparator;
     }
 
+    private Comparator<Element> deprecatedComparator = null;
+    /**
+     * Returns a Comparator for deprecated items listed on deprecated list page, by comparing the
+     * fully qualified names.
+     *
+     * @return a Comparator
+     */
+    public Comparator<Element> makeDeprecatedComparator() {
+        if (deprecatedComparator == null) {
+            deprecatedComparator = new Utils.ElementComparator() {
+                @Override
+                public int compare(Element e1, Element e2) {
+                    return compareFullyQualifiedNames(e1, e2);
+                }
+            };
+        }
+        return deprecatedComparator;
+    }
+
     private Comparator<SerialFieldTree> serialFieldTreeComparator = null;
     /**
      * Returns a Comparator for SerialFieldTree.
--- a/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsTask.java	Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/JdepsTask.java	Wed Oct 04 20:01:19 2017 +0000
@@ -234,49 +234,6 @@
             }
         },
 
-        new Option(true, CommandOption.CHECK_MODULES) {
-            void process(JdepsTask task, String opt, String arg) throws BadArgs {
-                if (task.command != null) {
-                    throw new BadArgs("err.command.set", task.command, opt);
-                }
-                Set<String> mods =  Set.of(arg.split(","));
-                task.options.addmods.addAll(mods);
-                task.command = task.checkModuleDeps(mods);
-            }
-        },
-        new Option(true, CommandOption.GENERATE_MODULE_INFO) {
-            void process(JdepsTask task, String opt, String arg) throws BadArgs {
-                if (task.command != null) {
-                    throw new BadArgs("err.command.set", task.command, opt);
-                }
-                task.command = task.genModuleInfo(Paths.get(arg), false);
-            }
-        },
-        new Option(true, CommandOption.GENERATE_OPEN_MODULE) {
-            void process(JdepsTask task, String opt, String arg) throws BadArgs {
-                if (task.command != null) {
-                    throw new BadArgs("err.command.set", task.command, opt);
-                }
-                task.command = task.genModuleInfo(Paths.get(arg), true);
-            }
-        },
-        new Option(false, CommandOption.LIST_DEPS) {
-            void process(JdepsTask task, String opt, String arg) throws BadArgs {
-                if (task.command != null) {
-                    throw new BadArgs("err.command.set", task.command, opt);
-                }
-                task.command = task.listModuleDeps(false);
-            }
-        },
-        new Option(false, CommandOption.LIST_REDUCED_DEPS) {
-            void process(JdepsTask task, String opt, String arg) throws BadArgs {
-                if (task.command != null) {
-                    throw new BadArgs("err.command.set", task.command, opt);
-                }
-                task.command = task.listModuleDeps(true);
-            }
-        },
-
         // ---- paths option ----
         new Option(true, "-cp", "-classpath", "--class-path") {
             void process(JdepsTask task, String opt, String arg) {
@@ -312,15 +269,6 @@
                 task.options.addmods.addAll(mods);
             }
         },
-        new Option(true, "-m", "--module") {
-            void process(JdepsTask task, String opt, String arg) throws BadArgs {
-                if (!task.options.rootModules.isEmpty()) {
-                    throw new BadArgs("err.option.already.specified", opt);
-                }
-                task.options.rootModules.add(arg);
-                task.options.addmods.add(arg);
-            }
-        },
         new Option(true, "--multi-release") {
             void process(JdepsTask task, String opt, String arg) throws BadArgs {
                 if (arg.equalsIgnoreCase("base")) {
@@ -338,6 +286,70 @@
                 }
             }
         },
+        new Option(false, "-q", "-quiet") {
+            void process(JdepsTask task, String opt, String arg) {
+                task.options.nowarning = true;
+            }
+        },
+        new Option(false, "-version", "--version") {
+            void process(JdepsTask task, String opt, String arg) {
+                task.options.version = true;
+            }
+        },
+
+        // ---- module-specific options ----
+
+        new Option(true, "-m", "--module") {
+            void process(JdepsTask task, String opt, String arg) throws BadArgs {
+                if (!task.options.rootModules.isEmpty()) {
+                    throw new BadArgs("err.option.already.specified", opt);
+                }
+                task.options.rootModules.add(arg);
+                task.options.addmods.add(arg);
+            }
+        },
+        new Option(true, CommandOption.GENERATE_MODULE_INFO) {
+            void process(JdepsTask task, String opt, String arg) throws BadArgs {
+                if (task.command != null) {
+                    throw new BadArgs("err.command.set", task.command, opt);
+                }
+                task.command = task.genModuleInfo(Paths.get(arg), false);
+            }
+        },
+        new Option(true, CommandOption.GENERATE_OPEN_MODULE) {
+            void process(JdepsTask task, String opt, String arg) throws BadArgs {
+                if (task.command != null) {
+                    throw new BadArgs("err.command.set", task.command, opt);
+                }
+                task.command = task.genModuleInfo(Paths.get(arg), true);
+            }
+        },
+        new Option(true, CommandOption.CHECK_MODULES) {
+            void process(JdepsTask task, String opt, String arg) throws BadArgs {
+                if (task.command != null) {
+                    throw new BadArgs("err.command.set", task.command, opt);
+                }
+                Set<String> mods =  Set.of(arg.split(","));
+                task.options.addmods.addAll(mods);
+                task.command = task.checkModuleDeps(mods);
+            }
+        },
+        new Option(false, CommandOption.LIST_DEPS) {
+            void process(JdepsTask task, String opt, String arg) throws BadArgs {
+                if (task.command != null) {
+                    throw new BadArgs("err.command.set", task.command, opt);
+                }
+                task.command = task.listModuleDeps(false);
+            }
+        },
+        new Option(false, CommandOption.LIST_REDUCED_DEPS) {
+            void process(JdepsTask task, String opt, String arg) throws BadArgs {
+                if (task.command != null) {
+                    throw new BadArgs("err.command.set", task.command, opt);
+                }
+                task.command = task.listModuleDeps(true);
+            }
+        },
 
         // ---- Target filtering options ----
         new Option(true, "-p", "-package", "--package") {
@@ -424,17 +436,6 @@
             }
         },
 
-        new Option(false, "-q", "-quiet") {
-            void process(JdepsTask task, String opt, String arg) {
-                task.options.nowarning = true;
-            }
-        },
-
-        new Option(false, "-version", "--version") {
-            void process(JdepsTask task, String opt, String arg) {
-                task.options.version = true;
-            }
-        },
         new HiddenOption(false, "-fullversion") {
             void process(JdepsTask task, String opt, String arg) {
                 task.options.fullVersion = true;
--- a/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/resources/jdeps.properties	Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.jdeps/share/classes/com/sun/tools/jdeps/resources/jdeps.properties	Wed Oct 04 20:01:19 2017 +0000
@@ -86,10 +86,6 @@
 \  --add-modules <module-name>[,<module-name>...]\n\
 \                                Adds modules to the root set for analysis
 
-main.opt.m=\
-\  -m <module-name>\n\
-\  --module <module-name>        Specify the root module for analysis
-
 main.opt.R=\
 \  -R       -recursive           Recursively traverse all run-time dependences.\n\
 \                                The -R option implies -filter:none.  If -p,\n\
@@ -121,6 +117,11 @@
 \                                type, method parameter types, returned type,\n\
 \                                checked exception types etc.
 
+main.opt.m=\n\
+\Module dependence analysis options:\n\
+\  -m <module-name>\n\
+\  --module <module-name>        Specify the root module for analysis
+
 main.opt.generate-module-info=\
 \  --generate-module-info <dir>  Generate module-info.java under the specified\n\
 \                                directory. The specified JAR files will be\n\
@@ -142,7 +143,6 @@
 \                                graph after transition reduction.  It also\n\
 \                                identifies any unused qualified exports.
 
-
 main.opt.dotoutput=\
 \  -dotoutput <dir>\n\
 \  --dot-output <dir>            Destination directory for DOT file output
@@ -157,15 +157,15 @@
 \                                WARNING: JDK internal APIs are inaccessible.
 
 main.opt.list-deps=\
-\  --list-deps                   Lists the dependences and use of JDK internal\n\
-\                                APIs.
+\  --list-deps                   Lists the module dependences and also the\n\
+\                                package names of JDK internal APIs if referenced.
 
 main.opt.list-reduced-deps=\
 \  --list-reduced-deps           Same as --list-deps with not listing\n\
 \                                the implied reads edges from the module graph\n\
-\                                If module M1 depends on M2 and M3,\n\
-\                                M2 requires public on M3, then M1 reading M3 is\n\
-\                                implied and removed from the module graph.
+\                                If module M1 reads M2, and M2 requires\n\
+\                                transitive on M3, then M1 reading M3 is implied\n\
+\                                and is not shown in the graph.
 
 main.opt.depth=\
 \  -depth=<depth>                Specify the depth of the transitive\n\
--- a/src/jdk.jshell/share/classes/jdk/jshell/Eval.java	Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.jshell/share/classes/jdk/jshell/Eval.java	Wed Oct 04 20:01:19 2017 +0000
@@ -40,6 +40,7 @@
 import com.sun.source.tree.IdentifierTree;
 import com.sun.source.tree.MethodTree;
 import com.sun.source.tree.ModifiersTree;
+import com.sun.source.tree.NewClassTree;
 import com.sun.source.tree.Tree;
 import com.sun.source.tree.VariableTree;
 import com.sun.tools.javac.tree.JCTree;
@@ -59,6 +60,7 @@
 import jdk.jshell.TaskFactory.BaseTask;
 import jdk.jshell.TaskFactory.CompileTask;
 import jdk.jshell.TaskFactory.ParseTask;
+import jdk.jshell.Wrap.CompoundWrap;
 import jdk.jshell.Wrap.Range;
 import jdk.jshell.Snippet.Status;
 import jdk.jshell.spi.ExecutionControl.ClassBytecodes;
@@ -274,26 +276,119 @@
         for (Tree unitTree : units) {
             VariableTree vt = (VariableTree) unitTree;
             String name = vt.getName().toString();
-            String typeName = EvalPretty.prettyExpr((JCTree) vt.getType(), false);
+            String typeName;
+            String fullTypeName;
+            TreeDependencyScanner tds = new TreeDependencyScanner();
+            Wrap typeWrap;
+            Wrap anonDeclareWrap = null;
+            Wrap winit = null;
+            StringBuilder sbBrackets = new StringBuilder();
             Tree baseType = vt.getType();
-            TreeDependencyScanner tds = new TreeDependencyScanner();
-            tds.scan(baseType); // Not dependent on initializer
-            StringBuilder sbBrackets = new StringBuilder();
-            while (baseType instanceof ArrayTypeTree) {
-                //TODO handle annotations too
-                baseType = ((ArrayTypeTree) baseType).getType();
-                sbBrackets.append("[]");
+            if (baseType != null) {
+                tds.scan(baseType); // Not dependent on initializer
+                fullTypeName = typeName = EvalPretty.prettyExpr((JCTree) vt.getType(), false);
+                while (baseType instanceof ArrayTypeTree) {
+                    //TODO handle annotations too
+                    baseType = ((ArrayTypeTree) baseType).getType();
+                    sbBrackets.append("[]");
+                }
+                Range rtype = dis.treeToRange(baseType);
+                typeWrap = Wrap.rangeWrap(compileSource, rtype);
+            } else {
+                Tree init = vt.getInitializer();
+                if (init != null) {
+                    Range rinit = dis.treeToRange(init);
+                    String initCode = rinit.part(compileSource);
+                    ExpressionInfo ei =
+                            ExpressionToTypeInfo.localVariableTypeForInitializer(initCode, state);
+                    typeName = ei == null ? "java.lang.Object" : ei.typeName;
+                    fullTypeName = ei == null ? "java.lang.Object" : ei.fullTypeName;
+                    if (ei != null && init.getKind() == Tree.Kind.NEW_CLASS &&
+                        ((NewClassTree) init).getClassBody() != null) {
+                        NewClassTree nct = (NewClassTree) init;
+                        StringBuilder constructor = new StringBuilder();
+                        constructor.append(fullTypeName).append("(");
+                        String sep = "";
+                        if (ei.enclosingInstanceType != null) {
+                            constructor.append(ei.enclosingInstanceType);
+                            constructor.append(" encl");
+                            sep = ", ";
+                        }
+                        int idx = 0;
+                        for (String type : ei.parameterTypes) {
+                            constructor.append(sep);
+                            constructor.append(type);
+                            constructor.append(" ");
+                            constructor.append("arg" + idx++);
+                            sep = ", ";
+                        }
+                        if (ei.enclosingInstanceType != null) {
+                            constructor.append(") { encl.super (");
+                        } else {
+                            constructor.append(") { super (");
+                        }
+                        sep = "";
+                        for (int i = 0; i < idx; i++) {
+                            constructor.append(sep);
+                            constructor.append("arg" + i++);
+                            sep = ", ";
+                        }
+                        constructor.append("); }");
+                        List<? extends Tree> members = nct.getClassBody().getMembers();
+                        Range bodyRange = dis.treeListToRange(members);
+                        Wrap bodyWrap;
+
+                        if (bodyRange != null) {
+                            bodyWrap = Wrap.rangeWrap(compileSource, bodyRange);
+                        } else {
+                            bodyWrap = Wrap.simpleWrap(" ");
+                        }
+
+                        Range argRange = dis.treeListToRange(nct.getArguments());
+                        Wrap argWrap;
+
+                        if (argRange != null) {
+                            argWrap = Wrap.rangeWrap(compileSource, argRange);
+                        } else {
+                            argWrap = Wrap.simpleWrap(" ");
+                        }
+
+                        if (ei.enclosingInstanceType != null) {
+                            Range enclosingRanges =
+                                    dis.treeToRange(nct.getEnclosingExpression());
+                            Wrap enclosingWrap = Wrap.rangeWrap(compileSource, enclosingRanges);
+                            argWrap = argRange != null ? new CompoundWrap(enclosingWrap,
+                                                                          Wrap.simpleWrap(","),
+                                                                          argWrap)
+                                                       : enclosingWrap;
+                        }
+                        Wrap hwrap = Wrap.simpleWrap("public static class " + fullTypeName +
+                                                     (ei.isClass ? " extends " : " implements ") +
+                                                     typeName + " { " + constructor);
+                        anonDeclareWrap = new CompoundWrap(hwrap, bodyWrap, Wrap.simpleWrap("}"));
+                        winit = new CompoundWrap("new " + fullTypeName + "(", argWrap, ")");
+
+                        String superType = typeName;
+
+                        typeName = fullTypeName;
+                        fullTypeName = ei.isClass ? "<anonymous class extending " + superType + ">"
+                                                  : "<anonymous class implementing " + superType + ">";
+                    }
+                    tds.scan(init);
+                } else {
+                    fullTypeName = typeName = "java.lang.Object";
+                }
+                typeWrap = Wrap.identityWrap(typeName);
             }
-            Range rtype = dis.treeToRange(baseType);
             Range runit = dis.treeToRange(vt);
             runit = new Range(runit.begin, runit.end - 1);
             ExpressionTree it = vt.getInitializer();
-            Range rinit = null;
             int nameMax = runit.end - 1;
             SubKind subkind;
             if (it != null) {
                 subkind = SubKind.VAR_DECLARATION_WITH_INITIALIZER_SUBKIND;
-                rinit = dis.treeToRange(it);
+                Range rinit = dis.treeToRange(it);
+                winit = winit == null ? Wrap.rangeWrap(compileSource, rinit) : winit;
                 nameMax = rinit.begin - 1;
             } else {
                 subkind = SubKind.VAR_DECLARATION_SUBKIND;
@@ -304,10 +399,11 @@
             }
             int nameEnd = nameStart + name.length();
             Range rname = new Range(nameStart, nameEnd);
-            Wrap guts = Wrap.varWrap(compileSource, rtype, sbBrackets.toString(), rname, rinit);
-            DiagList modDiag = modifierDiagnostics(vt.getModifiers(), dis, true);
+            Wrap guts = Wrap.varWrap(compileSource, typeWrap, sbBrackets.toString(), rname,
+                                     winit, anonDeclareWrap);
+                        DiagList modDiag = modifierDiagnostics(vt.getModifiers(), dis, true);
             Snippet snip = new VarSnippet(state.keyMap.keyForVariable(name), userSource, guts,
-                    name, subkind, typeName,
+                    name, subkind, fullTypeName,
                     tds.declareReferences(), modDiag);
             snippets.add(snip);
         }
--- a/src/jdk.jshell/share/classes/jdk/jshell/ExpressionToTypeInfo.java	Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.jshell/share/classes/jdk/jshell/ExpressionToTypeInfo.java	Wed Oct 04 20:01:19 2017 +0000
@@ -29,14 +29,20 @@
 import com.sun.source.tree.ClassTree;
 import com.sun.source.tree.CompilationUnitTree;
 import com.sun.source.tree.ConditionalExpressionTree;
+import com.sun.source.tree.ExpressionStatementTree;
 import com.sun.source.tree.ExpressionTree;
+import com.sun.source.tree.MethodInvocationTree;
 import com.sun.source.tree.MethodTree;
+import com.sun.source.tree.NewClassTree;
 import com.sun.source.tree.Tree;
+import com.sun.source.tree.Tree.Kind;
+import com.sun.source.tree.VariableTree;
 import com.sun.source.util.TreePath;
 import com.sun.source.util.TreePathScanner;
 import com.sun.tools.javac.code.Symtab;
 import com.sun.tools.javac.code.Type;
 import com.sun.tools.javac.code.Types;
+import com.sun.tools.javac.util.List;
 import jdk.jshell.TaskFactory.AnalyzeTask;
 
 /**
@@ -63,6 +69,10 @@
     public static class ExpressionInfo {
         ExpressionTree tree;
         String typeName;
+        String fullTypeName;
+        List<String> parameterTypes;
+        String enclosingInstanceType;
+        boolean isClass;
         boolean isNonVoid;
     }
 
@@ -111,6 +121,16 @@
                 return null;
             }
         }
+
+        @Override
+        public TreePath visitVariable(VariableTree node, Boolean isTargetContext) {
+            if (isTargetContext) {
+                throw new Result(getCurrentPath());
+            } else {
+                return null;
+            }
+        }
+
     }
 
     private Type pathToType(TreePath tp) {
@@ -156,6 +176,30 @@
         }
     }
 
+    /**
+     * Entry method: get expression info corresponding to a local variable declaration if its type
+     * has been inferred automatically from the given initializer.
+     * @param code the initializer as a string
+     * @param state a JShell instance
+     * @return type information
+     */
+    public static ExpressionInfo localVariableTypeForInitializer(String code, JShell state) {
+        if (code == null || code.isEmpty()) {
+            return null;
+        }
+        try {
+            OuterWrap codeWrap = state.outerMap.wrapInTrialClass(Wrap.methodWrap("var $$$ = " + code));
+            AnalyzeTask at = state.taskFactory.new AnalyzeTask(codeWrap);
+            CompilationUnitTree cu = at.firstCuTree();
+            if (at.hasErrors() || cu == null) {
+                return null;
+            }
+            return new ExpressionToTypeInfo(at, cu, state).typeOfExpression();
+        } catch (Exception ex) {
+            return null;
+        }
+    }
+
     private ExpressionInfo typeOfExpression() {
         return treeToInfo(findExpressionPath());
     }
@@ -172,9 +216,11 @@
     private ExpressionInfo treeToInfo(TreePath tp) {
         if (tp != null) {
             Tree tree = tp.getLeaf();
-            if (tree instanceof ExpressionTree) {
+            boolean isExpression = tree instanceof ExpressionTree;
+            if (isExpression || tree.getKind() == Kind.VARIABLE) {
                 ExpressionInfo ei = new ExpressionInfo();
-                ei.tree = (ExpressionTree) tree;
+                if (isExpression)
+                    ei.tree = (ExpressionTree) tree;
                 Type type = pathToType(tp, tree);
                 if (type != null) {
                     switch (type.getKind()) {
@@ -189,27 +235,56 @@
                             break;
                         default: {
                             ei.isNonVoid = true;
-                            ei.typeName = varTypeName(type);
-                            if (ei.typeName == null) {
-                                ei.typeName = OBJECT_TYPE_NAME;
-                            }
+                            ei.typeName = varTypeName(type, false);
+                            ei.fullTypeName = varTypeName(type, true);
                             break;
                         }
                     }
                 }
+                if (tree.getKind() == Tree.Kind.VARIABLE) {
+                    Tree init = ((VariableTree) tree).getInitializer();
+                    if (init.getKind() == Tree.Kind.NEW_CLASS &&
+                        ((NewClassTree) init).getClassBody() != null) {
+                        NewClassTree nct = (NewClassTree) init;
+                        ClassTree clazz = nct.getClassBody();
+                        MethodTree constructor = (MethodTree) clazz.getMembers().get(0);
+                        ExpressionStatementTree superCallStatement =
+                                (ExpressionStatementTree) constructor.getBody().getStatements().get(0);
+                        MethodInvocationTree superCall =
+                                (MethodInvocationTree) superCallStatement.getExpression();
+                        TreePath superCallPath =
+                                at.trees().getPath(tp.getCompilationUnit(), superCall.getMethodSelect());
+                        Type constrType = pathToType(superCallPath);
+                        ei.parameterTypes = constrType.getParameterTypes()
+                                                      .stream()
+                                                      .map(t -> varTypeName(t, false))
+                                                      .collect(List.collector());
+                        if (nct.getEnclosingExpression() != null) {
+                            TreePath enclPath = new TreePath(tp, nct.getEnclosingExpression());
+                            ei.enclosingInstanceType = varTypeName(pathToType(enclPath), false);
+                        }
+                        ei.isClass = at.task.getTypes().directSupertypes(type).size() == 1;
+                    }
+                }
                 return ei;
             }
         }
         return null;
     }
 
-    private String varTypeName(Type type) {
+    private String varTypeName(Type type, boolean printIntersectionTypes) {
         try {
-            TypePrinter tp = new VarTypePrinter(at.messages(),
-                    state.maps::fullClassNameAndPackageToClass, syms, types);
-            return tp.toString(type);
+            TypePrinter tp = new TypePrinter(at.messages(),
+                    state.maps::fullClassNameAndPackageToClass, printIntersectionTypes);
+            List<Type> captures = types.captures(type);
+            String res = tp.toString(types.upward(type, captures));
+
+            if (res == null)
+                res = OBJECT_TYPE_NAME;
+
+            return res;
         } catch (Exception ex) {
-            return null;
+            return OBJECT_TYPE_NAME;
         }
     }
 
--- a/src/jdk.jshell/share/classes/jdk/jshell/ReplParser.java	Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.jshell/share/classes/jdk/jshell/ReplParser.java	Wed Oct 04 20:01:19 2017 +0000
@@ -232,7 +232,7 @@
                             //mods.flags |= Flags.STATIC;
                             List<JCTree> defs
                                     = variableDeclaratorsRest(pos, mods, t, name, false, dc,
-                                            new ListBuffer<JCTree>()).toList();
+                                            new ListBuffer<JCTree>(), true).toList();
                             accept(SEMI);
                             storeEnd(defs.last(), S.prevToken().endPos);
                             return defs;
--- a/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java	Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.jshell/share/classes/jdk/jshell/SourceCodeAnalysisImpl.java	Wed Oct 04 20:01:19 2017 +0000
@@ -134,6 +134,8 @@
 
 import static java.util.stream.Collectors.joining;
 
+import javax.lang.model.type.IntersectionType;
+
 /**
  * The concrete implementation of SourceCodeAnalysis.
  * @author Robert Field
@@ -715,6 +717,13 @@
             return Collections.emptyList();
 
         switch (site.getKind()) {
+            case INTERSECTION: {
+                List<Element> result = new ArrayList<>();
+                for (TypeMirror bound : ((IntersectionType) site).getBounds()) {
+                    result.addAll(membersOf(at, bound, shouldGenerateDotClassItem));
+                }
+                return result;
+            }
             case DECLARED: {
                 TypeElement element = (TypeElement) at.getTypes().asElement(site);
                 List<Element> result = new ArrayList<>();
--- a/src/jdk.jshell/share/classes/jdk/jshell/TaskFactory.java	Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.jshell/share/classes/jdk/jshell/TaskFactory.java	Wed Oct 04 20:01:19 2017 +0000
@@ -61,7 +61,20 @@
 import javax.tools.FileObject;
 import jdk.jshell.MemoryFileManager.SourceMemoryJavaFileObject;
 import java.lang.Runtime.Version;
+import java.nio.CharBuffer;
 import com.sun.source.tree.Tree.Kind;
+import com.sun.tools.javac.code.Kinds;
+import com.sun.tools.javac.code.Symbol.ClassSymbol;
+import com.sun.tools.javac.code.Symbol.VarSymbol;
+import com.sun.tools.javac.parser.Parser;
+import com.sun.tools.javac.tree.JCTree.JCClassDecl;
+import com.sun.tools.javac.tree.JCTree.JCCompilationUnit;
+import com.sun.tools.javac.tree.JCTree.JCExpression;
+import com.sun.tools.javac.tree.JCTree.JCTypeCast;
+import com.sun.tools.javac.tree.JCTree.Tag;
+import com.sun.tools.javac.util.Context.Factory;
+import com.sun.tools.javac.util.Log.DiscardDiagnosticHandler;
+import jdk.jshell.Snippet.Status;
 
 /**
  * The primary interface to the compiler API.  Parsing, analysis, and
@@ -355,6 +368,7 @@
             Iterable<? extends JavaFileObject> compilationUnits = inputs
                             .map(in -> sh.sourceToFileObject(fileManager, in))
                             .collect(Collectors.toList());
+            JShellJavaCompiler.preRegister(context, state);
             this.task = (JavacTaskImpl) ((JavacTool) compiler).getTask(null,
                     fileManager, diagnostics, options, null,
                     compilationUnits, context);
@@ -464,4 +478,57 @@
         }
     }
 
+    private static final class JShellJavaCompiler extends com.sun.tools.javac.main.JavaCompiler {
+
+        public static void preRegister(Context c, JShell state) {
+            c.put(compilerKey, (Factory<com.sun.tools.javac.main.JavaCompiler>) i -> new JShellJavaCompiler(i, state));
+        }
+
+        private final JShell state;
+
+        public JShellJavaCompiler(Context context, JShell state) {
+            super(context);
+            this.state = state;
+        }
+
+        @Override
+        public void processAnnotations(com.sun.tools.javac.util.List<JCCompilationUnit> roots, Collection<String> classnames) {
+            super.processAnnotations(roots, classnames);
+            state.maps
+                 .snippetList()
+                 .stream()
+                 .filter(s -> s.status() == Status.VALID)
+                 .filter(s -> s.kind() == Snippet.Kind.VAR)
+                 .filter(s -> s.subKind() == Snippet.SubKind.VAR_DECLARATION_WITH_INITIALIZER_SUBKIND)
+                 .forEach(s -> setVariableType(roots, (VarSnippet) s));
+        }
+
+        private void setVariableType(com.sun.tools.javac.util.List<JCCompilationUnit> roots, VarSnippet s) {
+            ClassSymbol clazz = syms.getClass(syms.unnamedModule, names.fromString(s.classFullName()));
+            if (clazz == null || !clazz.isCompleted())
+                return;
+            VarSymbol field = (VarSymbol) clazz.members().findFirst(names.fromString(s.name()), sym -> sym.kind == Kinds.Kind.VAR);
+            if (field != null) {
+                JavaFileObject prev = log.useSource(null);
+                DiscardDiagnosticHandler h = new DiscardDiagnosticHandler(log);
+                try {
+                    String typeName = s.typeName();
+                    CharBuffer buf = CharBuffer.wrap(("(" + typeName +")x\u0000").toCharArray(), 0, typeName.length() + 3);
+                    Parser parser = parserFactory.newParser(buf, false, false, false);
+                    JCExpression expr = parser.parseExpression();
+                    if (expr.hasTag(Tag.TYPECAST)) {
+                        JCTypeCast tree = (JCTypeCast) expr;
+                        if (tree.clazz.hasTag(Tag.TYPEINTERSECTION)) {
+                            field.type = attr.attribType(tree.clazz,
+                                                         ((JCClassDecl) roots.head.getTypeDecls().head).sym);
+                        }
+                    }
+                } finally {
+                    log.popDiagnosticHandler(h);
+                    log.useSource(prev);
+                }
+            }
+        }
+    }
+
 }
--- a/src/jdk.jshell/share/classes/jdk/jshell/TreeDissector.java	Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.jshell/share/classes/jdk/jshell/TreeDissector.java	Wed Oct 04 20:01:19 2017 +0000
@@ -227,7 +227,7 @@
         Type typeImpl = (Type) type;
         try {
             TypePrinter tp = new TypePrinter(at.messages(),
-                    state.maps::fullClassNameAndPackageToClass);
+                    state.maps::fullClassNameAndPackageToClass, true);
             return tp.toString(typeImpl);
         } catch (Exception ex) {
             return null;
--- a/src/jdk.jshell/share/classes/jdk/jshell/TypePrinter.java	Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.jshell/share/classes/jdk/jshell/TypePrinter.java	Wed Oct 04 20:01:19 2017 +0000
@@ -32,9 +32,11 @@
 import com.sun.tools.javac.code.Symbol.PackageSymbol;
 import com.sun.tools.javac.code.Type;
 import com.sun.tools.javac.code.Type.ClassType;
+import com.sun.tools.javac.code.Type.IntersectionClassType;
 import com.sun.tools.javac.util.JavacMessages;
 import java.util.Locale;
 import java.util.function.BinaryOperator;
+import java.util.stream.Collectors;
 
 /**
  * Print types in source form.
@@ -45,10 +47,14 @@
 
     private final JavacMessages messages;
     private final BinaryOperator<String> fullClassNameAndPackageToClass;
+    private final boolean printEnhancedTypes;
 
-    TypePrinter(JavacMessages messages, BinaryOperator<String> fullClassNameAndPackageToClass) {
+    TypePrinter(JavacMessages messages,
+                BinaryOperator<String> fullClassNameAndPackageToClass,
+                boolean printEnhancedTypes) {
         this.messages = messages;
         this.fullClassNameAndPackageToClass = fullClassNameAndPackageToClass;
+        this.printEnhancedTypes = printEnhancedTypes;
     }
 
     String toString(Type t) {
@@ -92,8 +98,18 @@
     protected String className(ClassType t, boolean longform, Locale locale) {
         Symbol sym = t.tsym;
         if (sym.name.length() == 0 && (sym.flags() & COMPOUND) != 0) {
-            return OBJECT;
+            if (printEnhancedTypes) {
+                return ((IntersectionClassType) t).getExplicitComponents()
+                                                  .stream()
+                                                  .map(i -> visit(i, locale))
+                                                  .collect(Collectors.joining("&"));
+            } else {
+                return OBJECT;
+            }
         } else if (sym.name.length() == 0) {
+            if (printEnhancedTypes) {
+                return t.tsym.flatName().toString().substring(t.tsym.outermostClass().flatName().length());
+            }
             // Anonymous
             String s;
             ClassType norm = (ClassType) t.tsym.type;
--- a/src/jdk.jshell/share/classes/jdk/jshell/VarTypePrinter.java	Wed Oct 04 11:52:07 2017 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,265 +0,0 @@
-/*
- * 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;
-
-import java.util.HashSet;
-import com.sun.tools.javac.code.Type;
-import com.sun.tools.javac.code.Type.ClassType;
-import com.sun.tools.javac.util.JavacMessages;
-import java.util.Locale;
-import java.util.Set;
-import java.util.function.BinaryOperator;
-import com.sun.tools.javac.code.BoundKind;
-import com.sun.tools.javac.code.Flags;
-import com.sun.tools.javac.code.Symtab;
-import com.sun.tools.javac.code.Type.CapturedType;
-import com.sun.tools.javac.code.Type.StructuralTypeMapping;
-import com.sun.tools.javac.code.Type.TypeVar;
-import com.sun.tools.javac.code.Type.WildcardType;
-import com.sun.tools.javac.code.Types;
-import com.sun.tools.javac.code.Types.SimpleVisitor;
-import com.sun.tools.javac.util.List;
-import static com.sun.tools.javac.code.BoundKind.EXTENDS;
-import static com.sun.tools.javac.code.BoundKind.SUPER;
-import static com.sun.tools.javac.code.BoundKind.UNBOUND;
-import static com.sun.tools.javac.code.Type.ArrayType;
-import static com.sun.tools.javac.code.TypeTag.BOT;
-import static com.sun.tools.javac.code.TypeTag.WILDCARD;
-
-/**
- * Print variable types in source form.
- * TypeProjection and CaptureScanner are copied from Types in the JEP-286
- * Sandbox by Maurizio.  The checks for Non-Denotable in TypePrinter are
- * cribbed from denotableChecker of the same source.
- *
- * @author Maurizio Cimadamore
- * @author Robert Field
- */
-class VarTypePrinter extends TypePrinter {
-    private static final String WILD = "?";
-
-    private final Symtab syms;
-    private final Types types;
-
-    VarTypePrinter(JavacMessages messages, BinaryOperator<String> fullClassNameAndPackageToClass,
-            Symtab syms, Types types) {
-        super(messages, fullClassNameAndPackageToClass);
-        this.syms = syms;
-        this.types = types;
-    }
-
-    @Override
-    String toString(Type t) {
-        return super.toString(upward(t));
-    }
-
-    @Override
-    public String visitTypeVar(TypeVar t, Locale locale) {
-        /* Any type variable mentioned in the inferred type must have been declared as a type parameter
-                  (i.e cannot have been produced by inference (18.4))
-         */
-        // and beyond that, there are no global type vars, so if there are any
-        // type variables left, they need to be eliminated
-        return WILD; // Non-denotable
-    }
-
-    @Override
-    public String visitCapturedType(CapturedType t, Locale locale) {
-        /* Any type variable mentioned in the inferred type must have been declared as a type parameter
-                  (i.e cannot have been produced by capture conversion (5.1.10))
-         */
-        return WILD; // Non-denotable
-    }
-
-    public Type upward(Type t) {
-        List<Type> captures = captures(t);
-        return upward(t, captures);
-    }
-
-    /************* Following from JEP-286 Types.java ***********/
-
-    public Type upward(Type t, List<Type> vars) {
-        return t.map(new TypeProjection(vars), true);
-    }
-
-    public List<Type> captures(Type t) {
-        CaptureScanner cs = new CaptureScanner();
-        Set<Type> captures = new HashSet<>();
-        cs.visit(t, captures);
-        return List.from(captures);
-    }
-
-    class CaptureScanner extends SimpleVisitor<Void, Set<Type>> {
-
-        @Override
-        public Void visitType(Type t, Set<Type> types) {
-            return null;
-        }
-
-        @Override
-        public Void visitClassType(ClassType t, Set<Type> seen) {
-            if (t.isCompound()) {
-                types.directSupertypes(t).forEach(s -> visit(s, seen));
-            } else {
-                t.allparams().forEach(ta -> visit(ta, seen));
-            }
-            return null;
-        }
-
-        @Override
-        public Void visitArrayType(ArrayType t, Set<Type> seen) {
-            return visit(t.elemtype, seen);
-        }
-
-        @Override
-        public Void visitWildcardType(WildcardType t, Set<Type> seen) {
-            visit(t.type, seen);
-            return null;
-        }
-
-        @Override
-        public Void visitTypeVar(TypeVar t, Set<Type> seen) {
-            if ((t.tsym.flags() & Flags.SYNTHETIC) != 0 && seen.add(t)) {
-                visit(t.getUpperBound(), seen);
-            }
-            return null;
-        }
-
-        @Override
-        public Void visitCapturedType(CapturedType t, Set<Type> seen) {
-            if (seen.add(t)) {
-                visit(t.getUpperBound(), seen);
-                visit(t.getLowerBound(), seen);
-            }
-            return null;
-        }
-    }
-
-    class TypeProjection extends StructuralTypeMapping<Boolean> {
-
-        List<Type> vars;
-        Set<Type> seen = new HashSet<>();
-
-        public TypeProjection(List<Type> vars) {
-            this.vars = vars;
-        }
-
-        @Override
-        public Type visitClassType(ClassType t, Boolean upward) {
-            if (upward && !t.isCompound() && t.tsym.name.isEmpty()) {
-                //lift anonymous class type to first supertype (class or interface)
-                return types.directSupertypes(t).last();
-            } else if (t.isCompound()) {
-                List<Type> components = types.directSupertypes(t);
-                List<Type> components1 = components.map(c -> c.map(this, upward));
-                if (components == components1) return t;
-                else return types.makeIntersectionType(components1);
-            } else {
-                Type outer = t.getEnclosingType();
-                Type outer1 = visit(outer, upward);
-                List<Type> typarams = t.getTypeArguments();
-                List<Type> typarams1 = typarams.map(ta -> mapTypeArgument(ta, upward));
-                if (typarams1.stream().anyMatch(ta -> ta.hasTag(BOT))) {
-                    //not defined
-                    return syms.botType;
-                }
-                if (outer1 == outer && typarams1 == typarams) return t;
-                else return new ClassType(outer1, typarams1, t.tsym, t.getMetadata()) {
-                    @Override
-                    protected boolean needsStripping() {
-                        return true;
-                    }
-                };
-            }
-        }
-
-        protected Type makeWildcard(Type upper, Type lower) {
-            BoundKind bk;
-            Type bound;
-            if (upper.hasTag(BOT)) {
-                upper = syms.objectType;
-            }
-            boolean isUpperObject = types.isSameType(upper, syms.objectType);
-            if (!lower.hasTag(BOT) && isUpperObject) {
-                bound = lower;
-                bk = SUPER;
-            } else {
-                bound = upper;
-                bk = isUpperObject ? UNBOUND : EXTENDS;
-            }
-            return new WildcardType(bound, bk, syms.boundClass);
-        }
-
-        @Override
-        public Type visitTypeVar(TypeVar t, Boolean upward) {
-            if (vars.contains(t)) {
-                try {
-                    if (seen.add(t)) {
-                        return (upward ?
-                                t.getUpperBound() :
-                                (t.getLowerBound() == null) ?
-                                        syms.botType :
-                                        t.getLowerBound())
-                                    .map(this, upward);
-                    } else {
-                        //cycle
-                        return syms.objectType;
-                    }
-                } finally {
-                    seen.remove(t);
-                }
-            } else {
-                return t;
-            }
-        }
-
-        @Override
-        public Type visitWildcardType(WildcardType wt, Boolean upward) {
-            if (upward) {
-                return wt.isExtendsBound() ?
-                        wt.type.map(this, upward) :
-                        syms.objectType;
-            } else {
-                return wt.isSuperBound() ?
-                        wt.type.map(this, upward) :
-                        syms.botType;
-            }
-        }
-
-        private Type mapTypeArgument(Type t, boolean upward) {
-            if (!t.containsAny(vars)) {
-                return t;
-            } else if (!t.hasTag(WILDCARD) && !upward) {
-                //not defined
-                return syms.botType;
-            } else {
-                Type upper = t.map(this, upward);
-                Type lower = t.map(this, !upward);
-                return makeWildcard(upper, lower);
-            }
-        }
-    }
-}
--- a/src/jdk.jshell/share/classes/jdk/jshell/Wrap.java	Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.jshell/share/classes/jdk/jshell/Wrap.java	Wed Oct 04 20:01:19 2017 +0000
@@ -74,16 +74,15 @@
      * @param rdecl Type name and name
      * @return
      */
-    public static Wrap varWrap(String source, Range rtype, String brackets, Range rname, Range rinit) {
+    public static Wrap varWrap(String source, Wrap wtype, String brackets,
+                               Range rname, Wrap winit, Wrap anonDeclareWrap) {
         RangeWrap wname = new RangeWrap(source, rname);
-        RangeWrap wtype = new RangeWrap(source, rtype);
         Wrap wVarDecl = new VarDeclareWrap(wtype, brackets, wname);
         Wrap wmeth;
 
-        if (rinit == null) {
+        if (winit == null) {
             wmeth = new CompoundWrap(new NoWrap(" "), "   return null;\n");
         } else {
-            RangeWrap winit = new RangeWrap(source, rinit);
         // int x = y
             // int x_ = y; return x = x_;
             // decl + "_ = " + init ; + "return " + name + "=" + name + "_ ;"
@@ -93,7 +92,8 @@
             );
         }
         Wrap wInitMeth = new DoitMethodWrap(wmeth);
-        return new CompoundWrap(wVarDecl, wInitMeth);
+        return anonDeclareWrap != null ? new CompoundWrap(wVarDecl, wInitMeth, anonDeclareWrap)
+                                       : new CompoundWrap(wVarDecl, wInitMeth);
     }
 
     public static Wrap tempVarWrap(String source, String typename, String name) {
@@ -112,6 +112,14 @@
         return new NoWrap(source);
     }
 
+    public static Wrap identityWrap(String source) {
+        return new NoWrap(source);
+    }
+
+    public static Wrap rangeWrap(String source, Range range) {
+        return new RangeWrap(source, range);
+    }
+
     public static Wrap classMemberWrap(String source) {
         Wrap w = new NoWrap(source);
         return new CompoundWrap("    public static\n    ", w);
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CompilationPhase.java	Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/CompilationPhase.java	Wed Oct 04 20:01:19 2017 +0000
@@ -273,7 +273,8 @@
     private static final class LocalVariableTypeCalculationPhase extends CompilationPhase {
         @Override
         FunctionNode transform(final Compiler compiler, final CompilationPhases phases, final FunctionNode fn) {
-            final FunctionNode newFunctionNode = transformFunction(fn, new LocalVariableTypesCalculator(compiler));
+            final FunctionNode newFunctionNode = transformFunction(fn, new LocalVariableTypesCalculator(compiler,
+                    compiler.getReturnType()));
             final ScriptEnvironment senv = compiler.getScriptEnvironment();
             final PrintWriter       err  = senv.getErr();
 
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/Compiler.java	Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/Compiler.java	Wed Oct 04 20:01:19 2017 +0000
@@ -619,6 +619,10 @@
         return types == null ? null : types.get(fn, pos);
     }
 
+    Type getReturnType() {
+        return types == null || !isOnDemandCompilation() ? Type.UNKNOWN : types.getReturnType();
+    }
+
     /**
      * Do a compilation job
      *
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/LocalVariableTypesCalculator.java	Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/LocalVariableTypesCalculator.java	Wed Oct 04 20:01:19 2017 +0000
@@ -405,10 +405,15 @@
     // variables).
     private final Deque<Label> catchLabels = new ArrayDeque<>();
 
-    LocalVariableTypesCalculator(final Compiler compiler) {
+    private LocalVariableTypesCalculator(final Compiler compiler) {
         this.compiler = compiler;
     }
 
+    LocalVariableTypesCalculator(final Compiler compiler, final Type returnType) {
+        this(compiler);
+        this.returnType = returnType;
+    }
+
     private JumpTarget createJumpTarget(final Label label) {
         assert !jumpTargets.containsKey(label);
         final JumpTarget jumpTarget = new JumpTarget();
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/TypeMap.java	Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/codegen/TypeMap.java	Wed Oct 04 20:01:19 2017 +0000
@@ -117,6 +117,15 @@
         return null;
     }
 
+    /**
+     * Get the return type required for the call site we're compiling for. This only determines
+     * whether object return type is required or not.
+     * @return Type.OBJECT for call sites with object return types, Type.UNKNOWN for everything else
+     */
+    Type getReturnType() {
+        return returnType.isObject() ? Type.OBJECT : Type.UNKNOWN;
+    }
+
     @Override
     public String toString() {
         return toString("");
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeJava.java	Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/objects/NativeJava.java	Wed Oct 04 20:01:19 2017 +0000
@@ -43,6 +43,7 @@
 import jdk.dynalink.linker.support.TypeUtilities;
 import jdk.nashorn.api.scripting.JSObject;
 import jdk.nashorn.api.scripting.ScriptObjectMirror;
+import jdk.nashorn.api.scripting.ScriptUtils;
 import jdk.nashorn.internal.objects.annotations.Attribute;
 import jdk.nashorn.internal.objects.annotations.Function;
 import jdk.nashorn.internal.objects.annotations.ScriptClass;
@@ -430,9 +431,9 @@
         if (objArray == null) {
             return null;
         } else if (objArray instanceof Collection) {
-            return new NativeArray(((Collection<?>)objArray).toArray());
+            return new NativeArray(ScriptUtils.unwrapArray(((Collection<?>)objArray).toArray()));
         } else if (objArray instanceof Object[]) {
-            return new NativeArray(((Object[])objArray).clone());
+            return new NativeArray(ScriptUtils.unwrapArray(((Object[])objArray).clone()));
         } else if (objArray instanceof int[]) {
             return new NativeArray(((int[])objArray).clone());
         } else if (objArray instanceof double[]) {
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Parser.java	Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/parser/Parser.java	Wed Oct 04 20:01:19 2017 +0000
@@ -2053,10 +2053,18 @@
             if (outer != null) {
                 restoreBlock(outer);
                 if (body != null) {
+                    List<Statement> statements = new ArrayList<>();
+                    for (final Statement var : outer.getStatements()) {
+                        if(var instanceof VarNode && !((VarNode)var).isBlockScoped()) {
+                            appendStatement(var);
+                        }else {
+                            statements.add(var);
+                        }
+                    }
                     appendStatement(new BlockStatement(forLine, new Block(
                                     outer.getToken(),
                                     body.getFinish(),
-                                    outer.getStatements())));
+                                    statements)));
                 }
             }
         }
@@ -5101,8 +5109,13 @@
 
         final LiteralNode<Expression[]> rawStringArray = LiteralNode.newInstance(templateToken, finish, rawStrings);
         final LiteralNode<Expression[]> cookedStringArray = LiteralNode.newInstance(templateToken, finish, cookedStrings);
-        final RuntimeNode templateObject = new RuntimeNode(templateToken, finish, RuntimeNode.Request.GET_TEMPLATE_OBJECT, rawStringArray, cookedStringArray);
-        argumentList.set(0, templateObject);
+
+        if (!env._parse_only) {
+            final RuntimeNode templateObject = new RuntimeNode(templateToken, finish, RuntimeNode.Request.GET_TEMPLATE_OBJECT, rawStringArray, cookedStringArray);
+            argumentList.set(0, templateObject);
+        } else {
+            argumentList.set(0, rawStringArray);
+        }
         return optimizeList(argumentList);
     }
 
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Source.java	Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/Source.java	Wed Oct 04 20:01:19 2017 +0000
@@ -336,6 +336,7 @@
             }
         }
 
+        @SuppressWarnings("try")
         protected void loadMeta() throws IOException {
             if (length == 0 && lastModified == 0) {
                 final URLConnection c = url.openConnection();
--- a/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/LinkerCallSite.java	Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/linker/LinkerCallSite.java	Wed Oct 04 20:01:19 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2017, 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
@@ -59,7 +59,7 @@
  */
 public class LinkerCallSite extends ChainedCallSite {
     /** Maximum number of arguments passed directly. */
-    public static final int ARGLIMIT = 250;
+    public static final int ARGLIMIT = 125;
 
     private static final String PROFILEFILE = Options.getStringProperty("nashorn.profilefile", "NashornProfile.txt");
 
--- a/src/jdk.scripting.nashorn/share/classes/module-info.java	Wed Oct 04 11:52:07 2017 -0700
+++ b/src/jdk.scripting.nashorn/share/classes/module-info.java	Wed Oct 04 20:01:19 2017 +0000
@@ -44,8 +44,7 @@
 </pre>
  *
  * and then use it just as you would any other JSR-223 script engine. See
- * <a href="jdk/nashorn/api/scripting/package-summary.html">
- * {@code jdk.nashorn.api.scripting}</a> package for details.
+ * {@link jdk.nashorn.api.scripting} package for details.
  * <h1>Compatibility</h1>
  * Nashorn is 100% compliant with the
  * <a href="http://www.ecma-international.org/publications/standards/Ecma-262.htm"
--- a/src/sample/nashorn/autoimports.js	Wed Oct 04 11:52:07 2017 -0700
+++ b/src/sample/nashorn/autoimports.js	Wed Oct 04 20:01:19 2017 +0000
@@ -1,7 +1,7 @@
 # autoimports script requires -scripting mode
 
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -43,6 +43,12 @@
  * script, you can call autoimports to get the exact Java imports you need and replace
  * the autoimports load with the generated import statements (to avoid costly init of
  * the autoimports script).
+ *
+ * Example usage of autoimports.js in interactive mode:
+ *
+ *     jjs -scripting autoimports.js -
+ *     jjs> Vector
+ *     jjs> [JavaClass java.util.Vector]
  */
 
 (function() {
@@ -99,8 +105,8 @@
     Files.walk(root).forEach(function(p) {
         if (Files.isRegularFile(p)) {
             var str = p.toString();
-            if (str.endsWith(".class")) {
-                str = str.substring(1);
+            if (str.endsWith(".class") && !str.endsWith("module-info.class")) {
+                str = str.substring("/modules/".length);
                 var idx = str.indexOf('/');
                 if (idx != -1) {
                     str = str.substring(idx + 1);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/sample/nashorn/base64.js	Wed Oct 04 20:01:19 2017 +0000
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   - Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *
+ *   - Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ *   - Neither the name of Oracle nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// Usage: jjs --language=es6 base64.js
+
+const Base64 = Java.type("java.util.Base64");
+const ByteArray = Java.type("byte[]");
+const JString = Java.type("java.lang.String");
+
+function toBase64(s) {
+    const ba = s instanceof ByteArray? s : String(s).bytes;
+    return Base64.encoder.encodeToString(ba);
+}
+
+function fromBase64(s) {
+    const ba = s instanceof ByteArray? s : String(s).bytes;
+    return new JString(Base64.decoder.decode(ba));
+}
+
+print(toBase64`hello world`);
+print(fromBase64(toBase64`hello world`));
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/sample/nashorn/dom_tagged_literal.js	Wed Oct 04 20:01:19 2017 +0000
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   - Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *
+ *   - Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ *   - Neither the name of Oracle nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This sample demonstrates the use of es6 tagged template literal to
+ * create a java object. A XML DOM Document object is created from
+ * String using es6 tagged template literal.
+ *
+ * Usage:
+ *    jjs --language=es6 dom_tagged_literal.js
+ */
+
+// Java types used
+const BAIS = Java.type("java.io.ByteArrayInputStream")
+const DocBuilderFac = Java.type("javax.xml.parsers.DocumentBuilderFactory")
+const DOMSource = Java.type("javax.xml.transform.dom.DOMSource")
+const StreamResult = Java.type("javax.xml.transform.stream.StreamResult")
+const StringWriter = Java.type("java.io.StringWriter")
+const TransformerFactory = Java.type("javax.xml.transform.TransformerFactory")
+
+function DOM(str) {
+    var docBuilder = DocBuilderFac.newInstance().newDocumentBuilder()
+    docBuilder.validating = false
+    return docBuilder["parse(java.io.InputStream)"](new BAIS(String(str).bytes))
+}
+
+// es6 tagged template literal to create DOM from
+// multi-line XML string
+
+const dom = DOM`
+<foo>
+  <bar title="hello">world</bar>
+</foo>`
+
+// access DOM elements
+const foo = dom.documentElement
+print(foo.tagName)
+const bar = foo.getElementsByTagName("bar").item(0)
+print(bar.tagName)
+print(bar.getAttribute("title"))
+
+// modify DOM
+foo.setAttribute("name", "nashorn")
+foo.appendChild(dom.createElement("test"))
+
+// serialize DOM to XML string
+function domToXML(d) {
+    const transformer = TransformerFactory.newInstance().newTransformer()
+    const res = new StreamResult(new StringWriter())
+    transformer.transform(new DOMSource(d), res)
+    return res.writer.toString()
+}
+
+// serialize DOM to a String & print
+print(domToXML(dom))
--- a/src/sample/nashorn/dynalink/README	Wed Oct 04 11:52:07 2017 -0700
+++ b/src/sample/nashorn/dynalink/README	Wed Oct 04 20:01:19 2017 +0000
@@ -4,12 +4,6 @@
 "xyz_linker.js". These scripts build dynalink linker jar from java code and exec
 another jjs process with appropriate classpath set.
 
-Note: you need to build jdk9 forest and put "images/jdk/bin" in your PATH to use
-these scripts. This is because these scripts use javac to build dynalink jar and
-exec another jjs with classpath set! Alternatively, you can also manually build
-dynalink linker jars and invoke sample scripts by putting linker jar in jjs tool's
-classpath as well.
-
 Dynalink samples:
 
 * array_stream_linker.js
--- a/src/sample/nashorn/dynalink/array_stream_linker.js	Wed Oct 04 11:52:07 2017 -0700
+++ b/src/sample/nashorn/dynalink/array_stream_linker.js	Wed Oct 04 20:01:19 2017 +0000
@@ -1,7 +1,7 @@
 #! array stream linker example
 
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -37,10 +37,12 @@
 $EXEC.throwOnError=true
 
 // compile ArrayStreamLinkerExporter
-`javac -cp ../../dist/nashorn.jar ArrayStreamLinkerExporter.java`
+`javac ArrayStreamLinkerExporter.java`
+
+load("jarutil.js");
 
 // make a jar file out of pluggable linker
-`jar cvf array_stream_linker.jar ArrayStreamLinkerExporter*.class META-INF/`
+makeJar("array_stream_linker.jar");
 
 // run a sample script that uses pluggable linker
 // but make sure classpath points to the pluggable linker jar!
--- a/src/sample/nashorn/dynalink/buffer_indexing_linker.js	Wed Oct 04 11:52:07 2017 -0700
+++ b/src/sample/nashorn/dynalink/buffer_indexing_linker.js	Wed Oct 04 20:01:19 2017 +0000
@@ -1,7 +1,7 @@
 # buffer indexing linker example
 
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -37,10 +37,12 @@
 $EXEC.throwOnError=true
 
 // compile BufferIndexingLinkerExporter
-`javac -cp ../../dist/nashorn.jar BufferIndexingLinkerExporter.java`
+`javac BufferIndexingLinkerExporter.java`
+
+load("jarutil.js");
 
 // make a jar file out of pluggable linker
-`jar cvf buffer_indexing_linker.jar BufferIndexingLinkerExporter*.class META-INF/`
+makeJar("buffer_indexing_linker.jar");
 
 // run a sample script that uses pluggable linker
 // but make sure classpath points to the pluggable linker jar!
--- a/src/sample/nashorn/dynalink/dom_linker.js	Wed Oct 04 11:52:07 2017 -0700
+++ b/src/sample/nashorn/dynalink/dom_linker.js	Wed Oct 04 20:01:19 2017 +0000
@@ -37,10 +37,12 @@
 $EXEC.throwOnError=true
 
 // compile DOMLinkerExporter
-`javac -cp ../../dist/nashorn.jar DOMLinkerExporter.java`
+`javac DOMLinkerExporter.java`
+
+load("jarutil.js");
 
 // make a jar file out of pluggable linker
-`jar cvf dom_linker.jar DOMLinkerExporter*.class META-INF/`
+makeJar("dom_linker.jar");
 
 // run a sample script that uses pluggable linker
 // but make sure classpath points to the pluggable linker jar!
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/sample/nashorn/dynalink/jarutil.js	Wed Oct 04 20:01:19 2017 +0000
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   - Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *
+ *   - Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ *   - Neither the name of Oracle nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+function classFiles() {
+    var arr = new java.io.File(".").listFiles(
+        new java.io.FilenameFilter() {
+            accept: function(dir, str) str.endsWith(".class")
+        });
+    var str = "";
+    for (var i in arr) str += " " + arr[i];
+    return str;
+}
+
+function makeJar(name) {
+    $EXEC("jar cvf " + name + " META-INF/ " + classFiles());
+    print($ERR);
+}
--- a/src/sample/nashorn/dynalink/missing_method_linker.js	Wed Oct 04 11:52:07 2017 -0700
+++ b/src/sample/nashorn/dynalink/missing_method_linker.js	Wed Oct 04 20:01:19 2017 +0000
@@ -1,7 +1,7 @@
 #! missing method linker example
 
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -37,10 +37,12 @@
 $EXEC.throwOnError=true
 
 // compile MissingMethodLinkerExporter
-`javac -cp ../../dist/nashorn.jar MissingMethodLinkerExporter.java MissingMethodHandler.java MissingMethodExample.java`
+`javac MissingMethodLinkerExporter.java MissingMethodHandler.java MissingMethodExample.java`
+
+load("jarutil.js");
 
 // make a jar file out of pluggable linker
-`jar cvf missing_method_linker.jar MissingMethod*.class META-INF/`
+makeJar("missing_method_linker.jar");
 
 // run a sample script that uses pluggable linker
 // but make sure classpath points to the pluggable linker jar!
--- a/src/sample/nashorn/dynalink/underscore_linker.js	Wed Oct 04 11:52:07 2017 -0700
+++ b/src/sample/nashorn/dynalink/underscore_linker.js	Wed Oct 04 20:01:19 2017 +0000
@@ -1,7 +1,7 @@
 # underscore name translator dynalink linker example
 
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -37,10 +37,12 @@
 $EXEC.throwOnError=true
 
 // compile UnderscoreNameLinkerExporter
-`javac -cp ../../dist/nashorn.jar UnderscoreNameLinkerExporter.java`
+`javac UnderscoreNameLinkerExporter.java`
+
+load('jarutil.js');
 
 // make a jar file out of pluggable linker
-`jar cvf underscore_linker.jar UnderscoreNameLinkerExporter*.class META-INF/`
+makeJar("underscore_linker.jar");
 
 // run a sample script that uses pluggable linker
 // but make sure classpath points to the pluggable linker jar!
--- a/test/TestCommon.gmk	Wed Oct 04 11:52:07 2017 -0700
+++ b/test/TestCommon.gmk	Wed Oct 04 20:01:19 2017 +0000
@@ -273,7 +273,7 @@
 prep:
 	@$(MKDIR) -p $(ABS_TEST_OUTPUT_DIR)
 	@$(MKDIR) -p `$(DIRNAME) $(ARCHIVE_BUNDLE)`
-	@if [ ! -d $(TEST_ROOT)/../.hg ] ; then                                   \
+	@if [ ! -d $(TEST_ROOT)/../../.hg ] && [ ! -d $(TEST_ROOT)/../../../.hg ]; then  \
 	  $(FIND) $(TEST_ROOT) \( -name \*.dll -o -name \*.DLL -o -name \*.so \)  \
 	        -exec $(CHMOD) a+rx {} \; ;                                       \
 	fi
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/execstack/TestCheckJDK.java	Wed Oct 04 20:01:19 2017 +0000
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2017, 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 Testexecstack.java
+ * @summary Searches for all libraries in test VM and checks that they
+ *          have the noexecstack bit set.
+ * @requires (os.family == "linux")
+ * @library /test/lib
+ * @modules java.base/jdk.internal.misc
+ * @build sun.hotspot.WhiteBox
+ * @run driver ClassFileInstaller sun.hotspot.WhiteBox
+ *                                sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
+ *                   TestCheckJDK
+ */
+
+import jdk.test.lib.Asserts;
+import sun.hotspot.WhiteBox;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+public class TestCheckJDK {
+    static boolean testPassed = true;
+    private static final WhiteBox WB = WhiteBox.getWhiteBox();
+
+    static void checkExecStack(Path file) {
+        String filename = file.toString();
+        if (filename.endsWith(".so")) {
+            if (!WB.checkLibSpecifiesNoexecstack(filename)) {
+                System.out.println("Library does not have the noexecstack bit set: " + filename);
+                testPassed = false;
+            }
+        }
+    }
+
+    public static void main(String[] args) throws Throwable {
+        String vmInstallDir = System.getProperty("java.home");
+
+        Files.walk(Paths.get(vmInstallDir)).filter(Files::isRegularFile).forEach(TestCheckJDK::checkExecStack);
+
+        Asserts.assertTrue(testPassed,
+            "The tested VM contains libs that don't have the noexecstack " +
+            "bit set. They must be linked with -z,noexecstack.");
+    }
+}
--- a/test/jdk/java/lang/StackWalker/Basic.java	Wed Oct 04 11:52:07 2017 -0700
+++ b/test/jdk/java/lang/StackWalker/Basic.java	Wed Oct 04 20:01:19 2017 +0000
@@ -29,8 +29,9 @@
  */
 
 import java.lang.StackWalker.StackFrame;
+import java.lang.invoke.MethodType;
 import java.util.List;
-import java.util.Objects;
+import java.util.Map;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 import static java.lang.StackWalker.Option.*;
@@ -74,6 +75,37 @@
                      found);
     }
 
+    @Test
+    public static void testMethodSignature() throws Exception {
+        List<StackFrame> frames = new StackBuilder(16, 16).build();
+        Map<String, MethodType> methodTypes = StackBuilder.methodTypes();
+        for (StackFrame f : frames) {
+            MethodType type = methodTypes.get(f.getMethodName());
+            if (type != null) {
+                System.out.format("%s.%s %s%n", f.getClassName(), f.getMethodName(),
+                                  f.getDescriptor());
+
+                String descriptor = f.getDescriptor();
+                if (!descriptor.equals(type.toMethodDescriptorString())) {
+                    throw new RuntimeException("Expected: " + type.toMethodDescriptorString()
+                        + " got: " + f.getDescriptor());
+                }
+
+                if (!f.getMethodType().equals(type)) {
+                    throw new RuntimeException("Expected: " + type
+                        + " got: " + f.getMethodType());
+                }
+
+                // verify descriptor returned by getDescriptor() before and after
+                // getMethodType() is called
+                if (!descriptor.equals(f.getDescriptor())) {
+                    throw new RuntimeException("Mismatched: " + descriptor
+                        + " got: " + f.getDescriptor());
+                }
+            }
+        }
+    }
+
     private final int depth;
     Basic(int depth) {
         this.depth = depth;
@@ -132,7 +164,7 @@
         }
     }
 
-    class StackBuilder {
+    static class StackBuilder {
         private final int stackDepth;
         private final int limit;
         private int depth = 0;
@@ -150,15 +182,17 @@
             trace("m1");
             m2();
         }
-        void m2() {
+        List m2() {
             trace("m2");
             m3();
+            return null;
         }
-        void m3() {
+        int m3() {
             trace("m3");
-            m4();
+            m4(null);
+            return 0;
         }
-        void m4() {
+        void m4(Object o) {
             trace("m4");
             int remaining = stackDepth-depth-1;
             if (remaining >= 4) {
@@ -184,6 +218,13 @@
             if (verbose)
                 System.out.format("%2d: %s%n", depth, methodname);
         }
+
+        static Map<String, MethodType> methodTypes() throws Exception {
+            return Map.of("m1", MethodType.methodType(void.class),
+                          "m2", MethodType.methodType(List.class),
+                          "m3", MethodType.methodType(int.class),
+                          "m4", MethodType.methodType(void.class, Object.class));
+        }
     }
 
 }
--- a/test/jdk/java/lang/StackWalker/SanityTest.java	Wed Oct 04 11:52:07 2017 -0700
+++ b/test/jdk/java/lang/StackWalker/SanityTest.java	Wed Oct 04 20:01:19 2017 +0000
@@ -79,4 +79,24 @@
             throw new RuntimeException("NPE expected");
         } catch (NullPointerException e) {}
     }
+
+
+    @Test
+    public static void testUOEFromGetDeclaringClass() {
+        try {
+            StackWalker sw = StackWalker.getInstance();
+            sw.forEach(StackWalker.StackFrame::getDeclaringClass);
+            throw new RuntimeException("UOE expected");
+        } catch (UnsupportedOperationException expected) {
+        }
+    }
+
+    @Test
+    public static void testUOEFromGetMethodType() {
+        try {
+            StackWalker sw = StackWalker.getInstance();
+            sw.forEach(StackWalker.StackFrame::getMethodType);
+            throw new RuntimeException("UOE expected");
+        } catch (UnsupportedOperationException expected) {}
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/lang/invoke/InvokeWithArgumentsTest.java	Wed Oct 04 20:01:19 2017 +0000
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2017, 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 basic tests for MethodHandle.invokeWithArguments
+ * @run testng test.java.lang.invoke.InvokeWithArgumentsTest
+ */
+
+package test.java.lang.invoke;
+
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.WrongMethodTypeException;
+
+import static java.lang.invoke.MethodType.methodType;
+
+public class InvokeWithArgumentsTest {
+    static final MethodHandles.Lookup L = MethodHandles.lookup();
+
+    static Object[] arity(Object o1, Object o2, Object... a) {
+        return a;
+    }
+
+    @Test
+    public void testArity() throws Throwable {
+        MethodHandle mh = L.findStatic(L.lookupClass(), "arity",
+                                       methodType(Object[].class, Object.class, Object.class, Object[].class));
+
+        try {
+            mh.invokeWithArguments("");
+            Assert.fail("WrongMethodTypeException expected");
+        } catch (WrongMethodTypeException e) {}
+    }
+
+    static Object[] passThrough(String... a) {
+        return a;
+    }
+
+    static Object[] pack(Object o, Object... a) {
+        return a;
+    }
+
+    @Test
+    public void testArrayNoPassThrough() throws Throwable {
+        String[] actual = {"A", "B"};
+
+        MethodHandle mh = L.findStatic(L.lookupClass(), "passThrough",
+                                       methodType(Object[].class, String[].class));
+
+        // Note: the actual array is not preserved, the elements will be
+        // unpacked and then packed into a new array before invoking the method
+        String[] expected = (String[]) mh.invokeWithArguments(actual);
+
+        Assert.assertTrue(actual != expected, "Array should not pass through");
+        Assert.assertEquals(actual, expected, "Array contents should be equal");
+    }
+
+    @Test
+    public void testArrayPack() throws Throwable {
+        String[] actual = new String[]{"A", "B"};
+
+        MethodHandle mh = L.findStatic(L.lookupClass(), "pack",
+                                       methodType(Object[].class, Object.class, Object[].class));
+
+        // Note: since String[] can be cast to Object, the actual String[] array
+        // will cast to Object become the single element of a new Object[] array
+        Object[] expected = (Object[]) mh.invokeWithArguments("", actual);
+
+        Assert.assertEquals(1, expected.length, "Array should contain just one element");
+        Assert.assertTrue(actual == expected[0], "Array should pass through");
+    }
+
+    static void intArray(int... a) {
+    }
+
+    @Test
+    public void testPrimitiveArrayWithNull() throws Throwable {
+        MethodHandle mh = L.findStatic(L.lookupClass(), "intArray",
+                                       methodType(void.class, int[].class));
+        try {
+            mh.invokeWithArguments(null, null);
+            Assert.fail("NullPointerException expected");
+        } catch (NullPointerException e) {}
+    }
+
+    @Test
+    public void testPrimitiveArrayWithRef() throws Throwable {
+        MethodHandle mh = L.findStatic(L.lookupClass(), "intArray",
+                                       methodType(void.class, int[].class));
+        try {
+            mh.invokeWithArguments("A", "B");
+            Assert.fail("ClassCastException expected");
+        } catch (ClassCastException e) {}
+    }
+
+
+    static void numberArray(Number... a) {
+    }
+
+    @Test
+    public void testRefArrayWithCast() throws Throwable {
+        MethodHandle mh = L.findStatic(L.lookupClass(), "numberArray",
+                                       methodType(void.class, Number[].class));
+        // All numbers, should not throw
+        mh.invokeWithArguments(1, 1.0, 1.0F, 1L);
+
+        try {
+            mh.invokeWithArguments("A");
+            Assert.fail("ClassCastException expected");
+        } catch (ClassCastException e) {}
+    }
+}
--- a/test/jdk/java/lang/invoke/VarHandles/VarHandleBaseTest.java	Wed Oct 04 11:52:07 2017 -0700
+++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleBaseTest.java	Wed Oct 04 20:01:19 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, 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
@@ -203,10 +203,8 @@
 
     static List<TestAccessMode> testAccessModesOfType(TestAccessType... ats) {
         Stream<TestAccessMode> s = Stream.of(TestAccessMode.values());
-        for (TestAccessType at : ats) {
-            s = s.filter(e -> e.isOfType(at));
-        }
-        return s.collect(toList());
+        return s.filter(e -> Stream.of(ats).anyMatch(e::isOfType))
+                .collect(toList());
     }
 
     static List<VarHandle.AccessMode> accessModes() {
@@ -215,10 +213,9 @@
 
     static List<VarHandle.AccessMode> accessModesOfType(TestAccessType... ats) {
         Stream<TestAccessMode> s = Stream.of(TestAccessMode.values());
-        for (TestAccessType at : ats) {
-            s = s.filter(e -> e.isOfType(at));
-        }
-        return s.map(TestAccessMode::toAccessMode).collect(toList());
+        return s.filter(e -> Stream.of(ats).anyMatch(e::isOfType))
+                .map(TestAccessMode::toAccessMode)
+                .collect(toList());
     }
 
     static MethodHandle toMethodHandle(VarHandle vh, TestAccessMode tam, MethodType mt) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/net/HugeDataTransferTest.java	Wed Oct 04 20:01:19 2017 +0000
@@ -0,0 +1,881 @@
+/*
+ * Copyright (c) 2017, 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 8185072
+ * @summary network006 times out in many configs in JDK10-hs nightly
+ * @run main/othervm/manual HugeDataTransferTest 1
+ */
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.net.InetAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.UnknownHostException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Random;
+
+/**
+ * This test makes huge number of data transfers between 2 Java virtual machines
+ * using the TCP/IP protocol, and checks if those data are transfered correctly.
+ * Both client and server VMs run on the same local computer and attach TCP/IP