Merge
authorprr
Tue, 10 Apr 2018 13:58:47 -0700
changeset 49692 55ec43275ff2
parent 49691 7c99ed812272 (current diff)
parent 49566 7c224ec572d0 (diff)
child 49693 fa23ea24dade
Merge
make/hotspot/lib/CompileDtracePostJvm.gmk
make/hotspot/lib/CompileDtracePreJvm.gmk
make/hotspot/src/native/dtrace/generateJvmOffsets.h
src/java.base/linux/native/libjsig/jsig.c
src/java.base/macosx/native/libjsig/jsig.c
src/java.base/solaris/native/libjsig/jsig.c
--- a/make/CreateJmods.gmk	Mon Apr 09 08:34:30 2018 -0700
+++ b/make/CreateJmods.gmk	Tue Apr 10 13:58:47 2018 -0700
@@ -117,6 +117,17 @@
           --hash-modules '^(?!$(EXCLUDE_PATTERN)$$)'
     endif
   endif
+else # not java.base
+  ifeq ($(OPENJDK_TARGET_OS), windows)
+    # Only java.base needs to include the MSVC*_DLLs. Make sure no other module
+    # tries to include them (typically imported ones).
+    ifneq ($(wildcard $(LIBS_DIR)/$(notdir $(MSVCR_DLL))), )
+      JMOD_FLAGS += --exclude '$(notdir $(MSVCR_DLL))'
+    endif
+    ifneq ($(wildcard $(LIBS_DIR)/$(notdir $(MSVCP_DLL))), )
+      JMOD_FLAGS += --exclude '$(notdir $(MSVCP_DLL))'
+    endif
+  endif
 endif
 
 # Changes to the jmod tool itself should also trigger a rebuild of all jmods.
@@ -133,18 +144,21 @@
   DEPS := $(filter-out $(SUPPORT_OUTPUTDIR)/modules_libs/java.base/classlist, $(DEPS))
 endif
 
+JMOD_FLAGS += --exclude '**{_the.*,_*.marker,*.diz,*.debuginfo,*.dSYM/**,*.dSYM,*.pdb,*.map}'
+
 # Create jmods in a temp dir and then move them into place to keep the
 # module path in $(IMAGES_OUTPUTDIR)/jmods valid at all times.
 $(JMODS_DIR)/$(MODULE).jmod: $(DEPS)
 	$(call LogWarn, Creating $(patsubst $(OUTPUTDIR)/%, %, $@))
 	$(call MakeDir, $(JMODS_DIR) $(JMODS_TEMPDIR))
 	$(RM) $@ $(JMODS_TEMPDIR)/$(notdir $@)
-	$(JMOD) create \
-            --module-version $(VERSION_SHORT) \
-            --target-platform '$(OPENJDK_MODULE_TARGET_PLATFORM)' \
-            --module-path $(JMODS_DIR) \
-	    --exclude '**{_the.*,_*.marker,*.diz,*.debuginfo,*.dSYM/**,*.dSYM,*.pdb,*.map}' \
-	    $(JMOD_FLAGS) $(JMODS_TEMPDIR)/$(notdir $@)
+	$(call ExecuteWithLog, $(SUPPORT_OUTPUTDIR)/jmods/$(MODULE).jmod, \
+	    $(JMOD) create \
+	        --module-version $(VERSION_SHORT) \
+	        --target-platform '$(OPENJDK_MODULE_TARGET_PLATFORM)' \
+	        --module-path $(JMODS_DIR) \
+	        $(JMOD_FLAGS) $(JMODS_TEMPDIR)/$(notdir $@) \
+	)
 	$(MV) $(JMODS_TEMPDIR)/$(notdir $@) $@
 
 TARGETS += $(JMODS_DIR)/$(MODULE).jmod
--- a/make/autoconf/toolchain_windows.m4	Mon Apr 09 08:34:30 2018 -0700
+++ b/make/autoconf/toolchain_windows.m4	Tue Apr 10 13:58:47 2018 -0700
@@ -522,7 +522,6 @@
     if $ECHO "$MSVC_DLL_FILETYPE" | $GREP "$CORRECT_MSVCR_ARCH" 2>&1 > /dev/null; then
       AC_MSG_RESULT([ok])
       MSVC_DLL="$POSSIBLE_MSVC_DLL"
-      BASIC_FIXUP_PATH(MSVC_DLL)
       AC_MSG_CHECKING([for $DLL_NAME])
       AC_MSG_RESULT([$MSVC_DLL])
     else
--- a/make/common/NativeCompilation.gmk	Mon Apr 09 08:34:30 2018 -0700
+++ b/make/common/NativeCompilation.gmk	Tue Apr 10 13:58:47 2018 -0700
@@ -297,7 +297,7 @@
     endif
 
     $$($1_OBJ): $$($1_SRC_FILE) $$($$($1_BASE)_COMPILE_VARDEPS_FILE) \
-        $$($1_VARDEPS_FILE) | $$($$($1_BASE)_BUILD_INFO)
+        $$($$($1_BASE)_EXTRA_DEPS) $$($1_VARDEPS_FILE) | $$($$($1_BASE)_BUILD_INFO)
 	$$(call LogInfo, Compiling $$($1_FILENAME) (for $$($$($1_BASE)_BASENAME)))
 	$$(call MakeDir, $$(@D))
         ifneq ($(TOOLCHAIN_TYPE), microsoft)
@@ -366,6 +366,7 @@
 #   EXCLUDE_PATTERN exclude files matching any of these substrings
 #   EXTRA_FILES List of extra files not in any of the SRC dirs
 #   EXTRA_OBJECT_FILES List of extra object files to include when linking
+#   EXTRA_DEPS List of extra dependencies to be added to each compiled file
 #   VERSIONINFO_RESOURCE Input file for RC. Setting this implies that RC will be run
 #   RC_FLAGS flags for RC.
 #   EMBED_MANIFEST if true, embed manifest on Windows.
@@ -904,20 +905,22 @@
 
       $1_IMPORT_LIBRARY := $$($1_OBJECT_DIR)/$$($1_NAME).lib
       $1_EXTRA_LDFLAGS += "-implib:$$($1_IMPORT_LIBRARY)"
-      # To properly trigger downstream dependants of the import library, just as
-      # for debug files, we must have a recipe in the rule. To avoid rerunning
-      # the recipe every time have it touch the target. If an import library
-      # file is deleted by something external, explicitly delete the target to
-      # trigger a rebuild of both.
-      ifneq ($$(wildcard $$($1_IMPORT_LIBRARY)), $$($1_IMPORT_LIBRARY))
-        $$(call LogDebug, Deleting $$($1_BASENAME) because import library is missing)
-        $$(shell $(RM) $$($1_TARGET))
-      endif
-      $$($1_IMPORT_LIBRARY): $$($1_TARGET)
+      ifeq ($$($1_TYPE), LIBRARY)
+        # To properly trigger downstream dependants of the import library, just as
+        # for debug files, we must have a recipe in the rule. To avoid rerunning
+        # the recipe every time have it touch the target. If an import library
+        # file is deleted by something external, explicitly delete the target to
+        # trigger a rebuild of both.
+        ifneq ($$(wildcard $$($1_IMPORT_LIBRARY)), $$($1_IMPORT_LIBRARY))
+          $$(call LogDebug, Deleting $$($1_BASENAME) because import library is missing)
+          $$(shell $(RM) $$($1_TARGET))
+        endif
+        $$($1_IMPORT_LIBRARY): $$($1_TARGET)
 		$$(if $$(CORRECT_FUNCTION_IN_RECIPE_EVALUATION), \
 		  $$(if $$(wildcard $$@), , $$(error $$@ was not created for $$<)) \
 		)
 		$(TOUCH) $$@
+      endif
     endif
 
     $1_VARDEPS := $$($1_LD) $$($1_SYSROOT_LDFLAGS) $$($1_LDFLAGS) $$($1_EXTRA_LDFLAGS) \
--- a/make/hotspot/gensrc/GensrcDtrace.gmk	Mon Apr 09 08:34:30 2018 -0700
+++ b/make/hotspot/gensrc/GensrcDtrace.gmk	Tue Apr 10 13:58:47 2018 -0700
@@ -54,4 +54,56 @@
   TARGETS += $(patsubst $(DTRACE_SOURCE_DIR)/%.d, \
       $(DTRACE_GENSRC_DIR)/%.h, $(wildcard $(DTRACE_SOURCE_DIR)/*.d))
 
+  ifeq ($(OPENJDK_TARGET_OS), solaris)
+    ############################################################################
+    # First we need to generate the dtraceGenOffsets tool. When run, this will
+    # produce two header files and a C++ file. Note that generateJvmOffsets.cpp
+    # is using the same JVM_CFLAGS as libjvm.so.
+
+    # Include support files that will setup JVM compiler flags.
+    include lib/JvmFeatures.gmk
+    include lib/JvmFlags.gmk
+
+    # We cannot compile until the JVMTI gensrc has finished
+    JVMTI_H := $(JVM_VARIANT_OUTPUTDIR)/gensrc/jvmtifiles/jvmti.h
+
+    $(eval $(call SetupNativeCompilation, BUILD_DTRACE_GEN_OFFSETS, \
+        NAME := dtraceGenOffsets, \
+        TYPE := EXECUTABLE, \
+        SRC := $(TOPDIR)/make/hotspot/src/native/dtrace, \
+        TOOLCHAIN := $(TOOLCHAIN_BUILD), \
+        LDFLAGS := -m64, \
+        CFLAGS := -m64 $(JVM_CFLAGS), \
+        EXTRA_DEPS := $(JVMTI_H), \
+        OBJECT_DIR := $(JVM_VARIANT_OUTPUTDIR)/tools/dtrace-gen-offsets/objs, \
+        OUTPUT_DIR := $(JVM_VARIANT_OUTPUTDIR)/tools/dtrace-gen-offsets, \
+    ))
+
+    DTRACE_GEN_OFFSETS_TOOL := $(BUILD_DTRACE_GEN_OFFSETS_TARGET)
+
+    # Argument 1: Output filename
+    # Argument 2: dtrace-gen-offset tool command line option
+    define SetupDtraceOffsetsGeneration
+      $1: $$(BUILD_DTRACE_GEN_OFFSETS)
+	$$(call LogInfo, Generating dtrace $2 file $$(@F))
+	$$(call MakeDir, $$(@D))
+	$$(call ExecuteWithLog, $$@, ( $$(DTRACE_GEN_OFFSETS_TOOL) -$$(strip $2) > $$@ ) )
+
+      TARGETS += $1
+    endef
+
+    JVM_OFFSETS_H := $(DTRACE_GENSRC_DIR)/JvmOffsets.h
+    JVM_OFFSETS_CPP := $(DTRACE_GENSRC_DIR)/JvmOffsets.cpp
+    JVM_OFFSETS_INDEX_H := $(DTRACE_GENSRC_DIR)/JvmOffsetsIndex.h
+
+    ############################################################################
+    # Run the dtrace-gen-offset tool to generate these three files.
+    # The generated JvmOffsets.cpp is compiled with the rest of libjvm.
+    # The header files are used by libjvm_db and jhelper.d, respectively.
+
+    $(eval $(call SetupDtraceOffsetsGeneration, $(JVM_OFFSETS_H), header))
+    $(eval $(call SetupDtraceOffsetsGeneration, $(JVM_OFFSETS_INDEX_H), index))
+    $(eval $(call SetupDtraceOffsetsGeneration, $(JVM_OFFSETS_CPP), table))
+  endif
+
 endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/make/hotspot/lib/CompileDtraceLibraries.gmk	Tue Apr 10 13:58:47 2018 -0700
@@ -0,0 +1,60 @@
+#
+# Copyright (c) 2013, 2018, 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.
+#
+
+ifeq ($(call check-jvm-feature, dtrace), true)
+  ifeq ($(OPENJDK_TARGET_OS), solaris)
+
+    ############################################################################
+    # Build the stand-alone dtrace libraries.
+
+    LIBJVM_DTRACE_OUTPUTDIR := $(JVM_VARIANT_OUTPUTDIR)/libjvm_dtrace
+    $(eval $(call SetupNativeCompilation, BUILD_LIBJVM_DTRACE, \
+        NAME := jvm_dtrace, \
+        OUTPUT_DIR := $(JVM_LIB_OUTPUTDIR), \
+        SRC := $(TOPDIR)/src/java.base/solaris/native/libjvm_dtrace, \
+        CFLAGS := -m64 -G -mt -KPIC, \
+        LDFLAGS := -m64 -mt -xnolib $(SHARED_LIBRARY_FLAGS), \
+        LIBS := $(LIBDL) -lthread -ldoor, \
+        MAPFILE := $(TOPDIR)/make/mapfiles/libjvm_dtrace/mapfile-vers, \
+        OBJECT_DIR := $(LIBJVM_DTRACE_OUTPUTDIR)/objs, \
+    ))
+
+    # Note that libjvm_db.c has tests for COMPILER2, but this was never set by
+    # the old build.
+    LIBJVM_DB_OUTPUTDIR := $(JVM_VARIANT_OUTPUTDIR)/libjvm_db
+    $(eval $(call SetupNativeCompilation, BUILD_LIBJVM_DB, \
+        NAME := jvm_db, \
+        OUTPUT_DIR := $(JVM_LIB_OUTPUTDIR), \
+        SRC := $(TOPDIR)/src/java.base/solaris/native/libjvm_db, \
+        CFLAGS := -I$(DTRACE_GENSRC_DIR) -m64 -G -mt -KPIC, \
+        LDFLAGS := -m64 -mt -xnolib $(SHARED_LIBRARY_FLAGS), \
+        MAPFILE := $(TOPDIR)/make/mapfiles/libjvm_db/mapfile-vers, \
+        OBJECT_DIR := $(LIBJVM_DB_OUTPUTDIR)/objs, \
+    ))
+
+    TARGETS += $(BUILD_LIBJVM_DTRACE) $(BUILD_LIBJVM_DB)
+
+  endif
+endif
--- a/make/hotspot/lib/CompileDtracePostJvm.gmk	Mon Apr 09 08:34:30 2018 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,203 +0,0 @@
-#
-# Copyright (c) 2013, 2018, 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.
-#
-
-################################################################################
-# Support for dtrace integration with libjvm, and stand-alone dtrace library
-# compilation.
-
-ifeq ($(call check-jvm-feature, dtrace), true)
-  ##############################################################################
-
-  ifeq ($(OPENJDK_TARGET_OS), solaris)
-    ############################################################################
-    # Integrate with libjvm. Here we generate three object files which are
-    # linked with libjvm.so. This step is complicated from a dependency
-    # perspective, since it needs the rest of the compiled object files from the
-    # libjvm compilation, but the output is object files that are to be included
-    # when linking libjvm.so. So this generation must happen as a part of the
-    # libjvm compilation.
-
-    # First we need to generate the dtraceGenOffsets tool. When run, this will
-    # produce more header files and a C++ file.
-
-    # Note that generateJvmOffsets.cpp must be compiled as if it were a file
-    # in the libjvm.so, using JVM_CFLAGS as setup in CompileJvm.gmk. Otherwise
-    # this would preferrably have been done as a part of GensrcDtrace.gmk.
-    $(eval $(call SetupNativeCompilation, BUILD_DTRACE_GEN_OFFSETS, \
-        NAME := dtraceGenOffsets, \
-        TYPE := EXECUTABLE, \
-        SRC := $(TOPDIR)/make/hotspot/src/native/dtrace, \
-        TOOLCHAIN := $(TOOLCHAIN_BUILD), \
-        LDFLAGS := -m64, \
-        CFLAGS := -m64 $(JVM_CFLAGS), \
-        OBJECT_DIR := $(JVM_VARIANT_OUTPUTDIR)/tools/dtrace-gen-offsets/objs, \
-        OUTPUT_DIR := $(JVM_VARIANT_OUTPUTDIR)/tools/dtrace-gen-offsets, \
-    ))
-
-    DTRACE_GEN_OFFSETS_TOOL := $(BUILD_DTRACE_GEN_OFFSETS_TARGET)
-
-    # Argument 1: Output filename
-    # Argument 2: dtrace-gen-offset tool command line option
-    define SetupDtraceOffsetsGeneration
-      $1: $$(BUILD_DTRACE_GEN_OFFSETS)
-	$$(call LogInfo, Generating dtrace $2 file $$(@F))
-	$$(call MakeDir, $$(@D))
-	$$(call ExecuteWithLog, $$@, ( $$(DTRACE_GEN_OFFSETS_TOOL) -$$(strip $2) > $$@ ) )
-
-      TARGETS += $1
-    endef
-
-    JVM_OFFSETS_H := $(DTRACE_SUPPORT_DIR)/JvmOffsets.h
-    JVM_OFFSETS_CPP := $(DTRACE_SUPPORT_DIR)/JvmOffsets.cpp
-    JVM_OFFSETS_INDEX_H := $(DTRACE_SUPPORT_DIR)/JvmOffsetsIndex.h
-
-    # Run the dtrace-gen-offset tool to generate these three files.
-    # The generated JvmOffsets.cpp is compiled with the rest of libjvm.
-    $(eval $(call SetupDtraceOffsetsGeneration, $(JVM_OFFSETS_H), header))
-    $(eval $(call SetupDtraceOffsetsGeneration, $(JVM_OFFSETS_INDEX_H), index))
-    $(eval $(call SetupDtraceOffsetsGeneration, $(JVM_OFFSETS_CPP), table))
-
-    ############################################################################
-    # Generate DTRACE_OBJ which is linked with libjvm.so.
-
-    # Concatenate all *.d files into a single file
-    DTRACE_SOURCE_FILES := $(addprefix $(TOPDIR)/src/hotspot/os/posix/dtrace/, \
-        hotspot_jni.d \
-        hotspot.d \
-        hs_private.d \
-    )
-
-    $(JVM_OUTPUTDIR)/objs/dtrace.d: $(DTRACE_SOURCE_FILES)
-	$(call LogInfo, Generating $(@F))
-	$(call MakeDir, $(@D))
-	$(CAT) $^ > $@
-
-    DTRACE_INSTRUMENTED_OBJS := $(addprefix $(JVM_OUTPUTDIR)/objs/, \
-        ciEnv.o \
-        classLoadingService.o \
-        compileBroker.o \
-        hashtable.o \
-        instanceKlass.o \
-        java.o \
-        jni.o \
-        jvm.o \
-        memoryManager.o \
-        nmethod.o \
-        objectMonitor.o \
-        runtimeService.o \
-        sharedRuntime.o \
-        synchronizer.o \
-        thread.o \
-        unsafe.o \
-        vmThread.o \
-        vmGCOperations.o \
-    )
-
-    ifeq ($(call check-jvm-feature, all-gcs), true)
-      DTRACE_INSTRUMENTED_OBJS += $(addprefix $(JVM_OUTPUTDIR)/objs/, \
-          vmCMSOperations.o \
-          vmPSOperations.o \
-      )
-    endif
-
-    DTRACE_FLAGS := -64 -G
-    DTRACE_CPP_FLAGS := -D_LP64
-
-    # Make sure we run our selected compiler for preprocessing instead of letting
-    # the dtrace tool pick it on it's own.
-    $(DTRACE_OBJ): $(JVM_OUTPUTDIR)/objs/dtrace.d $(DTRACE_INSTRUMENTED_OBJS)
-	$(call LogInfo, Generating $(@F) from $(<F) and object files)
-	$(call MakeDir, $(DTRACE_SUPPORT_DIR))
-	$(call ExecuteWithLog, $(DTRACE_SUPPORT_DIR)/$(@F).d, \
-	    ($(CPP) $(DTRACE_CPP_FLAGS) $< > $(DTRACE_SUPPORT_DIR)/$(@F).d))
-	$(call ExecuteWithLog, $@, $(DTRACE) $(DTRACE_FLAGS) -xlazyload -o $@ \
-	    -s $(DTRACE_SUPPORT_DIR)/$(@F).d $(sort $(DTRACE_INSTRUMENTED_OBJS)))
-
-    ############################################################################
-    # Generate DTRACE_JHELPER_OBJ which is linked with libjvm.so.
-
-    # Unfortunately dtrace generates incorrect types for some symbols in
-    # dtrace_jhelper.o, resulting in "warning: symbol X has differing types"
-    # See JDK-6890703 for details.
-    # We work around this by fixing the types for these symbols using elfedit,
-    # after dtrace has generated the .o file.
-    JHELPER_DTRACE_SRC := $(TOPDIR)/src/hotspot/os/solaris/dtrace/jhelper.d
-
-    GetElfeditCommands = \
-      $(foreach symbol, \
-          $(shell $(GREP) ^extern $(JHELPER_DTRACE_SRC) | $(AWK) '{ gsub(";","") ; print $$3 }'), \
-          -e 'sym:st_type $(symbol) 1')
-
-    # Make sure we run our selected compiler for preprocessing instead of letting
-    # the dtrace tool pick it on it's own.
-    $(DTRACE_JHELPER_OBJ): $(JHELPER_DTRACE_SRC) $(JVM_OFFSETS_INDEX_H)
-	$(call LogInfo, Running dtrace for $(<F))
-	$(call MakeDir, $(DTRACE_SUPPORT_DIR))
-	$(call ExecuteWithLog, $(DTRACE_SUPPORT_DIR)/$(@F).d, \
-	    ($(CPP) $(DTRACE_CPP_FLAGS) -I$(DTRACE_SUPPORT_DIR) $^ \
-	    > $(DTRACE_SUPPORT_DIR)/$(@F).d))
-	$(call ExecuteWithLog, $@, $(DTRACE) $(DTRACE_FLAGS) -o $@ \
-	    -s $(DTRACE_SUPPORT_DIR)/$(@F).d)
-        ifeq ($(OPENJDK_TARGET_CPU_ARCH), sparc)
-	  $(call ExecuteWithLog, $@.elfedit, $(ELFEDIT) $(call GetElfeditCommands) $@)
-        endif
-
-    ############################################################################
-    # Build the stand-alone dtrace libraries
-
-    LIBJVM_DTRACE_OUTPUTDIR := $(JVM_VARIANT_OUTPUTDIR)/libjvm_dtrace
-
-    $(eval $(call SetupNativeCompilation, BUILD_LIBJVM_DTRACE, \
-        NAME := jvm_dtrace, \
-        OUTPUT_DIR := $(JVM_LIB_OUTPUTDIR), \
-        SRC := $(TOPDIR)/src/java.base/solaris/native/libjvm_dtrace, \
-        CFLAGS := -m64 -G -mt -KPIC, \
-        LDFLAGS := -m64 -mt -xnolib $(SHARED_LIBRARY_FLAGS), \
-        LIBS := $(LIBDL) -lthread -ldoor, \
-        MAPFILE := $(TOPDIR)/make/mapfiles/libjvm_dtrace/mapfile-vers, \
-        OBJECT_DIR := $(LIBJVM_DTRACE_OUTPUTDIR)/objs, \
-    ))
-
-    LIBJVM_DB_OUTPUTDIR := $(JVM_VARIANT_OUTPUTDIR)/libjvm_db
-
-    # Note that libjvm_db.c has tests for COMPILER2, but this was never set by
-    # the old build.
-    $(eval $(call SetupNativeCompilation, BUILD_LIBJVM_DB, \
-        NAME := jvm_db, \
-        OUTPUT_DIR := $(JVM_LIB_OUTPUTDIR), \
-        SRC := $(TOPDIR)/src/java.base/solaris/native/libjvm_db, \
-        CFLAGS := -I$(JVM_VARIANT_OUTPUTDIR)/gensrc -I$(DTRACE_SUPPORT_DIR) \
-            -m64 -G -mt -KPIC, \
-        LDFLAGS := -m64 -mt -xnolib $(SHARED_LIBRARY_FLAGS), \
-        MAPFILE := $(TOPDIR)/make/mapfiles/libjvm_db/mapfile-vers, \
-        OBJECT_DIR := $(LIBJVM_DB_OUTPUTDIR)/objs, \
-    ))
-
-    # We need the generated JvmOffsets.h before we can compile the libjvm_db source code.
-    $(BUILD_LIBJVM_DB_ALL_OBJS): $(JVM_OFFSETS_H)
-
-    TARGETS += $(BUILD_LIBJVM_DTRACE) $(BUILD_LIBJVM_DB)
-  endif
-endif
--- a/make/hotspot/lib/CompileDtracePreJvm.gmk	Mon Apr 09 08:34:30 2018 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,39 +0,0 @@
-#
-# Copyright (c) 2016, 2018, 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.
-#
-
-ifeq ($(call check-jvm-feature, dtrace), true)
-  ifeq ($(OPENJDK_TARGET_OS), solaris)
-    # These files are are generated by CompileDtrace.gmk but consumed by
-    # CompileJvm.gmk
-    DTRACE_OBJ := $(JVM_OUTPUTDIR)/objs/dtrace.o
-    DTRACE_JHELPER_OBJ := $(JVM_OUTPUTDIR)/objs/dtrace_jhelper.o
-    DTRACE_EXTRA_OBJECT_FILES := $(DTRACE_OBJ) $(DTRACE_JHELPER_OBJ)
-
-    # Since we cannot generate JvmOffsets.cpp as part of the gensrc step,
-    # we need this special hook to get it to compile with the rest of libjvm.
-    JVM_OFFSETS_CPP := $(DTRACE_SUPPORT_DIR)/JvmOffsets.cpp
-    DTRACE_EXTRA_SOURCE_FILES := $(JVM_OFFSETS_CPP)
-  endif
-endif
--- a/make/hotspot/lib/CompileJvm.gmk	Mon Apr 09 08:34:30 2018 -0700
+++ b/make/hotspot/lib/CompileJvm.gmk	Tue Apr 10 13:58:47 2018 -0700
@@ -24,11 +24,13 @@
 #
 
 # Include support files that will setup compiler flags due to the selected
-# jvm feature set, and specific file overrides.
+# jvm feature set, specific file overrides, and general flags.
 include lib/JvmFeatures.gmk
 include lib/JvmOverrideFiles.gmk
+include lib/JvmFlags.gmk
 
-$(eval $(call IncludeCustomExtension, hotspot/lib/CompileJvm.gmk))
+# Include support files that will setup DTRACE_EXTRA_OBJECT_FILES.
+include lib/JvmDtraceObjects.gmk
 
 ################################################################################
 # Setup compilation of the main Hotspot native library (libjvm).
@@ -39,71 +41,6 @@
 ################################################################################
 # Platform independent setup
 
-# This variable may be added to by a custom extension
-JVM_SRC_ROOTS += $(TOPDIR)/src/hotspot
-
-JVM_SRC_DIRS += $(call uniq, $(wildcard $(foreach d, $(JVM_SRC_ROOTS), \
-        $d/share \
-        $d/os/$(HOTSPOT_TARGET_OS) \
-        $d/os/$(HOTSPOT_TARGET_OS_TYPE) \
-        $d/cpu/$(HOTSPOT_TARGET_CPU_ARCH) \
-        $d/os_cpu/$(HOTSPOT_TARGET_OS)_$(HOTSPOT_TARGET_CPU_ARCH) \
-    ))) \
-    $(JVM_VARIANT_OUTPUTDIR)/gensrc/jvmtifiles \
-    $(JVM_VARIANT_OUTPUTDIR)/gensrc/tracefiles \
-    #
-
-JVM_CFLAGS_INCLUDES += \
-    $(patsubst %,-I%,$(filter-out $(JVM_VARIANT_OUTPUTDIR)/gensrc/%, $(JVM_SRC_DIRS))) \
-    -I$(JVM_VARIANT_OUTPUTDIR)/gensrc \
-    -I$(TOPDIR)/src/hotspot/share/precompiled \
-    -I$(TOPDIR)/src/hotspot/share/include \
-    -I$(TOPDIR)/src/hotspot/os/$(HOTSPOT_TARGET_OS_TYPE)/include \
-    -I$(SUPPORT_OUTPUTDIR)/modules_include/java.base \
-    -I$(SUPPORT_OUTPUTDIR)/modules_include/java.base/$(OPENJDK_TARGET_OS_INCLUDE_SUBDIR) \
-    -I$(TOPDIR)/src/java.base/share/native/libjimage \
-    #
-
-# INCLUDE_SUFFIX_* is only meant for including the proper
-# platform files. Don't use it to guard code. Use the value of
-# HOTSPOT_TARGET_CPU_DEFINE etc. instead.
-# Remaining TARGET_ARCH_* is needed to select the cpu specific
-# sources for 64-bit ARM ports (arm versus aarch64).
-JVM_CFLAGS_TARGET_DEFINES += \
-    -DTARGET_ARCH_$(HOTSPOT_TARGET_CPU_ARCH) \
-    -DINCLUDE_SUFFIX_OS=_$(HOTSPOT_TARGET_OS) \
-    -DINCLUDE_SUFFIX_CPU=_$(HOTSPOT_TARGET_CPU_ARCH) \
-    -DINCLUDE_SUFFIX_COMPILER=_$(HOTSPOT_TOOLCHAIN_TYPE) \
-    -DTARGET_COMPILER_$(HOTSPOT_TOOLCHAIN_TYPE) \
-    -D$(HOTSPOT_TARGET_CPU_DEFINE) \
-    -DHOTSPOT_LIB_ARCH='"$(OPENJDK_TARGET_CPU_LEGACY_LIB)"' \
-    #
-
-ifeq ($(DEBUG_LEVEL), release)
-  # For hotspot, release builds differ internally between "optimized" and "product"
-  # in that "optimize" does not define PRODUCT.
-  ifneq ($(HOTSPOT_DEBUG_LEVEL), optimized)
-    JVM_CFLAGS_DEBUGLEVEL := -DPRODUCT
-  endif
-else ifeq ($(DEBUG_LEVEL), fastdebug)
-  JVM_CFLAGS_DEBUGLEVEL := -DASSERT
-  ifeq ($(filter $(OPENJDK_TARGET_OS), windows aix), )
-    # NOTE: Old build did not define CHECK_UNHANDLED_OOPS on Windows and AIX.
-    JVM_CFLAGS_DEBUGLEVEL += -DCHECK_UNHANDLED_OOPS
-  endif
-else ifeq ($(DEBUG_LEVEL), slowdebug)
-  # _NMT_NOINLINE_ informs NMT that no inlining is done by the compiler
-  JVM_CFLAGS_DEBUGLEVEL := -DASSERT -D_NMT_NOINLINE_
-endif
-
-JVM_CFLAGS += \
-    $(JVM_CFLAGS_DEBUGLEVEL) \
-    $(JVM_CFLAGS_TARGET_DEFINES) \
-    $(JVM_CFLAGS_FEATURES) \
-    $(JVM_CFLAGS_INCLUDES) \
-    $(EXTRA_CFLAGS) \
-    #
-
 JVM_LDFLAGS += \
     $(SHARED_LIBRARY_FLAGS) \
     $(JVM_LDFLAGS_FEATURES) \
@@ -142,11 +79,6 @@
     -DCPU='"$(OPENJDK_TARGET_CPU_VM_VERSION)"' \
     #
 
-# -DDONT_USE_PRECOMPILED_HEADER will exclude all includes in precompiled.hpp.
-ifeq ($(USE_PRECOMPILED_HEADER), false)
-  JVM_CFLAGS += -DDONT_USE_PRECOMPILED_HEADER
-endif
-
 ################################################################################
 # Platform specific setup
 
@@ -214,7 +146,6 @@
     TOOLCHAIN := TOOLCHAIN_LINK_CXX, \
     OUTPUT_DIR := $(JVM_LIB_OUTPUTDIR), \
     SRC := $(JVM_SRC_DIRS), \
-    EXTRA_FILES := $(DTRACE_EXTRA_SOURCE_FILES), \
     EXCLUDES := $(JVM_EXCLUDES), \
     EXCLUDE_FILES := $(JVM_EXCLUDE_FILES), \
     EXCLUDE_PATTERNS := $(JVM_EXCLUDE_PATTERNS), \
--- a/make/hotspot/lib/CompileLibraries.gmk	Mon Apr 09 08:34:30 2018 -0700
+++ b/make/hotspot/lib/CompileLibraries.gmk	Tue Apr 10 13:58:47 2018 -0700
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 #
 # This code is free software; you can redistribute it and/or modify it
@@ -31,11 +31,8 @@
 
 include HotspotCommon.gmk
 
-# The dtrace setup must be done both before and after CompileJvm.gmk, due to
-# intricate dependencies.
-include lib/CompileDtracePreJvm.gmk
 include lib/CompileJvm.gmk
-include lib/CompileDtracePostJvm.gmk
+include lib/CompileDtraceLibraries.gmk
 
 ifeq ($(BUILD_GTEST), true)
   include lib/CompileGtest.gmk
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/make/hotspot/lib/JvmDtraceObjects.gmk	Tue Apr 10 13:58:47 2018 -0700
@@ -0,0 +1,134 @@
+#
+# Copyright (c) 2013, 2018, 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.
+#
+
+ifeq ($(call check-jvm-feature, dtrace), true)
+  ifeq ($(OPENJDK_TARGET_OS), solaris)
+
+    ############################################################################
+    # Integrate with libjvm. Here we generate two object files which are
+    # linked with libjvm.so. This step is complicated from a dependency
+    # perspective. We add these two files to the linking of libjvm using
+    # EXTRA_OBJECT_FILES, but they need to be created outside the call to
+    # SetupNativeCompilation. Also, one of the files is dependent on compiled
+    # object files from the libjvm compilation, so this generation must happen
+    # as a part of the libjvm compilation.
+
+    DTRACE_OBJ := $(JVM_OUTPUTDIR)/objs/dtrace.o
+    DTRACE_JHELPER_OBJ := $(JVM_OUTPUTDIR)/objs/dtrace_jhelper.o
+
+    DTRACE_EXTRA_OBJECT_FILES := $(DTRACE_OBJ) $(DTRACE_JHELPER_OBJ)
+
+    ############################################################################
+    # Generate DTRACE_OBJ which is linked with libjvm.so. It depends on a set of
+    # object files from the compilation.
+
+    # Concatenate all *.d files into a single file
+    DTRACE_SOURCE_FILES := $(addprefix $(TOPDIR)/src/hotspot/os/posix/dtrace/, \
+        hotspot_jni.d \
+        hotspot.d \
+        hs_private.d \
+    )
+
+    $(JVM_OUTPUTDIR)/objs/dtrace.d: $(DTRACE_SOURCE_FILES)
+	$(call LogInfo, Generating $(@F))
+	$(call MakeDir, $(@D))
+	$(CAT) $^ > $@
+
+    DTRACE_INSTRUMENTED_OBJS := $(addprefix $(JVM_OUTPUTDIR)/objs/, \
+        ciEnv.o \
+        classLoadingService.o \
+        compileBroker.o \
+        hashtable.o \
+        instanceKlass.o \
+        java.o \
+        jni.o \
+        jvm.o \
+        memoryManager.o \
+        nmethod.o \
+        objectMonitor.o \
+        runtimeService.o \
+        sharedRuntime.o \
+        synchronizer.o \
+        thread.o \
+        unsafe.o \
+        vmThread.o \
+        vmGCOperations.o \
+    )
+
+    ifeq ($(call check-jvm-feature, all-gcs), true)
+      DTRACE_INSTRUMENTED_OBJS += $(addprefix $(JVM_OUTPUTDIR)/objs/, \
+          vmCMSOperations.o \
+          vmPSOperations.o \
+      )
+    endif
+
+    DTRACE_FLAGS := -64 -G
+    DTRACE_CPP_FLAGS := -D_LP64
+
+    # Make sure we run our selected compiler for preprocessing instead of letting
+    # the dtrace tool pick it on it's own.
+    $(DTRACE_OBJ): $(JVM_OUTPUTDIR)/objs/dtrace.d $(DTRACE_INSTRUMENTED_OBJS)
+	$(call LogInfo, Generating $(@F) from $(<F) and object files)
+	$(call MakeDir, $(DTRACE_SUPPORT_DIR))
+	$(call ExecuteWithLog, $(DTRACE_SUPPORT_DIR)/$(@F).d, \
+	    ($(CPP) $(DTRACE_CPP_FLAGS) $< > $(DTRACE_SUPPORT_DIR)/$(@F).d))
+	$(call ExecuteWithLog, $@, $(DTRACE) $(DTRACE_FLAGS) -xlazyload -o $@ \
+	    -s $(DTRACE_SUPPORT_DIR)/$(@F).d $(sort $(DTRACE_INSTRUMENTED_OBJS)))
+
+    ############################################################################
+    # Generate DTRACE_JHELPER_OBJ which is linked with libjvm.so.
+
+    JHELPER_DTRACE_SRC := $(TOPDIR)/src/hotspot/os/solaris/dtrace/jhelper.d
+
+    # jhelper.d includes JvmOffsetsIndex.h which was created by the gensrc step.
+    DTRACE_GENSRC_DIR := $(JVM_VARIANT_OUTPUTDIR)/gensrc/dtracefiles
+    JVM_OFFSETS_INDEX_H := $(DTRACE_GENSRC_DIR)/JvmOffsetsIndex.h
+
+    # Unfortunately dtrace generates incorrect types for some symbols in
+    # dtrace_jhelper.o, resulting in "warning: symbol X has differing types"
+    # See JDK-6890703 for details.
+    # We work around this by fixing the types for these symbols using elfedit,
+    # after dtrace has generated the .o file.
+    GetElfeditCommands = \
+      $(foreach symbol, \
+          $(shell $(GREP) ^extern $(JHELPER_DTRACE_SRC) | $(AWK) '{ gsub(";","") ; print $$3 }'), \
+          -e 'sym:st_type $(symbol) 1')
+
+    # Make sure we run our selected compiler for preprocessing instead of letting
+    # the dtrace tool pick it on it's own.
+    $(DTRACE_JHELPER_OBJ): $(JHELPER_DTRACE_SRC) $(JVM_OFFSETS_INDEX_H)
+	$(call LogInfo, Running dtrace for $(<F))
+	$(call MakeDir, $(DTRACE_SUPPORT_DIR))
+	$(call ExecuteWithLog, $(DTRACE_SUPPORT_DIR)/$(@F).d, \
+	    ($(CPP) $(DTRACE_CPP_FLAGS) -I$(DTRACE_GENSRC_DIR) $^ \
+	    > $(DTRACE_SUPPORT_DIR)/$(@F).d))
+	$(call ExecuteWithLog, $@, $(DTRACE) $(DTRACE_FLAGS) -o $@ \
+	    -s $(DTRACE_SUPPORT_DIR)/$(@F).d)
+        ifeq ($(OPENJDK_TARGET_CPU_ARCH), sparc)
+	  $(call ExecuteWithLog, $@.elfedit, $(ELFEDIT) $(call GetElfeditCommands) $@)
+        endif
+
+  endif
+endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/make/hotspot/lib/JvmFlags.gmk	Tue Apr 10 13:58:47 2018 -0700
@@ -0,0 +1,97 @@
+#
+# Copyright (c) 2013, 2018, 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.
+#
+
+$(eval $(call IncludeCustomExtension, hotspot/lib/JvmFlags.gmk))
+
+################################################################################
+# Setup JVM_CFLAGS. These are shared between GensrcDtrace.gmk and CompileJvm.gmk.
+
+# This variable may be added to by a custom extension
+JVM_SRC_ROOTS += $(TOPDIR)/src/hotspot
+
+JVM_SRC_DIRS += $(call uniq, $(wildcard $(foreach d, $(JVM_SRC_ROOTS), \
+        $d/share \
+        $d/os/$(HOTSPOT_TARGET_OS) \
+        $d/os/$(HOTSPOT_TARGET_OS_TYPE) \
+        $d/cpu/$(HOTSPOT_TARGET_CPU_ARCH) \
+        $d/os_cpu/$(HOTSPOT_TARGET_OS)_$(HOTSPOT_TARGET_CPU_ARCH) \
+    ))) \
+    $(JVM_VARIANT_OUTPUTDIR)/gensrc
+    #
+
+JVM_CFLAGS_INCLUDES += \
+    $(patsubst %,-I%,$(JVM_SRC_DIRS)) \
+    -I$(TOPDIR)/src/hotspot/share/precompiled \
+    -I$(TOPDIR)/src/hotspot/share/include \
+    -I$(TOPDIR)/src/hotspot/os/$(HOTSPOT_TARGET_OS_TYPE)/include \
+    -I$(SUPPORT_OUTPUTDIR)/modules_include/java.base \
+    -I$(SUPPORT_OUTPUTDIR)/modules_include/java.base/$(OPENJDK_TARGET_OS_INCLUDE_SUBDIR) \
+    -I$(TOPDIR)/src/java.base/share/native/libjimage \
+    #
+
+# INCLUDE_SUFFIX_* is only meant for including the proper
+# platform files. Don't use it to guard code. Use the value of
+# HOTSPOT_TARGET_CPU_DEFINE etc. instead.
+# Remaining TARGET_ARCH_* is needed to select the cpu specific
+# sources for 64-bit ARM ports (arm versus aarch64).
+JVM_CFLAGS_TARGET_DEFINES += \
+    -DTARGET_ARCH_$(HOTSPOT_TARGET_CPU_ARCH) \
+    -DINCLUDE_SUFFIX_OS=_$(HOTSPOT_TARGET_OS) \
+    -DINCLUDE_SUFFIX_CPU=_$(HOTSPOT_TARGET_CPU_ARCH) \
+    -DINCLUDE_SUFFIX_COMPILER=_$(HOTSPOT_TOOLCHAIN_TYPE) \
+    -DTARGET_COMPILER_$(HOTSPOT_TOOLCHAIN_TYPE) \
+    -D$(HOTSPOT_TARGET_CPU_DEFINE) \
+    -DHOTSPOT_LIB_ARCH='"$(OPENJDK_TARGET_CPU_LEGACY_LIB)"' \
+    #
+
+ifeq ($(DEBUG_LEVEL), release)
+  # For hotspot, release builds differ internally between "optimized" and "product"
+  # in that "optimize" does not define PRODUCT.
+  ifneq ($(HOTSPOT_DEBUG_LEVEL), optimized)
+    JVM_CFLAGS_DEBUGLEVEL := -DPRODUCT
+  endif
+else ifeq ($(DEBUG_LEVEL), fastdebug)
+  JVM_CFLAGS_DEBUGLEVEL := -DASSERT
+  ifeq ($(filter $(OPENJDK_TARGET_OS), windows aix), )
+    # NOTE: Old build did not define CHECK_UNHANDLED_OOPS on Windows and AIX.
+    JVM_CFLAGS_DEBUGLEVEL += -DCHECK_UNHANDLED_OOPS
+  endif
+else ifeq ($(DEBUG_LEVEL), slowdebug)
+  # _NMT_NOINLINE_ informs NMT that no inlining is done by the compiler
+  JVM_CFLAGS_DEBUGLEVEL := -DASSERT -D_NMT_NOINLINE_
+endif
+
+JVM_CFLAGS += \
+    $(JVM_CFLAGS_DEBUGLEVEL) \
+    $(JVM_CFLAGS_TARGET_DEFINES) \
+    $(JVM_CFLAGS_FEATURES) \
+    $(JVM_CFLAGS_INCLUDES) \
+    $(EXTRA_CFLAGS) \
+    #
+
+# -DDONT_USE_PRECOMPILED_HEADER will exclude all includes in precompiled.hpp.
+ifeq ($(USE_PRECOMPILED_HEADER), false)
+  JVM_CFLAGS += -DDONT_USE_PRECOMPILED_HEADER
+endif
--- a/make/hotspot/src/native/dtrace/generateJvmOffsets.cpp	Mon Apr 09 08:34:30 2018 -0700
+++ b/make/hotspot/src/native/dtrace/generateJvmOffsets.cpp	Tue Apr 10 13:58:47 2018 -0700
@@ -31,29 +31,23 @@
  * GENOFFS_SCCS_VER 34
  */
 
-#include "generateJvmOffsets.h"
+#include <stdio.h>
+#include <strings.h>
 
 /* A workaround for private and protected fields */
 #define private   public
 #define protected public
 
 #include <proc_service.h>
-#include "code/codeBlob.hpp"
-#include "code/nmethod.hpp"
-#include "code/pcDesc.hpp"
 #include "gc/shared/collectedHeap.hpp"
-#include "memory/heap.hpp"
-#include "memory/memRegion.hpp"
-#include "memory/universe.hpp"
-#include "memory/virtualspace.hpp"
-#include "oops/constMethod.hpp"
-#include "oops/klass.hpp"
-#include "oops/method.hpp"
-#include "oops/oop.hpp"
-#include "oops/symbol.hpp"
 #include "runtime/vmStructs.hpp"
-#include "utilities/accessFlags.hpp"
-#include "utilities/globalDefinitions.hpp"
+
+typedef enum GEN_variant {
+        GEN_OFFSET = 0,
+        GEN_INDEX  = 1,
+        GEN_TABLE  = 2
+} GEN_variant;
+
 #ifdef COMPILER1
 #ifdef ASSERT
 
--- a/make/hotspot/src/native/dtrace/generateJvmOffsets.h	Mon Apr 09 08:34:30 2018 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,43 +0,0 @@
-/*
- * Copyright (c) 2003, 2010, 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.
- *
- */
-
-#ifndef OS_SOLARIS_DTRACE_GENERATEJVMOFFSETS_H
-#define OS_SOLARIS_DTRACE_GENERATEJVMOFFSETS_H
-
-#include <stdio.h>
-#include <strings.h>
-
-typedef enum GEN_variant {
-        GEN_OFFSET = 0,
-        GEN_INDEX  = 1,
-        GEN_TABLE  = 2
-} GEN_variant;
-
-extern "C" {
-        int generateJvmOffsets(GEN_variant gen_var);
-        void gen_prologue(GEN_variant gen_var);
-        void gen_epilogue(GEN_variant gen_var);
-}
-
-#endif // OS_SOLARIS_DTRACE_GENERATEJVMOFFSETS_H
--- a/make/launcher/Launcher-jdk.pack.gmk	Mon Apr 09 08:34:30 2018 -0700
+++ b/make/launcher/Launcher-jdk.pack.gmk	Tue Apr 10 13:58:47 2018 -0700
@@ -88,6 +88,7 @@
     CFLAGS_solaris := -KPIC, \
     CFLAGS_macosx := -fPIC, \
     DISABLED_WARNINGS_gcc := unused-result implicit-fallthrough, \
+    DISABLED_WARNINGS_microsoft := 4005, \
     LDFLAGS := $(UNPACKEXE_ZIPOBJS) \
         $(LDFLAGS_JDKEXE) $(LDFLAGS_CXX_JDK) \
         $(call SET_SHARED_LIBRARY_ORIGIN), \
--- a/make/lib/Awt2dLibraries.gmk	Mon Apr 09 08:34:30 2018 -0700
+++ b/make/lib/Awt2dLibraries.gmk	Tue Apr 10 13:58:47 2018 -0700
@@ -543,7 +543,7 @@
       DISABLED_WARNINGS_solstudio := \
          E_STATEMENT_NOT_REACHED \
          E_END_OF_LOOP_CODE_NOT_REACHED, \
-      DISABLED_WARNINGS_microsoft := 4267 4244, \
+      DISABLED_WARNINGS_microsoft := 4267 4244 4312, \
       LDFLAGS := $(LDFLAGS_JDKLIB) \
           $(call SET_SHARED_LIBRARY_ORIGIN), \
   ))
--- a/make/lib/Lib-java.base.gmk	Mon Apr 09 08:34:30 2018 -0700
+++ b/make/lib/Lib-java.base.gmk	Tue Apr 10 13:58:47 2018 -0700
@@ -155,10 +155,10 @@
 ################################################################################
 # Create the jsig library
 
-ifneq ($(OPENJDK_TARGET_OS), windows)
+ifeq ($(OPENJDK_TARGET_OS_TYPE), unix)
   ifeq ($(STATIC_BUILD), false)
 
-    LIBJSIG_SRC_DIR := $(TOPDIR)/src/java.base/$(OPENJDK_TARGET_OS)/native/libjsig
+    LIBJSIG_SRC_DIR := $(TOPDIR)/src/java.base/$(OPENJDK_TARGET_OS_TYPE)/native/libjsig
     LIBJSIG_MAPFILE := $(wildcard $(TOPDIR)/make/mapfiles/libjsig/mapfile-vers-$(OPENJDK_TARGET_OS))
 
     ifeq ($(OPENJDK_TARGET_OS), linux)
--- a/make/lib/Lib-java.desktop.gmk	Mon Apr 09 08:34:30 2018 -0700
+++ b/make/lib/Lib-java.desktop.gmk	Tue Apr 10 13:58:47 2018 -0700
@@ -50,6 +50,7 @@
 
   LIBJSOUND_CFLAGS := \
       -I$(SUPPORT_OUTPUTDIR)/headers/java.desktop \
+      $(ALSA_CFLAGS) \
       $(LIBJAVA_HEADER_FLAGS) \
       $(foreach dir, $(LIBJSOUND_SRC_DIRS), -I$(dir)) \
       -DX_PLATFORM=X_$(OPENJDK_TARGET_OS_UPPERCASE) \
--- a/make/lib/Lib-jdk.accessibility.gmk	Mon Apr 09 08:34:30 2018 -0700
+++ b/make/lib/Lib-jdk.accessibility.gmk	Tue Apr 10 13:58:47 2018 -0700
@@ -45,6 +45,7 @@
         NAME := javaaccessbridge$1, \
         SRC := $(JAVA_AB_SRCDIR), \
         OPTIMIZATION := LOW, \
+        DISABLED_WARNINGS_microsoft := 4311 4302 4312, \
         CFLAGS := $(CFLAGS_JDKLIB) $(ACCESSBRIDGE_CFLAGS) \
             $(addprefix -I,$(JAVA_AB_SRCDIR)) \
             -I$(ROOT_SRCDIR)/include/bridge \
@@ -69,6 +70,7 @@
         NAME := windowsaccessbridge$1, \
         SRC := $(WIN_AB_SRCDIR), \
         OPTIMIZATION := LOW, \
+        DISABLED_WARNINGS_microsoft := 4311 4302 4312, \
         CFLAGS := $(filter-out -MD, $(CFLAGS_JDKLIB)) -MT $(ACCESSBRIDGE_CFLAGS) \
             $(addprefix -I,$(WIN_AB_SRCDIR)) \
             -I$(ROOT_SRCDIR)/include/bridge \
--- a/make/lib/Lib-jdk.pack.gmk	Mon Apr 09 08:34:30 2018 -0700
+++ b/make/lib/Lib-jdk.pack.gmk	Tue Apr 10 13:58:47 2018 -0700
@@ -40,6 +40,7 @@
         $(LIBJAVA_HEADER_FLAGS), \
     CFLAGS_release := -DPRODUCT, \
     DISABLED_WARNINGS_gcc := implicit-fallthrough, \
+    DISABLED_WARNINGS_microsoft := 4005, \
     LDFLAGS := $(LDFLAGS_JDKLIB) $(LDFLAGS_CXX_JDK) \
         $(call SET_SHARED_LIBRARY_ORIGIN), \
     LDFLAGS_windows := -map:$(SUPPORT_OUTPUTDIR)/native/$(MODULE)/unpack.map -debug, \
--- a/make/mapfiles/libjsig/mapfile-vers-solaris	Mon Apr 09 08:34:30 2018 -0700
+++ b/make/mapfiles/libjsig/mapfile-vers-solaris	Tue Apr 10 13:58:47 2018 -0700
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2005, 2018, 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,7 +28,6 @@
         global:
             JVM_begin_signal_setting;
             JVM_end_signal_setting;
-            JVM_get_libjsig_version;
             JVM_get_signal_action;
             sigaction;
             signal;
--- a/src/hotspot/os/solaris/os_solaris.cpp	Mon Apr 09 08:34:30 2018 -0700
+++ b/src/hotspot/os/solaris/os_solaris.cpp	Tue Apr 10 13:58:47 2018 -0700
@@ -2101,8 +2101,6 @@
 static int *preinstalled_sigs = NULL;
 static struct sigaction *chainedsigactions = NULL;
 static Semaphore* sig_sem = NULL;
-typedef int (*version_getting_t)();
-version_getting_t os::Solaris::get_libjsig_version = NULL;
 
 int os::sigexitnum_pd() {
   assert(Sigexit > 0, "signal memory not yet initialized");
@@ -3968,13 +3966,7 @@
                                         dlsym(RTLD_DEFAULT, "JVM_end_signal_setting"));
     get_signal_action = CAST_TO_FN_PTR(get_signal_t,
                                        dlsym(RTLD_DEFAULT, "JVM_get_signal_action"));
-    get_libjsig_version = CAST_TO_FN_PTR(version_getting_t,
-                                         dlsym(RTLD_DEFAULT, "JVM_get_libjsig_version"));
     libjsig_is_loaded = true;
-    if (os::Solaris::get_libjsig_version != NULL) {
-      int libjsigversion =  (*os::Solaris::get_libjsig_version)();
-      assert(libjsigversion == JSIG_VERSION_1_4_1, "libjsig version mismatch");
-    }
     assert(UseSignalChaining, "should enable signal-chaining");
   }
   if (libjsig_is_loaded) {
--- a/src/java.base/linux/native/libjsig/jsig.c	Mon Apr 09 08:34:30 2018 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,230 +0,0 @@
-/*
- * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-/* CopyrightVersion 1.2 */
-
-/* This is a special library that should be loaded before libc &
- * libthread to interpose the signal handler installation functions:
- * sigaction(), signal(), sigset().
- * Used for signal-chaining. See RFE 4381843.
- */
-
-#include <signal.h>
-#include <dlfcn.h>
-#include <pthread.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-
-#define bool int
-#define true 1
-#define false 0
-
-#define MASK(sig) ((uint64_t)1 << (sig-1))  // 0 is not a signal.
-// Check whether all signals fit into jvmsigs. -1 as MASK shifts by -1.
-#if (64 < NSIG-1)
-#error "Not all signals can be encoded in jvmsigs. Adapt its type!"
-#endif
-static struct sigaction sact[NSIG]; /* saved signal handlers */
-static uint64_t jvmsigs = 0; /* signals used by jvm */
-
-/* used to synchronize the installation of signal handlers */
-static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
-static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
-static pthread_t tid = 0;
-
-typedef void (*sa_handler_t)(int);
-typedef void (*sa_sigaction_t)(int, siginfo_t *, void *);
-typedef sa_handler_t (*signal_t)(int, sa_handler_t);
-typedef int (*sigaction_t)(int, const struct sigaction *, struct sigaction *);
-
-static signal_t os_signal = 0; /* os's version of signal()/sigset() */
-static sigaction_t os_sigaction = 0; /* os's version of sigaction() */
-
-static bool jvm_signal_installing = false;
-static bool jvm_signal_installed = false;
-
-static void signal_lock() {
-  pthread_mutex_lock(&mutex);
-  /* When the jvm is installing its set of signal handlers, threads
-   * other than the jvm thread should wait */
-  if (jvm_signal_installing) {
-    if (tid != pthread_self()) {
-      pthread_cond_wait(&cond, &mutex);
-    }
-  }
-}
-
-static void signal_unlock() {
-  pthread_mutex_unlock(&mutex);
-}
-
-static sa_handler_t call_os_signal(int sig, sa_handler_t disp,
-                                   bool is_sigset) {
-  if (os_signal == NULL) {
-    if (!is_sigset) {
-      os_signal = (signal_t)dlsym(RTLD_NEXT, "signal");
-    } else {
-      os_signal = (signal_t)dlsym(RTLD_NEXT, "sigset");
-    }
-    if (os_signal == NULL) {
-      printf("%s\n", dlerror());
-      exit(0);
-    }
-  }
-  return (*os_signal)(sig, disp);
-}
-
-static void save_signal_handler(int sig, sa_handler_t disp) {
-  sigset_t set;
-  sact[sig].sa_handler = disp;
-  sigemptyset(&set);
-  sact[sig].sa_mask = set;
-  sact[sig].sa_flags = 0;
-}
-
-static sa_handler_t set_signal(int sig, sa_handler_t disp, bool is_sigset) {
-  sa_handler_t oldhandler;
-  bool sigused;
-
-  signal_lock();
-
-  sigused = (sig < NSIG) && ((MASK(sig) & jvmsigs) != 0);
-  if (jvm_signal_installed && sigused) {
-    /* jvm has installed its signal handler for this signal. */
-    /* Save the handler. Don't really install it. */
-    oldhandler = sact[sig].sa_handler;
-    save_signal_handler(sig, disp);
-
-    signal_unlock();
-    return oldhandler;
-  } else if (sig < NSIG && jvm_signal_installing) {
-    /* jvm is installing its signal handlers. Install the new
-     * handlers and save the old ones. jvm uses sigaction().
-     * Leave the piece here just in case. */
-    oldhandler = call_os_signal(sig, disp, is_sigset);
-    save_signal_handler(sig, oldhandler);
-
-    /* Record the signals used by jvm */
-    jvmsigs |= MASK(sig);
-
-    signal_unlock();
-    return oldhandler;
-  } else {
-    /* jvm has no relation with this signal (yet). Install the
-     * the handler. */
-    oldhandler = call_os_signal(sig, disp, is_sigset);
-
-    signal_unlock();
-    return oldhandler;
-  }
-}
-
-sa_handler_t signal(int sig, sa_handler_t disp) {
-  return set_signal(sig, disp, false);
-}
-
-sa_handler_t sigset(int sig, sa_handler_t disp) {
-  return set_signal(sig, disp, true);
- }
-
-static int call_os_sigaction(int sig, const struct sigaction  *act,
-                             struct sigaction *oact) {
-  if (os_sigaction == NULL) {
-    os_sigaction = (sigaction_t)dlsym(RTLD_NEXT, "sigaction");
-    if (os_sigaction == NULL) {
-      printf("%s\n", dlerror());
-      exit(0);
-    }
-  }
-  return (*os_sigaction)(sig, act, oact);
-}
-
-int sigaction(int sig, const struct sigaction *act, struct sigaction *oact) {
-  int res;
-  bool sigused;
-  struct sigaction oldAct;
-
-  signal_lock();
-
-  sigused = (sig < NSIG) && ((MASK(sig) & jvmsigs) != 0);
-  if (jvm_signal_installed && sigused) {
-    /* jvm has installed its signal handler for this signal. */
-    /* Save the handler. Don't really install it. */
-    if (oact != NULL) {
-      *oact = sact[sig];
-    }
-    if (act != NULL) {
-      sact[sig] = *act;
-    }
-
-    signal_unlock();
-    return 0;
-  } else if (sig < NSIG && jvm_signal_installing) {
-    /* jvm is installing its signal handlers. Install the new
-     * handlers and save the old ones. */
-    res = call_os_sigaction(sig, act, &oldAct);
-    sact[sig] = oldAct;
-    if (oact != NULL) {
-      *oact = oldAct;
-    }
-
-    /* Record the signals used by jvm */
-    jvmsigs |= MASK(sig);
-
-    signal_unlock();
-    return res;
-  } else {
-    /* jvm has no relation with this signal (yet). Install the
-     * the handler. */
-    res = call_os_sigaction(sig, act, oact);
-
-    signal_unlock();
-    return res;
-  }
-}
-
-/* The three functions for the jvm to call into */
-void JVM_begin_signal_setting() {
-  signal_lock();
-  jvm_signal_installing = true;
-  tid = pthread_self();
-  signal_unlock();
-}
-
-void JVM_end_signal_setting() {
-  signal_lock();
-  jvm_signal_installed = true;
-  jvm_signal_installing = false;
-  pthread_cond_broadcast(&cond);
-  signal_unlock();
-}
-
-struct sigaction *JVM_get_signal_action(int sig) {
-  /* Does race condition make sense here? */
-  if ((MASK(sig) & jvmsigs) != 0) {
-    return &sact[sig];
-  }
-  return NULL;
-}
--- a/src/java.base/macosx/native/libjsig/jsig.c	Mon Apr 09 08:34:30 2018 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,237 +0,0 @@
-/*
- * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-/* CopyrightVersion 1.2 */
-
-/* This is a special library that should be loaded before libc &
- * libthread to interpose the signal handler installation functions:
- * sigaction(), signal(), sigset().
- * Used for signal-chaining. See RFE 4381843.
- */
-
-#include <signal.h>
-#include <dlfcn.h>
-#include <pthread.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdbool.h>
-#include <stdint.h>
-
-#define MASK(sig) ((uint32_t)1 << (sig-1))  // 0 is not a signal.
-#if (32 < NSIG-1)
-#error "Not all signals can be encoded in jvmsigs. Adapt its type!"
-#endif
-static struct sigaction sact[NSIG]; /* saved signal handlers */
-static uint32_t jvmsigs = 0; /* signals used by jvm */
-static __thread bool reentry = false; /* prevent reentry deadlock (per-thread) */
-
-/* used to synchronize the installation of signal handlers */
-static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
-static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
-static pthread_t tid = 0;
-
-typedef void (*sa_handler_t)(int);
-typedef void (*sa_sigaction_t)(int, siginfo_t *, void *);
-typedef sa_handler_t (*signal_t)(int, sa_handler_t);
-typedef int (*sigaction_t)(int, const struct sigaction *, struct sigaction *);
-
-static signal_t os_signal = 0; /* os's version of signal()/sigset() */
-static sigaction_t os_sigaction = 0; /* os's version of sigaction() */
-
-static bool jvm_signal_installing = false;
-static bool jvm_signal_installed = false;
-
-static void signal_lock() {
-  pthread_mutex_lock(&mutex);
-  /* When the jvm is installing its set of signal handlers, threads
-   * other than the jvm thread should wait */
-  if (jvm_signal_installing) {
-    if (tid != pthread_self()) {
-      pthread_cond_wait(&cond, &mutex);
-    }
-  }
-}
-
-static void signal_unlock() {
-  pthread_mutex_unlock(&mutex);
-}
-
-static sa_handler_t call_os_signal(int sig, sa_handler_t disp,
-                                   bool is_sigset) {
-  sa_handler_t res;
-
-  if (os_signal == NULL) {
-    if (!is_sigset) {
-      os_signal = (signal_t)dlsym(RTLD_NEXT, "signal");
-    } else {
-      os_signal = (signal_t)dlsym(RTLD_NEXT, "sigset");
-    }
-    if (os_signal == NULL) {
-      printf("%s\n", dlerror());
-      exit(0);
-    }
-  }
-  reentry = true;
-  res = (*os_signal)(sig, disp);
-  reentry = false;
-  return res;
-}
-
-static void save_signal_handler(int sig, sa_handler_t disp) {
-  sigset_t set;
-  sact[sig].sa_handler = disp;
-  sigemptyset(&set);
-  sact[sig].sa_mask = set;
-  sact[sig].sa_flags = 0;
-}
-
-static sa_handler_t set_signal(int sig, sa_handler_t disp, bool is_sigset) {
-  sa_handler_t oldhandler;
-  bool sigused;
-
-  signal_lock();
-
-  sigused = (MASK(sig) & jvmsigs) != 0;
-  if (jvm_signal_installed && sigused) {
-    /* jvm has installed its signal handler for this signal. */
-    /* Save the handler. Don't really install it. */
-    oldhandler = sact[sig].sa_handler;
-    save_signal_handler(sig, disp);
-
-    signal_unlock();
-    return oldhandler;
-  } else if (jvm_signal_installing) {
-    /* jvm is installing its signal handlers. Install the new
-     * handlers and save the old ones. jvm uses sigaction().
-     * Leave the piece here just in case. */
-    oldhandler = call_os_signal(sig, disp, is_sigset);
-    save_signal_handler(sig, oldhandler);
-
-    /* Record the signals used by jvm */
-    jvmsigs |= MASK(sig);
-
-    signal_unlock();
-    return oldhandler;
-  } else {
-    /* jvm has no relation with this signal (yet). Install the
-     * the handler. */
-    oldhandler = call_os_signal(sig, disp, is_sigset);
-
-    signal_unlock();
-    return oldhandler;
-  }
-}
-
-sa_handler_t signal(int sig, sa_handler_t disp) {
-  return set_signal(sig, disp, false);
-}
-
-sa_handler_t sigset(int sig, sa_handler_t disp) {
-  printf("sigset() is not supported by BSD");
-  exit(0);
- }
-
-static int call_os_sigaction(int sig, const struct sigaction  *act,
-                             struct sigaction *oact) {
-  if (os_sigaction == NULL) {
-    os_sigaction = (sigaction_t)dlsym(RTLD_NEXT, "sigaction");
-    if (os_sigaction == NULL) {
-      printf("%s\n", dlerror());
-      exit(0);
-    }
-  }
-  return (*os_sigaction)(sig, act, oact);
-}
-
-int sigaction(int sig, const struct sigaction *act, struct sigaction *oact) {
-  int res;
-  bool sigused;
-  struct sigaction oldAct;
-
-  if (reentry) {
-    return call_os_sigaction(sig, act, oact);
-  }
-
-  signal_lock();
-
-  sigused = (MASK(sig) & jvmsigs) != 0;
-  if (jvm_signal_installed && sigused) {
-    /* jvm has installed its signal handler for this signal. */
-    /* Save the handler. Don't really install it. */
-    if (oact != NULL) {
-      *oact = sact[sig];
-    }
-    if (act != NULL) {
-      sact[sig] = *act;
-    }
-
-    signal_unlock();
-    return 0;
-  } else if (jvm_signal_installing) {
-    /* jvm is installing its signal handlers. Install the new
-     * handlers and save the old ones. */
-    res = call_os_sigaction(sig, act, &oldAct);
-    sact[sig] = oldAct;
-    if (oact != NULL) {
-      *oact = oldAct;
-    }
-
-    /* Record the signals used by jvm */
-    jvmsigs |= MASK(sig);
-
-    signal_unlock();
-    return res;
-  } else {
-    /* jvm has no relation with this signal (yet). Install the
-     * the handler. */
-    res = call_os_sigaction(sig, act, oact);
-
-    signal_unlock();
-    return res;
-  }
-}
-
-/* The three functions for the jvm to call into */
-void JVM_begin_signal_setting() {
-  signal_lock();
-  jvm_signal_installing = true;
-  tid = pthread_self();
-  signal_unlock();
-}
-
-void JVM_end_signal_setting() {
-  signal_lock();
-  jvm_signal_installed = true;
-  jvm_signal_installing = false;
-  pthread_cond_broadcast(&cond);
-  signal_unlock();
-}
-
-struct sigaction *JVM_get_signal_action(int sig) {
-  /* Does race condition make sense here? */
-  if ((MASK(sig) & jvmsigs) != 0) {
-    return &sact[sig];
-  }
-  return NULL;
-}
--- a/src/java.base/share/classes/java/lang/StringCoding.java	Mon Apr 09 08:34:30 2018 -0700
+++ b/src/java.base/share/classes/java/lang/StringCoding.java	Tue Apr 10 13:58:47 2018 -0700
@@ -42,7 +42,6 @@
 import sun.nio.cs.HistoricallyNamedCharset;
 import sun.nio.cs.ArrayDecoder;
 import sun.nio.cs.ArrayEncoder;
-import sun.nio.cs.StandardCharsets;
 
 import static java.lang.String.LATIN1;
 import static java.lang.String.UTF16;
@@ -52,9 +51,6 @@
 import static java.lang.Character.lowSurrogate;
 import static java.lang.Character.isSupplementaryCodePoint;
 import static java.lang.StringUTF16.putChar;
-import static java.nio.charset.StandardCharsets.ISO_8859_1;
-import static java.nio.charset.StandardCharsets.US_ASCII;
-import static java.nio.charset.StandardCharsets.UTF_8;
 
 /**
  * Utility class for string encoding and decoding.
@@ -70,6 +66,10 @@
     private static final ThreadLocal<SoftReference<StringEncoder>> encoder =
         new ThreadLocal<>();
 
+    private static final Charset ISO_8859_1 = sun.nio.cs.ISO_8859_1.INSTANCE;
+    private static final Charset US_ASCII = sun.nio.cs.US_ASCII.INSTANCE;
+    private static final Charset UTF_8 = sun.nio.cs.UTF_8.INSTANCE;
+
     private static <T> T deref(ThreadLocal<SoftReference<T>> tl) {
         SoftReference<T> sr = tl.get();
         if (sr == null)
--- a/src/java.base/share/classes/java/nio/charset/Charset.java	Mon Apr 09 08:34:30 2018 -0700
+++ b/src/java.base/share/classes/java/nio/charset/Charset.java	Tue Apr 10 13:58:47 2018 -0700
@@ -609,7 +609,7 @@
                 if (cs != null)
                     defaultCharset = cs;
                 else
-                    defaultCharset = StandardCharsets.UTF_8;
+                    defaultCharset = sun.nio.cs.UTF_8.INSTANCE;
             }
         }
         return defaultCharset;
--- a/src/java.base/share/classes/java/nio/charset/StandardCharsets.java	Mon Apr 09 08:34:30 2018 -0700
+++ b/src/java.base/share/classes/java/nio/charset/StandardCharsets.java	Tue Apr 10 13:58:47 2018 -0700
@@ -34,22 +34,28 @@
  */
 public final class StandardCharsets {
 
+    // To avoid accidental eager initialization of often unused Charsets
+    // from happening while the VM is booting up, which may delay
+    // initialization of VM components, we should generally avoid depending
+    // on this class from elsewhere in java.base.
+
     private StandardCharsets() {
         throw new AssertionError("No java.nio.charset.StandardCharsets instances for you!");
     }
+
     /**
      * Seven-bit ASCII, a.k.a. ISO646-US, a.k.a. the Basic Latin block of the
      * Unicode character set
      */
-    public static final Charset US_ASCII = new sun.nio.cs.US_ASCII();
+    public static final Charset US_ASCII = sun.nio.cs.US_ASCII.INSTANCE;
     /**
      * ISO Latin Alphabet No. 1, a.k.a. ISO-LATIN-1
      */
-    public static final Charset ISO_8859_1 = new sun.nio.cs.ISO_8859_1();
+    public static final Charset ISO_8859_1 = sun.nio.cs.ISO_8859_1.INSTANCE;
     /**
      * Eight-bit UCS Transformation Format
      */
-    public static final Charset UTF_8 = new sun.nio.cs.UTF_8();
+    public static final Charset UTF_8 = sun.nio.cs.UTF_8.INSTANCE;
     /**
      * Sixteen-bit UCS Transformation Format, big-endian byte order
      */
--- a/src/java.base/share/classes/java/util/ArrayDeque.java	Mon Apr 09 08:34:30 2018 -0700
+++ b/src/java.base/share/classes/java/util/ArrayDeque.java	Tue Apr 10 13:58:47 2018 -0700
@@ -208,7 +208,7 @@
      */
     public ArrayDeque(Collection<? extends E> c) {
         this(c.size());
-        addAll(c);
+        copyElements(c);
     }
 
     /**
@@ -322,8 +322,12 @@
         final int s, needed;
         if ((needed = (s = size()) + c.size() + 1 - elements.length) > 0)
             grow(needed);
+        copyElements(c);
+        return size() > s;
+    }
+
+    private void copyElements(Collection<? extends E> c) {
         c.forEach(this::addLast);
-        return size() > s;
     }
 
     /**
--- a/src/java.base/share/classes/java/util/Deque.java	Mon Apr 09 08:34:30 2018 -0700
+++ b/src/java.base/share/classes/java/util/Deque.java	Tue Apr 10 13:58:47 2018 -0700
@@ -141,8 +141,8 @@
  * <p>Deques can also be used as LIFO (Last-In-First-Out) stacks.  This
  * interface should be used in preference to the legacy {@link Stack} class.
  * When a deque is used as a stack, elements are pushed and popped from the
- * beginning of the deque.  Stack methods are precisely equivalent to
- * {@code Deque} methods as indicated in the table below:
+ * beginning of the deque.  Stack methods are equivalent to {@code Deque}
+ * methods as indicated in the table below:
  *
  * <table class="striped">
  * <caption>Comparison of Stack and Deque methods</caption>
@@ -163,7 +163,7 @@
  *  </tr>
  *  <tr>
  *    <th scope="row">{@link #peek() peek()}</th>
- *    <td>{@link #peekFirst() peekFirst()}</td>
+ *    <td>{@link #getFirst() getFirst()}</td>
  *  </tr>
  *  </tbody>
  * </table>
--- a/src/java.base/share/classes/java/util/concurrent/CompletableFuture.java	Mon Apr 09 08:34:30 2018 -0700
+++ b/src/java.base/share/classes/java/util/concurrent/CompletableFuture.java	Tue Apr 10 13:58:47 2018 -0700
@@ -2883,7 +2883,7 @@
             STACK = l.findVarHandle(CompletableFuture.class, "stack", Completion.class);
             NEXT = l.findVarHandle(Completion.class, "next", Completion.class);
         } catch (ReflectiveOperationException e) {
-            throw new Error(e);
+            throw new ExceptionInInitializerError(e);
         }
 
         // Reduce the risk of rare disastrous classloading in first call to
--- a/src/java.base/share/classes/java/util/concurrent/ConcurrentHashMap.java	Mon Apr 09 08:34:30 2018 -0700
+++ b/src/java.base/share/classes/java/util/concurrent/ConcurrentHashMap.java	Tue Apr 10 13:58:47 2018 -0700
@@ -6383,7 +6383,7 @@
         ABASE = U.arrayBaseOffset(Node[].class);
         int scale = U.arrayIndexScale(Node[].class);
         if ((scale & (scale - 1)) != 0)
-            throw new Error("array index scale not a power of two");
+            throw new ExceptionInInitializerError("array index scale not a power of two");
         ASHIFT = 31 - Integer.numberOfLeadingZeros(scale);
 
         // Reduce the risk of rare disastrous classloading in first call to
--- a/src/java.base/share/classes/java/util/concurrent/ConcurrentLinkedDeque.java	Mon Apr 09 08:34:30 2018 -0700
+++ b/src/java.base/share/classes/java/util/concurrent/ConcurrentLinkedDeque.java	Tue Apr 10 13:58:47 2018 -0700
@@ -1671,7 +1671,7 @@
             NEXT = l.findVarHandle(Node.class, "next", Node.class);
             ITEM = l.findVarHandle(Node.class, "item", Object.class);
         } catch (ReflectiveOperationException e) {
-            throw new Error(e);
+            throw new ExceptionInInitializerError(e);
         }
     }
 }
--- a/src/java.base/share/classes/java/util/concurrent/ConcurrentLinkedQueue.java	Mon Apr 09 08:34:30 2018 -0700
+++ b/src/java.base/share/classes/java/util/concurrent/ConcurrentLinkedQueue.java	Tue Apr 10 13:58:47 2018 -0700
@@ -1069,7 +1069,7 @@
             ITEM = l.findVarHandle(Node.class, "item", Object.class);
             NEXT = l.findVarHandle(Node.class, "next", Node.class);
         } catch (ReflectiveOperationException e) {
-            throw new Error(e);
+            throw new ExceptionInInitializerError(e);
         }
     }
 }
--- a/src/java.base/share/classes/java/util/concurrent/ConcurrentSkipListMap.java	Mon Apr 09 08:34:30 2018 -0700
+++ b/src/java.base/share/classes/java/util/concurrent/ConcurrentSkipListMap.java	Tue Apr 10 13:58:47 2018 -0700
@@ -3412,7 +3412,7 @@
             VAL = l.findVarHandle(Node.class, "val", Object.class);
             RIGHT = l.findVarHandle(Index.class, "right", Index.class);
         } catch (ReflectiveOperationException e) {
-            throw new Error(e);
+            throw new ExceptionInInitializerError(e);
         }
     }
 }
--- a/src/java.base/share/classes/java/util/concurrent/CopyOnWriteArrayList.java	Mon Apr 09 08:34:30 2018 -0700
+++ b/src/java.base/share/classes/java/util/concurrent/CopyOnWriteArrayList.java	Tue Apr 10 13:58:47 2018 -0700
@@ -35,7 +35,6 @@
 package java.util.concurrent;
 
 import java.lang.reflect.Field;
-import java.util.AbstractList;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Comparator;
@@ -134,17 +133,17 @@
      * @throws NullPointerException if the specified collection is null
      */
     public CopyOnWriteArrayList(Collection<? extends E> c) {
-        Object[] elements;
+        Object[] es;
         if (c.getClass() == CopyOnWriteArrayList.class)
-            elements = ((CopyOnWriteArrayList<?>)c).getArray();
+            es = ((CopyOnWriteArrayList<?>)c).getArray();
         else {
-            elements = c.toArray();
+            es = c.toArray();
             // defend against c.toArray (incorrectly) not returning Object[]
             // (see e.g. https://bugs.openjdk.java.net/browse/JDK-6260652)
-            if (elements.getClass() != Object[].class)
-                elements = Arrays.copyOf(elements, elements.length, Object[].class);
+            if (es.getClass() != Object[].class)
+                es = Arrays.copyOf(es, es.length, Object[].class);
         }
-        setArray(elements);
+        setArray(es);
     }
 
     /**
@@ -180,20 +179,19 @@
      * static version of indexOf, to allow repeated calls without
      * needing to re-acquire array each time.
      * @param o element to search for
-     * @param elements the array
-     * @param index first index to search
-     * @param fence one past last index to search
+     * @param es the array
+     * @param from first index to search
+     * @param to one past last index to search
      * @return index of element, or -1 if absent
      */
-    private static int indexOf(Object o, Object[] elements,
-                               int index, int fence) {
+    private static int indexOfRange(Object o, Object[] es, int from, int to) {
         if (o == null) {
-            for (int i = index; i < fence; i++)
-                if (elements[i] == null)
+            for (int i = from; i < to; i++)
+                if (es[i] == null)
                     return i;
         } else {
-            for (int i = index; i < fence; i++)
-                if (o.equals(elements[i]))
+            for (int i = from; i < to; i++)
+                if (o.equals(es[i]))
                     return i;
         }
         return -1;
@@ -202,18 +200,19 @@
     /**
      * static version of lastIndexOf.
      * @param o element to search for
-     * @param elements the array
-     * @param index first index to search
+     * @param es the array
+     * @param from index of first element of range, last element to search
+     * @param to one past last element of range, first element to search
      * @return index of element, or -1 if absent
      */
-    private static int lastIndexOf(Object o, Object[] elements, int index) {
+    private static int lastIndexOfRange(Object o, Object[] es, int from, int to) {
         if (o == null) {
-            for (int i = index; i >= 0; i--)
-                if (elements[i] == null)
+            for (int i = to - 1; i >= from; i--)
+                if (es[i] == null)
                     return i;
         } else {
-            for (int i = index; i >= 0; i--)
-                if (o.equals(elements[i]))
+            for (int i = to - 1; i >= from; i--)
+                if (o.equals(es[i]))
                     return i;
         }
         return -1;
@@ -228,16 +227,15 @@
      * @return {@code true} if this list contains the specified element
      */
     public boolean contains(Object o) {
-        Object[] elements = getArray();
-        return indexOf(o, elements, 0, elements.length) >= 0;
+        return indexOf(o) >= 0;
     }
 
     /**
      * {@inheritDoc}
      */
     public int indexOf(Object o) {
-        Object[] elements = getArray();
-        return indexOf(o, elements, 0, elements.length);
+        Object[] es = getArray();
+        return indexOfRange(o, es, 0, es.length);
     }
 
     /**
@@ -256,16 +254,16 @@
      * @throws IndexOutOfBoundsException if the specified index is negative
      */
     public int indexOf(E e, int index) {
-        Object[] elements = getArray();
-        return indexOf(e, elements, index, elements.length);
+        Object[] es = getArray();
+        return indexOfRange(e, es, index, es.length);
     }
 
     /**
      * {@inheritDoc}
      */
     public int lastIndexOf(Object o) {
-        Object[] elements = getArray();
-        return lastIndexOf(o, elements, elements.length - 1);
+        Object[] es = getArray();
+        return lastIndexOfRange(o, es, 0, es.length);
     }
 
     /**
@@ -285,8 +283,8 @@
      *         than or equal to the current size of this list
      */
     public int lastIndexOf(E e, int index) {
-        Object[] elements = getArray();
-        return lastIndexOf(e, elements, index);
+        Object[] es = getArray();
+        return lastIndexOfRange(e, es, 0, index + 1);
     }
 
     /**
@@ -322,8 +320,7 @@
      * @return an array containing all the elements in this list
      */
     public Object[] toArray() {
-        Object[] elements = getArray();
-        return Arrays.copyOf(elements, elements.length);
+        return getArray().clone();
     }
 
     /**
@@ -366,12 +363,12 @@
      */
     @SuppressWarnings("unchecked")
     public <T> T[] toArray(T[] a) {
-        Object[] elements = getArray();
-        int len = elements.length;
+        Object[] es = getArray();
+        int len = es.length;
         if (a.length < len)
-            return (T[]) Arrays.copyOf(elements, len, a.getClass());
+            return (T[]) Arrays.copyOf(es, len, a.getClass());
         else {
-            System.arraycopy(elements, 0, a, 0, len);
+            System.arraycopy(es, 0, a, 0, len);
             if (a.length > len)
                 a[len] = null;
             return a;
@@ -406,17 +403,13 @@
      */
     public E set(int index, E element) {
         synchronized (lock) {
-            Object[] elements = getArray();
-            E oldValue = elementAt(elements, index);
+            Object[] es = getArray();
+            E oldValue = elementAt(es, index);
 
             if (oldValue != element) {
-                int len = elements.length;
-                Object[] newElements = Arrays.copyOf(elements, len);
-                newElements[index] = element;
-                setArray(newElements);
-            } else {
-                // Not quite a no-op; ensures volatile write semantics
-                setArray(elements);
+                es = es.clone();
+                es[index] = element;
+                setArray(es);
             }
             return oldValue;
         }
@@ -430,11 +423,11 @@
      */
     public boolean add(E e) {
         synchronized (lock) {
-            Object[] elements = getArray();
-            int len = elements.length;
-            Object[] newElements = Arrays.copyOf(elements, len + 1);
-            newElements[len] = e;
-            setArray(newElements);
+            Object[] es = getArray();
+            int len = es.length;
+            es = Arrays.copyOf(es, len + 1);
+            es[len] = e;
+            setArray(es);
             return true;
         }
     }
@@ -448,18 +441,18 @@
      */
     public void add(int index, E element) {
         synchronized (lock) {
-            Object[] elements = getArray();
-            int len = elements.length;
+            Object[] es = getArray();
+            int len = es.length;
             if (index > len || index < 0)
                 throw new IndexOutOfBoundsException(outOfBounds(index, len));
             Object[] newElements;
             int numMoved = len - index;
             if (numMoved == 0)
-                newElements = Arrays.copyOf(elements, len + 1);
+                newElements = Arrays.copyOf(es, len + 1);
             else {
                 newElements = new Object[len + 1];
-                System.arraycopy(elements, 0, newElements, 0, index);
-                System.arraycopy(elements, index, newElements, index + 1,
+                System.arraycopy(es, 0, newElements, 0, index);
+                System.arraycopy(es, index, newElements, index + 1,
                                  numMoved);
             }
             newElements[index] = element;
@@ -476,19 +469,20 @@
      */
     public E remove(int index) {
         synchronized (lock) {
-            Object[] elements = getArray();
-            int len = elements.length;
-            E oldValue = elementAt(elements, index);
+            Object[] es = getArray();
+            int len = es.length;
+            E oldValue = elementAt(es, index);
             int numMoved = len - index - 1;
+            Object[] newElements;
             if (numMoved == 0)
-                setArray(Arrays.copyOf(elements, len - 1));
+                newElements = Arrays.copyOf(es, len - 1);
             else {
-                Object[] newElements = new Object[len - 1];
-                System.arraycopy(elements, 0, newElements, 0, index);
-                System.arraycopy(elements, index + 1, newElements, index,
+                newElements = new Object[len - 1];
+                System.arraycopy(es, 0, newElements, 0, index);
+                System.arraycopy(es, index + 1, newElements, index,
                                  numMoved);
-                setArray(newElements);
             }
+            setArray(newElements);
             return oldValue;
         }
     }
@@ -507,7 +501,7 @@
      */
     public boolean remove(Object o) {
         Object[] snapshot = getArray();
-        int index = indexOf(o, snapshot, 0, snapshot.length);
+        int index = indexOfRange(o, snapshot, 0, snapshot.length);
         return index >= 0 && remove(o, snapshot, index);
     }
 
@@ -532,7 +526,7 @@
                     return false;
                 if (current[index] == o)
                     break findIndex;
-                index = indexOf(o, current, index, len);
+                index = indexOfRange(o, current, index, len);
                 if (index < 0)
                     return false;
             }
@@ -560,19 +554,19 @@
      */
     void removeRange(int fromIndex, int toIndex) {
         synchronized (lock) {
-            Object[] elements = getArray();
-            int len = elements.length;
+            Object[] es = getArray();
+            int len = es.length;
 
             if (fromIndex < 0 || toIndex > len || toIndex < fromIndex)
                 throw new IndexOutOfBoundsException();
             int newlen = len - (toIndex - fromIndex);
             int numMoved = len - toIndex;
             if (numMoved == 0)
-                setArray(Arrays.copyOf(elements, newlen));
+                setArray(Arrays.copyOf(es, newlen));
             else {
                 Object[] newElements = new Object[newlen];
-                System.arraycopy(elements, 0, newElements, 0, fromIndex);
-                System.arraycopy(elements, toIndex, newElements,
+                System.arraycopy(es, 0, newElements, 0, fromIndex);
+                System.arraycopy(es, toIndex, newElements,
                                  fromIndex, numMoved);
                 setArray(newElements);
             }
@@ -587,7 +581,7 @@
      */
     public boolean addIfAbsent(E e) {
         Object[] snapshot = getArray();
-        return indexOf(e, snapshot, 0, snapshot.length) < 0
+        return indexOfRange(e, snapshot, 0, snapshot.length) < 0
             && addIfAbsent(e, snapshot);
     }
 
@@ -606,7 +600,7 @@
                     if (current[i] != snapshot[i]
                         && Objects.equals(e, current[i]))
                         return false;
-                if (indexOf(e, current, common, len) >= 0)
+                if (indexOfRange(e, current, common, len) >= 0)
                         return false;
             }
             Object[] newElements = Arrays.copyOf(current, len + 1);
@@ -627,10 +621,10 @@
      * @see #contains(Object)
      */
     public boolean containsAll(Collection<?> c) {
-        Object[] elements = getArray();
-        int len = elements.length;
+        Object[] es = getArray();
+        int len = es.length;
         for (Object e : c) {
-            if (indexOf(e, elements, 0, len) < 0)
+            if (indexOfRange(e, es, 0, len) < 0)
                 return false;
         }
         return true;
@@ -694,18 +688,18 @@
         if (cs.length == 0)
             return 0;
         synchronized (lock) {
-            Object[] elements = getArray();
-            int len = elements.length;
+            Object[] es = getArray();
+            int len = es.length;
             int added = 0;
             // uniquify and compact elements in cs
             for (int i = 0; i < cs.length; ++i) {
                 Object e = cs[i];
-                if (indexOf(e, elements, 0, len) < 0 &&
-                    indexOf(e, cs, 0, added) < 0)
+                if (indexOfRange(e, es, 0, len) < 0 &&
+                    indexOfRange(e, cs, 0, added) < 0)
                     cs[added++] = e;
             }
             if (added > 0) {
-                Object[] newElements = Arrays.copyOf(elements, len + added);
+                Object[] newElements = Arrays.copyOf(es, len + added);
                 System.arraycopy(cs, 0, newElements, len, added);
                 setArray(newElements);
             }
@@ -739,15 +733,16 @@
         if (cs.length == 0)
             return false;
         synchronized (lock) {
-            Object[] elements = getArray();
-            int len = elements.length;
+            Object[] es = getArray();
+            int len = es.length;
+            Object[] newElements;
             if (len == 0 && cs.getClass() == Object[].class)
-                setArray(cs);
+                newElements = cs;
             else {
-                Object[] newElements = Arrays.copyOf(elements, len + cs.length);
+                newElements = Arrays.copyOf(es, len + cs.length);
                 System.arraycopy(cs, 0, newElements, len, cs.length);
-                setArray(newElements);
             }
+            setArray(newElements);
             return true;
         }
     }
@@ -771,8 +766,8 @@
     public boolean addAll(int index, Collection<? extends E> c) {
         Object[] cs = c.toArray();
         synchronized (lock) {
-            Object[] elements = getArray();
-            int len = elements.length;
+            Object[] es = getArray();
+            int len = es.length;
             if (index > len || index < 0)
                 throw new IndexOutOfBoundsException(outOfBounds(index, len));
             if (cs.length == 0)
@@ -780,11 +775,11 @@
             int numMoved = len - index;
             Object[] newElements;
             if (numMoved == 0)
-                newElements = Arrays.copyOf(elements, len + cs.length);
+                newElements = Arrays.copyOf(es, len + cs.length);
             else {
                 newElements = new Object[len + cs.length];
-                System.arraycopy(elements, 0, newElements, 0, index);
-                System.arraycopy(elements, index,
+                System.arraycopy(es, 0, newElements, 0, index);
+                System.arraycopy(es, index,
                                  newElements, index + cs.length,
                                  numMoved);
             }
@@ -866,14 +861,14 @@
     }
 
     public void replaceAll(UnaryOperator<E> operator) {
-        Objects.requireNonNull(operator);
         synchronized (lock) {
-            replaceAll(operator, 0, getArray().length);
+            replaceAllRange(operator, 0, getArray().length);
         }
     }
 
-    void replaceAll(UnaryOperator<E> operator, int i, int end) {
+    void replaceAllRange(UnaryOperator<E> operator, int i, int end) {
         // assert Thread.holdsLock(lock);
+        Objects.requireNonNull(operator);
         final Object[] es = getArray().clone();
         for (; i < end; i++)
             es[i] = operator.apply(elementAt(es, i));
@@ -882,12 +877,12 @@
 
     public void sort(Comparator<? super E> c) {
         synchronized (lock) {
-            sort(c, 0, getArray().length);
+            sortRange(c, 0, getArray().length);
         }
     }
 
     @SuppressWarnings("unchecked")
-    void sort(Comparator<? super E> c, int i, int end) {
+    void sortRange(Comparator<? super E> c, int i, int end) {
         // assert Thread.holdsLock(lock);
         final Object[] es = getArray().clone();
         Arrays.sort(es, i, end, (Comparator<Object>)c);
@@ -908,12 +903,12 @@
 
         s.defaultWriteObject();
 
-        Object[] elements = getArray();
+        Object[] es = getArray();
         // Write out array length
-        s.writeInt(elements.length);
+        s.writeInt(es.length);
 
         // Write out all elements in the proper order.
-        for (Object element : elements)
+        for (Object element : es)
             s.writeObject(element);
     }
 
@@ -935,12 +930,12 @@
         // Read in array length and allocate array
         int len = s.readInt();
         SharedSecrets.getJavaObjectInputStreamAccess().checkArray(s, Object[].class, len);
-        Object[] elements = new Object[len];
+        Object[] es = new Object[len];
 
         // Read in all elements in the proper order.
         for (int i = 0; i < len; i++)
-            elements[i] = s.readObject();
-        setArray(elements);
+            es[i] = s.readObject();
+        setArray(es);
     }
 
     /**
@@ -986,6 +981,15 @@
         return !it.hasNext();
     }
 
+    private static int hashCodeOfRange(Object[] es, int from, int to) {
+        int hashCode = 1;
+        for (int i = from; i < to; i++) {
+            Object x = es[i];
+            hashCode = 31 * hashCode + (x == null ? 0 : x.hashCode());
+        }
+        return hashCode;
+    }
+
     /**
      * Returns the hash code value for this list.
      *
@@ -994,10 +998,8 @@
      * @return the hash code value for this list
      */
     public int hashCode() {
-        int hashCode = 1;
-        for (Object x : getArray())
-            hashCode = 31 * hashCode + (x == null ? 0 : x.hashCode());
-        return hashCode;
+        Object[] es = getArray();
+        return hashCodeOfRange(es, 0, es.length);
     }
 
     /**
@@ -1037,12 +1039,12 @@
      * @throws IndexOutOfBoundsException {@inheritDoc}
      */
     public ListIterator<E> listIterator(int index) {
-        Object[] elements = getArray();
-        int len = elements.length;
+        Object[] es = getArray();
+        int len = es.length;
         if (index < 0 || index > len)
             throw new IndexOutOfBoundsException(outOfBounds(index, len));
 
-        return new COWIterator<E>(elements, index);
+        return new COWIterator<E>(es, index);
     }
 
     /**
@@ -1070,9 +1072,9 @@
         /** Index of element to be returned by subsequent call to next.  */
         private int cursor;
 
-        COWIterator(Object[] elements, int initialCursor) {
+        COWIterator(Object[] es, int initialCursor) {
             cursor = initialCursor;
-            snapshot = elements;
+            snapshot = es;
         }
 
         public boolean hasNext() {
@@ -1102,7 +1104,7 @@
         }
 
         public int previousIndex() {
-            return cursor-1;
+            return cursor - 1;
         }
 
         /**
@@ -1133,14 +1135,13 @@
         }
 
         @Override
-        @SuppressWarnings("unchecked")
         public void forEachRemaining(Consumer<? super E> action) {
             Objects.requireNonNull(action);
             final int size = snapshot.length;
-            for (int i = cursor; i < size; i++) {
-                action.accept((E) snapshot[i]);
-            }
+            int i = cursor;
             cursor = size;
+            for (; i < size; i++)
+                action.accept(elementAt(snapshot, i));
         }
     }
 
@@ -1161,136 +1162,264 @@
      */
     public List<E> subList(int fromIndex, int toIndex) {
         synchronized (lock) {
-            Object[] elements = getArray();
-            int len = elements.length;
-            if (fromIndex < 0 || toIndex > len || fromIndex > toIndex)
+            Object[] es = getArray();
+            int len = es.length;
+            int size = toIndex - fromIndex;
+            if (fromIndex < 0 || toIndex > len || size < 0)
                 throw new IndexOutOfBoundsException();
-            return new COWSubList<E>(this, fromIndex, toIndex);
+            return new COWSubList(es, fromIndex, size);
         }
     }
 
     /**
      * Sublist for CopyOnWriteArrayList.
      */
-    private static class COWSubList<E>
-        extends AbstractList<E>
-        implements RandomAccess
-    {
-        private final CopyOnWriteArrayList<E> l;
+    private class COWSubList implements List<E>, RandomAccess {
         private final int offset;
         private int size;
         private Object[] expectedArray;
 
-        // only call this holding l's lock
-        COWSubList(CopyOnWriteArrayList<E> list,
-                   int fromIndex, int toIndex) {
-            // assert Thread.holdsLock(list.lock);
-            l = list;
-            expectedArray = l.getArray();
-            offset = fromIndex;
-            size = toIndex - fromIndex;
+        COWSubList(Object[] es, int offset, int size) {
+            // assert Thread.holdsLock(lock);
+            expectedArray = es;
+            this.offset = offset;
+            this.size = size;
         }
 
-        // only call this holding l's lock
         private void checkForComodification() {
-            // assert Thread.holdsLock(l.lock);
-            if (l.getArray() != expectedArray)
+            // assert Thread.holdsLock(lock);
+            if (getArray() != expectedArray)
                 throw new ConcurrentModificationException();
         }
 
         private Object[] getArrayChecked() {
-            // assert Thread.holdsLock(l.lock);
-            Object[] a = l.getArray();
+            // assert Thread.holdsLock(lock);
+            Object[] a = getArray();
             if (a != expectedArray)
                 throw new ConcurrentModificationException();
             return a;
         }
 
-        // only call this holding l's lock
         private void rangeCheck(int index) {
-            // assert Thread.holdsLock(l.lock);
+            // assert Thread.holdsLock(lock);
             if (index < 0 || index >= size)
                 throw new IndexOutOfBoundsException(outOfBounds(index, size));
         }
 
+        private void rangeCheckForAdd(int index) {
+            // assert Thread.holdsLock(lock);
+            if (index < 0 || index > size)
+                throw new IndexOutOfBoundsException(outOfBounds(index, size));
+        }
+
+        public Object[] toArray() {
+            final Object[] es;
+            final int offset;
+            final int size;
+            synchronized (lock) {
+                es = getArrayChecked();
+                offset = this.offset;
+                size = this.size;
+            }
+            return Arrays.copyOfRange(es, offset, offset + size);
+        }
+
+        @SuppressWarnings("unchecked")
+        public <T> T[] toArray(T[] a) {
+            final Object[] es;
+            final int offset;
+            final int size;
+            synchronized (lock) {
+                es = getArrayChecked();
+                offset = this.offset;
+                size = this.size;
+            }
+            if (a.length < size)
+                return (T[]) Arrays.copyOfRange(
+                        es, offset, offset + size, a.getClass());
+            else {
+                System.arraycopy(es, offset, a, 0, size);
+                if (a.length > size)
+                    a[size] = null;
+                return a;
+            }
+        }
+
+        public int indexOf(Object o) {
+            final Object[] es;
+            final int offset;
+            final int size;
+            synchronized (lock) {
+                es = getArrayChecked();
+                offset = this.offset;
+                size = this.size;
+            }
+            int i = indexOfRange(o, es, offset, offset + size);
+            return (i == -1) ? -1 : i - offset;
+        }
+
+        public int lastIndexOf(Object o) {
+            final Object[] es;
+            final int offset;
+            final int size;
+            synchronized (lock) {
+                es = getArrayChecked();
+                offset = this.offset;
+                size = this.size;
+            }
+            int i = lastIndexOfRange(o, es, offset, offset + size);
+            return (i == -1) ? -1 : i - offset;
+        }
+
+        public boolean contains(Object o) {
+            return indexOf(o) >= 0;
+        }
+
+        public boolean containsAll(Collection<?> c) {
+            final Object[] es;
+            final int offset;
+            final int size;
+            synchronized (lock) {
+                es = getArrayChecked();
+                offset = this.offset;
+                size = this.size;
+            }
+            for (Object o : c)
+                if (indexOfRange(o, es, offset, offset + size) < 0)
+                    return false;
+            return true;
+        }
+
+        public boolean isEmpty() {
+            return size() == 0;
+        }
+
+        public String toString() {
+            return Arrays.toString(toArray());
+        }
+
+        public int hashCode() {
+            final Object[] es;
+            final int offset;
+            final int size;
+            synchronized (lock) {
+                es = getArrayChecked();
+                offset = this.offset;
+                size = this.size;
+            }
+            return hashCodeOfRange(es, offset, offset + size);
+        }
+
+        public boolean equals(Object o) {
+            if (o == this)
+                return true;
+            if (!(o instanceof List))
+                return false;
+            Iterator<?> it = ((List<?>)o).iterator();
+
+            final Object[] es;
+            final int offset;
+            final int size;
+            synchronized (lock) {
+                es = getArrayChecked();
+                offset = this.offset;
+                size = this.size;
+            }
+
+            for (int i = offset, end = offset + size; i < end; i++)
+                if (!it.hasNext() || !Objects.equals(es[i], it.next()))
+                    return false;
+            return !it.hasNext();
+        }
+
         public E set(int index, E element) {
-            synchronized (l.lock) {
+            synchronized (lock) {
                 rangeCheck(index);
                 checkForComodification();
-                E x = l.set(offset + index, element);
-                expectedArray = l.getArray();
+                E x = CopyOnWriteArrayList.this.set(offset + index, element);
+                expectedArray = getArray();
                 return x;
             }
         }
 
         public E get(int index) {
-            synchronized (l.lock) {
+            synchronized (lock) {
                 rangeCheck(index);
                 checkForComodification();
-                return l.get(offset + index);
+                return CopyOnWriteArrayList.this.get(offset + index);
             }
         }
 
         public int size() {
-            synchronized (l.lock) {
+            synchronized (lock) {
                 checkForComodification();
                 return size;
             }
         }
 
         public boolean add(E element) {
-            synchronized (l.lock) {
+            synchronized (lock) {
                 checkForComodification();
-                l.add(offset + size, element);
-                expectedArray = l.getArray();
+                CopyOnWriteArrayList.this.add(offset + size, element);
+                expectedArray = getArray();
                 size++;
             }
             return true;
         }
 
         public void add(int index, E element) {
-            synchronized (l.lock) {
+            synchronized (lock) {
                 checkForComodification();
-                if (index < 0 || index > size)
-                    throw new IndexOutOfBoundsException
-                        (outOfBounds(index, size));
-                l.add(offset + index, element);
-                expectedArray = l.getArray();
+                rangeCheckForAdd(index);
+                CopyOnWriteArrayList.this.add(offset + index, element);
+                expectedArray = getArray();
                 size++;
             }
         }
 
         public boolean addAll(Collection<? extends E> c) {
-            synchronized (l.lock) {
+            synchronized (lock) {
                 final Object[] oldArray = getArrayChecked();
-                boolean modified = l.addAll(offset + size, c);
-                size += (expectedArray = l.getArray()).length - oldArray.length;
+                boolean modified =
+                    CopyOnWriteArrayList.this.addAll(offset + size, c);
+                size += (expectedArray = getArray()).length - oldArray.length;
+                return modified;
+            }
+        }
+
+        public boolean addAll(int index, Collection<? extends E> c) {
+            synchronized (lock) {
+                rangeCheckForAdd(index);
+                final Object[] oldArray = getArrayChecked();
+                boolean modified =
+                    CopyOnWriteArrayList.this.addAll(offset + index, c);
+                size += (expectedArray = getArray()).length - oldArray.length;
                 return modified;
             }
         }
 
         public void clear() {
-            synchronized (l.lock) {
+            synchronized (lock) {
                 checkForComodification();
-                l.removeRange(offset, offset + size);
-                expectedArray = l.getArray();
+                removeRange(offset, offset + size);
+                expectedArray = getArray();
                 size = 0;
             }
         }
 
         public E remove(int index) {
-            synchronized (l.lock) {
+            synchronized (lock) {
                 rangeCheck(index);
                 checkForComodification();
-                E result = l.remove(offset + index);
-                expectedArray = l.getArray();
+                E result = CopyOnWriteArrayList.this.remove(offset + index);
+                expectedArray = getArray();
                 size--;
                 return result;
             }
         }
 
         public boolean remove(Object o) {
-            synchronized (l.lock) {
+            synchronized (lock) {
                 checkForComodification();
                 int index = indexOf(o);
                 if (index == -1)
@@ -1301,36 +1430,35 @@
         }
 
         public Iterator<E> iterator() {
-            synchronized (l.lock) {
-                checkForComodification();
-                return new COWSubListIterator<E>(l, 0, offset, size);
-            }
+            return listIterator(0);
+        }
+
+        public ListIterator<E> listIterator() {
+            return listIterator(0);
         }
 
         public ListIterator<E> listIterator(int index) {
-            synchronized (l.lock) {
+            synchronized (lock) {
                 checkForComodification();
-                if (index < 0 || index > size)
-                    throw new IndexOutOfBoundsException
-                        (outOfBounds(index, size));
-                return new COWSubListIterator<E>(l, index, offset, size);
+                rangeCheckForAdd(index);
+                return new COWSubListIterator<E>(
+                    CopyOnWriteArrayList.this, index, offset, size);
             }
         }
 
         public List<E> subList(int fromIndex, int toIndex) {
-            synchronized (l.lock) {
+            synchronized (lock) {
                 checkForComodification();
                 if (fromIndex < 0 || toIndex > size || fromIndex > toIndex)
                     throw new IndexOutOfBoundsException();
-                return new COWSubList<E>(l, fromIndex + offset,
-                                         toIndex + offset);
+                return new COWSubList(expectedArray, fromIndex + offset, toIndex - fromIndex);
             }
         }
 
         public void forEach(Consumer<? super E> action) {
             Objects.requireNonNull(action);
             int i, end; final Object[] es;
-            synchronized (l.lock) {
+            synchronized (lock) {
                 es = getArrayChecked();
                 i = offset;
                 end = i + size;
@@ -1340,19 +1468,18 @@
         }
 
         public void replaceAll(UnaryOperator<E> operator) {
-            Objects.requireNonNull(operator);
-            synchronized (l.lock) {
+            synchronized (lock) {
                 checkForComodification();
-                l.replaceAll(operator, offset, offset + size);
-                expectedArray = l.getArray();
+                replaceAllRange(operator, offset, offset + size);
+                expectedArray = getArray();
             }
         }
 
         public void sort(Comparator<? super E> c) {
-            synchronized (l.lock) {
+            synchronized (lock) {
                 checkForComodification();
-                l.sort(c, offset, offset + size);
-                expectedArray = l.getArray();
+                sortRange(c, offset, offset + size);
+                expectedArray = getArray();
             }
         }
 
@@ -1372,16 +1499,17 @@
         }
 
         private boolean bulkRemove(Predicate<? super E> filter) {
-            synchronized (l.lock) {
+            synchronized (lock) {
                 final Object[] oldArray = getArrayChecked();
-                boolean modified = l.bulkRemove(filter, offset, offset + size);
-                size += (expectedArray = l.getArray()).length - oldArray.length;
+                boolean modified = CopyOnWriteArrayList.this.bulkRemove(
+                    filter, offset, offset + size);
+                size += (expectedArray = getArray()).length - oldArray.length;
                 return modified;
             }
         }
 
         public Spliterator<E> spliterator() {
-            synchronized (l.lock) {
+            synchronized (lock) {
                 return Spliterators.spliterator(
                         getArrayChecked(), offset, offset + size,
                         Spliterator.IMMUTABLE | Spliterator.ORDERED);
@@ -1398,7 +1526,7 @@
         COWSubListIterator(List<E> l, int index, int offset, int size) {
             this.offset = offset;
             this.size = size;
-            it = l.listIterator(index+offset);
+            it = l.listIterator(index + offset);
         }
 
         public boolean hasNext() {
@@ -1447,7 +1575,7 @@
         @SuppressWarnings("unchecked")
         public void forEachRemaining(Consumer<? super E> action) {
             Objects.requireNonNull(action);
-            while (nextIndex() < size) {
+            while (hasNext()) {
                 action.accept(it.next());
             }
         }
--- a/src/java.base/share/classes/java/util/concurrent/CountedCompleter.java	Mon Apr 09 08:34:30 2018 -0700
+++ b/src/java.base/share/classes/java/util/concurrent/CountedCompleter.java	Tue Apr 10 13:58:47 2018 -0700
@@ -775,7 +775,7 @@
             PENDING = l.findVarHandle(CountedCompleter.class, "pending", int.class);
 
         } catch (ReflectiveOperationException e) {
-            throw new Error(e);
+            throw new ExceptionInInitializerError(e);
         }
     }
 }
--- a/src/java.base/share/classes/java/util/concurrent/Exchanger.java	Mon Apr 09 08:34:30 2018 -0700
+++ b/src/java.base/share/classes/java/util/concurrent/Exchanger.java	Tue Apr 10 13:58:47 2018 -0700
@@ -641,7 +641,7 @@
             MATCH = l.findVarHandle(Node.class, "match", Object.class);
             AA = MethodHandles.arrayElementVarHandle(Node[].class);
         } catch (ReflectiveOperationException e) {
-            throw new Error(e);
+            throw new ExceptionInInitializerError(e);
         }
     }
 
--- a/src/java.base/share/classes/java/util/concurrent/ForkJoinPool.java	Mon Apr 09 08:34:30 2018 -0700
+++ b/src/java.base/share/classes/java/util/concurrent/ForkJoinPool.java	Tue Apr 10 13:58:47 2018 -0700
@@ -184,17 +184,22 @@
      * functionality and control for a set of worker threads:
      * Submissions from non-FJ threads enter into submission queues.
      * Workers take these tasks and typically split them into subtasks
-     * that may be stolen by other workers.  Preference rules give
-     * first priority to processing tasks from their own queues (LIFO
-     * or FIFO, depending on mode), then to randomized FIFO steals of
-     * tasks in other queues.  This framework began as vehicle for
-     * supporting tree-structured parallelism using work-stealing.
-     * Over time, its scalability advantages led to extensions and
-     * changes to better support more diverse usage contexts.  Because
-     * most internal methods and nested classes are interrelated,
-     * their main rationale and descriptions are presented here;
-     * individual methods and nested classes contain only brief
-     * comments about details.
+     * that may be stolen by other workers. Work-stealing based on
+     * randomized scans generally leads to better throughput than
+     * "work dealing" in which producers assign tasks to idle threads,
+     * in part because threads that have finished other tasks before
+     * the signalled thread wakes up (which can be a long time) can
+     * take the task instead.  Preference rules give first priority to
+     * processing tasks from their own queues (LIFO or FIFO, depending
+     * on mode), then to randomized FIFO steals of tasks in other
+     * queues.  This framework began as vehicle for supporting
+     * tree-structured parallelism using work-stealing.  Over time,
+     * its scalability advantages led to extensions and changes to
+     * better support more diverse usage contexts.  Because most
+     * internal methods and nested classes are interrelated, their
+     * main rationale and descriptions are presented here; individual
+     * methods and nested classes contain only brief comments about
+     * details.
      *
      * WorkQueues
      * ==========
@@ -227,9 +232,10 @@
      *
      * (The actual code needs to null-check and size-check the array,
      * uses masking, not mod, for indexing a power-of-two-sized array,
-     * properly fences accesses, and possibly signals waiting workers
-     * to start scanning -- see below.)  Both a successful pop and
-     * poll mainly entail a CAS of a slot from non-null to null.
+     * adds a release fence for publication, and possibly signals
+     * waiting workers to start scanning -- see below.)  Both a
+     * successful pop and poll mainly entail a CAS of a slot from
+     * non-null to null.
      *
      * The pop operation (always performed by owner) is:
      *   if ((the task at top slot is not null) and
@@ -241,9 +247,14 @@
      *        (CAS slot to null))
      *           increment base and return task;
      *
-     * There are several variants of each of these. In particular,
-     * almost all uses of poll occur within scan operations that also
-     * interleave contention tracking (with associated code sprawl.)
+     * There are several variants of each of these. Most uses occur
+     * within operations that also interleave contention or emptiness
+     * tracking or inspection of elements before extracting them, so
+     * must interleave these with the above code. When performed by
+     * owner, getAndSet is used instead of CAS (see for example method
+     * nextLocalTask) which is usually more efficient, and possible
+     * because the top index cannot independently change during the
+     * operation.
      *
      * Memory ordering.  See "Correct and Efficient Work-Stealing for
      * Weak Memory Models" by Le, Pop, Cohen, and Nardelli, PPoPP 2013
@@ -252,30 +263,37 @@
      * algorithms similar to (but different than) the one used here.
      * Extracting tasks in array slots via (fully fenced) CAS provides
      * primary synchronization. The base and top indices imprecisely
-     * guide where to extract from. We do not always require strict
-     * orderings of array and index updates, so sometimes let them be
-     * subject to compiler and processor reorderings. However, the
-     * volatile "base" index also serves as a basis for memory
-     * ordering: Slot accesses are preceded by a read of base,
-     * ensuring happens-before ordering with respect to stealers (so
-     * the slots themselves can be read via plain array reads.)  The
-     * only other memory orderings relied on are maintained in the
-     * course of signalling and activation (see below).  A check that
-     * base == top indicates (momentary) emptiness, but otherwise may
-     * err on the side of possibly making the queue appear nonempty
-     * when a push, pop, or poll have not fully committed, or making
-     * it appear empty when an update of top has not yet been visibly
-     * written.  (Method isEmpty() checks the case of a partially
-     * completed removal of the last element.)  Because of this, the
-     * poll operation, considered individually, is not wait-free. One
-     * thief cannot successfully continue until another in-progress
-     * one (or, if previously empty, a push) visibly completes.
-     * However, in the aggregate, we ensure at least probabilistic
+     * guide where to extract from. We do not usually require strict
+     * orderings of array and index updates. Many index accesses use
+     * plain mode, with ordering constrained by surrounding context
+     * (usually with respect to element CASes or the two WorkQueue
+     * volatile fields source and phase). When not otherwise already
+     * constrained, reads of "base" by queue owners use acquire-mode,
+     * and some externally callable methods preface accesses with
+     * acquire fences.  Additionally, to ensure that index update
+     * writes are not coalesced or postponed in loops etc, "opaque"
+     * mode is used in a few cases where timely writes are not
+     * otherwise ensured. The "locked" versions of push- and pop-
+     * based methods for shared queues differ from owned versions
+     * because locking already forces some of the ordering.
+     *
+     * Because indices and slot contents cannot always be consistent,
+     * a check that base == top indicates (momentary) emptiness, but
+     * otherwise may err on the side of possibly making the queue
+     * appear nonempty when a push, pop, or poll have not fully
+     * committed, or making it appear empty when an update of top has
+     * not yet been visibly written.  (Method isEmpty() checks the
+     * case of a partially completed removal of the last element.)
+     * Because of this, the poll operation, considered individually,
+     * is not wait-free. One thief cannot successfully continue until
+     * another in-progress one (or, if previously empty, a push)
+     * visibly completes.  This can stall threads when required to
+     * consume from a given queue (see method poll()).  However, in
+     * the aggregate, we ensure at least probabilistic
      * non-blockingness.  If an attempted steal fails, a scanning
      * thief chooses a different random victim target to try next. So,
      * in order for one thief to progress, it suffices for any
-     * in-progress poll or new push on any empty queue to
-     * complete.
+     * in-progress poll or new push on any empty queue to complete.
      *
      * This approach also enables support of a user mode in which
      * local task processing is in FIFO, not LIFO order, simply by
@@ -296,7 +314,7 @@
      * different position to use or create other queues -- they block
      * only when creating and registering new queues. Because it is
      * used only as a spinlock, unlocking requires only a "releasing"
-     * store (using setRelease).
+     * store (using setRelease) unless otherwise signalling.
      *
      * Management
      * ==========
@@ -317,10 +335,10 @@
      *
      * Field "ctl" contains 64 bits holding information needed to
      * atomically decide to add, enqueue (on an event queue), and
-     * dequeue (and release)-activate workers.  To enable this
-     * packing, we restrict maximum parallelism to (1<<15)-1 (which is
-     * far in excess of normal operating range) to allow ids, counts,
-     * and their negations (used for thresholding) to fit into 16bit
+     * dequeue and release workers.  To enable this packing, we
+     * restrict maximum parallelism to (1<<15)-1 (which is far in
+     * excess of normal operating range) to allow ids, counts, and
+     * their negations (used for thresholding) to fit into 16bit
      * subfields.
      *
      * Field "mode" holds configuration parameters as well as lifetime
@@ -332,13 +350,14 @@
      * lock (using field workerNamePrefix as lock), but is otherwise
      * concurrently readable, and accessed directly. We also ensure
      * that uses of the array reference itself never become too stale
-     * in case of resizing.  To simplify index-based operations, the
-     * array size is always a power of two, and all readers must
-     * tolerate null slots. Worker queues are at odd indices. Shared
-     * (submission) queues are at even indices, up to a maximum of 64
-     * slots, to limit growth even if array needs to expand to add
-     * more workers. Grouping them together in this way simplifies and
-     * speeds up task scanning.
+     * in case of resizing, by arranging that (re-)reads are separated
+     * by at least one acquiring read access.  To simplify index-based
+     * operations, the array size is always a power of two, and all
+     * readers must tolerate null slots. Worker queues are at odd
+     * indices. Shared (submission) queues are at even indices, up to
+     * a maximum of 64 slots, to limit growth even if the array needs
+     * to expand to add more workers. Grouping them together in this
+     * way simplifies and speeds up task scanning.
      *
      * All worker thread creation is on-demand, triggered by task
      * submissions, replacement of terminated workers, and/or
@@ -416,8 +435,8 @@
      * releases so usage requires care -- seeing a negative phase does
      * not guarantee that the worker is available. When queued, the
      * lower 16 bits of scanState must hold its pool index. So we
-     * place the index there upon initialization (see registerWorker)
-     * and otherwise keep it there or restore it when necessary.
+     * place the index there upon initialization and otherwise keep it
+     * there or restore it when necessary.
      *
      * The ctl field also serves as the basis for memory
      * synchronization surrounding activation. This uses a more
@@ -425,48 +444,56 @@
      * consumers sync with each other by both writing/CASing ctl (even
      * if to its current value).  This would be extremely costly. So
      * we relax it in several ways: (1) Producers only signal when
-     * their queue is empty. Other workers propagate this signal (in
-     * method scan) when they find tasks; to further reduce flailing,
-     * each worker signals only one other per activation. (2) Workers
-     * only enqueue after scanning (see below) and not finding any
-     * tasks.  (3) Rather than CASing ctl to its current value in the
-     * common case where no action is required, we reduce write
+     * their queue is possibly empty at some point during a push
+     * operation (which requires conservatively checking size zero or
+     * one to cover races). (2) Other workers propagate this signal
+     * when they find tasks in a queue with size greater than one. (3)
+     * Workers only enqueue after scanning (see below) and not finding
+     * any tasks.  (4) Rather than CASing ctl to its current value in
+     * the common case where no action is required, we reduce write
      * contention by equivalently prefacing signalWork when called by
      * an external task producer using a memory access with
      * full-volatile semantics or a "fullFence".
      *
-     * Almost always, too many signals are issued. A task producer
-     * cannot in general tell if some existing worker is in the midst
-     * of finishing one task (or already scanning) and ready to take
-     * another without being signalled. So the producer might instead
-     * activate a different worker that does not find any work, and
-     * then inactivates. This scarcely matters in steady-state
-     * computations involving all workers, but can create contention
-     * and bookkeeping bottlenecks during ramp-up, ramp-down, and small
-     * computations involving only a few workers.
+     * Almost always, too many signals are issued, in part because a
+     * task producer cannot tell if some existing worker is in the
+     * midst of finishing one task (or already scanning) and ready to
+     * take another without being signalled. So the producer might
+     * instead activate a different worker that does not find any
+     * work, and then inactivates. This scarcely matters in
+     * steady-state computations involving all workers, but can create
+     * contention and bookkeeping bottlenecks during ramp-up,
+     * ramp-down, and small computations involving only a few workers.
      *
-     * Scanning. Method runWorker performs top-level scanning for
-     * tasks.  Each scan traverses and tries to poll from each queue
-     * starting at a random index and circularly stepping. Scans are
-     * not performed in ideal random permutation order, to reduce
-     * cacheline contention.  The pseudorandom generator need not have
+     * Scanning. Method scan (from runWorker) performs top-level
+     * scanning for tasks. (Similar scans appear in helpQuiesce and
+     * pollScan.)  Each scan traverses and tries to poll from each
+     * queue starting at a random index. Scans are not performed in
+     * ideal random permutation order, to reduce cacheline
+     * contention. The pseudorandom generator need not have
      * high-quality statistical properties in the long term, but just
      * within computations; We use Marsaglia XorShifts (often via
      * ThreadLocalRandom.nextSecondarySeed), which are cheap and
-     * suffice. Scanning also employs contention reduction: When
+     * suffice. Scanning also includes contention reduction: When
      * scanning workers fail to extract an apparently existing task,
-     * they soon restart at a different pseudorandom index.  This
-     * improves throughput when many threads are trying to take tasks
-     * from few queues, which can be common in some usages.  Scans do
-     * not otherwise explicitly take into account core affinities,
-     * loads, cache localities, etc, However, they do exploit temporal
-     * locality (which usually approximates these) by preferring to
-     * re-poll (at most #workers times) from the same queue after a
-     * successful poll before trying others.
+     * they soon restart at a different pseudorandom index.  This form
+     * of backoff improves throughput when many threads are trying to
+     * take tasks from few queues, which can be common in some usages.
+     * Scans do not otherwise explicitly take into account core
+     * affinities, loads, cache localities, etc, However, they do
+     * exploit temporal locality (which usually approximates these) by
+     * preferring to re-poll from the same queue after a successful
+     * poll before trying others (see method topLevelExec). However
+     * this preference is bounded (see TOP_BOUND_SHIFT) as a safeguard
+     * against infinitely unfair looping under unbounded user task
+     * recursion, and also to reduce long-term contention when many
+     * threads poll few queues holding many small tasks. The bound is
+     * high enough to avoid much impact on locality and scheduling
+     * overhead.
      *
      * Trimming workers. To release resources after periods of lack of
      * use, a worker starting to wait when the pool is quiescent will
-     * time out and terminate (see method scan) if the pool has
+     * time out and terminate (see method runWorker) if the pool has
      * remained quiescent for period given by field keepAlive.
      *
      * Shutdown and Termination. A call to shutdownNow invokes
@@ -534,13 +561,14 @@
      * time. Some previous versions of this class employed immediate
      * compensations for any blocked join. However, in practice, the
      * vast majority of blockages are transient byproducts of GC and
-     * other JVM or OS activities that are made worse by replacement.
-     * Rather than impose arbitrary policies, we allow users to
-     * override the default of only adding threads upon apparent
-     * starvation.  The compensation mechanism may also be bounded.
-     * Bounds for the commonPool (see COMMON_MAX_SPARES) better enable
-     * JVMs to cope with programming errors and abuse before running
-     * out of resources to do so.
+     * other JVM or OS activities that are made worse by replacement
+     * when they cause longer-term oversubscription.  Rather than
+     * impose arbitrary policies, we allow users to override the
+     * default of only adding threads upon apparent starvation.  The
+     * compensation mechanism may also be bounded.  Bounds for the
+     * commonPool (see COMMON_MAX_SPARES) better enable JVMs to cope
+     * with programming errors and abuse before running out of
+     * resources to do so.
      *
      * Common Pool
      * ===========
@@ -573,6 +601,18 @@
      * in ForkJoinWorkerThread) may be JVM-dependent and must access
      * particular Thread class fields to achieve this effect.
      *
+     * Memory placement
+     * ================
+     *
+     * Performance can be very sensitive to placement of instances of
+     * ForkJoinPool and WorkQueues and their queue arrays. To reduce
+     * false-sharing impact, the @Contended annotation isolates
+     * adjacent WorkQueue instances, as well as the ForkJoinPool.ctl
+     * field. WorkQueue arrays are allocated (by their threads) with
+     * larger initial sizes than most ever need, mostly to reduce
+     * false sharing with current garbage collectors that use cardmark
+     * tables.
+     *
      * Style notes
      * ===========
      *
@@ -580,13 +620,15 @@
      * awkward and ugly, but also reflects the need to control
      * outcomes across the unusual cases that arise in very racy code
      * with very few invariants. All fields are read into locals
-     * before use, and null-checked if they are references.  This is
-     * usually done in a "C"-like style of listing declarations at the
-     * heads of methods or blocks, and using inline assignments on
-     * first encounter.  Nearly all explicit checks lead to
-     * bypass/return, not exception throws, because they may
-     * legitimately arise due to cancellation/revocation during
-     * shutdown.
+     * before use, and null-checked if they are references.  Array
+     * accesses using masked indices include checks (that are always
+     * true) that the array length is non-zero to avoid compilers
+     * inserting more expensive traps.  This is usually done in a
+     * "C"-like style of listing declarations at the heads of methods
+     * or blocks, and using inline assignments on first encounter.
+     * Nearly all explicit checks lead to bypass/return, not exception
+     * throws, because they may legitimately arise due to
+     * cancellation/revocation during shutdown.
      *
      * There is a lot of representation-level coupling among classes
      * ForkJoinPool, ForkJoinWorkerThread, and ForkJoinTask.  The
@@ -596,10 +638,11 @@
      * representations will need to be accompanied by algorithmic
      * changes anyway. Several methods intrinsically sprawl because
      * they must accumulate sets of consistent reads of fields held in
-     * local variables.  There are also other coding oddities
-     * (including several unnecessary-looking hoisted null checks)
-     * that help some methods perform reasonably even when interpreted
-     * (not compiled).
+     * local variables. Some others are artificially broken up to
+     * reduce producer/consumer imbalances due to dynamic compilation.
+     * There are also other coding oddities (including several
+     * unnecessary-looking hoisted null checks) that help some methods
+     * perform reasonably even when interpreted (not compiled).
      *
      * The order of declarations in this file is (with a few exceptions):
      * (1) Static utility functions
@@ -703,54 +746,43 @@
     static final int DORMANT      = QUIET | UNSIGNALLED;
 
     /**
-     * The maximum number of local polls from the same queue before
-     * checking others. This is a safeguard against infinitely unfair
-     * looping under unbounded user task recursion, and must be larger
-     * than plausible cases of intentional bounded task recursion.
+     * Initial capacity of work-stealing queue array.
+     * Must be a power of two, at least 2.
      */
-    static final int POLL_LIMIT = 1 << 10;
+    static final int INITIAL_QUEUE_CAPACITY = 1 << 13;
+
+    /**
+     * Maximum capacity for queue arrays. Must be a power of two less
+     * than or equal to 1 << (31 - width of array entry) to ensure
+     * lack of wraparound of index calculations, but defined to a
+     * value a bit less than this to help users trap runaway programs
+     * before saturating systems.
+     */
+    static final int MAXIMUM_QUEUE_CAPACITY = 1 << 26; // 64M
+
+    /**
+     * The maximum number of top-level polls per worker before
+     * checking other queues, expressed as a bit shift to, in effect,
+     * multiply by pool size, and then use as random value mask, so
+     * average bound is about poolSize*(1<<TOP_BOUND_SHIFT).  See
+     * above for rationale.
+     */
+    static final int TOP_BOUND_SHIFT = 10;
 
     /**
      * Queues supporting work-stealing as well as external task
      * submission. See above for descriptions and algorithms.
-     * Performance on most platforms is very sensitive to placement of
-     * instances of both WorkQueues and their arrays -- we absolutely
-     * do not want multiple WorkQueue instances or multiple queue
-     * arrays sharing cache lines. The @Contended annotation alerts
-     * JVMs to try to keep instances apart.
      */
     @jdk.internal.vm.annotation.Contended
     static final class WorkQueue {
-
-        /**
-         * Capacity of work-stealing queue array upon initialization.
-         * Must be a power of two; at least 4, but should be larger to
-         * reduce or eliminate cacheline sharing among queues.
-         * Currently, it is much larger, as a partial workaround for
-         * the fact that JVMs often place arrays in locations that
-         * share GC bookkeeping (especially cardmarks) such that
-         * per-write accesses encounter serious memory contention.
-         */
-        static final int INITIAL_QUEUE_CAPACITY = 1 << 13;
-
-        /**
-         * Maximum size for queue arrays. Must be a power of two less
-         * than or equal to 1 << (31 - width of array entry) to ensure
-         * lack of wraparound of index calculations, but defined to a
-         * value a bit less than this to help users trap runaway
-         * programs before saturating systems.
-         */
-        static final int MAXIMUM_QUEUE_CAPACITY = 1 << 26; // 64M
-
-        // Instance fields
+        volatile int source;       // source queue id, or sentinel
+        int id;                    // pool index, mode, tag
+        int base;                  // index of next slot for poll
+        int top;                   // index of next slot for push
         volatile int phase;        // versioned, negative: queued, 1: locked
         int stackPred;             // pool stack (ctl) predecessor link
         int nsteals;               // number of steals
-        int id;                    // index, mode, tag
-        volatile int source;       // source queue id, or sentinel
-        volatile int base;         // index of next slot for poll
-        int top;                   // index of next slot for push
-        ForkJoinTask<?>[] array;   // the elements (initially unallocated)
+        ForkJoinTask<?>[] array;   // the queued tasks; power of 2 size
         final ForkJoinPool pool;   // the containing pool (may be null)
         final ForkJoinWorkerThread owner; // owning thread or null if shared
 
@@ -762,6 +794,17 @@
         }
 
         /**
+         * Tries to lock shared queue by CASing phase field.
+         */
+        final boolean tryLockPhase() {
+            return PHASE.compareAndSet(this, 0, 1);
+        }
+
+        final void releasePhaseLock() {
+            PHASE.setRelease(this, 0);
+        }
+
+        /**
          * Returns an exportable index (used by ForkJoinWorkerThread).
          */
         final int getPoolIndex() {
@@ -772,7 +815,7 @@
          * Returns the approximate number of tasks in the queue.
          */
         final int queueSize() {
-            int n = base - top;       // read base first
+            int n = (int)BASE.getAcquire(this) - top;
             return (n >= 0) ? 0 : -n; // ignore transient negative
         }
 
@@ -782,14 +825,14 @@
          * near-empty queue has at least one unclaimed task.
          */
         final boolean isEmpty() {
-            ForkJoinTask<?>[] a; int n, al, b;
+            ForkJoinTask<?>[] a; int n, cap, b;
+            VarHandle.acquireFence(); // needed by external callers
             return ((n = (b = base) - top) >= 0 || // possibly one task
                     (n == -1 && ((a = array) == null ||
-                                 (al = a.length) == 0 ||
-                                 a[(al - 1) & b] == null)));
+                                 (cap = a.length) == 0 ||
+                                 a[(cap - 1) & b] == null)));
         }
 
-
         /**
          * Pushes a task. Call only by owner in unshared queues.
          *
@@ -797,94 +840,99 @@
          * @throws RejectedExecutionException if array cannot be resized
          */
         final void push(ForkJoinTask<?> task) {
-            int s = top; ForkJoinTask<?>[] a; int al, d;
-            if ((a = array) != null && (al = a.length) > 0) {
-                int index = (al - 1) & s;
-                ForkJoinPool p = pool;
+            ForkJoinTask<?>[] a;
+            int s = top, d, cap, m;
+            ForkJoinPool p = pool;
+            if ((a = array) != null && (cap = a.length) > 0) {
+                QA.setRelease(a, (m = cap - 1) & s, task);
                 top = s + 1;
-                QA.setRelease(a, index, task);
-                if ((d = base - s) == 0 && p != null) {
+                if (((d = s - (int)BASE.getAcquire(this)) & ~1) == 0 &&
+                    p != null) {                 // size 0 or 1
                     VarHandle.fullFence();
                     p.signalWork();
                 }
-                else if (d + al == 1)
-                    growArray();
+                else if (d == m)
+                    growArray(false);
             }
         }
 
         /**
-         * Initializes or doubles the capacity of array. Call either
-         * by owner or with lock held -- it is OK for base, but not
-         * top, to move while resizings are in progress.
+         * Version of push for shared queues. Call only with phase lock held.
+         * @return true if should signal work
          */
-        final ForkJoinTask<?>[] growArray() {
-            ForkJoinTask<?>[] oldA = array;
-            int oldSize = oldA != null ? oldA.length : 0;
-            int size = oldSize > 0 ? oldSize << 1 : INITIAL_QUEUE_CAPACITY;
-            if (size < INITIAL_QUEUE_CAPACITY || size > MAXIMUM_QUEUE_CAPACITY)
-                throw new RejectedExecutionException("Queue capacity exceeded");
-            int oldMask, t, b;
-            ForkJoinTask<?>[] a = array = new ForkJoinTask<?>[size];
-            if (oldA != null && (oldMask = oldSize - 1) > 0 &&
-                (t = top) - (b = base) > 0) {
-                int mask = size - 1;
-                do { // emulate poll from old array, push to new array
-                    int index = b & oldMask;
-                    ForkJoinTask<?> x = (ForkJoinTask<?>)
-                        QA.getAcquire(oldA, index);
-                    if (x != null &&
-                        QA.compareAndSet(oldA, index, x, null))
-                        a[b & mask] = x;
-                } while (++b != t);
-                VarHandle.releaseFence();
+        final boolean lockedPush(ForkJoinTask<?> task) {
+            ForkJoinTask<?>[] a;
+            boolean signal = false;
+            int s = top, b = base, cap, d;
+            if ((a = array) != null && (cap = a.length) > 0) {
+                a[(cap - 1) & s] = task;
+                top = s + 1;
+                if (b - s + cap - 1 == 0)
+                    growArray(true);
+                else {
+                    phase = 0; // full volatile unlock
+                    if (((s - base) & ~1) == 0) // size 0 or 1
+                        signal = true;
+                }
             }
-            return a;
+            return signal;
         }
 
         /**
-         * Takes next task, if one exists, in LIFO order.  Call only
-         * by owner in unshared queues.
+         * Doubles the capacity of array. Call either by owner or with
+         * lock held -- it is OK for base, but not top, to move while
+         * resizings are in progress.
          */
-        final ForkJoinTask<?> pop() {
-            int b = base, s = top, al, i; ForkJoinTask<?>[] a;
-            if ((a = array) != null && b != s && (al = a.length) > 0) {
-                int index = (al - 1) & --s;
-                ForkJoinTask<?> t = (ForkJoinTask<?>)
-                    QA.get(a, index);
-                if (t != null &&
-                    QA.compareAndSet(a, index, t, null)) {
-                    top = s;
-                    VarHandle.releaseFence();
-                    return t;
+        final void growArray(boolean locked) {
+            ForkJoinTask<?>[] newA = null;
+            try {
+                ForkJoinTask<?>[] oldA; int oldSize, newSize;
+                if ((oldA = array) != null && (oldSize = oldA.length) > 0 &&
+                    (newSize = oldSize << 1) <= MAXIMUM_QUEUE_CAPACITY &&
+                    newSize > 0) {
+                    try {
+                        newA = new ForkJoinTask<?>[newSize];
+                    } catch (OutOfMemoryError ex) {
+                    }
+                    if (newA != null) { // poll from old array, push to new
+                        int oldMask = oldSize - 1, newMask = newSize - 1;
+                        for (int s = top - 1, k = oldMask; k >= 0; --k) {
+                            ForkJoinTask<?> x = (ForkJoinTask<?>)
+                                QA.getAndSet(oldA, s & oldMask, null);
+                            if (x != null)
+                                newA[s-- & newMask] = x;
+                            else
+                                break;
+                        }
+                        array = newA;
+                        VarHandle.releaseFence();
+                    }
                 }
+            } finally {
+                if (locked)
+                    phase = 0;
             }
-            return null;
+            if (newA == null)
+                throw new RejectedExecutionException("Queue capacity exceeded");
         }
 
         /**
          * Takes next task, if one exists, in FIFO order.
          */
         final ForkJoinTask<?> poll() {
-            for (;;) {
-                int b = base, s = top, d, al; ForkJoinTask<?>[] a;
-                if ((a = array) != null && (d = b - s) < 0 &&
-                    (al = a.length) > 0) {
-                    int index = (al - 1) & b;
-                    ForkJoinTask<?> t = (ForkJoinTask<?>)
-                        QA.getAcquire(a, index);
-                    if (b++ == base) {
-                        if (t != null) {
-                            if (QA.compareAndSet(a, index, t, null)) {
-                                base = b;
-                                return t;
-                            }
-                        }
-                        else if (d == -1)
-                            break; // now empty
+            int b, k, cap; ForkJoinTask<?>[] a;
+            while ((a = array) != null && (cap = a.length) > 0 &&
+                   top - (b = base) > 0) {
+                ForkJoinTask<?> t = (ForkJoinTask<?>)
+                    QA.getAcquire(a, k = (cap - 1) & b);
+                if (base == b++) {
+                    if (t == null)
+                        Thread.yield(); // await index advance
+                    else if (QA.compareAndSet(a, k, t, null)) {
+                        BASE.setOpaque(this, b);
+                        return t;
                     }
                 }
-                else
-                    break;
             }
             return null;
         }
@@ -893,33 +941,61 @@
          * Takes next task, if one exists, in order specified by mode.
          */
         final ForkJoinTask<?> nextLocalTask() {
-            return ((id & FIFO) != 0) ? poll() : pop();
+            ForkJoinTask<?> t = null;
+            int md = id, b, s, d, cap; ForkJoinTask<?>[] a;
+            if ((a = array) != null && (cap = a.length) > 0 &&
+                (d = (s = top) - (b = base)) > 0) {
+                if ((md & FIFO) == 0 || d == 1) {
+                    if ((t = (ForkJoinTask<?>)
+                         QA.getAndSet(a, (cap - 1) & --s, null)) != null)
+                        TOP.setOpaque(this, s);
+                }
+                else if ((t = (ForkJoinTask<?>)
+                          QA.getAndSet(a, (cap - 1) & b++, null)) != null) {
+                    BASE.setOpaque(this, b);
+                }
+                else // on contention in FIFO mode, use regular poll
+                    t = poll();
+            }
+            return t;
         }
 
         /**
          * Returns next task, if one exists, in order specified by mode.
          */
         final ForkJoinTask<?> peek() {
-            int al; ForkJoinTask<?>[] a;
-            return ((a = array) != null && (al = a.length) > 0) ?
-                a[(al - 1) &
-                  ((id & FIFO) != 0 ? base : top - 1)] : null;
+            int cap; ForkJoinTask<?>[] a;
+            return ((a = array) != null && (cap = a.length) > 0) ?
+                a[(cap - 1) & ((id & FIFO) != 0 ? base : top - 1)] : null;
         }
 
         /**
          * Pops the given task only if it is at the current top.
          */
         final boolean tryUnpush(ForkJoinTask<?> task) {
-            int b = base, s = top, al; ForkJoinTask<?>[] a;
-            if ((a = array) != null && b != s && (al = a.length) > 0) {
-                int index = (al - 1) & --s;
-                if (QA.compareAndSet(a, index, task, null)) {
+            boolean popped = false;
+            int s, cap; ForkJoinTask<?>[] a;
+            if ((a = array) != null && (cap = a.length) > 0 &&
+                (s = top) != base &&
+                (popped = QA.compareAndSet(a, (cap - 1) & --s, task, null)))
+                TOP.setOpaque(this, s);
+            return popped;
+        }
+
+        /**
+         * Shared version of tryUnpush.
+         */
+        final boolean tryLockedUnpush(ForkJoinTask<?> task) {
+            boolean popped = false;
+            int s = top - 1, k, cap; ForkJoinTask<?>[] a;
+            if ((a = array) != null && (cap = a.length) > 0 &&
+                a[k = (cap - 1) & s] == task && tryLockPhase()) {
+                if (top == s + 1 && array == a &&
+                    (popped = QA.compareAndSet(a, k, task, null)))
                     top = s;
-                    VarHandle.releaseFence();
-                    return true;
-                }
+                releasePhaseLock();
             }
-            return false;
+            return popped;
         }
 
         /**
@@ -933,58 +1009,29 @@
         // Specialized execution methods
 
         /**
-         * Pops and executes up to limit consecutive tasks or until empty.
-         *
-         * @param limit max runs, or zero for no limit
+         * Runs the given (stolen) task if nonnull, as well as
+         * remaining local tasks and others available from the given
+         * queue, up to bound n (to avoid infinite unfairness).
          */
-        final void localPopAndExec(int limit) {
-            for (;;) {
-                int b = base, s = top, al; ForkJoinTask<?>[] a;
-                if ((a = array) != null && b != s && (al = a.length) > 0) {
-                    int index = (al - 1) & --s;
-                    ForkJoinTask<?> t = (ForkJoinTask<?>)
-                        QA.getAndSet(a, index, null);
-                    if (t != null) {
-                        top = s;
-                        VarHandle.releaseFence();
-                        t.doExec();
-                        if (limit != 0 && --limit == 0)
+        final void topLevelExec(ForkJoinTask<?> t, WorkQueue q, int n) {
+            if (t != null && q != null) { // hoist checks
+                int nstolen = 1;
+                for (;;) {
+                    t.doExec();
+                    if (n-- < 0)
+                        break;
+                    else if ((t = nextLocalTask()) == null) {
+                        if ((t = q.poll()) == null)
                             break;
+                        else
+                            ++nstolen;
                     }
-                    else
-                        break;
                 }
-                else
-                    break;
-            }
-        }
-
-        /**
-         * Polls and executes up to limit consecutive tasks or until empty.
-         *
-         * @param limit, or zero for no limit
-         */
-        final void localPollAndExec(int limit) {
-            for (int polls = 0;;) {
-                int b = base, s = top, d, al; ForkJoinTask<?>[] a;
-                if ((a = array) != null && (d = b - s) < 0 &&
-                    (al = a.length) > 0) {
-                    int index = (al - 1) & b++;
-                    ForkJoinTask<?> t = (ForkJoinTask<?>)
-                        QA.getAndSet(a, index, null);
-                    if (t != null) {
-                        base = b;
-                        t.doExec();
-                        if (limit != 0 && ++polls == limit)
-                            break;
-                    }
-                    else if (d == -1)
-                        break;     // now empty
-                    else
-                        polls = 0; // stolen; reset
-                }
-                else
-                    break;
+                ForkJoinWorkerThread thread = owner;
+                nsteals += nstolen;
+                source = 0;
+                if (thread != null)
+                    thread.afterTopLevelExec();
             }
         }
 
@@ -992,25 +1039,24 @@
          * If present, removes task from queue and executes it.
          */
         final void tryRemoveAndExec(ForkJoinTask<?> task) {
-            ForkJoinTask<?>[] wa; int s, wal;
-            if (base - (s = top) < 0 && // traverse from top
-                (wa = array) != null && (wal = wa.length) > 0) {
-                for (int m = wal - 1, ns = s - 1, i = ns; ; --i) {
+            ForkJoinTask<?>[] a; int s, cap;
+            if ((a = array) != null && (cap = a.length) > 0 &&
+                (s = top) - base > 0) { // traverse from top
+                for (int m = cap - 1, ns = s - 1, i = ns; ; --i) {
                     int index = i & m;
-                    ForkJoinTask<?> t = (ForkJoinTask<?>)
-                        QA.get(wa, index);
+                    ForkJoinTask<?> t = (ForkJoinTask<?>)QA.get(a, index);
                     if (t == null)
                         break;
                     else if (t == task) {
-                        if (QA.compareAndSet(wa, index, t, null)) {
+                        if (QA.compareAndSet(a, index, t, null)) {
                             top = ns;   // safely shift down
                             for (int j = i; j != ns; ++j) {
                                 ForkJoinTask<?> f;
                                 int pindex = (j + 1) & m;
-                                f = (ForkJoinTask<?>)QA.get(wa, pindex);
-                                QA.setVolatile(wa, pindex, null);
+                                f = (ForkJoinTask<?>)QA.get(a, pindex);
+                                QA.setVolatile(a, pindex, null);
                                 int jindex = j & m;
-                                QA.setRelease(wa, jindex, f);
+                                QA.setRelease(a, jindex, f);
                             }
                             VarHandle.releaseFence();
                             t.doExec();
@@ -1022,43 +1068,52 @@
         }
 
         /**
-         * Tries to steal and run tasks within the target's
-         * computation until done, not found, or limit exceeded.
+         * Tries to pop and run tasks within the target's computation
+         * until done, not found, or limit exceeded.
          *
          * @param task root of CountedCompleter computation
          * @param limit max runs, or zero for no limit
+         * @param shared true if must lock to extract task
          * @return task status on exit
          */
-        final int localHelpCC(CountedCompleter<?> task, int limit) {
+        final int helpCC(CountedCompleter<?> task, int limit, boolean shared) {
             int status = 0;
             if (task != null && (status = task.status) >= 0) {
-                for (;;) {
-                    boolean help = false;
-                    int b = base, s = top, al; ForkJoinTask<?>[] a;
-                    if ((a = array) != null && b != s && (al = a.length) > 0) {
-                        int index = (al - 1) & (s - 1);
-                        ForkJoinTask<?> o = (ForkJoinTask<?>)
-                            QA.get(a, index);
-                        if (o instanceof CountedCompleter) {
-                            CountedCompleter<?> t = (CountedCompleter<?>)o;
-                            for (CountedCompleter<?> f = t;;) {
-                                if (f != task) {
-                                    if ((f = f.completer) == null) // try parent
-                                        break;
+                int s, k, cap; ForkJoinTask<?>[] a;
+                while ((a = array) != null && (cap = a.length) > 0 &&
+                       (s = top) - base > 0) {
+                    CountedCompleter<?> v = null;
+                    ForkJoinTask<?> o = a[k = (cap - 1) & (s - 1)];
+                    if (o instanceof CountedCompleter) {
+                        CountedCompleter<?> t = (CountedCompleter<?>)o;
+                        for (CountedCompleter<?> f = t;;) {
+                            if (f != task) {
+                                if ((f = f.completer) == null)
+                                    break;
+                            }
+                            else if (shared) {
+                                if (tryLockPhase()) {
+                                    if (top == s && array == a &&
+                                        QA.compareAndSet(a, k, t, null)) {
+                                        top = s - 1;
+                                        v = t;
+                                    }
+                                    releasePhaseLock();
                                 }
-                                else {
-                                    if (QA.compareAndSet(a, index, t, null)) {
-                                        top = s - 1;
-                                        VarHandle.releaseFence();
-                                        t.doExec();
-                                        help = true;
-                                    }
-                                    break;
+                                break;
+                            }
+                            else {
+                                if (QA.compareAndSet(a, k, t, null)) {
+                                    top = s - 1;
+                                    v = t;
                                 }
+                                break;
                             }
                         }
                     }
-                    if ((status = task.status) < 0 || !help ||
+                    if (v != null)
+                        v.doExec();
+                    if ((status = task.status) < 0 || v == null ||
                         (limit != 0 && --limit == 0))
                         break;
                 }
@@ -1066,79 +1121,31 @@
             return status;
         }
 
-        // Operations on shared queues
-
         /**
-         * Tries to lock shared queue by CASing phase field.
-         */
-        final boolean tryLockSharedQueue() {
-            return PHASE.compareAndSet(this, 0, QLOCK);
-        }
-
-        /**
-         * Shared version of tryUnpush.
+         * Tries to poll and run AsynchronousCompletionTasks until
+         * none found or blocker is released
+         *
+         * @param blocker the blocker
          */
-        final boolean trySharedUnpush(ForkJoinTask<?> task) {
-            boolean popped = false;
-            int s = top - 1, al; ForkJoinTask<?>[] a;
-            if ((a = array) != null && (al = a.length) > 0) {
-                int index = (al - 1) & s;
-                ForkJoinTask<?> t = (ForkJoinTask<?>) QA.get(a, index);
-                if (t == task &&
-                    PHASE.compareAndSet(this, 0, QLOCK)) {
-                    if (top == s + 1 && array == a &&
-                        QA.compareAndSet(a, index, task, null)) {
-                        popped = true;
-                        top = s;
+        final void helpAsyncBlocker(ManagedBlocker blocker) {
+            if (blocker != null) {
+                int b, k, cap; ForkJoinTask<?>[] a; ForkJoinTask<?> t;
+                while ((a = array) != null && (cap = a.length) > 0 &&
+                       top - (b = base) > 0) {
+                    t = (ForkJoinTask<?>)QA.getAcquire(a, k = (cap - 1) & b);
+                    if (blocker.isReleasable())
+                        break;
+                    else if (base == b++ && t != null) {
+                        if (!(t instanceof CompletableFuture.
+                              AsynchronousCompletionTask))
+                            break;
+                        else if (QA.compareAndSet(a, k, t, null)) {
+                            BASE.setOpaque(this, b);
+                            t.doExec();
+                        }
                     }
-                    PHASE.setRelease(this, 0);
                 }
             }
-            return popped;
-        }
-
-        /**
-         * Shared version of localHelpCC.
-         */
-        final int sharedHelpCC(CountedCompleter<?> task, int limit) {
-            int status = 0;
-            if (task != null && (status = task.status) >= 0) {
-                for (;;) {
-                    boolean help = false;
-                    int b = base, s = top, al; ForkJoinTask<?>[] a;
-                    if ((a = array) != null && b != s && (al = a.length) > 0) {
-                        int index = (al - 1) & (s - 1);
-                        ForkJoinTask<?> o = (ForkJoinTask<?>)
-                            QA.get(a, index);
-                        if (o instanceof CountedCompleter) {
-                            CountedCompleter<?> t = (CountedCompleter<?>)o;
-                            for (CountedCompleter<?> f = t;;) {
-                                if (f != task) {
-                                    if ((f = f.completer) == null)
-                                        break;
-                                }
-                                else {
-                                    if (PHASE.compareAndSet(this, 0, QLOCK)) {
-                                        if (top == s && array == a &&
-                                            QA.compareAndSet(a, index, t, null)) {
-                                            help = true;
-                                            top = s - 1;
-                                        }
-                                        PHASE.setRelease(this, 0);
-                                        if (help)
-                                            t.doExec();
-                                    }
-                                    break;
-                                }
-                            }
-                        }
-                    }
-                    if ((status = task.status) < 0 || !help ||
-                        (limit != 0 && --limit == 0))
-                        break;
-                }
-            }
-            return status;
         }
 
         /**
@@ -1153,13 +1160,17 @@
         }
 
         // VarHandle mechanics.
-        private static final VarHandle PHASE;
+        static final VarHandle PHASE;
+        static final VarHandle BASE;
+        static final VarHandle TOP;
         static {
             try {
                 MethodHandles.Lookup l = MethodHandles.lookup();
                 PHASE = l.findVarHandle(WorkQueue.class, "phase", int.class);
+                BASE = l.findVarHandle(WorkQueue.class, "base", int.class);
+                TOP = l.findVarHandle(WorkQueue.class, "top", int.class);
             } catch (ReflectiveOperationException e) {
-                throw new Error(e);
+                throw new ExceptionInInitializerError(e);
             }
         }
     }
@@ -1356,39 +1367,37 @@
         wt.setDaemon(true);                             // configure thread
         if ((handler = ueh) != null)
             wt.setUncaughtExceptionHandler(handler);
+        int tid = 0;                                    // for thread name
+        int idbits = mode & FIFO;
+        String prefix = workerNamePrefix;
         WorkQueue w = new WorkQueue(this, wt);
-        int tid = 0;                                    // for thread name
-        int fifo = mode & FIFO;
-        String prefix = workerNamePrefix;
         if (prefix != null) {
             synchronized (prefix) {
                 WorkQueue[] ws = workQueues; int n;
                 int s = indexSeed += SEED_INCREMENT;
+                idbits |= (s & ~(SMASK | FIFO | DORMANT));
                 if (ws != null && (n = ws.length) > 1) {
                     int m = n - 1;
-                    tid = s & m;
-                    int i = m & ((s << 1) | 1);         // odd-numbered indices
+                    tid = m & ((s << 1) | 1);           // odd-numbered indices
                     for (int probes = n >>> 1;;) {      // find empty slot
                         WorkQueue q;
-                        if ((q = ws[i]) == null || q.phase == QUIET)
+                        if ((q = ws[tid]) == null || q.phase == QUIET)
                             break;
                         else if (--probes == 0) {
-                            i = n | 1;                  // resize below
+                            tid = n | 1;                // resize below
                             break;
                         }
                         else
-                            i = (i + 2) & m;
+                            tid = (tid + 2) & m;
                     }
+                    w.phase = w.id = tid | idbits;      // now publishable
 
-                    int id = i | fifo | (s & ~(SMASK | FIFO | DORMANT));
-                    w.phase = w.id = id;                // now publishable
-
-                    if (i < n)
-                        ws[i] = w;
+                    if (tid < n)
+                        ws[tid] = w;
                     else {                              // expand array
                         int an = n << 1;
                         WorkQueue[] as = new WorkQueue[an];
-                        as[i] = w;
+                        as[tid] = w;
                         int am = an - 1;
                         for (int j = 0; j < n; ++j) {
                             WorkQueue v;                // copy external queue
@@ -1421,14 +1430,14 @@
         int phase = 0;
         if (wt != null && (w = wt.workQueue) != null) {
             Object lock = workerNamePrefix;
+            int wid = w.id;
             long ns = (long)w.nsteals & 0xffffffffL;
-            int idx = w.id & SMASK;
             if (lock != null) {
-                WorkQueue[] ws;                       // remove index from array
                 synchronized (lock) {
-                    if ((ws = workQueues) != null && ws.length > idx &&
-                        ws[idx] == w)
-                        ws[idx] = null;
+                    WorkQueue[] ws; int n, i;         // remove index from array
+                    if ((ws = workQueues) != null && (n = ws.length) > 0 &&
+                        ws[i = wid & (n - 1)] == w)
+                        ws[i] = null;
                     stealCount += ns;
                 }
             }
@@ -1480,7 +1489,7 @@
                 Thread vt = v.owner;
                 if (sp == vp && CTL.compareAndSet(this, c, nc)) {
                     v.phase = np;
-                    if (v.source < 0)
+                    if (vt != null && v.source < 0)
                         LockSupport.unpark(vt);
                     break;
                 }
@@ -1521,7 +1530,7 @@
                     long nc = ((long)v.stackPred & SP_MASK) | uc;
                     if (vp == sp && CTL.compareAndSet(this, c, nc)) {
                         v.phase = np;
-                        if (v.source < 0)
+                        if (vt != null && v.source < 0)
                             LockSupport.unpark(vt);
                         return (wp < 0) ? -1 : 1;
                     }
@@ -1578,101 +1587,88 @@
      * See above for explanation.
      */
     final void runWorker(WorkQueue w) {
-        WorkQueue[] ws;
-        w.growArray();                                  // allocate queue
-        int r = w.id ^ ThreadLocalRandom.nextSecondarySeed();
-        if (r == 0)                                     // initial nonzero seed
-            r = 1;
-        int lastSignalId = 0;                           // avoid unneeded signals
-        while ((ws = workQueues) != null) {
-            boolean nonempty = false;                   // scan
-            for (int n = ws.length, j = n, m = n - 1; j > 0; --j) {
-                WorkQueue q; int i, b, al; ForkJoinTask<?>[] a;
-                if ((i = r & m) >= 0 && i < n &&        // always true
-                    (q = ws[i]) != null && (b = q.base) - q.top < 0 &&
-                    (a = q.array) != null && (al = a.length) > 0) {
-                    int qid = q.id;                     // (never zero)
-                    int index = (al - 1) & b;
-                    ForkJoinTask<?> t = (ForkJoinTask<?>)
-                        QA.getAcquire(a, index);
-                    if (t != null && b++ == q.base &&
-                        QA.compareAndSet(a, index, t, null)) {
-                        if ((q.base = b) - q.top < 0 && qid != lastSignalId)
-                            signalWork();               // propagate signal
-                        w.source = lastSignalId = qid;
-                        t.doExec();
-                        if ((w.id & FIFO) != 0)         // run remaining locals
-                            w.localPollAndExec(POLL_LIMIT);
-                        else
-                            w.localPopAndExec(POLL_LIMIT);
-                        ForkJoinWorkerThread thread = w.owner;
-                        ++w.nsteals;
-                        w.source = 0;                   // now idle
-                        if (thread != null)
-                            thread.afterTopLevelExec();
-                    }
-                    nonempty = true;
-                }
-                else if (nonempty)
-                    break;
-                else
-                    ++r;
+        int r = (w.id ^ ThreadLocalRandom.nextSecondarySeed()) | FIFO; // rng
+        w.array = new ForkJoinTask<?>[INITIAL_QUEUE_CAPACITY]; // initialize
+        for (;;) {
+            int phase;
+            if (scan(w, r)) {                     // scan until apparently empty
+                r ^= r << 13; r ^= r >>> 17; r ^= r << 5; // move (xorshift)
             }
-
-            if (nonempty) {                             // move (xorshift)
-                r ^= r << 13; r ^= r >>> 17; r ^= r << 5;
+            else if ((phase = w.phase) >= 0) {    // enqueue, then rescan
+                long np = (w.phase = (phase + SS_SEQ) | UNSIGNALLED) & SP_MASK;
+                long c, nc;
+                do {
+                    w.stackPred = (int)(c = ctl);
+                    nc = ((c - RC_UNIT) & UC_MASK) | np;
+                } while (!CTL.weakCompareAndSet(this, c, nc));
             }
-            else {
-                int phase;
-                lastSignalId = 0;                       // clear for next scan
-                if ((phase = w.phase) >= 0) {           // enqueue
-                    int np = w.phase = (phase + SS_SEQ) | UNSIGNALLED;
-                    long c, nc;
-                    do {
-                        w.stackPred = (int)(c = ctl);
-                        nc = ((c - RC_UNIT) & UC_MASK) | (SP_MASK & np);
-                    } while (!CTL.weakCompareAndSet(this, c, nc));
-                }
-                else {                                  // already queued
-                    int pred = w.stackPred;
-                    w.source = DORMANT;                 // enable signal
-                    for (int steps = 0;;) {
-                        int md, rc; long c;
-                        if (w.phase >= 0) {
-                            w.source = 0;
-                            break;
-                        }
-                        else if ((md = mode) < 0)       // shutting down
-                            return;
-                        else if ((rc = ((md & SMASK) +  // possibly quiescent
-                                        (int)((c = ctl) >> RC_SHIFT))) <= 0 &&
-                                 (md & SHUTDOWN) != 0 &&
-                                 tryTerminate(false, false))
-                            return;                     // help terminate
-                        else if ((++steps & 1) == 0)
-                            Thread.interrupted();       // clear between parks
-                        else if (rc <= 0 && pred != 0 && phase == (int)c) {
-                            long d = keepAlive + System.currentTimeMillis();
-                            LockSupport.parkUntil(this, d);
-                            if (ctl == c &&
-                                d - System.currentTimeMillis() <= TIMEOUT_SLOP) {
-                                long nc = ((UC_MASK & (c - TC_UNIT)) |
-                                           (SP_MASK & pred));
-                                if (CTL.compareAndSet(this, c, nc)) {
-                                    w.phase = QUIET;
-                                    return;             // drop on timeout
-                                }
-                            }
-                        }
-                        else
-                            LockSupport.park(this);
+            else {                                // already queued
+                int pred = w.stackPred;
+                Thread.interrupted();             // clear before park
+                w.source = DORMANT;               // enable signal
+                long c = ctl;
+                int md = mode, rc = (md & SMASK) + (int)(c >> RC_SHIFT);
+                if (md < 0)                       // terminating
+                    break;
+                else if (rc <= 0 && (md & SHUTDOWN) != 0 &&
+                         tryTerminate(false, false))
+                    break;                        // quiescent shutdown
+                else if (rc <= 0 && pred != 0 && phase == (int)c) {
+                    long nc = (UC_MASK & (c - TC_UNIT)) | (SP_MASK & pred);
+                    long d = keepAlive + System.currentTimeMillis();
+                    LockSupport.parkUntil(this, d);
+                    if (ctl == c &&               // drop on timeout if all idle
+                        d - System.currentTimeMillis() <= TIMEOUT_SLOP &&
+                        CTL.compareAndSet(this, c, nc)) {
+                        w.phase = QUIET;
+                        break;
                     }
                 }
+                else if (w.phase < 0)
+                    LockSupport.park(this);       // OK if spuriously woken
+                w.source = 0;                     // disable signal
             }
         }
     }
 
     /**
+     * Scans for and if found executes one or more top-level tasks from a queue.
+     *
+     * @return true if found an apparently non-empty queue, and
+     * possibly ran task(s).
+     */
+    private boolean scan(WorkQueue w, int r) {
+        WorkQueue[] ws; int n;
+        if ((ws = workQueues) != null && (n = ws.length) > 0 && w != null) {
+            for (int m = n - 1, j = r & m;;) {
+                WorkQueue q; int b;
+                if ((q = ws[j]) != null && q.top != (b = q.base)) {
+                    int qid = q.id;
+                    ForkJoinTask<?>[] a; int cap, k; ForkJoinTask<?> t;
+                    if ((a = q.array) != null && (cap = a.length) > 0) {
+                        t = (ForkJoinTask<?>)QA.getAcquire(a, k = (cap - 1) & b);
+                        if (q.base == b++ && t != null &&
+                            QA.compareAndSet(a, k, t, null)) {
+                            q.base = b;
+                            w.source = qid;
+                            if (q.top - b > 0)
+                                signalWork();
+                            w.topLevelExec(t, q,  // random fairness bound
+                                           r & ((n << TOP_BOUND_SHIFT) - 1));
+                        }
+                    }
+                    return true;
+                }
+                else if (--n > 0)
+                    j = (j + 1) & m;
+                else
+                    break;
+            }
+        }
+        return false;
+    }
+
+    /**
      * Helps and/or blocks until the given task is done or timeout.
      * First tries locally helping, then scans other queues for a task
      * produced by one of w's stealers; compensating and blocking if
@@ -1685,42 +1681,44 @@
      */
     final int awaitJoin(WorkQueue w, ForkJoinTask<?> task, long deadline) {
         int s = 0;
+        int seed = ThreadLocalRandom.nextSecondarySeed();
         if (w != null && task != null &&
             (!(task instanceof CountedCompleter) ||
-             (s = w.localHelpCC((CountedCompleter<?>)task, 0)) >= 0)) {
+             (s = w.helpCC((CountedCompleter<?>)task, 0, false)) >= 0)) {
             w.tryRemoveAndExec(task);
             int src = w.source, id = w.id;
+            int r = (seed >>> 16) | 1, step = (seed & ~1) | 2;
             s = task.status;
             while (s >= 0) {
                 WorkQueue[] ws;
-                boolean nonempty = false;
-                int r = ThreadLocalRandom.nextSecondarySeed() | 1; // odd indices
-                if ((ws = workQueues) != null) {       // scan for matching id
-                    for (int n = ws.length, m = n - 1, j = -n; j < n; j += 2) {
-                        WorkQueue q; int i, b, al; ForkJoinTask<?>[] a;
-                        if ((i = (r + j) & m) >= 0 && i < n &&
-                            (q = ws[i]) != null && q.source == id &&
-                            (b = q.base) - q.top < 0 &&
-                            (a = q.array) != null && (al = a.length) > 0) {
-                            int qid = q.id;
-                            int index = (al - 1) & b;
+                int n = (ws = workQueues) == null ? 0 : ws.length, m = n - 1;
+                while (n > 0) {
+                    WorkQueue q; int b;
+                    if ((q = ws[r & m]) != null && q.source == id &&
+                        q.top != (b = q.base)) {
+                        ForkJoinTask<?>[] a; int cap, k;
+                        int qid = q.id;
+                        if ((a = q.array) != null && (cap = a.length) > 0) {
                             ForkJoinTask<?> t = (ForkJoinTask<?>)
-                                QA.getAcquire(a, index);
-                            if (t != null && b++ == q.base && id == q.source &&
-                                QA.compareAndSet(a, index, t, null)) {
+                                QA.getAcquire(a, k = (cap - 1) & b);
+                            if (q.source == id && q.base == b++ &&
+                                t != null && QA.compareAndSet(a, k, t, null)) {
                                 q.base = b;
                                 w.source = qid;
                                 t.doExec();
                                 w.source = src;
                             }
-                            nonempty = true;
-                            break;
                         }
+                        break;
+                    }
+                    else {
+                        r += step;
+                        --n;
                     }
                 }
                 if ((s = task.status) < 0)
                     break;
-                else if (!nonempty) {
+                else if (n == 0) { // empty scan
                     long ms, ns; int block;
                     if (deadline == 0L)
                         ms = 0L;                       // untimed
@@ -1745,44 +1743,44 @@
      * find tasks either.
      */
     final void helpQuiescePool(WorkQueue w) {
-        int prevSrc = w.source, fifo = w.id & FIFO;
+        int prevSrc = w.source;
+        int seed = ThreadLocalRandom.nextSecondarySeed();
+        int r = seed >>> 16, step = r | 1;
         for (int source = prevSrc, released = -1;;) { // -1 until known
-            WorkQueue[] ws;
-            if (fifo != 0)
-                w.localPollAndExec(0);
-            else
-                w.localPopAndExec(0);
-            if (released == -1 && w.phase >= 0)
+            ForkJoinTask<?> localTask; WorkQueue[] ws;
+            while ((localTask = w.nextLocalTask()) != null)
+                localTask.doExec();
+            if (w.phase >= 0 && released == -1)
                 released = 1;
             boolean quiet = true, empty = true;
-            int r = ThreadLocalRandom.nextSecondarySeed();
-            if ((ws = workQueues) != null) {
-                for (int n = ws.length, j = n, m = n - 1; j > 0; --j) {
-                    WorkQueue q; int i, b, al; ForkJoinTask<?>[] a;
-                    if ((i = (r - j) & m) >= 0 && i < n && (q = ws[i]) != null) {
-                        if ((b = q.base) - q.top < 0 &&
-                            (a = q.array) != null && (al = a.length) > 0) {
-                            int qid = q.id;
+            int n = (ws = workQueues) == null ? 0 : ws.length;
+            for (int m = n - 1; n > 0; r += step, --n) {
+                WorkQueue q; int b;
+                if ((q = ws[r & m]) != null) {
+                    int qs = q.source;
+                    if (q.top != (b = q.base)) {
+                        quiet = empty = false;
+                        ForkJoinTask<?>[] a; int cap, k;
+                        int qid = q.id;
+                        if ((a = q.array) != null && (cap = a.length) > 0) {
                             if (released == 0) {    // increment
                                 released = 1;
                                 CTL.getAndAdd(this, RC_UNIT);
                             }
-                            int index = (al - 1) & b;
                             ForkJoinTask<?> t = (ForkJoinTask<?>)
-                                QA.getAcquire(a, index);
-                            if (t != null && b++ == q.base &&
-                                QA.compareAndSet(a, index, t, null)) {
+                                QA.getAcquire(a, k = (cap - 1) & b);
+                            if (q.base == b++ && t != null &&
+                                QA.compareAndSet(a, k, t, null)) {
                                 q.base = b;
-                                w.source = source = q.id;
+                                w.source = qid;
                                 t.doExec();
                                 w.source = source = prevSrc;
                             }
-                            quiet = empty = false;
-                            break;
                         }
-                        else if ((q.source & QUIET) == 0)
-                            quiet = false;
+                        break;
                     }
+                    else if ((qs & QUIET) == 0)
+                        quiet = false;
                 }
             }
             if (quiet) {
@@ -1824,28 +1822,24 @@
                 origin = r & m;
                 step = h | 1;
             }
-            for (int k = origin, oldSum = 0, checkSum = 0;;) {
-                WorkQueue q; int b, al; ForkJoinTask<?>[] a;
-                if ((q = ws[k]) != null) {
-                    checkSum += b = q.base;
-                    if (b - q.top < 0 &&
-                        (a = q.array) != null && (al = a.length) > 0) {
-                        int index = (al - 1) & b;
-                        ForkJoinTask<?> t = (ForkJoinTask<?>)
-                            QA.getAcquire(a, index);
-                        if (t != null && b++ == q.base &&
-                            QA.compareAndSet(a, index, t, null)) {
-                            q.base = b;
+            boolean nonempty = false;
+            for (int i = origin, oldSum = 0, checkSum = 0;;) {
+                WorkQueue q;
+                if ((q = ws[i]) != null) {
+                    int b; ForkJoinTask<?> t;
+                    if (q.top - (b = q.base) > 0) {
+                        nonempty = true;
+                        if ((t = q.poll()) != null)
                             return t;
-                        }
-                        else
-                            break; // restart
                     }
+                    else
+                        checkSum += b + q.id;
                 }
-                if ((k = (k + step) & m) == origin) {
-                    if (oldSum == (oldSum = checkSum))
+                if ((i = (i + step) & m) == origin) {
+                    if (!nonempty && oldSum == (oldSum = checkSum))
                         break rescan;
                     checkSum = 0;
+                    nonempty = false;
                 }
             }
         }
@@ -1859,11 +1853,9 @@
      */
     final ForkJoinTask<?> nextTaskFor(WorkQueue w) {
         ForkJoinTask<?> t;
-        if (w != null &&
-            (t = (w.id & FIFO) != 0 ? w.poll() : w.pop()) != null)
-            return t;
-        else
-            return pollScan(false);
+        if (w == null || (t = w.nextLocalTask()) == null)
+            t = pollScan(false);
+        return t;
     }
 
     // External operations
@@ -1881,64 +1873,35 @@
             r = ThreadLocalRandom.getProbe();
         }
         for (;;) {
+            WorkQueue q;
             int md = mode, n;
             WorkQueue[] ws = workQueues;
             if ((md & SHUTDOWN) != 0 || ws == null || (n = ws.length) <= 0)
                 throw new RejectedExecutionException();
-            else {
-                WorkQueue q;
-                boolean push = false, grow = false;
-                if ((q = ws[(n - 1) & r & SQMASK]) == null) {
-                    Object lock = workerNamePrefix;
-                    int qid = (r | QUIET) & ~(FIFO | OWNED);
-                    q = new WorkQueue(this, null);
-                    q.id = qid;
-                    q.source = QUIET;
-                    q.phase = QLOCK;          // lock queue
-                    if (lock != null) {
-                        synchronized (lock) { // lock pool to install
-                            int i;
-                            if ((ws = workQueues) != null &&
-                                (n = ws.length) > 0 &&
-                                ws[i = qid & (n - 1) & SQMASK] == null) {
-                                ws[i] = q;
-                                push = grow = true;
-                            }
-                        }
+            else if ((q = ws[(n - 1) & r & SQMASK]) == null) { // add queue
+                int qid = (r | QUIET) & ~(FIFO | OWNED);
+                Object lock = workerNamePrefix;
+                ForkJoinTask<?>[] qa =
+                    new ForkJoinTask<?>[INITIAL_QUEUE_CAPACITY];
+                q = new WorkQueue(this, null);
+                q.array = qa;
+                q.id = qid;
+                q.source = QUIET;
+                if (lock != null) {     // unless disabled, lock pool to install
+                    synchronized (lock) {
+                        WorkQueue[] vs; int i, vn;
+                        if ((vs = workQueues) != null && (vn = vs.length) > 0 &&
+                            vs[i = qid & (vn - 1) & SQMASK] == null)
+                            vs[i] = q;  // else another thread already installed
                     }
                 }
-                else if (q.tryLockSharedQueue()) {
-                    int b = q.base, s = q.top, al, d; ForkJoinTask<?>[] a;
-                    if ((a = q.array) != null && (al = a.length) > 0 &&
-                        al - 1 + (d = b - s) > 0) {
-                        a[(al - 1) & s] = task;
-                        q.top = s + 1;        // relaxed writes OK here
-                        q.phase = 0;
-                        if (d < 0 && q.base - s < -1)
-                            break;            // no signal needed
-                    }
-                    else
-                        grow = true;
-                    push = true;
-                }
-                if (push) {
-                    if (grow) {
-                        try {
-                            q.growArray();
-                            int s = q.top, al; ForkJoinTask<?>[] a;
-                            if ((a = q.array) != null && (al = a.length) > 0) {
-                                a[(al - 1) & s] = task;
-                                q.top = s + 1;
-                            }
-                        } finally {
-                            q.phase = 0;
-                        }
-                    }
+            }
+            else if (!q.tryLockPhase()) // move if busy
+                r = ThreadLocalRandom.advanceProbe(r);
+            else {
+                if (q.lockedPush(task))
                     signalWork();
-                    break;
-                }
-                else                          // move if busy
-                    r = ThreadLocalRandom.advanceProbe(r);
+                return;
             }
         }
     }
@@ -1980,7 +1943,7 @@
         return ((ws = workQueues) != null &&
                 (n = ws.length) > 0 &&
                 (w = ws[(n - 1) & r & SQMASK]) != null &&
-                w.trySharedUnpush(task));
+                w.tryLockedUnpush(task));
     }
 
     /**
@@ -1991,7 +1954,7 @@
         WorkQueue[] ws; WorkQueue w; int n;
         return ((ws = workQueues) != null && (n = ws.length) > 0 &&
                 (w = ws[(n - 1) & r & SQMASK]) != null) ?
-            w.sharedHelpCC(task, maxTasks) : 0;
+            w.helpCC(task, maxTasks, true) : 0;
     }
 
     /**
@@ -2006,7 +1969,7 @@
      */
     final int helpComplete(WorkQueue w, CountedCompleter<?> task,
                            int maxTasks) {
-        return (w == null) ? 0 : w.localHelpCC(task, maxTasks);
+        return (w == null) ? 0 : w.helpCC(task, maxTasks, false);
     }
 
     /**
@@ -2097,15 +2060,18 @@
                     if ((md & SMASK) + (int)(checkSum >> RC_SHIFT) > 0)
                         running = true;
                     else if (ws != null) {
-                        WorkQueue w; int b;
+                        WorkQueue w;
                         for (int i = 0; i < ws.length; ++i) {
                             if ((w = ws[i]) != null) {
-                                checkSum += (b = w.base) + w.id;
+                                int s = w.source, p = w.phase;
+                                int d = w.id, b = w.base;
                                 if (b != w.top ||
-                                    ((i & 1) == 1 && w.source >= 0)) {
+                                    ((d & 1) == 1 && (s >= 0 || p >= 0))) {
                                     running = true;
-                                    break;
+                                    break;     // working, scanning, or have work
                                 }
+                                checkSum += (((long)s << 48) + ((long)p << 32) +
+                                             ((long)b << 16) + (long)d);
                             }
                         }
                     }
@@ -2136,7 +2102,7 @@
                                 } catch (Throwable ignore) {
                                 }
                             }
-                            checkSum += w.base + w.id;
+                            checkSum += ((long)w.phase << 32) + w.base;
                         }
                     }
                 }
@@ -2629,8 +2595,9 @@
      * @return the number of worker threads
      */
     public int getRunningThreadCount() {
+        WorkQueue[] ws; WorkQueue w;
+        VarHandle.acquireFence();
         int rc = 0;
-        WorkQueue[] ws; WorkQueue w;
         if ((ws = workQueues) != null) {
             for (int i = 1; i < ws.length; i += 2) {
                 if ((w = ws[i]) != null && w.isApparentlyUnblocked())
@@ -2678,7 +2645,7 @@
                 if ((ws = workQueues) != null) {
                     for (int i = 1; i < ws.length; i += 2) {
                         if ((v = ws[i]) != null) {
-                            if ((v.source & QUIET) == 0)
+                            if (v.source > 0)
                                 return false;
                             --tc;
                         }
@@ -2724,8 +2691,9 @@
      * @return the number of queued tasks
      */
     public long getQueuedTaskCount() {
-        long count = 0;
         WorkQueue[] ws; WorkQueue w;
+        VarHandle.acquireFence();
+        int count = 0;
         if ((ws = workQueues) != null) {
             for (int i = 1; i < ws.length; i += 2) {
                 if ((w = ws[i]) != null)
@@ -2743,8 +2711,9 @@
      * @return the number of queued submissions
      */
     public int getQueuedSubmissionCount() {
+        WorkQueue[] ws; WorkQueue w;
+        VarHandle.acquireFence();
         int count = 0;
-        WorkQueue[] ws; WorkQueue w;
         if ((ws = workQueues) != null) {
             for (int i = 0; i < ws.length; i += 2) {
                 if ((w = ws[i]) != null)
@@ -2762,6 +2731,7 @@
      */
     public boolean hasQueuedSubmissions() {
         WorkQueue[] ws; WorkQueue w;
+        VarHandle.acquireFence();
         if ((ws = workQueues) != null) {
             for (int i = 0; i < ws.length; i += 2) {
                 if ((w = ws[i]) != null && !w.isEmpty())
@@ -2800,8 +2770,9 @@
      * @return the number of elements transferred
      */
     protected int drainTasksTo(Collection<? super ForkJoinTask<?>> c) {
+        WorkQueue[] ws; WorkQueue w; ForkJoinTask<?> t;
+        VarHandle.acquireFence();
         int count = 0;
-        WorkQueue[] ws; WorkQueue w; ForkJoinTask<?> t;
         if ((ws = workQueues) != null) {
             for (int i = 0; i < ws.length; ++i) {
                 if ((w = ws[i]) != null) {
@@ -2824,8 +2795,10 @@
      */
     public String toString() {
         // Use a single pass through workQueues to collect counts
+        int md = mode; // read volatile fields first
+        long c = ctl;
+        long st = stealCount;
         long qt = 0L, qs = 0L; int rc = 0;
-        long st = stealCount;
         WorkQueue[] ws; WorkQueue w;
         if ((ws = workQueues) != null) {
             for (int i = 0; i < ws.length; ++i) {
@@ -2843,9 +2816,7 @@
             }
         }
 
-        int md = mode;
         int pc = (md & SMASK);
-        long c = ctl;
         int tc = pc + (short)(c >>> TC_SHIFT);
         int ac = pc + (int)(c >> RC_SHIFT);
         if (ac < 0) // ignore transient negative
@@ -3131,6 +3102,7 @@
      */
     public static void managedBlock(ManagedBlocker blocker)
         throws InterruptedException {
+        if (blocker == null) throw new NullPointerException();
         ForkJoinPool p;
         ForkJoinWorkerThread wt;
         WorkQueue w;
@@ -3163,7 +3135,7 @@
      * available or blocker is released.
      */
     static void helpAsyncBlocker(Executor e, ManagedBlocker blocker) {
-        if (blocker != null && (e instanceof ForkJoinPool)) {
+        if (e instanceof ForkJoinPool) {
             WorkQueue w; ForkJoinWorkerThread wt; WorkQueue[] ws; int r, n;
             ForkJoinPool p = (ForkJoinPool)e;
             Thread thread = Thread.currentThread();
@@ -3175,34 +3147,8 @@
                 w = ws[(n - 1) & r & SQMASK];
             else
                 w = null;
-            if (w != null) {
-                for (;;) {
-                    int b = w.base, s = w.top, d, al; ForkJoinTask<?>[] a;
-                    if ((a = w.array) != null && (d = b - s) < 0 &&
-                        (al = a.length) > 0) {
-                        int index = (al - 1) & b;
-                        ForkJoinTask<?> t = (ForkJoinTask<?>)
-                            QA.getAcquire(a, index);
-                        if (blocker.isReleasable())
-                            break;
-                        else if (b++ == w.base) {
-                            if (t == null) {
-                                if (d == -1)
-                                    break;
-                            }
-                            else if (!(t instanceof CompletableFuture.
-                                  AsynchronousCompletionTask))
-                                break;
-                            else if (QA.compareAndSet(a, index, t, null)) {
-                                w.base = b;
-                                t.doExec();
-                            }
-                        }
-                    }
-                    else
-                        break;
-                }
-            }
+            if (w != null)
+                w.helpAsyncBlocker(blocker);
         }
     }
 
@@ -3221,7 +3167,7 @@
     // VarHandle mechanics
     private static final VarHandle CTL;
     private static final VarHandle MODE;
-    private static final VarHandle QA;
+    static final VarHandle QA;
 
     static {
         try {
@@ -3230,7 +3176,7 @@
             MODE = l.findVarHandle(ForkJoinPool.class, "mode", int.class);
             QA = MethodHandles.arrayElementVarHandle(ForkJoinTask[].class);
         } catch (ReflectiveOperationException e) {
-            throw new Error(e);
+            throw new ExceptionInInitializerError(e);
         }
 
         // Reduce the risk of rare disastrous classloading in first call to
--- a/src/java.base/share/classes/java/util/concurrent/ForkJoinTask.java	Mon Apr 09 08:34:30 2018 -0700
+++ b/src/java.base/share/classes/java/util/concurrent/ForkJoinTask.java	Tue Apr 10 13:58:47 2018 -0700
@@ -1540,7 +1540,7 @@
             MethodHandles.Lookup l = MethodHandles.lookup();
             STATUS = l.findVarHandle(ForkJoinTask.class, "status", int.class);
         } catch (ReflectiveOperationException e) {
-            throw new Error(e);
+            throw new ExceptionInInitializerError(e);
         }
     }
 
--- a/src/java.base/share/classes/java/util/concurrent/FutureTask.java	Mon Apr 09 08:34:30 2018 -0700
+++ b/src/java.base/share/classes/java/util/concurrent/FutureTask.java	Tue Apr 10 13:58:47 2018 -0700
@@ -526,7 +526,7 @@
             RUNNER = l.findVarHandle(FutureTask.class, "runner", Thread.class);
             WAITERS = l.findVarHandle(FutureTask.class, "waiters", WaitNode.class);
         } catch (ReflectiveOperationException e) {
-            throw new Error(e);
+            throw new ExceptionInInitializerError(e);
         }
 
         // Reduce the risk of rare disastrous classloading in first call to
--- a/src/java.base/share/classes/java/util/concurrent/LinkedTransferQueue.java	Mon Apr 09 08:34:30 2018 -0700
+++ b/src/java.base/share/classes/java/util/concurrent/LinkedTransferQueue.java	Tue Apr 10 13:58:47 2018 -0700
@@ -1739,7 +1739,7 @@
             NEXT = l.findVarHandle(Node.class, "next", Node.class);
             WAITER = l.findVarHandle(Node.class, "waiter", Thread.class);
         } catch (ReflectiveOperationException e) {
-            throw new Error(e);
+            throw new ExceptionInInitializerError(e);
         }
 
         // Reduce the risk of rare disastrous classloading in first call to
--- a/src/java.base/share/classes/java/util/concurrent/Phaser.java	Mon Apr 09 08:34:30 2018 -0700
+++ b/src/java.base/share/classes/java/util/concurrent/Phaser.java	Tue Apr 10 13:58:47 2018 -0700
@@ -1137,7 +1137,7 @@
             MethodHandles.Lookup l = MethodHandles.lookup();
             STATE = l.findVarHandle(Phaser.class, "state", long.class);
         } catch (ReflectiveOperationException e) {
-            throw new Error(e);
+            throw new ExceptionInInitializerError(e);
         }
 
         // Reduce the risk of rare disastrous classloading in first call to
--- a/src/java.base/share/classes/java/util/concurrent/PriorityBlockingQueue.java	Mon Apr 09 08:34:30 2018 -0700
+++ b/src/java.base/share/classes/java/util/concurrent/PriorityBlockingQueue.java	Tue Apr 10 13:58:47 2018 -0700
@@ -1014,7 +1014,7 @@
                                                  "allocationSpinLock",
                                                  int.class);
         } catch (ReflectiveOperationException e) {
-            throw new Error(e);
+            throw new ExceptionInInitializerError(e);
         }
     }
 }
--- a/src/java.base/share/classes/java/util/concurrent/SubmissionPublisher.java	Mon Apr 09 08:34:30 2018 -0700
+++ b/src/java.base/share/classes/java/util/concurrent/SubmissionPublisher.java	Tue Apr 10 13:58:47 2018 -0700
@@ -1096,7 +1096,7 @@
             if (cap > 0) {
                 boolean added;
                 if (n >= cap && cap < maxCapacity) // resize
-                    added = growAndoffer(item, a, t);
+                    added = growAndOffer(item, a, t);
                 else if (n >= cap || unowned)      // need volatile CAS
                     added = QA.compareAndSet(a, i, null, item);
                 else {                             // can use release mode
@@ -1115,7 +1115,7 @@
          * Tries to expand buffer and add item, returning true on
          * success. Currently fails only if out of memory.
          */
-        final boolean growAndoffer(T item, Object[] a, int t) {
+        final boolean growAndOffer(T item, Object[] a, int t) {
             int cap = 0, newCap = 0;
             Object[] newArray = null;
             if (a != null && (cap = a.length) > 0 && (newCap = cap << 1) > 0) {
@@ -1466,7 +1466,7 @@
                                          long.class);
                 QA = MethodHandles.arrayElementVarHandle(Object[].class);
             } catch (ReflectiveOperationException e) {
-                throw new Error(e);
+                throw new ExceptionInInitializerError(e);
             }
 
             // Reduce the risk of rare disastrous classloading in first call to
--- a/src/java.base/share/classes/java/util/concurrent/SynchronousQueue.java	Mon Apr 09 08:34:30 2018 -0700
+++ b/src/java.base/share/classes/java/util/concurrent/SynchronousQueue.java	Tue Apr 10 13:58:47 2018 -0700
@@ -293,7 +293,7 @@
                     SMATCH = l.findVarHandle(SNode.class, "match", SNode.class);
                     SNEXT = l.findVarHandle(SNode.class, "next", SNode.class);
                 } catch (ReflectiveOperationException e) {
-                    throw new Error(e);
+                    throw new ExceptionInInitializerError(e);
                 }
             }
         }
@@ -516,7 +516,7 @@
                 MethodHandles.Lookup l = MethodHandles.lookup();
                 SHEAD = l.findVarHandle(TransferStack.class, "head", SNode.class);
             } catch (ReflectiveOperationException e) {
-                throw new Error(e);
+                throw new ExceptionInInitializerError(e);
             }
         }
     }
@@ -583,7 +583,7 @@
                     QITEM = l.findVarHandle(QNode.class, "item", Object.class);
                     QNEXT = l.findVarHandle(QNode.class, "next", QNode.class);
                 } catch (ReflectiveOperationException e) {
-                    throw new Error(e);
+                    throw new ExceptionInInitializerError(e);
                 }
             }
         }
@@ -830,7 +830,7 @@
                 QCLEANME = l.findVarHandle(TransferQueue.class, "cleanMe",
                                            QNode.class);
             } catch (ReflectiveOperationException e) {
-                throw new Error(e);
+                throw new ExceptionInInitializerError(e);
             }
         }
     }
--- a/src/java.base/share/classes/java/util/concurrent/atomic/AtomicBoolean.java	Mon Apr 09 08:34:30 2018 -0700
+++ b/src/java.base/share/classes/java/util/concurrent/atomic/AtomicBoolean.java	Tue Apr 10 13:58:47 2018 -0700
@@ -56,7 +56,7 @@
             MethodHandles.Lookup l = MethodHandles.lookup();
             VALUE = l.findVarHandle(AtomicBoolean.class, "value", int.class);
         } catch (ReflectiveOperationException e) {
-            throw new Error(e);
+            throw new ExceptionInInitializerError(e);
         }
     }
 
--- a/src/java.base/share/classes/java/util/concurrent/atomic/AtomicMarkableReference.java	Mon Apr 09 08:34:30 2018 -0700
+++ b/src/java.base/share/classes/java/util/concurrent/atomic/AtomicMarkableReference.java	Tue Apr 10 13:58:47 2018 -0700
@@ -199,7 +199,7 @@
             PAIR = l.findVarHandle(AtomicMarkableReference.class, "pair",
                                    Pair.class);
         } catch (ReflectiveOperationException e) {
-            throw new Error(e);
+            throw new ExceptionInInitializerError(e);
         }
     }
 
--- a/src/java.base/share/classes/java/util/concurrent/atomic/AtomicReference.java	Mon Apr 09 08:34:30 2018 -0700
+++ b/src/java.base/share/classes/java/util/concurrent/atomic/AtomicReference.java	Tue Apr 10 13:58:47 2018 -0700
@@ -56,7 +56,7 @@
             MethodHandles.Lookup l = MethodHandles.lookup();
             VALUE = l.findVarHandle(AtomicReference.class, "value", Object.class);
         } catch (ReflectiveOperationException e) {
-            throw new Error(e);
+            throw new ExceptionInInitializerError(e);
         }
     }
 
--- a/src/java.base/share/classes/java/util/concurrent/atomic/AtomicStampedReference.java	Mon Apr 09 08:34:30 2018 -0700
+++ b/src/java.base/share/classes/java/util/concurrent/atomic/AtomicStampedReference.java	Tue Apr 10 13:58:47 2018 -0700
@@ -199,7 +199,7 @@
             PAIR = l.findVarHandle(AtomicStampedReference.class, "pair",
                                    Pair.class);
         } catch (ReflectiveOperationException e) {
-            throw new Error(e);
+            throw new ExceptionInInitializerError(e);
         }
     }
 
--- a/src/java.base/share/classes/java/util/concurrent/atomic/Striped64.java	Mon Apr 09 08:34:30 2018 -0700
+++ b/src/java.base/share/classes/java/util/concurrent/atomic/Striped64.java	Tue Apr 10 13:58:47 2018 -0700
@@ -144,7 +144,7 @@
                 MethodHandles.Lookup l = MethodHandles.lookup();
                 VALUE = l.findVarHandle(Cell.class, "value", long.class);
             } catch (ReflectiveOperationException e) {
-                throw new Error(e);
+                throw new ExceptionInInitializerError(e);
             }
         }
     }
@@ -396,13 +396,13 @@
                             try {
                                 return MethodHandles.privateLookupIn(Thread.class, MethodHandles.lookup());
                             } catch (ReflectiveOperationException e) {
-                                throw new Error(e);
+                                throw new ExceptionInInitializerError(e);
                             }
                         }});
             THREAD_PROBE = l.findVarHandle(Thread.class,
                     "threadLocalRandomProbe", int.class);
         } catch (ReflectiveOperationException e) {
-            throw new Error(e);
+            throw new ExceptionInInitializerError(e);
         }
     }
 
--- a/src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java	Mon Apr 09 08:34:30 2018 -0700
+++ b/src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java	Tue Apr 10 13:58:47 2018 -0700
@@ -1830,7 +1830,7 @@
             HEAD = l.findVarHandle(AbstractQueuedLongSynchronizer.class, "head", Node.class);
             TAIL = l.findVarHandle(AbstractQueuedLongSynchronizer.class, "tail", Node.class);
         } catch (ReflectiveOperationException e) {
-            throw new Error(e);
+            throw new ExceptionInInitializerError(e);
         }
 
         // Reduce the risk of rare disastrous classloading in first call to
--- a/src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedSynchronizer.java	Mon Apr 09 08:34:30 2018 -0700
+++ b/src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedSynchronizer.java	Tue Apr 10 13:58:47 2018 -0700
@@ -555,7 +555,7 @@
                 THREAD = l.findVarHandle(Node.class, "thread", Thread.class);
                 WAITSTATUS = l.findVarHandle(Node.class, "waitStatus", int.class);
             } catch (ReflectiveOperationException e) {
-                throw new Error(e);
+                throw new ExceptionInInitializerError(e);
             }
         }
     }
@@ -2308,7 +2308,7 @@
             HEAD = l.findVarHandle(AbstractQueuedSynchronizer.class, "head", Node.class);
             TAIL = l.findVarHandle(AbstractQueuedSynchronizer.class, "tail", Node.class);
         } catch (ReflectiveOperationException e) {
-            throw new Error(e);
+            throw new ExceptionInInitializerError(e);
         }
 
         // Reduce the risk of rare disastrous classloading in first call to
--- a/src/java.base/share/classes/java/util/concurrent/locks/StampedLock.java	Mon Apr 09 08:34:30 2018 -0700
+++ b/src/java.base/share/classes/java/util/concurrent/locks/StampedLock.java	Tue Apr 10 13:58:47 2018 -0700
@@ -1614,7 +1614,7 @@
             WNEXT = l.findVarHandle(WNode.class, "next", WNode.class);
             WCOWAIT = l.findVarHandle(WNode.class, "cowait", WNode.class);
         } catch (ReflectiveOperationException e) {
-            throw new Error(e);
+            throw new ExceptionInInitializerError(e);
         }
     }
 }
--- a/src/java.base/share/classes/java/util/regex/Pattern.java	Mon Apr 09 08:34:30 2018 -0700
+++ b/src/java.base/share/classes/java/util/regex/Pattern.java	Tue Apr 10 13:58:47 2018 -0700
@@ -5809,10 +5809,21 @@
     static final Node lastAccept = new LastNode();
 
     /**
-     * Creates a predicate which can be used to match a string.
+     * Creates a predicate that tests if this pattern is found in a given input
+     * string.
      *
-     * @return  The predicate which can be used for matching on a string
+     * @apiNote
+     * This method creates a predicate that behaves as if it creates a matcher
+     * from the input sequence and then calls {@code find}, for example a
+     * predicate of the form:
+     * <pre>{@code
+     *   s -> matcher(s).find();
+     * }</pre>
+     *
+     * @return  The predicate which can be used for finding a match on a
+     * subsequence of a string
      * @since   1.8
+     * @see Matcher#find
      */
     public Predicate<String> asPredicate() {
         return s -> matcher(s).find();
--- a/src/java.base/share/classes/sun/nio/cs/ISO_8859_1.java	Mon Apr 09 08:34:30 2018 -0700
+++ b/src/java.base/share/classes/sun/nio/cs/ISO_8859_1.java	Tue Apr 10 13:58:47 2018 -0700
@@ -39,6 +39,8 @@
     extends Charset
     implements HistoricallyNamedCharset
 {
+    public static final ISO_8859_1 INSTANCE = new ISO_8859_1();
+
     public ISO_8859_1() {
         super("ISO-8859-1", StandardCharsets.aliases_ISO_8859_1());
     }
--- a/src/java.base/share/classes/sun/nio/cs/StandardCharsets.java.template	Mon Apr 09 08:34:30 2018 -0700
+++ b/src/java.base/share/classes/sun/nio/cs/StandardCharsets.java.template	Tue Apr 10 13:58:47 2018 -0700
@@ -83,9 +83,9 @@
         Map<String,Charset> map = cache;
         if (map == null) {
             map = new Cache();
-            map.put("utf-8", java.nio.charset.StandardCharsets.UTF_8);
-            map.put("iso-8859-1", java.nio.charset.StandardCharsets.ISO_8859_1);
-            map.put("us-ascii", java.nio.charset.StandardCharsets.US_ASCII);
+            map.put("utf-8", UTF_8.INSTANCE);
+            map.put("iso-8859-1", ISO_8859_1.INSTANCE);
+            map.put("us-ascii", US_ASCII.INSTANCE);
             map.put("utf-16", java.nio.charset.StandardCharsets.UTF_16);
             map.put("utf-16be", java.nio.charset.StandardCharsets.UTF_16BE);
             map.put("utf-16le", java.nio.charset.StandardCharsets.UTF_16LE);
@@ -122,15 +122,19 @@
     private Charset lookup(String charsetName) {
         init();
 
-        // By checking these built-ins we can avoid initializing Aliases and
-        // Classes eagerly during bootstrap
+        // By checking these built-ins we can avoid initializing Aliases,
+        // Classes and Cache eagerly during bootstrap.
+        //
+        // Initialization of java.nio.charset.StandardCharsets should be
+        // avoided here to minimize time spent in System.initPhase1, as it
+        // may delay initialization of performance critical VM subsystems.
         String csn;
         if (charsetName.equals("UTF-8")) {
-            return java.nio.charset.StandardCharsets.UTF_8;
+            return UTF_8.INSTANCE;
         } else if (charsetName.equals("US-ASCII")) {
-            return java.nio.charset.StandardCharsets.US_ASCII;
+            return US_ASCII.INSTANCE;
         } else if (charsetName.equals("ISO-8859-1")) {
-            return java.nio.charset.StandardCharsets.ISO_8859_1;
+            return ISO_8859_1.INSTANCE;
         } else {
             csn = canonicalize(toLower(charsetName));
         }
--- a/src/java.base/share/classes/sun/nio/cs/US_ASCII.java	Mon Apr 09 08:34:30 2018 -0700
+++ b/src/java.base/share/classes/sun/nio/cs/US_ASCII.java	Tue Apr 10 13:58:47 2018 -0700
@@ -36,6 +36,8 @@
     extends Charset
     implements HistoricallyNamedCharset
 {
+    public static final US_ASCII INSTANCE = new US_ASCII();
+
     public US_ASCII() {
         super("US-ASCII", StandardCharsets.aliases_US_ASCII());
     }
--- a/src/java.base/share/classes/sun/nio/cs/UTF_8.java	Mon Apr 09 08:34:30 2018 -0700
+++ b/src/java.base/share/classes/sun/nio/cs/UTF_8.java	Tue Apr 10 13:58:47 2018 -0700
@@ -55,6 +55,9 @@
  */
 
 public final class UTF_8 extends Unicode {
+
+    public static final UTF_8 INSTANCE = new UTF_8();
+
     public UTF_8() {
         super("UTF-8", StandardCharsets.aliases_UTF_8());
     }
--- a/src/java.base/share/native/libjava/jni_util.c	Mon Apr 09 08:34:30 2018 -0700
+++ b/src/java.base/share/native/libjava/jni_util.c	Tue Apr 10 13:58:47 2018 -0700
@@ -774,8 +774,10 @@
     return newSizedStringJava(env, str, len);
 }
 
-/* Initialize the fast encoding from the encoding name. */
-void
+/* Initialize the fast encoding from the encoding name.
+ * Export InitializeEncoding so that the VM can initialize it if required.
+ */
+JNIEXPORT void
 InitializeEncoding(JNIEnv *env, const char *encname)
 {
     jclass strClazz = NULL;
--- a/src/java.base/share/native/libjava/jni_util.h	Mon Apr 09 08:34:30 2018 -0700
+++ b/src/java.base/share/native/libjava/jni_util.h	Tue Apr 10 13:58:47 2018 -0700
@@ -388,7 +388,7 @@
 
 int getFastEncoding();
 
-void InitializeEncoding(JNIEnv *env, const char *name);
+JNIEXPORT void InitializeEncoding(JNIEnv *env, const char *name);
 
 void* getProcessHandle();
 
--- a/src/java.base/solaris/native/libjsig/jsig.c	Mon Apr 09 08:34:30 2018 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,278 +0,0 @@
-/*
- * Copyright (c) 2001, 2010, 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.
- *
- */
-
-/* CopyrightVersion 1.2 */
-
-/* This is a special library that should be loaded before libc &
- * libthread to interpose the signal handler installation functions:
- * sigaction(), signal(), sigset().
- * Used for signal-chaining. See RFE 4381843.
- */
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <signal.h>
-#include <dlfcn.h>
-#include <thread.h>
-#include <synch.h>
-#include "jni.h"
-#include "jvm_md.h"
-
-#define bool int
-#define true 1
-#define false 0
-
-static struct sigaction *sact = (struct sigaction *)NULL; /* saved signal handlers */
-static sigset_t jvmsigs;
-
-/* used to synchronize the installation of signal handlers */
-static mutex_t mutex = DEFAULTMUTEX;
-static cond_t cond = DEFAULTCV;
-static thread_t tid = 0;
-
-typedef void (*sa_handler_t)(int);
-typedef void (*sa_sigaction_t)(int, siginfo_t *, void *);
-typedef sa_handler_t (*signal_t)(int, sa_handler_t);
-typedef int (*sigaction_t)(int, const struct sigaction *, struct sigaction *);
-
-static signal_t os_signal = 0; /* os's version of signal()/sigset() */
-static sigaction_t os_sigaction = 0; /* os's version of sigaction() */
-
-static bool jvm_signal_installing = false;
-static bool jvm_signal_installed = false;
-
-
-/* assume called within signal_lock */
-static void allocate_sact() {
-  size_t maxsignum;
-  maxsignum = SIGRTMAX;
-  if (sact == NULL) {
-    sact = (struct sigaction *)malloc((maxsignum+1) * (size_t)sizeof(struct sigaction));
-    memset(sact, 0, (maxsignum+1) * (size_t)sizeof(struct sigaction));
-  }
-
-  if (sact == NULL) {
-    printf("%s\n", "libjsig.so unable to allocate memory");
-    exit(0);
-  }
-
-  sigemptyset(&jvmsigs);
-}
-
-static void signal_lock() {
-  mutex_lock(&mutex);
-  /* When the jvm is installing its set of signal handlers, threads
-   * other than the jvm thread should wait */
-  if (jvm_signal_installing) {
-    if (tid != thr_self()) {
-      cond_wait(&cond, &mutex);
-    }
-  }
-}
-
-static void signal_unlock() {
-  mutex_unlock(&mutex);
-}
-
-static sa_handler_t call_os_signal(int sig, sa_handler_t disp,
-                                   bool is_sigset) {
-  if (os_signal == NULL) {
-    if (!is_sigset) {
-      os_signal = (signal_t)dlsym(RTLD_NEXT, "signal");
-    } else {
-      os_signal = (signal_t)dlsym(RTLD_NEXT, "sigset");
-    }
-    if (os_signal == NULL) {
-      printf("%s\n", dlerror());
-      exit(0);
-    }
-  }
-  return (*os_signal)(sig, disp);
-}
-
-static void save_signal_handler(int sig, sa_handler_t disp, bool is_sigset) {
-  sigset_t set;
-  if (sact == NULL) {
-    allocate_sact();
-  }
-  sact[sig].sa_handler = disp;
-  sigemptyset(&set);
-  sact[sig].sa_mask = set;
-  if (!is_sigset) {
-    sact[sig].sa_flags = SA_NODEFER;
-    if (sig != SIGILL && sig != SIGTRAP && sig != SIGPWR) {
-      sact[sig].sa_flags |= SA_RESETHAND;
-    }
-  } else {
-    sact[sig].sa_flags = 0;
-  }
-}
-
-static sa_handler_t set_signal(int sig, sa_handler_t disp, bool is_sigset) {
-  sa_handler_t oldhandler;
-  bool sigblocked;
-
-  signal_lock();
-  if (sact == NULL) {
-    allocate_sact();
-  }
-
-  if (jvm_signal_installed && sigismember(&jvmsigs, sig)) {
-    /* jvm has installed its signal handler for this signal. */
-    /* Save the handler. Don't really install it. */
-    if (is_sigset) {
-      /* We won't honor the SIG_HOLD request to change the signal mask */
-      sigblocked = sigismember(&(sact[sig].sa_mask), sig);
-    }
-    oldhandler = sact[sig].sa_handler;
-    save_signal_handler(sig, disp, is_sigset);
-
-    if (is_sigset && sigblocked) {
-      oldhandler = SIG_HOLD;
-    }
-
-    signal_unlock();
-    return oldhandler;
-  } else if (jvm_signal_installing) {
-    /* jvm is installing its signal handlers. Install the new
-     * handlers and save the old ones. jvm uses sigaction().
-     * Leave the piece here just in case. */
-    oldhandler = call_os_signal(sig, disp, is_sigset);
-    save_signal_handler(sig, oldhandler, is_sigset);
-
-    /* Record the signals used by jvm */
-    sigaddset(&jvmsigs, sig);
-
-    signal_unlock();
-    return oldhandler;
-  } else {
-    /* jvm has no relation with this signal (yet). Install the
-     * the handler. */
-    oldhandler = call_os_signal(sig, disp, is_sigset);
-
-    signal_unlock();
-    return oldhandler;
-  }
-}
-
-sa_handler_t signal(int sig, sa_handler_t disp) {
-  return set_signal(sig, disp, false);
-}
-
-sa_handler_t sigset(int sig, sa_handler_t disp) {
-  return set_signal(sig, disp, true);
-}
-
-static int call_os_sigaction(int sig, const struct sigaction  *act,
-                             struct sigaction *oact) {
-  if (os_sigaction == NULL) {
-    os_sigaction = (sigaction_t)dlsym(RTLD_NEXT, "sigaction");
-    if (os_sigaction == NULL) {
-      printf("%s\n", dlerror());
-      exit(0);
-    }
-  }
-  return (*os_sigaction)(sig, act, oact);
-}
-
-int sigaction(int sig, const struct sigaction *act, struct sigaction *oact) {
-  int res;
-  struct sigaction oldAct;
-
-  signal_lock();
-
-  if (sact == NULL ) {
-    allocate_sact();
-  }
-  if (jvm_signal_installed && sigismember(&jvmsigs, sig)) {
-    /* jvm has installed its signal handler for this signal. */
-    /* Save the handler. Don't really install it. */
-    if (oact != NULL) {
-      *oact = sact[sig];
-    }
-    if (act != NULL) {
-      sact[sig] = *act;
-    }
-
-    signal_unlock();
-    return 0;
-  } else if (jvm_signal_installing) {
-    /* jvm is installing its signal handlers. Install the new
-     * handlers and save the old ones. */
-    res = call_os_sigaction(sig, act, &oldAct);
-    sact[sig] = oldAct;
-    if (oact != NULL) {
-      *oact = oldAct;
-    }
-
-    /* Record the signals used by jvm */
-    sigaddset(&jvmsigs, sig);
-
-    signal_unlock();
-    return res;
-  } else {
-    /* jvm has no relation with this signal (yet). Install the
-     * the handler. */
-    res = call_os_sigaction(sig, act, oact);
-
-    signal_unlock();
-    return res;
-  }
-}
-
-/* The four functions for the jvm to call into */
-JNIEXPORT void JNICALL
-JVM_begin_signal_setting() {
-  signal_lock();
-  jvm_signal_installing = true;
-  tid = thr_self();
-  signal_unlock();
-}
-
-JNIEXPORT void JNICALL
-JVM_end_signal_setting() {
-  signal_lock();
-  jvm_signal_installed = true;
-  jvm_signal_installing = false;
-  cond_broadcast(&cond);
-  signal_unlock();
-}
-
-JNIEXPORT struct sigaction * JNICALL
-JVM_get_signal_action(int sig) {
-  if (sact == NULL) {
-    allocate_sact();
-  }
-  /* Does race condition make sense here? */
-  if (sigismember(&jvmsigs, sig)) {
-    return &sact[sig];
-  }
-  return NULL;
-}
-
-JNIEXPORT int JNICALL
-JVM_get_libjsig_version() {
-  return JSIG_VERSION_1_4_1;
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/unix/native/libjsig/jsig.c	Tue Apr 10 13:58:47 2018 -0700
@@ -0,0 +1,326 @@
+/*
+ * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2015 SAP SE. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute 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.
+ *
+ */
+
+/* This is a special library that should be loaded before libc &
+ * libthread to interpose the signal handler installation functions:
+ * sigaction(), signal(), sigset().
+ * Used for signal-chaining. See RFE 4381843.
+ */
+
+#include <dlfcn.h>
+#include <errno.h>
+#include <pthread.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if (__STDC_VERSION__ >= 199901L)
+  #include <stdbool.h>
+#else
+  #define bool int
+  #define true 1
+  #define false 0
+#endif
+
+#ifdef SOLARIS
+#define MAX_SIGNALS (SIGRTMAX+1)
+
+/* On solaris, MAX_SIGNALS is a macro, not a constant, so we must allocate sact dynamically. */
+static struct sigaction *sact = (struct sigaction *)NULL; /* saved signal handlers */
+#else
+#define MAX_SIGNALS NSIG
+
+static struct sigaction sact[MAX_SIGNALS]; /* saved signal handlers */
+#endif
+
+static sigset_t jvmsigs; /* Signals used by jvm. */
+
+#ifdef MACOSX
+static __thread bool reentry = false; /* prevent reentry deadlock (per-thread) */
+#endif
+
+/* Used to synchronize the installation of signal handlers. */
+static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
+static pthread_t tid = 0;
+
+typedef void (*sa_handler_t)(int);
+typedef void (*sa_sigaction_t)(int, siginfo_t *, void *);
+typedef sa_handler_t (*signal_function_t)(int, sa_handler_t);
+typedef int (*sigaction_t)(int, const struct sigaction *, struct sigaction *);
+
+static signal_function_t os_signal = 0; /* os's version of signal()/sigset() */
+static sigaction_t os_sigaction = 0; /* os's version of sigaction() */
+
+static bool jvm_signal_installing = false;
+static bool jvm_signal_installed = false;
+
+
+/* assume called within signal_lock */
+static void allocate_sact() {
+#ifdef SOLARIS
+  if (sact == NULL) {
+    sact = (struct sigaction *)malloc((MAX_SIGNALS) * (size_t)sizeof(struct sigaction));
+    if (sact == NULL) {
+      printf("%s\n", "libjsig.so unable to allocate memory");
+      exit(0);
+    }
+    memset(sact, 0, (MAX_SIGNALS) * (size_t)sizeof(struct sigaction));
+  }
+#endif
+}
+
+static void signal_lock() {
+  pthread_mutex_lock(&mutex);
+  /* When the jvm is installing its set of signal handlers, threads
+   * other than the jvm thread should wait. */
+  if (jvm_signal_installing) {
+    if (tid != pthread_self()) {
+      pthread_cond_wait(&cond, &mutex);
+    }
+  }
+}
+
+static void signal_unlock() {
+  pthread_mutex_unlock(&mutex);
+}
+
+static sa_handler_t call_os_signal(int sig, sa_handler_t disp,
+                                   bool is_sigset) {
+  sa_handler_t res;
+
+  if (os_signal == NULL) {
+    if (!is_sigset) {
+      os_signal = (signal_function_t)dlsym(RTLD_NEXT, "signal");
+    } else {
+      os_signal = (signal_function_t)dlsym(RTLD_NEXT, "sigset");
+    }
+    if (os_signal == NULL) {
+      printf("%s\n", dlerror());
+      exit(0);
+    }
+  }
+
+#ifdef MACOSX
+  /* On macosx, the OS implementation of signal calls sigaction.
+   * Make sure we do not deadlock with ourself. (See JDK-8072147). */
+  reentry = true;
+#endif
+
+  res = (*os_signal)(sig, disp);
+
+#ifdef MACOSX
+  reentry = false;
+#endif
+
+  return res;
+}
+
+static void save_signal_handler(int sig, sa_handler_t disp, bool is_sigset) {
+  sigset_t set;
+
+  sact[sig].sa_handler = disp;
+  sigemptyset(&set);
+  sact[sig].sa_mask = set;
+  if (!is_sigset) {
+#ifdef SOLARIS
+    sact[sig].sa_flags = SA_NODEFER;
+    if (sig != SIGILL && sig != SIGTRAP && sig != SIGPWR) {
+      sact[sig].sa_flags |= SA_RESETHAND;
+    }
+#else
+    sact[sig].sa_flags = 0;
+#endif
+  } else {
+    sact[sig].sa_flags = 0;
+  }
+}
+
+static sa_handler_t set_signal(int sig, sa_handler_t disp, bool is_sigset) {
+  sa_handler_t oldhandler;
+  bool sigused;
+  bool sigblocked;
+
+  signal_lock();
+  allocate_sact();
+
+  sigused = sigismember(&jvmsigs, sig);
+  if (jvm_signal_installed && sigused) {
+    /* jvm has installed its signal handler for this signal. */
+    /* Save the handler. Don't really install it. */
+    if (is_sigset) {
+      sigblocked = sigismember(&(sact[sig].sa_mask), sig);
+    }
+    oldhandler = sact[sig].sa_handler;
+    save_signal_handler(sig, disp, is_sigset);
+
+#ifdef SOLARIS
+    if (is_sigset && sigblocked) {
+      /* We won't honor the SIG_HOLD request to change the signal mask */
+      oldhandler = SIG_HOLD;
+    }
+#endif
+
+    signal_unlock();
+    return oldhandler;
+  } else if (jvm_signal_installing) {
+    /* jvm is installing its signal handlers. Install the new
+     * handlers and save the old ones. jvm uses sigaction().
+     * Leave the piece here just in case. */
+    oldhandler = call_os_signal(sig, disp, is_sigset);
+    save_signal_handler(sig, oldhandler, is_sigset);
+
+    /* Record the signals used by jvm */
+    sigaddset(&jvmsigs, sig);
+
+    signal_unlock();
+    return oldhandler;
+  } else {
+    /* jvm has no relation with this signal (yet). Install the
+     * the handler. */
+    oldhandler = call_os_signal(sig, disp, is_sigset);
+
+    signal_unlock();
+    return oldhandler;
+  }
+}
+
+sa_handler_t signal(int sig, sa_handler_t disp) {
+  if (sig < 0 || sig >= MAX_SIGNALS) {
+    errno = EINVAL;
+    return SIG_ERR;
+  }
+
+  return set_signal(sig, disp, false);
+}
+
+sa_handler_t sigset(int sig, sa_handler_t disp) {
+#ifdef _ALLBSD_SOURCE
+  printf("sigset() is not supported by BSD");
+  exit(0);
+#else
+  if (sig < 0 || sig >= MAX_SIGNALS) {
+    errno = EINVAL;
+    return (sa_handler_t)-1;
+  }
+
+  return set_signal(sig, disp, true);
+#endif
+}
+
+static int call_os_sigaction(int sig, const struct sigaction  *act,
+                             struct sigaction *oact) {
+  if (os_sigaction == NULL) {
+    os_sigaction = (sigaction_t)dlsym(RTLD_NEXT, "sigaction");
+    if (os_sigaction == NULL) {
+      printf("%s\n", dlerror());
+      exit(0);
+    }
+  }
+  return (*os_sigaction)(sig, act, oact);
+}
+
+int sigaction(int sig, const struct sigaction *act, struct sigaction *oact) {
+  int res;
+  bool sigused;
+  struct sigaction oldAct;
+
+  if (sig < 0 || sig >= MAX_SIGNALS) {
+    errno = EINVAL;
+    return -1;
+  }
+
+#ifdef MACOSX
+  if (reentry) {
+    return call_os_sigaction(sig, act, oact);
+  }
+#endif
+
+  signal_lock();
+
+  allocate_sact();
+  sigused = sigismember(&jvmsigs, sig);
+  if (jvm_signal_installed && sigused) {
+    /* jvm has installed its signal handler for this signal. */
+    /* Save the handler. Don't really install it. */
+    if (oact != NULL) {
+      *oact = sact[sig];
+    }
+    if (act != NULL) {
+      sact[sig] = *act;
+    }
+
+    signal_unlock();
+    return 0;
+  } else if (jvm_signal_installing) {
+    /* jvm is installing its signal handlers. Install the new
+     * handlers and save the old ones. */
+    res = call_os_sigaction(sig, act, &oldAct);
+    sact[sig] = oldAct;
+    if (oact != NULL) {
+      *oact = oldAct;
+    }
+
+    /* Record the signals used by jvm. */
+    sigaddset(&jvmsigs, sig);
+
+    signal_unlock();
+    return res;
+  } else {
+    /* jvm has no relation with this signal (yet). Install the
+     * the handler. */
+    res = call_os_sigaction(sig, act, oact);
+
+    signal_unlock();
+    return res;
+  }
+}
+
+/* The three functions for the jvm to call into. */
+void JVM_begin_signal_setting() {
+  signal_lock();
+  sigemptyset(&jvmsigs);
+  jvm_signal_installing = true;
+  tid = pthread_self();
+  signal_unlock();
+}
+
+void JVM_end_signal_setting() {
+  signal_lock();
+  jvm_signal_installed = true;
+  jvm_signal_installing = false;
+  pthread_cond_broadcast(&cond);
+  signal_unlock();
+}
+
+struct sigaction *JVM_get_signal_action(int sig) {
+  allocate_sact();
+  /* Does race condition make sense here? */
+  if (sigismember(&jvmsigs, sig)) {
+    return &sact[sig];
+  }
+  return NULL;
+}
--- a/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthParser.java	Mon Apr 09 08:34:30 2018 -0700
+++ b/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthParser.java	Tue Apr 10 13:58:47 2018 -0700
@@ -746,12 +746,7 @@
                 value = lookup(aValue, Object.class);
                 break;
             case 1: // boolean
-                if (aValue.toUpperCase().equals("TRUE")) {
-                    value = Boolean.TRUE;
-                }
-                else {
-                    value = Boolean.FALSE;
-                }
+                value = Boolean.parseBoolean(aValue);
                 break;
             case 2: // dimension
                 StringTokenizer tok = new StringTokenizer(aValue);
@@ -939,11 +934,11 @@
                   ": destinationInsets must be top left bottom right");
             }
             else if (key.equals(ATTRIBUTE_PAINT_CENTER)) {
-                paintCenter = value.toLowerCase().equals("true");
+                paintCenter = Boolean.parseBoolean(value);
                 paintCenterSpecified = true;
             }
             else if (key.equals(ATTRIBUTE_STRETCH)) {
-                stretch = value.toLowerCase().equals("true");
+                stretch = Boolean.parseBoolean(value);
                 stretchSpecified = true;
             }
             else if (key.equals(ATTRIBUTE_DIRECTION)) {
@@ -989,7 +984,7 @@
                 }
             }
             else if (key.equals(ATTRIBUTE_CENTER)) {
-                center = value.toLowerCase().equals("true");
+                center = Boolean.parseBoolean(value);
             }
         }
         if (painter == null) {
--- a/src/java.instrument/share/native/libinstrument/Reentrancy.c	Mon Apr 09 08:34:30 2018 -0700
+++ b/src/java.instrument/share/native/libinstrument/Reentrancy.c	Tue Apr 10 13:58:47 2018 -0700
@@ -90,7 +90,7 @@
                 jthread         thread,
                 const void *    expected) {
     jvmtiError  error;
-    void *      test = (void *) 0x99999999UL;
+    void *      test = (void *) 0x99999999ULL;
 
     /* now check if we do a fetch we get what we wrote */
     error = (*jvmtienv)->GetThreadLocalStorage(
--- a/src/java.management/share/classes/sun/management/MemoryPoolImpl.java	Mon Apr 09 08:34:30 2018 -0700
+++ b/src/java.management/share/classes/sun/management/MemoryPoolImpl.java	Tue Apr 10 13:58:47 2018 -0700
@@ -55,10 +55,10 @@
     private long  usageThreshold;
     private long  collectionThreshold;
 
-    private boolean usageSensorRegistered;
-    private boolean gcSensorRegistered;
-    private Sensor  usageSensor;
-    private Sensor  gcSensor;
+    private boolean usageSensorRegistered; // VM-initialized to false
+    private boolean gcSensorRegistered;    // VM-initialized to false
+    private final Sensor usageSensor;
+    private final Sensor gcSensor;
 
     MemoryPoolImpl(String name, boolean isHeap, long usageThreshold,
                    long gcThreshold) {
@@ -72,8 +72,6 @@
         this.collectionThresholdSupported = (gcThreshold >= 0);
         this.usageSensor = new PoolSensor(this, name + " usage sensor");
         this.gcSensor = new CollectionSensor(this, name + " collection sensor");
-        this.usageSensorRegistered = false;
-        this.gcSensorRegistered = false;
     }
 
     public String getName() {
@@ -290,7 +288,7 @@
      * unless the memory usage has returned below the threshold.
      */
     class PoolSensor extends Sensor {
-        MemoryPoolImpl pool;
+        final MemoryPoolImpl pool;
 
         PoolSensor(MemoryPoolImpl pool, String name) {
             super(name);
@@ -316,10 +314,10 @@
      * when the memory usage of a memory pool after GC is crossing
      * the collection threshold.
      * The VM will trigger this sensor in subsequent crossing
-     * regardless if the memory usage has changed siince the previous GC.
+     * regardless if the memory usage has changed since the previous GC.
      */
     class CollectionSensor extends Sensor {
-        MemoryPoolImpl pool;
+        final MemoryPoolImpl pool;
         CollectionSensor(MemoryPoolImpl pool, String name) {
             super(name);
             this.pool = pool;
--- a/src/java.management/share/classes/sun/management/Sensor.java	Mon Apr 09 08:34:30 2018 -0700
+++ b/src/java.management/share/classes/sun/management/Sensor.java	Tue Apr 10 13:58:47 2018 -0700
@@ -48,10 +48,10 @@
  */
 
 public abstract class Sensor {
-    private Object  lock;
-    private String  name;
-    private long    count;
-    private boolean on;
+    private final Object lock = new Object();
+    private final String name;
+    private long count;                 // VM-initialized to 0
+    private boolean on;                 // VM-initialized to false
 
     /**
      * Constructs a {@code Sensor} object.
@@ -60,9 +60,6 @@
      */
     public Sensor(String name) {
         this.name = name;
-        this.count = 0;
-        this.on = false;
-        this.lock = new Object();
     }
 
     /**
--- a/src/java.security.jgss/share/classes/sun/security/krb5/internal/util/KerberosString.java	Mon Apr 09 08:34:30 2018 -0700
+++ b/src/java.security.jgss/share/classes/sun/security/krb5/internal/util/KerberosString.java	Tue Apr 10 13:58:47 2018 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -26,8 +26,7 @@
 package sun.security.krb5.internal.util;
 
 import java.io.IOException;
-import java.security.AccessController;
-import sun.security.action.GetBooleanAction;
+import sun.security.action.GetPropertyAction;
 import sun.security.util.DerValue;
 
 /**
@@ -45,15 +44,21 @@
 public final class KerberosString {
     /**
      * RFC 4120 defines KerberosString as GeneralString (IA5String), which
-     * only includes ASCII characters. However, other implementations have been
-     * known to use GeneralString to contain UTF-8 encoding. To interop
-     * with these implementations, the following system property is defined.
-     * When set as true, KerberosString is encoded as UTF-8. Note that this
-     * only affects the byte encoding, the tag of the ASN.1 type is still
-     * GeneralString.
+     * only includes ASCII characters. However, most implementations have been
+     * known to use GeneralString to contain UTF-8 encoding. The following
+     * system property is defined. When set as true, KerberosString is encoded
+     * as UTF-8. Otherwise, it's ASCII. The default is true.
+     *
+     * Note that this only affects the byte encoding, the tag of the ASN.1
+     * type is still GeneralString.
      */
-    public static final boolean MSNAME = AccessController.doPrivileged(
-            new GetBooleanAction("sun.security.krb5.msinterop.kstring"));
+    public static final boolean MSNAME;
+
+    static {
+        String prop = GetPropertyAction.privilegedGetProperty(
+                "sun.security.krb5.msinterop.kstring", "true");
+        MSNAME = Boolean.parseBoolean(prop);
+    }
 
     private final String s;
 
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractIndexWriter.java	Mon Apr 09 08:34:30 2018 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractIndexWriter.java	Tue Apr 10 13:58:47 2018 -0700
@@ -42,6 +42,8 @@
 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag;
 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
+import jdk.javadoc.internal.doclets.formats.html.markup.Navigation;
+import jdk.javadoc.internal.doclets.formats.html.markup.Navigation.PageMode;
 import jdk.javadoc.internal.doclets.formats.html.markup.StringContent;
 import jdk.javadoc.internal.doclets.toolkit.Content;
 import jdk.javadoc.internal.doclets.toolkit.util.DocFile;
@@ -72,6 +74,8 @@
      */
     protected IndexBuilder indexbuilder;
 
+    protected Navigation navBar;
+
     /**
      * This constructor will be used by {@link SplitIndexWriter}. Initializes
      * path to this file and relative path from this file.
@@ -85,17 +89,7 @@
                                   IndexBuilder indexbuilder) {
         super(configuration, path);
         this.indexbuilder = indexbuilder;
-    }
-
-    /**
-     * Get the index label for navigation bar.
-     *
-     * @return a content tree for the tree label
-     */
-    @Override
-    protected Content getNavLinkIndex() {
-        Content li = HtmlTree.LI(HtmlStyle.navBarCell1Rev, contents.indexLabel);
-        return li;
+        this.navBar = new Navigation(null, configuration, fixedNavDiv, PageMode.INDEX, path);
     }
 
     /**
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractMemberWriter.java	Mon Apr 09 08:34:30 2018 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractMemberWriter.java	Tue Apr 10 13:58:47 2018 -0700
@@ -45,6 +45,7 @@
 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag;
 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
 import jdk.javadoc.internal.doclets.formats.html.markup.Links;
+import jdk.javadoc.internal.doclets.formats.html.markup.Navigation;
 import jdk.javadoc.internal.doclets.formats.html.markup.StringContent;
 import jdk.javadoc.internal.doclets.toolkit.Content;
 import jdk.javadoc.internal.doclets.toolkit.MemberSummaryWriter;
@@ -215,23 +216,6 @@
     protected abstract Content getDeprecatedLink(Element member);
 
     /**
-     * Get the navigation summary link.
-     *
-     * @param typeElement the TypeElement to be documented
-     * @param link true if its a link else the label to be printed
-     * @return a content tree for the navigation summary link.
-     */
-    protected abstract Content getNavSummaryLink(TypeElement typeElement, boolean link);
-
-    /**
-     * Add the navigation detail link.
-     *
-     * @param link true if its a link else the label to be printed
-     * @param liNav the content tree to which the navigation detail link will be added
-     */
-    protected abstract void addNavDetailLink(boolean link, Content liNav);
-
-    /**
      * Add the member name to the content tree.
      *
      * @param name the member name to be added to the content tree.
@@ -474,41 +458,6 @@
         }
     }
 
-    /**
-     * Add the navigation detail link.
-     *
-     * @param members the members to be linked
-     * @param liNav the content tree to which the navigation detail link will be added
-     */
-    protected void addNavDetailLink(SortedSet<Element> members, Content liNav) {
-        addNavDetailLink(!members.isEmpty(), liNav);
-    }
-
-    /**
-     * Add the navigation summary link.
-     *
-     * @param members members to be linked
-     * @param visibleMemberMap the visible inherited members map
-     * @param liNav the content tree to which the navigation summary link will be added
-     */
-    protected void addNavSummaryLink(SortedSet<? extends Element> members,
-            VisibleMemberMap visibleMemberMap, Content liNav) {
-        if (!members.isEmpty()) {
-            liNav.addContent(getNavSummaryLink(null, true));
-            return;
-        }
-
-        TypeElement superClass = utils.getSuperClass(typeElement);
-        while (superClass != null) {
-            if (visibleMemberMap.hasMembers(superClass)) {
-                liNav.addContent(getNavSummaryLink(superClass, true));
-                return;
-            }
-            superClass = utils.getSuperClass(superClass);
-        }
-        liNav.addContent(getNavSummaryLink(null, false));
-    }
-
     protected void serialWarning(Element e, String key, String a1, String a2) {
         if (configuration.serialwarn) {
             configuration.messages.warning(e, key, a1, a2);
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractModuleIndexWriter.java	Mon Apr 09 08:34:30 2018 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractModuleIndexWriter.java	Tue Apr 10 13:58:47 2018 -0700
@@ -37,6 +37,8 @@
 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag;
 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
+import jdk.javadoc.internal.doclets.formats.html.markup.Navigation;
+import jdk.javadoc.internal.doclets.formats.html.markup.Navigation.PageMode;
 import jdk.javadoc.internal.doclets.formats.html.markup.RawHtml;
 import jdk.javadoc.internal.doclets.toolkit.Content;
 import jdk.javadoc.internal.doclets.toolkit.util.DocFileIOException;
@@ -61,6 +63,8 @@
      */
     protected SortedMap<ModuleElement, Set<PackageElement>> modules;
 
+    protected Navigation navBar;
+
     /**
      * Constructor. Also initializes the modules variable.
      *
@@ -71,6 +75,7 @@
                                       DocPath filename) {
         super(configuration, filename);
         modules = configuration.modulePackages;
+        this.navBar = new Navigation(null, configuration, fixedNavDiv, PageMode.OVERVIEW, path);
     }
 
     /**
@@ -252,18 +257,6 @@
     }
 
     /**
-     * Returns highlighted "Overview", in the navigation bar as this is the
-     * overview page.
-     *
-     * @return a Content object to be added to the documentation tree
-     */
-    @Override
-    protected Content getNavLinkContents() {
-        Content li = HtmlTree.LI(HtmlStyle.navBarCell1Rev, contents.overviewLabel);
-        return li;
-    }
-
-    /**
      * Do nothing. This will be overridden in ModuleIndexFrameWriter.
      *
      * @param div the document tree to which the all classes link will be added
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractPackageIndexWriter.java	Mon Apr 09 08:34:30 2018 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractPackageIndexWriter.java	Tue Apr 10 13:58:47 2018 -0700
@@ -33,6 +33,8 @@
 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag;
 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
+import jdk.javadoc.internal.doclets.formats.html.markup.Navigation;
+import jdk.javadoc.internal.doclets.formats.html.markup.Navigation.PageMode;
 import jdk.javadoc.internal.doclets.formats.html.markup.RawHtml;
 import jdk.javadoc.internal.doclets.toolkit.Content;
 import jdk.javadoc.internal.doclets.toolkit.util.DocFileIOException;
@@ -58,6 +60,8 @@
      */
     protected SortedSet<PackageElement> packages;
 
+    protected Navigation navBar;
+
     /**
      * Constructor. Also initializes the packages variable.
      *
@@ -68,6 +72,7 @@
                                       DocPath filename) {
         super(configuration, filename);
         packages = configuration.packages;
+        this.navBar = new Navigation(null, configuration, fixedNavDiv, PageMode.OVERVIEW, path);
     }
 
     /**
@@ -174,18 +179,6 @@
     }
 
     /**
-     * Returns highlighted "Overview", in the navigation bar as this is the
-     * overview page.
-     *
-     * @return a Content object to be added to the documentation tree
-     */
-    @Override
-    protected Content getNavLinkContents() {
-        Content li = HtmlTree.LI(HtmlStyle.navBarCell1Rev, contents.overviewLabel);
-        return li;
-    }
-
-    /**
      * Do nothing. This will be overridden.
      *
      * @param div the document tree to which the all classes link will be added
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractTreeWriter.java	Mon Apr 09 08:34:30 2018 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractTreeWriter.java	Tue Apr 10 13:58:47 2018 -0700
@@ -184,14 +184,4 @@
     protected void addPartialInfo(TypeElement typeElement, Content contentTree) {
         addPreQualifiedStrongClassLink(LinkInfoImpl.Kind.TREE, typeElement, contentTree);
     }
-
-    /**
-     * Get the tree label for the navigation bar.
-     *
-     * @return a content tree for the tree label
-     */
-    protected Content getNavLinkTree() {
-        Content li = HtmlTree.LI(HtmlStyle.navBarCell1Rev, contents.treeLabel);
-        return li;
-    }
 }
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AnnotationTypeFieldWriterImpl.java	Mon Apr 09 08:34:30 2018 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AnnotationTypeFieldWriterImpl.java	Tue Apr 10 13:58:47 2018 -0700
@@ -37,7 +37,7 @@
 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag;
 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
-import jdk.javadoc.internal.doclets.formats.html.markup.Links;
+import jdk.javadoc.internal.doclets.formats.html.markup.Navigation;
 import jdk.javadoc.internal.doclets.formats.html.markup.StringContent;
 import jdk.javadoc.internal.doclets.toolkit.AnnotationTypeFieldWriter;
 import jdk.javadoc.internal.doclets.toolkit.Content;
@@ -285,31 +285,6 @@
                 member, utils.getFullyQualifiedName(member));
     }
 
-    /**
-     * {@inheritDoc}
-     */
-    protected Content getNavSummaryLink(TypeElement typeElement, boolean link) {
-        if (link) {
-            return links.createLink(
-                    SectionName.ANNOTATION_TYPE_FIELD_SUMMARY,
-                    contents.navField);
-        } else {
-            return contents.navField;
-        }
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    protected void addNavDetailLink(boolean link, Content liNav) {
-        if (link) {
-            liNav.addContent(links.createLink(
-                    SectionName.ANNOTATION_TYPE_FIELD_DETAIL,
-                    contents.navField));
-        } else {
-            liNav.addContent(contents.navField);
-        }
-    }
     private TypeMirror getType(Element member) {
         if (utils.isConstructor(member))
             return null;
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AnnotationTypeOptionalMemberWriterImpl.java	Mon Apr 09 08:34:30 2018 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AnnotationTypeOptionalMemberWriterImpl.java	Tue Apr 10 13:58:47 2018 -0700
@@ -35,7 +35,7 @@
 
 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlConstants;
 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
-import jdk.javadoc.internal.doclets.formats.html.markup.Links;
+import jdk.javadoc.internal.doclets.formats.html.markup.Navigation;
 import jdk.javadoc.internal.doclets.formats.html.markup.StringContent;
 import jdk.javadoc.internal.doclets.toolkit.AnnotationTypeOptionalMemberWriter;
 import jdk.javadoc.internal.doclets.toolkit.Content;
@@ -152,18 +152,4 @@
         memberTree.addContent(links.createAnchor(
                 SectionName.ANNOTATION_TYPE_OPTIONAL_ELEMENT_SUMMARY));
     }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    protected Content getNavSummaryLink(TypeElement typeElement, boolean link) {
-        if (link) {
-            return links.createLink(
-                    SectionName.ANNOTATION_TYPE_OPTIONAL_ELEMENT_SUMMARY,
-                    contents.navAnnotationTypeOptionalMember);
-        } else {
-            return contents.navAnnotationTypeOptionalMember;
-        }
-    }
 }
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AnnotationTypeRequiredMemberWriterImpl.java	Mon Apr 09 08:34:30 2018 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AnnotationTypeRequiredMemberWriterImpl.java	Tue Apr 10 13:58:47 2018 -0700
@@ -37,7 +37,7 @@
 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag;
 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
-import jdk.javadoc.internal.doclets.formats.html.markup.Links;
+import jdk.javadoc.internal.doclets.formats.html.markup.Navigation;
 import jdk.javadoc.internal.doclets.formats.html.markup.StringContent;
 import jdk.javadoc.internal.doclets.toolkit.AnnotationTypeRequiredMemberWriter;
 import jdk.javadoc.internal.doclets.toolkit.Content;
@@ -300,32 +300,6 @@
         return writer.getDocLink(LinkInfoImpl.Kind.MEMBER, member, name);
     }
 
-    /**
-     * {@inheritDoc}
-     */
-    protected Content getNavSummaryLink(TypeElement typeElement, boolean link) {
-        if (link) {
-            return links.createLink(
-                    SectionName.ANNOTATION_TYPE_REQUIRED_ELEMENT_SUMMARY,
-                    contents.navAnnotationTypeRequiredMember);
-        } else {
-            return contents.navAnnotationTypeRequiredMember;
-        }
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    protected void addNavDetailLink(boolean link, Content liNav) {
-        if (link) {
-            liNav.addContent(links.createLink(
-                    SectionName.ANNOTATION_TYPE_ELEMENT_DETAIL,
-                    contents.navAnnotationTypeMember));
-        } else {
-            liNav.addContent(contents.navAnnotationTypeMember);
-        }
-    }
-
     private TypeMirror getType(Element member) {
         return utils.isExecutableElement(member)
                 ? utils.getReturnType((ExecutableElement) member)
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AnnotationTypeWriterImpl.java	Mon Apr 09 08:34:30 2018 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AnnotationTypeWriterImpl.java	Tue Apr 10 13:58:47 2018 -0700
@@ -30,21 +30,20 @@
 import javax.lang.model.element.ModuleElement;
 import javax.lang.model.element.PackageElement;
 import javax.lang.model.element.TypeElement;
-import javax.lang.model.type.TypeMirror;
 
 import com.sun.source.doctree.DocTree;
 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlConstants;
 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag;
 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
+import jdk.javadoc.internal.doclets.formats.html.markup.Navigation;
+import jdk.javadoc.internal.doclets.formats.html.markup.Navigation.PageMode;
 import jdk.javadoc.internal.doclets.formats.html.markup.StringContent;
 import jdk.javadoc.internal.doclets.toolkit.AnnotationTypeWriter;
 import jdk.javadoc.internal.doclets.toolkit.Content;
 import jdk.javadoc.internal.doclets.toolkit.builders.MemberSummaryBuilder;
 import jdk.javadoc.internal.doclets.toolkit.util.CommentHelper;
 import jdk.javadoc.internal.doclets.toolkit.util.DocFileIOException;
-import jdk.javadoc.internal.doclets.toolkit.util.DocPath;
-import jdk.javadoc.internal.doclets.toolkit.util.DocPaths;
 import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberMap;
 
 /**
@@ -69,6 +68,8 @@
 
     protected TypeElement annotationType;
 
+    private final Navigation navBar;
+
     /**
      * @param configuration the configuration
      * @param annotationType the annotation type being documented.
@@ -78,55 +79,7 @@
         super(configuration, configuration.docPaths.forClass(annotationType));
         this.annotationType = annotationType;
         configuration.currentTypeElement = annotationType;
-    }
-
-    /**
-     * Get the module link.
-     *
-     * @return a content tree for the module link
-     */
-    @Override
-    protected Content getNavLinkModule() {
-        Content linkContent = getModuleLink(utils.elementUtils.getModuleOf(annotationType),
-                contents.moduleLabel);
-        Content li = HtmlTree.LI(linkContent);
-        return li;
-    }
-
-    /**
-     * Get this package link.
-     *
-     * @return a content tree for the package link
-     */
-    @Override
-    protected Content getNavLinkPackage() {
-        Content linkContent = links.createLink(DocPaths.PACKAGE_SUMMARY,
-                contents.packageLabel);
-        Content li = HtmlTree.LI(linkContent);
-        return li;
-    }
-
-    /**
-     * Get the class link.
-     *
-     * @return a content tree for the class link
-     */
-    @Override
-    protected Content getNavLinkClass() {
-        Content li = HtmlTree.LI(HtmlStyle.navBarCell1Rev, contents.classLabel);
-        return li;
-    }
-
-    /**
-     * Get the class use link.
-     *
-     * @return a content tree for the class use link
-     */
-    @Override
-    protected Content getNavLinkClassUse() {
-        Content linkContent = links.createLink(DocPaths.CLASS_USE.resolve(filename), contents.useLabel);
-        Content li = HtmlTree.LI(linkContent);
-        return li;
+        this.navBar = new Navigation(annotationType, configuration, fixedNavDiv, PageMode.CLASS, path);
     }
 
     /**
@@ -139,7 +92,12 @@
                 ? HtmlTree.HEADER()
                 : bodyTree;
         addTop(htmlTree);
-        addNavLinks(true, htmlTree);
+        Content linkContent = getModuleLink(utils.elementUtils.getModuleOf(annotationType),
+                contents.moduleLabel);
+        navBar.setNavLinkModule(linkContent);
+        navBar.setMemberSummaryBuilder(configuration.getBuilderFactory().getMemberSummaryBuilder(this));
+        navBar.setUserHeader(getUserHeaderFooter(true));
+        htmlTree.addContent(navBar.getContent(true));
         if (configuration.allowTag(HtmlTag.HEADER)) {
             bodyTree.addContent(htmlTree);
         }
@@ -195,7 +153,8 @@
         Content htmlTree = (configuration.allowTag(HtmlTag.FOOTER))
                 ? HtmlTree.FOOTER()
                 : contentTree;
-        addNavLinks(false, htmlTree);
+        navBar.setUserFooter(getUserHeaderFooter(false));
+        htmlTree.addContent(navBar.getContent(false));
         addBottom(htmlTree);
         if (configuration.allowTag(HtmlTag.FOOTER)) {
             contentTree.addContent(htmlTree);
@@ -299,123 +258,6 @@
      * {@inheritDoc}
      */
     @Override
-    protected Content getNavLinkTree() {
-        Content treeLinkContent = links.createLink(DocPaths.PACKAGE_TREE,
-                contents.treeLabel, "", "");
-        Content li = HtmlTree.LI(treeLinkContent);
-        return li;
-    }
-
-    /**
-     * Add summary details to the navigation bar.
-     *
-     * @param subDiv the content tree to which the summary detail links will be added
-     */
-    @Override
-    protected void addSummaryDetailLinks(Content subDiv) {
-        Content div = HtmlTree.DIV(getNavSummaryLinks());
-        div.addContent(getNavDetailLinks());
-        subDiv.addContent(div);
-    }
-
-    /**
-     * Get summary links for navigation bar.
-     *
-     * @return the content tree for the navigation summary links
-     */
-    protected Content getNavSummaryLinks() {
-        Content li = HtmlTree.LI(contents.summaryLabel);
-        li.addContent(Contents.SPACE);
-        Content ulNav = HtmlTree.UL(HtmlStyle.subNavList, li);
-        MemberSummaryBuilder memberSummaryBuilder =
-                configuration.getBuilderFactory().getMemberSummaryBuilder(this);
-        Content liNavField = new HtmlTree(HtmlTag.LI);
-        addNavSummaryLink(memberSummaryBuilder,
-                "doclet.navField",
-                VisibleMemberMap.Kind.ANNOTATION_TYPE_FIELDS, liNavField);
-        addNavGap(liNavField);
-        ulNav.addContent(liNavField);
-        Content liNavReq = new HtmlTree(HtmlTag.LI);
-        addNavSummaryLink(memberSummaryBuilder,
-                "doclet.navAnnotationTypeRequiredMember",
-                VisibleMemberMap.Kind.ANNOTATION_TYPE_MEMBER_REQUIRED, liNavReq);
-        addNavGap(liNavReq);
-        ulNav.addContent(liNavReq);
-        Content liNavOpt = new HtmlTree(HtmlTag.LI);
-        addNavSummaryLink(memberSummaryBuilder,
-                "doclet.navAnnotationTypeOptionalMember",
-                VisibleMemberMap.Kind.ANNOTATION_TYPE_MEMBER_OPTIONAL, liNavOpt);
-        ulNav.addContent(liNavOpt);
-        return ulNav;
-    }
-
-    /**
-     * Add the navigation summary link.
-     *
-     * @param builder builder for the member to be documented
-     * @param label the label for the navigation
-     * @param type type to be documented
-     * @param liNav the content tree to which the navigation summary link will be added
-     */
-    protected void addNavSummaryLink(MemberSummaryBuilder builder,
-            String label, VisibleMemberMap.Kind type, Content liNav) {
-        AbstractMemberWriter writer = ((AbstractMemberWriter) builder.
-                getMemberSummaryWriter(type));
-        if (writer == null) {
-            liNav.addContent(contents.getContent(label));
-        } else {
-            liNav.addContent(writer.getNavSummaryLink(null,
-                    ! builder.getVisibleMemberMap(type).noVisibleMembers()));
-        }
-    }
-
-    /**
-     * Get detail links for the navigation bar.
-     *
-     * @return the content tree for the detail links
-     */
-    protected Content getNavDetailLinks() {
-        Content li = HtmlTree.LI(contents.detailLabel);
-        li.addContent(Contents.SPACE);
-        Content ulNav = HtmlTree.UL(HtmlStyle.subNavList, li);
-        MemberSummaryBuilder memberSummaryBuilder =
-                configuration.getBuilderFactory().getMemberSummaryBuilder(this);
-        AbstractMemberWriter writerField =
-                ((AbstractMemberWriter) memberSummaryBuilder.
-                getMemberSummaryWriter(VisibleMemberMap.Kind.ANNOTATION_TYPE_FIELDS));
-        AbstractMemberWriter writerOptional =
-                ((AbstractMemberWriter) memberSummaryBuilder.
-                getMemberSummaryWriter(VisibleMemberMap.Kind.ANNOTATION_TYPE_MEMBER_OPTIONAL));
-        AbstractMemberWriter writerRequired =
-                ((AbstractMemberWriter) memberSummaryBuilder.
-                getMemberSummaryWriter(VisibleMemberMap.Kind.ANNOTATION_TYPE_MEMBER_REQUIRED));
-        Content liNavField = new HtmlTree(HtmlTag.LI);
-        if (writerField != null) {
-            writerField.addNavDetailLink(!utils.getAnnotationFields(annotationType).isEmpty(), liNavField);
-        } else {
-            liNavField.addContent(contents.navField);
-        }
-        addNavGap(liNavField);
-        ulNav.addContent(liNavField);
-        if (writerOptional != null){
-            Content liNavOpt = new HtmlTree(HtmlTag.LI);
-            writerOptional.addNavDetailLink(!annotationType.getAnnotationMirrors().isEmpty(), liNavOpt);
-            ulNav.addContent(liNavOpt);
-        } else if (writerRequired != null){
-            Content liNavReq = new HtmlTree(HtmlTag.LI);
-            writerRequired.addNavDetailLink(!annotationType.getAnnotationMirrors().isEmpty(), liNavReq);
-            ulNav.addContent(liNavReq);
-        } else {
-            Content liNav = HtmlTree.LI(contents.navAnnotationTypeMember);
-            ulNav.addContent(liNav);
-        }
-        return ulNav;
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
     public TypeElement getAnnotationTypeElement() {
         return annotationType;
     }
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassUseWriter.java	Mon Apr 09 08:34:30 2018 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassUseWriter.java	Tue Apr 10 13:58:47 2018 -0700
@@ -47,7 +47,8 @@
 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag;
 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
-import jdk.javadoc.internal.doclets.formats.html.markup.Links;
+import jdk.javadoc.internal.doclets.formats.html.markup.Navigation;
+import jdk.javadoc.internal.doclets.formats.html.markup.Navigation.PageMode;
 import jdk.javadoc.internal.doclets.formats.html.markup.StringContent;
 import jdk.javadoc.internal.doclets.toolkit.Content;
 import jdk.javadoc.internal.doclets.toolkit.util.ClassTree;
@@ -106,6 +107,7 @@
     final String methodUseTableSummary;
     final String constructorUseTableSummary;
     final String packageUseTableSummary;
+    private final Navigation navBar;
 
     /**
      * The HTML tree for main tag.
@@ -178,6 +180,7 @@
                 resources.getText("doclet.constructors"));
         packageUseTableSummary = MessageFormat.format(useTableSummary,
                 resources.getText("doclet.packages"));
+        this.navBar = new Navigation(typeElement, configuration, fixedNavDiv, PageMode.USE, path);
     }
 
     /**
@@ -264,7 +267,8 @@
         HtmlTree htmlTree = (configuration.allowTag(HtmlTag.FOOTER))
                 ? HtmlTree.FOOTER()
                 : body;
-        addNavLinks(false, htmlTree);
+        navBar.setUserFooter(getUserHeaderFooter(false));
+        htmlTree.addContent(navBar.getContent(false));
         addBottom(htmlTree);
         if (configuration.allowTag(HtmlTag.FOOTER)) {
             body.addContent(htmlTree);
@@ -476,7 +480,15 @@
                 ? HtmlTree.HEADER()
                 : bodyTree;
         addTop(htmlTree);
-        addNavLinks(true, htmlTree);
+        Content mdleLinkContent = getModuleLink(utils.elementUtils.getModuleOf(typeElement),
+                contents.moduleLabel);
+        navBar.setNavLinkModule(mdleLinkContent);
+        Content classLinkContent = getLink(new LinkInfoImpl(
+                configuration, LinkInfoImpl.Kind.CLASS_USE_HEADER, typeElement)
+                .label(configuration.getText("doclet.Class")));
+        navBar.setNavLinkClass(classLinkContent);
+        navBar.setUserHeader(getUserHeaderFooter(true));
+        htmlTree.addContent(navBar.getContent(true));
         if (configuration.allowTag(HtmlTag.HEADER)) {
             bodyTree.addContent(htmlTree);
         }
@@ -494,65 +506,4 @@
         }
         return bodyTree;
     }
-
-    /**
-     * Get the module link.
-     *
-     * @return a content tree for the module link
-     */
-    @Override
-    protected Content getNavLinkModule() {
-        Content linkContent = getModuleLink(utils.elementUtils.getModuleOf(typeElement),
-                contents.moduleLabel);
-        Content li = HtmlTree.LI(linkContent);
-        return li;
-    }
-
-    /**
-     * Get this package link.
-     *
-     * @return a content tree for the package link
-     */
-    protected Content getNavLinkPackage() {
-        Content linkContent =
-                links.createLink(DocPath.parent.resolve(DocPaths.PACKAGE_SUMMARY), contents.packageLabel);
-        Content li = HtmlTree.LI(linkContent);
-        return li;
-    }
-
-    /**
-     * Get class page link.
-     *
-     * @return a content tree for the class page link
-     */
-    protected Content getNavLinkClass() {
-        Content linkContent = getLink(new LinkInfoImpl(
-                configuration, LinkInfoImpl.Kind.CLASS_USE_HEADER, typeElement)
-                .label(configuration.getText("doclet.Class")));
-        Content li = HtmlTree.LI(linkContent);
-        return li;
-    }
-
-    /**
-     * Get the use link.
-     *
-     * @return a content tree for the use link
-     */
-    protected Content getNavLinkClassUse() {
-        Content li = HtmlTree.LI(HtmlStyle.navBarCell1Rev, contents.useLabel);
-        return li;
-    }
-
-    /**
-     * Get the tree link.
-     *
-     * @return a content tree for the tree link
-     */
-    protected Content getNavLinkTree() {
-        Content linkContent = utils.isEnclosingPackageIncluded(typeElement)
-                ? links.createLink(DocPath.parent.resolve(DocPaths.PACKAGE_TREE), contents.treeLabel)
-                : links.createLink(pathToRoot.resolve(DocPaths.OVERVIEW_TREE), contents.treeLabel);
-        Content li = HtmlTree.LI(linkContent);
-        return li;
-    }
 }
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassWriterImpl.java	Mon Apr 09 08:34:30 2018 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassWriterImpl.java	Tue Apr 10 13:58:47 2018 -0700
@@ -40,6 +40,8 @@
 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag;
 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
+import jdk.javadoc.internal.doclets.formats.html.markup.Navigation;
+import jdk.javadoc.internal.doclets.formats.html.markup.Navigation.PageMode;
 import jdk.javadoc.internal.doclets.formats.html.markup.StringContent;
 import jdk.javadoc.internal.doclets.toolkit.ClassWriter;
 import jdk.javadoc.internal.doclets.toolkit.Content;
@@ -48,11 +50,9 @@
 import jdk.javadoc.internal.doclets.toolkit.util.ClassTree;
 import jdk.javadoc.internal.doclets.toolkit.util.CommentHelper;
 import jdk.javadoc.internal.doclets.toolkit.util.DocFileIOException;
-import jdk.javadoc.internal.doclets.toolkit.util.DocPath;
 import jdk.javadoc.internal.doclets.toolkit.util.DocPaths;
 import jdk.javadoc.internal.doclets.toolkit.util.DocletConstants;
 import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberMap;
-import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberMap.Kind;
 
 /**
  * Generate the Class Information Page.
@@ -78,6 +78,8 @@
 
     protected final ClassTree classtree;
 
+    private final Navigation navBar;
+
     /**
      * @param configuration the configuration data for the doclet
      * @param typeElement the class being documented.
@@ -89,55 +91,7 @@
         this.typeElement = typeElement;
         configuration.currentTypeElement = typeElement;
         this.classtree = classTree;
-    }
-
-    /**
-     * Get the module link.
-     *
-     * @return a content tree for the module link
-     */
-    @Override
-    protected Content getNavLinkModule() {
-        Content linkContent = getModuleLink(utils.elementUtils.getModuleOf(typeElement),
-                contents.moduleLabel);
-        Content li = HtmlTree.LI(linkContent);
-        return li;
-    }
-
-    /**
-     * Get this package link.
-     *
-     * @return a content tree for the package link
-     */
-    @Override
-    protected Content getNavLinkPackage() {
-        Content linkContent = links.createLink(DocPaths.PACKAGE_SUMMARY,
-                contents.packageLabel);
-        Content li = HtmlTree.LI(linkContent);
-        return li;
-    }
-
-    /**
-     * Get the class link.
-     *
-     * @return a content tree for the class link
-     */
-    @Override
-    protected Content getNavLinkClass() {
-        Content li = HtmlTree.LI(HtmlStyle.navBarCell1Rev, contents.classLabel);
-        return li;
-    }
-
-    /**
-     * Get the class use link.
-     *
-     * @return a content tree for the class use link
-     */
-    @Override
-    protected Content getNavLinkClassUse() {
-        Content linkContent = links.createLink(DocPaths.CLASS_USE.resolve(filename), contents.useLabel);
-        Content li = HtmlTree.LI(linkContent);
-        return li;
+        this.navBar = new Navigation(typeElement, configuration, fixedNavDiv, PageMode.CLASS, path);
     }
 
     /**
@@ -150,7 +104,12 @@
                 ? HtmlTree.HEADER()
                 : bodyTree;
         addTop(htmlTree);
-        addNavLinks(true, htmlTree);
+        Content linkContent = getModuleLink(utils.elementUtils.getModuleOf(typeElement),
+                contents.moduleLabel);
+        navBar.setNavLinkModule(linkContent);
+        navBar.setMemberSummaryBuilder(configuration.getBuilderFactory().getMemberSummaryBuilder(this));
+        navBar.setUserHeader(getUserHeaderFooter(true));
+        htmlTree.addContent(navBar.getContent(true));
         if (configuration.allowTag(HtmlTag.HEADER)) {
             bodyTree.addContent(htmlTree);
         }
@@ -210,7 +169,8 @@
         Content htmlTree = (configuration.allowTag(HtmlTag.FOOTER))
                 ? HtmlTree.FOOTER()
                 : contentTree;
-        addNavLinks(false, htmlTree);
+        navBar.setUserFooter(getUserHeaderFooter(false));
+        htmlTree.addContent(navBar.getContent(false));
         addBottom(htmlTree);
         if (configuration.allowTag(HtmlTag.FOOTER)) {
             contentTree.addContent(htmlTree);
@@ -609,100 +569,6 @@
     }
 
     /**
-     * {@inheritDoc}
-     */
-    @Override
-    protected Content getNavLinkTree() {
-        Content treeLinkContent = links.createLink(DocPaths.PACKAGE_TREE,
-                contents.treeLabel, "", "");
-        Content li = HtmlTree.LI(treeLinkContent);
-        return li;
-    }
-
-    /**
-     * Add summary details to the navigation bar.
-     *
-     * @param subDiv the content tree to which the summary detail links will be added
-     */
-    @Override
-    protected void addSummaryDetailLinks(Content subDiv) {
-        Content div = HtmlTree.DIV(getNavSummaryLinks());
-        div.addContent(getNavDetailLinks());
-        subDiv.addContent(div);
-    }
-
-    /**
-     * Get summary links for navigation bar.
-     *
-     * @return the content tree for the navigation summary links
-     */
-    protected Content getNavSummaryLinks() {
-        Content li = HtmlTree.LI(contents.summaryLabel);
-        li.addContent(Contents.SPACE);
-        Content ulNav = HtmlTree.UL(HtmlStyle.subNavList, li);
-        MemberSummaryBuilder memberSummaryBuilder =
-                configuration.getBuilderFactory().getMemberSummaryBuilder(this);
-        for (VisibleMemberMap.Kind kind : VisibleMemberMap.Kind.summarySet) {
-            Content liNav = new HtmlTree(HtmlTag.LI);
-            if (kind == VisibleMemberMap.Kind.ENUM_CONSTANTS && !utils.isEnum(typeElement)) {
-                continue;
-            }
-            if (kind == VisibleMemberMap.Kind.CONSTRUCTORS && utils.isEnum(typeElement)) {
-                continue;
-            }
-            AbstractMemberWriter writer =
-                ((AbstractMemberWriter) memberSummaryBuilder.getMemberSummaryWriter(kind));
-            if (writer == null) {
-                liNav.addContent(contents.getContent(VisibleMemberMap.Kind.getNavLinkLabels(kind)));
-            } else {
-                writer.addNavSummaryLink(
-                        memberSummaryBuilder.members(kind),
-                        memberSummaryBuilder.getVisibleMemberMap(kind), liNav);
-            }
-            if (kind != Kind.METHODS) {
-                addNavGap(liNav);
-            }
-            ulNav.addContent(liNav);
-        }
-        return ulNav;
-    }
-
-    /**
-     * Get detail links for the navigation bar.
-     *
-     * @return the content tree for the detail links
-     */
-    protected Content getNavDetailLinks() {
-        Content li = HtmlTree.LI(contents.detailLabel);
-        li.addContent(Contents.SPACE);
-        Content ulNav = HtmlTree.UL(HtmlStyle.subNavList, li);
-        MemberSummaryBuilder memberSummaryBuilder =
-                configuration.getBuilderFactory().getMemberSummaryBuilder(this);
-        for (VisibleMemberMap.Kind kind : VisibleMemberMap.Kind.detailSet) {
-            Content liNav = new HtmlTree(HtmlTag.LI);
-            AbstractMemberWriter writer =
-                    ((AbstractMemberWriter) memberSummaryBuilder.
-                    getMemberSummaryWriter(kind));
-            if (kind == VisibleMemberMap.Kind.ENUM_CONSTANTS && !utils.isEnum(typeElement)) {
-                continue;
-            }
-            if (kind == VisibleMemberMap.Kind.CONSTRUCTORS && utils.isEnum(typeElement)) {
-                continue;
-            }
-            if (writer == null) {
-                liNav.addContent(contents.getContent(VisibleMemberMap.Kind.getNavLinkLabels(kind)));
-            } else {
-                writer.addNavDetailLink(memberSummaryBuilder.members(kind), liNav);
-            }
-            if (kind != Kind.METHODS) {
-                addNavGap(liNav);
-            }
-            ulNav.addContent(liNav);
-        }
-        return ulNav;
-    }
-
-    /**
      * Return the TypeElement being documented.
      *
      * @return the TypeElement being documented.
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ConstantsSummaryWriterImpl.java	Mon Apr 09 08:34:30 2018 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ConstantsSummaryWriterImpl.java	Tue Apr 10 13:58:47 2018 -0700
@@ -40,7 +40,8 @@
 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag;
 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
-import jdk.javadoc.internal.doclets.formats.html.markup.Links;
+import jdk.javadoc.internal.doclets.formats.html.markup.Navigation;
+import jdk.javadoc.internal.doclets.formats.html.markup.Navigation.PageMode;
 import jdk.javadoc.internal.doclets.formats.html.markup.StringContent;
 import jdk.javadoc.internal.doclets.toolkit.ConstantsSummaryWriter;
 import jdk.javadoc.internal.doclets.toolkit.Content;
@@ -86,6 +87,8 @@
      */
     private HtmlTree summaryTree;
 
+    private final Navigation navBar;
+
     /**
      * Construct a ConstantsSummaryWriter.
      * @param configuration the configuration used in this run
@@ -98,6 +101,7 @@
                 configuration.getText("doclet.Constants_Summary"));
         constantsTableHeader = new TableHeader(
                 contents.modifierAndTypeLabel, contents.constantFieldLabel, contents.valueLabel);
+        this.navBar = new Navigation(null, configuration, fixedNavDiv, PageMode.CONSTANTVALUES, path);
     }
 
     /**
@@ -111,7 +115,8 @@
                 ? HtmlTree.HEADER()
                 : bodyTree;
         addTop(htmlTree);
-        addNavLinks(true, htmlTree);
+        navBar.setUserHeader(getUserHeaderFooter(true));
+        htmlTree.addContent(navBar.getContent(true));
         if (configuration.allowTag(HtmlTag.HEADER)) {
             bodyTree.addContent(htmlTree);
         }
@@ -341,7 +346,8 @@
         Content htmlTree = (configuration.allowTag(HtmlTag.FOOTER))
                 ? HtmlTree.FOOTER()
                 : contentTree;
-        addNavLinks(false, htmlTree);
+        navBar.setUserFooter(getUserHeaderFooter(false));
+        htmlTree.addContent(navBar.getContent(false));
         addBottom(htmlTree);
         if (configuration.allowTag(HtmlTag.FOOTER)) {
             contentTree.addContent(htmlTree);
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ConstructorWriterImpl.java	Mon Apr 09 08:34:30 2018 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ConstructorWriterImpl.java	Tue Apr 10 13:58:47 2018 -0700
@@ -38,7 +38,7 @@
 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag;
 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
-import jdk.javadoc.internal.doclets.formats.html.markup.Links;
+import jdk.javadoc.internal.doclets.formats.html.markup.Navigation;
 import jdk.javadoc.internal.doclets.formats.html.markup.StringContent;
 import jdk.javadoc.internal.doclets.toolkit.ConstructorWriter;
 import jdk.javadoc.internal.doclets.toolkit.Content;
@@ -298,33 +298,6 @@
      * {@inheritDoc}
      */
     @Override
-    protected Content getNavSummaryLink(TypeElement typeElement, boolean link) {
-        if (link) {
-            return links.createLink(SectionName.CONSTRUCTOR_SUMMARY,
-                    contents.navConstructor);
-        } else {
-            return contents.navConstructor;
-        }
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    protected void addNavDetailLink(boolean link, Content liNav) {
-        if (link) {
-            liNav.addContent(links.createLink(
-                    SectionName.CONSTRUCTOR_DETAIL,
-                    contents.navConstructor));
-        } else {
-            liNav.addContent(contents.navConstructor);
-        }
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
     protected void addSummaryType(Element member, Content tdSummaryType) {
         if (foundNonPubConstructor) {
             Content code = new HtmlTree(HtmlTag.CODE);
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/DeprecatedListWriter.java	Mon Apr 09 08:34:30 2018 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/DeprecatedListWriter.java	Tue Apr 10 13:58:47 2018 -0700
@@ -42,6 +42,8 @@
 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag;
 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
+import jdk.javadoc.internal.doclets.formats.html.markup.Navigation;
+import jdk.javadoc.internal.doclets.formats.html.markup.Navigation.PageMode;
 import jdk.javadoc.internal.doclets.formats.html.markup.StringContent;
 import jdk.javadoc.internal.doclets.toolkit.Content;
 import jdk.javadoc.internal.doclets.toolkit.util.DeprecatedAPIListBuilder;
@@ -209,6 +211,8 @@
 
     private HtmlConfiguration configuration;
 
+    private final Navigation navBar;
+
     /**
      * Constructor.
      *
@@ -219,6 +223,7 @@
     public DeprecatedListWriter(HtmlConfiguration configuration, DocPath filename) {
         super(configuration, filename);
         this.configuration = configuration;
+        this.navBar = new Navigation(null, configuration, fixedNavDiv, PageMode.DEPRECATED, path);
         NestedClassWriterImpl classW = new NestedClassWriterImpl(this);
         writerMap = new EnumMap<>(DeprElementKind.class);
         for (DeprElementKind kind : DeprElementKind.values()) {
@@ -307,7 +312,8 @@
         htmlTree = (configuration.allowTag(HtmlTag.FOOTER))
                 ? HtmlTree.FOOTER()
                 : body;
-        addNavLinks(false, htmlTree);
+        navBar.setUserFooter(getUserHeaderFooter(false));
+        htmlTree.addContent(navBar.getContent(false));
         addBottom(htmlTree);
         if (configuration.allowTag(HtmlTag.FOOTER)) {
             body.addContent(htmlTree);
@@ -378,7 +384,8 @@
                 ? HtmlTree.HEADER()
                 : bodyTree;
         addTop(htmlTree);
-        addNavLinks(true, htmlTree);
+        navBar.setUserHeader(getUserHeaderFooter(true));
+        htmlTree.addContent(navBar.getContent(true));
         if (configuration.allowTag(HtmlTag.HEADER)) {
             bodyTree.addContent(htmlTree);
         }
@@ -386,17 +393,6 @@
     }
 
     /**
-     * Get the deprecated label.
-     *
-     * @return a content tree for the deprecated label
-     */
-    @Override
-    protected Content getNavLinkDeprecated() {
-        Content li = HtmlTree.LI(HtmlStyle.navBarCell1Rev, contents.deprecatedLabel);
-        return li;
-    }
-
-    /**
      * Add deprecated information to the documentation tree
      *
      * @param deprList list of deprecated API elements
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/DocFilesHandlerImpl.java	Mon Apr 09 08:34:30 2018 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/DocFilesHandlerImpl.java	Tue Apr 10 13:58:47 2018 -0700
@@ -27,16 +27,15 @@
 
 import com.sun.source.doctree.AttributeTree;
 import com.sun.source.doctree.AttributeTree.ValueKind;
-import com.sun.source.doctree.DocRootTree;
 import com.sun.source.doctree.DocTree;
 import com.sun.source.doctree.EndElementTree;
-import com.sun.source.doctree.LinkTree;
 import com.sun.source.doctree.StartElementTree;
 import com.sun.source.doctree.TextTree;
 import com.sun.source.util.SimpleDocTreeVisitor;
 import com.sun.tools.doclint.HtmlTag;
 import com.sun.tools.doclint.HtmlTag.Attr;
 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
+import jdk.javadoc.internal.doclets.formats.html.markup.Navigation;
 import jdk.javadoc.internal.doclets.toolkit.Content;
 import jdk.javadoc.internal.doclets.toolkit.DocFileElement;
 import jdk.javadoc.internal.doclets.toolkit.DocFilesHandler;
@@ -51,15 +50,19 @@
 import javax.lang.model.element.PackageElement;
 import javax.tools.FileObject;
 import javax.tools.JavaFileManager.Location;
+
 import java.util.Collections;
 import java.util.List;
 
+import jdk.javadoc.internal.doclets.formats.html.markup.Navigation.PageMode;
+
 public class DocFilesHandlerImpl implements DocFilesHandler {
 
     public final Element element;
     public final Location location;
     public final DocPath  source;
     public final HtmlConfiguration configuration;
+    private Navigation navBar;
 
     /**
      * Constructor to construct the DocFilesWriter object.
@@ -171,14 +174,24 @@
         String title = getWindowTitle(docletWriter, dfElement).trim();
         HtmlTree htmlContent = docletWriter.getBody(true, title);
         docletWriter.addTop(htmlContent);
-        docletWriter.addNavLinks(true, htmlContent);
+        PackageElement pkg = (PackageElement) element;
+        this.navBar = new Navigation(pkg, configuration, docletWriter.fixedNavDiv,
+                PageMode.DOCFILE, docletWriter.path);
+        Content mdleLinkContent = docletWriter.getModuleLink(utils.elementUtils.getModuleOf(pkg),
+                docletWriter.contents.moduleLabel);
+        navBar.setNavLinkModule(mdleLinkContent);
+        Content pkgLinkContent = docletWriter.getPackageLink(pkg, docletWriter.contents.packageLabel);
+        navBar.setNavLinkPackage(pkgLinkContent);
+        navBar.setUserHeader(docletWriter.getUserHeaderFooter(true));
+        htmlContent.addContent(navBar.getContent(true));
         List<? extends DocTree> fullBody = utils.getFullBody(dfElement);
         Content bodyContent = docletWriter.commentTagsToContent(null, dfElement, fullBody, false);
 
         docletWriter.addTagsInfo(dfElement, bodyContent);
         htmlContent.addContent(bodyContent);
 
-        docletWriter.addNavLinks(false, htmlContent);
+        navBar.setUserFooter(docletWriter.getUserHeaderFooter(false));
+        htmlContent.addContent(navBar.getContent(false));
         docletWriter.addBottom(htmlContent);
         docletWriter.printHtmlDocument(Collections.emptyList(), false, htmlContent);
         return true;
@@ -301,31 +314,5 @@
                     throw new AssertionError("unsupported element: " + e.getKind());
             }
         }
-
-        /**
-         * Get the module link.
-         *
-         * @return a content tree for the module link
-         */
-        @Override
-        protected Content getNavLinkModule() {
-            Content linkContent = getModuleLink(utils.elementUtils.getModuleOf(pkg),
-                    contents.moduleLabel);
-            Content li = HtmlTree.LI(linkContent);
-            return li;
-        }
-
-        /**
-         * Get this package link.
-         *
-         * @return a content tree for the package link
-         */
-        @Override
-        protected Content getNavLinkPackage() {
-            Content linkContent = getPackageLink(pkg,
-                    contents.packageLabel);
-            Content li = HtmlTree.LI(linkContent);
-            return li;
-        }
     }
 }
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/EnumConstantWriterImpl.java	Mon Apr 09 08:34:30 2018 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/EnumConstantWriterImpl.java	Tue Apr 10 13:58:47 2018 -0700
@@ -37,7 +37,7 @@
 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag;
 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
-import jdk.javadoc.internal.doclets.formats.html.markup.Links;
+import jdk.javadoc.internal.doclets.formats.html.markup.Navigation;
 import jdk.javadoc.internal.doclets.formats.html.markup.StringContent;
 import jdk.javadoc.internal.doclets.toolkit.Content;
 import jdk.javadoc.internal.doclets.toolkit.EnumConstantWriter;
@@ -273,37 +273,4 @@
         String name = utils.getFullyQualifiedName(member) + "." + member.getSimpleName();
         return writer.getDocLink(LinkInfoImpl.Kind.MEMBER, member, name);
     }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    protected Content getNavSummaryLink(TypeElement typeElement, boolean link) {
-        if (link) {
-            if (typeElement == null) {
-                return links.createLink(SectionName.ENUM_CONSTANT_SUMMARY,
-                        contents.navEnum);
-            } else {
-                return links.createLink(
-                        SectionName.ENUM_CONSTANTS_INHERITANCE,
-                        configuration.getClassName(typeElement), contents.navEnum);
-            }
-        } else {
-            return contents.navEnum;
-        }
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    protected void addNavDetailLink(boolean link, Content liNav) {
-        if (link) {
-            liNav.addContent(links.createLink(
-                    SectionName.ENUM_CONSTANT_DETAIL,
-                    contents.navEnum));
-        } else {
-            liNav.addContent(contents.navEnum);
-        }
-    }
 }
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/FieldWriterImpl.java	Mon Apr 09 08:34:30 2018 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/FieldWriterImpl.java	Tue Apr 10 13:58:47 2018 -0700
@@ -39,7 +39,7 @@
 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag;
 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
-import jdk.javadoc.internal.doclets.formats.html.markup.Links;
+import jdk.javadoc.internal.doclets.formats.html.markup.Navigation;
 import jdk.javadoc.internal.doclets.formats.html.markup.StringContent;
 import jdk.javadoc.internal.doclets.toolkit.Content;
 import jdk.javadoc.internal.doclets.toolkit.FieldWriter;
@@ -302,38 +302,4 @@
         String name = utils.getFullyQualifiedName(member) + "." + member.getSimpleName();
         return writer.getDocLink(LinkInfoImpl.Kind.MEMBER, member, name);
     }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    protected Content getNavSummaryLink(TypeElement typeElement, boolean link) {
-        if (link) {
-            if (typeElement == null) {
-                return links.createLink(
-                        SectionName.FIELD_SUMMARY,
-                        contents.navField);
-            } else {
-                return links.createLink(
-                        SectionName.FIELDS_INHERITANCE,
-                        configuration.getClassName(typeElement), contents.navField);
-            }
-        } else {
-            return contents.navField;
-        }
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    protected void addNavDetailLink(boolean link, Content liNav) {
-        if (link) {
-            liNav.addContent(links.createLink(
-                    SectionName.FIELD_DETAIL,
-                    contents.navField));
-        } else {
-            liNav.addContent(contents.navField);
-        }
-    }
 }
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HelpWriter.java	Mon Apr 09 08:34:30 2018 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HelpWriter.java	Tue Apr 10 13:58:47 2018 -0700
@@ -29,6 +29,8 @@
 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag;
 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
+import jdk.javadoc.internal.doclets.formats.html.markup.Navigation;
+import jdk.javadoc.internal.doclets.formats.html.markup.Navigation.PageMode;
 import jdk.javadoc.internal.doclets.formats.html.markup.StringContent;
 import jdk.javadoc.internal.doclets.toolkit.Content;
 import jdk.javadoc.internal.doclets.toolkit.util.DocFileIOException;
@@ -51,6 +53,8 @@
 
     HtmlTree mainTree = HtmlTree.MAIN();
 
+    private final Navigation navBar;
+
     /**
      * Constructor to construct HelpWriter object.
      * @param configuration the configuration
@@ -59,6 +63,7 @@
     public HelpWriter(HtmlConfiguration configuration,
                       DocPath filename) {
         super(configuration, filename);
+        this.navBar = new Navigation(null, configuration, fixedNavDiv, PageMode.HELP, path);
     }
 
     /**
@@ -88,7 +93,8 @@
                 ? HtmlTree.HEADER()
                 : body;
         addTop(htmlTree);
-        addNavLinks(true, htmlTree);
+        navBar.setUserHeader(getUserHeaderFooter(true));
+        htmlTree.addContent(navBar.getContent(true));
         if (configuration.allowTag(HtmlTag.HEADER)) {
             body.addContent(htmlTree);
         }
@@ -96,7 +102,8 @@
         if (configuration.allowTag(HtmlTag.FOOTER)) {
             htmlTree = HtmlTree.FOOTER();
         }
-        addNavLinks(false, htmlTree);
+        navBar.setUserFooter(getUserHeaderFooter(false));
+        htmlTree.addContent(navBar.getContent(false));
         addBottom(htmlTree);
         if (configuration.allowTag(HtmlTag.FOOTER)) {
             body.addContent(htmlTree);
@@ -428,15 +435,4 @@
             contentTree.addContent(divContent);
         }
     }
-
-    /**
-     * Get the help label.
-     *
-     * @return a content tree for the help label
-     */
-    @Override
-    protected Content getNavLinkHelp() {
-        Content li = HtmlTree.LI(HtmlStyle.navBarCell1Rev, contents.helpLabel);
-        return li;
-    }
 }
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlConfiguration.java	Mon Apr 09 08:34:30 2018 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlConfiguration.java	Tue Apr 10 13:58:47 2018 -0700
@@ -247,11 +247,11 @@
 
     protected Set<Character> tagSearchIndexKeys;
 
-    protected final Contents contents;
+    public final Contents contents;
 
     protected final Messages messages;
 
-    protected DocPaths docPaths;
+    public DocPaths docPaths;
 
     /**
      * Creates an object to hold the configuration for a doclet.
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java	Mon Apr 09 08:34:30 2018 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java	Tue Apr 10 13:58:47 2018 -0700
@@ -69,13 +69,13 @@
 
 import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder;
 import jdk.javadoc.internal.doclets.formats.html.markup.DocType;
-import jdk.javadoc.internal.doclets.formats.html.markup.HtmlAttr;
 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlConstants;
 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlDocument;
 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag;
 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
 import jdk.javadoc.internal.doclets.formats.html.markup.Links;
+import jdk.javadoc.internal.doclets.formats.html.markup.Navigation;
 import jdk.javadoc.internal.doclets.formats.html.markup.RawHtml;
 import jdk.javadoc.internal.doclets.formats.html.markup.Script;
 import jdk.javadoc.internal.doclets.formats.html.markup.StringContent;
@@ -491,261 +491,6 @@
     }
 
     /**
-     * Adds the navigation bar for the Html page at the top and and the bottom.
-     *
-     * @param header If true print navigation bar at the top of the page else
-     * @param htmlTree the HtmlTree to which the nav links will be added
-     */
-    protected void addNavLinks(boolean header, Content htmlTree) {
-        if (!configuration.nonavbar) {
-            Content tree = (configuration.allowTag(HtmlTag.NAV))
-                    ? HtmlTree.NAV()
-                    : htmlTree;
-            String allClassesId = "allclasses_";
-            HtmlTree navDiv = new HtmlTree(HtmlTag.DIV);
-            fixedNavDiv.setStyle(HtmlStyle.fixedNav);
-            Content skipNavLinks = configuration.getContent("doclet.Skip_navigation_links");
-            if (header) {
-                fixedNavDiv.addContent(HtmlConstants.START_OF_TOP_NAVBAR);
-                navDiv.setStyle(HtmlStyle.topNav);
-                allClassesId += "navbar_top";
-                Content a = links.createAnchor(SectionName.NAVBAR_TOP);
-                //WCAG - Hyperlinks should contain text or an image with alt text - for AT tools
-                navDiv.addContent(a);
-                Content skipLinkContent = HtmlTree.DIV(HtmlStyle.skipNav,
-                        links.createLink(SectionName.SKIP_NAVBAR_TOP, skipNavLinks,
-                        skipNavLinks.toString(), ""));
-                navDiv.addContent(skipLinkContent);
-            } else {
-                tree.addContent(HtmlConstants.START_OF_BOTTOM_NAVBAR);
-                navDiv.setStyle(HtmlStyle.bottomNav);
-                allClassesId += "navbar_bottom";
-                Content a = links.createAnchor(SectionName.NAVBAR_BOTTOM);
-                navDiv.addContent(a);
-                Content skipLinkContent = HtmlTree.DIV(HtmlStyle.skipNav,
-                        links.createLink(SectionName.SKIP_NAVBAR_BOTTOM, skipNavLinks,
-                        skipNavLinks.toString(), ""));
-                navDiv.addContent(skipLinkContent);
-            }
-            if (header) {
-                navDiv.addContent(links.createAnchor(SectionName.NAVBAR_TOP_FIRSTROW));
-            } else {
-                navDiv.addContent(links.createAnchor(SectionName.NAVBAR_BOTTOM_FIRSTROW));
-            }
-            HtmlTree navList = new HtmlTree(HtmlTag.UL);
-            navList.setStyle(HtmlStyle.navList);
-            navList.addAttr(HtmlAttr.TITLE,
-                            configuration.getText("doclet.Navigation"));
-            if (configuration.createoverview) {
-                navList.addContent(getNavLinkContents());
-            }
-            if (configuration.showModules) {
-                if (configuration.modules.size() == 1) {
-                    navList.addContent(getNavLinkModule(configuration.modules.first()));
-                } else if (!configuration.modules.isEmpty()) {
-                    navList.addContent(getNavLinkModule());
-                }
-            }
-            if (configuration.packages.size() == 1) {
-                navList.addContent(getNavLinkPackage(configuration.packages.first()));
-            } else if (!configuration.packages.isEmpty()) {
-                navList.addContent(getNavLinkPackage());
-            }
-            navList.addContent(getNavLinkClass());
-            if(configuration.classuse) {
-                navList.addContent(getNavLinkClassUse());
-            }
-            if(configuration.createtree) {
-                navList.addContent(getNavLinkTree());
-            }
-            if(!(configuration.nodeprecated ||
-                     configuration.nodeprecatedlist)) {
-                navList.addContent(getNavLinkDeprecated());
-            }
-            if(configuration.createindex) {
-                navList.addContent(getNavLinkIndex());
-            }
-            if (!configuration.nohelp) {
-                navList.addContent(getNavLinkHelp());
-            }
-            navDiv.addContent(navList);
-            Content aboutDiv = HtmlTree.DIV(HtmlStyle.aboutLanguage, getUserHeaderFooter(header));
-            navDiv.addContent(aboutDiv);
-            if (header) {
-                fixedNavDiv.addContent(navDiv);
-            } else {
-                tree.addContent(navDiv);
-            }
-            HtmlTree subDiv = new HtmlTree(HtmlTag.DIV);
-            subDiv.setStyle(HtmlStyle.subNav);
-            if (configuration.frames) {
-                Content ulFrames = HtmlTree.UL(HtmlStyle.navList,
-                    getNavShowLists(), getNavHideLists(filename));
-                subDiv.addContent(ulFrames);
-            }
-            HtmlTree ulAllClasses = HtmlTree.UL(HtmlStyle.navList, getNavLinkClassIndex());
-            ulAllClasses.addAttr(HtmlAttr.ID, allClassesId);
-            subDiv.addContent(ulAllClasses);
-            if (header && configuration.createindex) {
-                String searchValueId = "search";
-                String reset = "reset";
-                HtmlTree inputText = HtmlTree.INPUT("text", searchValueId, searchValueId);
-                HtmlTree inputReset = HtmlTree.INPUT(reset, reset, reset);
-                Content searchTxt = configuration.getContent("doclet.search");
-                HtmlTree liInput = HtmlTree.LI(HtmlTree.LABEL(searchValueId, searchTxt));
-                liInput.addContent(inputText);
-                liInput.addContent(inputReset);
-                HtmlTree ulSearch = HtmlTree.UL(HtmlStyle.navListSearch, liInput);
-                subDiv.addContent(ulSearch);
-            }
-            subDiv.addContent(getAllClassesLinkScript(allClassesId));
-            addSummaryDetailLinks(subDiv);
-            if (header) {
-                subDiv.addContent(links.createAnchor(SectionName.SKIP_NAVBAR_TOP));
-                fixedNavDiv.addContent(subDiv);
-                fixedNavDiv.addContent(HtmlConstants.END_OF_TOP_NAVBAR);
-                tree.addContent(fixedNavDiv);
-                HtmlTree paddingDiv = HtmlTree.DIV(HtmlStyle.navPadding, Contents.SPACE);
-                tree.addContent(paddingDiv);
-                Script script = new Script(
-                        "<!--\n"
-                        + "$('.navPadding').css('padding-top', $('.fixedNav').css(\"height\"));\n"
-                        + "//-->\n");
-                tree.addContent(script.asContent());
-            } else {
-                subDiv.addContent(links.createAnchor(SectionName.SKIP_NAVBAR_BOTTOM));
-                tree.addContent(subDiv);
-                tree.addContent(HtmlConstants.END_OF_BOTTOM_NAVBAR);
-            }
-            if (configuration.allowTag(HtmlTag.NAV)) {
-                htmlTree.addContent(tree);
-            }
-        }
-    }
-
-    /**
-     * Do nothing. This is the default method.
-     */
-    protected void addSummaryDetailLinks(Content navDiv) {
-    }
-
-    /**
-     * Get link to the "overview-summary.html" page.
-     *
-     * @return a content tree for the link
-     */
-    protected Content getNavLinkContents() {
-        Content linkContent = links.createLink(pathToRoot.resolve(DocPaths.overviewSummary(configuration.frames)),
-                contents.overviewLabel, "", "");
-        Content li = HtmlTree.LI(linkContent);
-        return li;
-    }
-
-    /**
-     * Get link to the module summary page for the module passed.
-     *
-     * @param mdle Module to which link will be generated
-     * @return a content tree for the link
-     */
-    protected Content getNavLinkModule(ModuleElement mdle) {
-        Content linkContent = getModuleLink(mdle, contents.moduleLabel);
-        Content li = HtmlTree.LI(linkContent);
-        return li;
-    }
-
-    /**
-     * Get the word "Module", to indicate that link is not available here.
-     *
-     * @return a content tree for the link
-     */
-    protected Content getNavLinkModule() {
-        Content li = HtmlTree.LI(contents.moduleLabel);
-        return li;
-    }
-
-    /**
-     * Get link to the "package-summary.html" page for the package passed.
-     *
-     * @param pkg Package to which link will be generated
-     * @return a content tree for the link
-     */
-    protected Content getNavLinkPackage(PackageElement pkg) {
-        Content linkContent = getPackageLink(pkg, contents.packageLabel);
-        Content li = HtmlTree.LI(linkContent);
-        return li;
-    }
-
-    /**
-     * Get the word "Package" , to indicate that link is not available here.
-     *
-     * @return a content tree for the link
-     */
-    protected Content getNavLinkPackage() {
-        Content li = HtmlTree.LI(contents.packageLabel);
-        return li;
-    }
-
-    /**
-     * Get the word "Use", to indicate that link is not available.
-     *
-     * @return a content tree for the link
-     */
-    protected Content getNavLinkClassUse() {
-        Content li = HtmlTree.LI(contents.useLabel);
-        return li;
-    }
-
-    /**
-     * Get "FRAMES" link, to switch to the frame version of the output.
-     *
-     * @param link File to be linked, "index.html"
-     * @return a content tree for the link
-     */
-    protected Content getNavShowLists(DocPath link) {
-        DocLink dl = new DocLink(link, path.getPath(), null);
-        Content framesContent = links.createLink(dl, contents.framesLabel, "", "_top");
-        Content li = HtmlTree.LI(framesContent);
-        return li;
-    }
-
-    /**
-     * Get "FRAMES" link, to switch to the frame version of the output.
-     *
-     * @return a content tree for the link
-     */
-    protected Content getNavShowLists() {
-        return getNavShowLists(pathToRoot.resolve(DocPaths.INDEX));
-    }
-
-    /**
-     * Get "NO FRAMES" link, to switch to the non-frame version of the output.
-     *
-     * @param link File to be linked
-     * @return a content tree for the link
-     */
-    protected Content getNavHideLists(DocPath link) {
-        Content noFramesContent = links.createLink(link, contents.noFramesLabel, "", "_top");
-        Content li = HtmlTree.LI(noFramesContent);
-        return li;
-    }
-
-    /**
-     * Get "Tree" link in the navigation bar. If there is only one package
-     * specified on the command line, then the "Tree" link will be to the
-     * only "package-tree.html" file otherwise it will be to the
-     * "overview-tree.html" file.
-     *
-     * @return a content tree for the link
-     */
-    protected Content getNavLinkTree() {
-        List<PackageElement> packages = new ArrayList<>(configuration.getSpecifiedPackageElements());
-        DocPath docPath = packages.size() == 1 && configuration.getSpecifiedTypeElements().isEmpty()
-                ? pathString(packages.get(0), DocPaths.PACKAGE_TREE)
-                : pathToRoot.resolve(DocPaths.OVERVIEW_TREE);
-        return HtmlTree.LI(links.createLink(docPath, contents.treeLabel, "", ""));
-    }
-
-    /**
      * Get the overview tree link for the main tree.
      *
      * @param label the label for the link
@@ -759,91 +504,6 @@
     }
 
     /**
-     * Get the word "Class", to indicate that class link is not available.
-     *
-     * @return a content tree for the link
-     */
-    protected Content getNavLinkClass() {
-        Content li = HtmlTree.LI(contents.classLabel);
-        return li;
-    }
-
-    /**
-     * Get "Deprecated" API link in the navigation bar.
-     *
-     * @return a content tree for the link
-     */
-    protected Content getNavLinkDeprecated() {
-        Content linkContent = links.createLink(pathToRoot.resolve(DocPaths.DEPRECATED_LIST),
-                contents.deprecatedLabel, "", "");
-        Content li = HtmlTree.LI(linkContent);
-        return li;
-    }
-
-    /**
-     * Get link for generated index. If the user has used "-splitindex"
-     * command line option, then link to file "index-files/index-1.html" is
-     * generated otherwise link to file "index-all.html" is generated.
-     *
-     * @return a content tree for the link
-     */
-    protected Content getNavLinkClassIndex() {
-        Content allClassesContent = links.createLink(pathToRoot.resolve(
-                DocPaths.AllClasses(configuration.frames)),
-                contents.allClassesLabel, "", "");
-        Content li = HtmlTree.LI(allClassesContent);
-        return li;
-    }
-
-    /**
-     * Get link for generated class index.
-     *
-     * @return a content tree for the link
-     */
-    protected Content getNavLinkIndex() {
-        Content linkContent = links.createLink(pathToRoot.resolve(
-                (configuration.splitindex
-                    ? DocPaths.INDEX_FILES.resolve(DocPaths.indexN(1))
-                    : DocPaths.INDEX_ALL)),
-            contents.indexLabel, "", "");
-        Content li = HtmlTree.LI(linkContent);
-        return li;
-    }
-
-    /**
-     * Get help file link. If user has provided a help file, then generate a
-     * link to the user given file, which is already copied to current or
-     * destination directory.
-     *
-     * @return a content tree for the link
-     */
-    protected Content getNavLinkHelp() {
-        String helpfile = configuration.helpfile;
-        DocPath helpfilenm;
-        if (helpfile.isEmpty()) {
-            helpfilenm = DocPaths.HELP_DOC;
-        } else {
-            DocFile file = DocFile.createFileForInput(configuration, helpfile);
-            helpfilenm = DocPath.create(file.getName());
-        }
-        Content linkContent = links.createLink(pathToRoot.resolve(helpfilenm),
-                contents.helpLabel, "", "");
-        Content li = HtmlTree.LI(linkContent);
-        return li;
-    }
-
-    /**
-     * Add gap between navigation bar elements.
-     *
-     * @param liNav the content tree to which the gap will be added
-     */
-    protected void addNavGap(Content liNav) {
-        liNav.addContent(Contents.SPACE);
-        liNav.addContent("|");
-        liNav.addContent(Contents.SPACE);
-    }
-
-    /**
      * Get table caption.
      *
      * @param title the content for the caption
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/MethodWriterImpl.java	Mon Apr 09 08:34:30 2018 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/MethodWriterImpl.java	Tue Apr 10 13:58:47 2018 -0700
@@ -40,7 +40,7 @@
 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag;
 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
-import jdk.javadoc.internal.doclets.formats.html.markup.Links;
+import jdk.javadoc.internal.doclets.formats.html.markup.Navigation;
 import jdk.javadoc.internal.doclets.formats.html.markup.StringContent;
 import jdk.javadoc.internal.doclets.toolkit.Content;
 import jdk.javadoc.internal.doclets.toolkit.MemberSummaryWriter;
@@ -424,37 +424,4 @@
             htmltree.addContent(Contents.SPACE);
         }
     }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    protected Content getNavSummaryLink(TypeElement typeElement, boolean link) {
-        if (link) {
-            if (typeElement == null) {
-                return links.createLink(
-                        SectionName.METHOD_SUMMARY,
-                        contents.navMethod);
-            } else {
-                return links.createLink(
-                        SectionName.METHODS_INHERITANCE,
-                        configuration.getClassName(typeElement), contents.navMethod);
-            }
-        } else {
-            return contents.navMethod;
-        }
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    protected void addNavDetailLink(boolean link, Content liNav) {
-        if (link) {
-            liNav.addContent(links.createLink(
-                    SectionName.METHOD_DETAIL, contents.navMethod));
-        } else {
-            liNav.addContent(contents.navMethod);
-        }
-    }
 }
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ModuleIndexWriter.java	Mon Apr 09 08:34:30 2018 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ModuleIndexWriter.java	Tue Apr 10 13:58:47 2018 -0700
@@ -227,7 +227,8 @@
                 ? HtmlTree.HEADER()
                 : body;
         addTop(tree);
-        addNavLinks(true, tree);
+        navBar.setUserHeader(getUserHeaderFooter(true));
+        tree.addContent(navBar.getContent(true));
         if (configuration.allowTag(HtmlTag.HEADER)) {
             body.addContent(tree);
         }
@@ -244,7 +245,8 @@
         Content htmltree = (configuration.allowTag(HtmlTag.FOOTER))
                 ? HtmlTree.FOOTER()
                 : body;
-        addNavLinks(false, htmltree);
+        navBar.setUserFooter(getUserHeaderFooter(false));
+        htmltree.addContent(navBar.getContent(false));
         addBottom(htmltree);
         if (configuration.allowTag(HtmlTag.FOOTER)) {
             body.addContent(htmltree);
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ModuleWriterImpl.java	Mon Apr 09 08:34:30 2018 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ModuleWriterImpl.java	Tue Apr 10 13:58:47 2018 -0700
@@ -50,13 +50,14 @@
 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag;
 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
+import jdk.javadoc.internal.doclets.formats.html.markup.Navigation;
+import jdk.javadoc.internal.doclets.formats.html.markup.Navigation.PageMode;
 import jdk.javadoc.internal.doclets.formats.html.markup.RawHtml;
 import jdk.javadoc.internal.doclets.formats.html.markup.StringContent;
 import jdk.javadoc.internal.doclets.toolkit.Content;
 import jdk.javadoc.internal.doclets.toolkit.ModuleSummaryWriter;
 import jdk.javadoc.internal.doclets.toolkit.util.CommentHelper;
 import jdk.javadoc.internal.doclets.toolkit.util.DocFileIOException;
-import jdk.javadoc.internal.doclets.toolkit.util.DocPaths;
 
 /**
  * Class to generate file for each module contents in the right-hand frame. This will list all the
@@ -171,6 +172,8 @@
      */
     protected HtmlTree sectionTree = HtmlTree.SECTION();
 
+    private final Navigation navBar;
+
     /**
      * Constructor to construct ModuleWriter object and to generate "moduleName-summary.html" file.
      *
@@ -181,6 +184,7 @@
         super(configuration, configuration.docPaths.moduleSummary(mdle));
         this.mdle = mdle;
         this.moduleMode = configuration.docEnv.getModuleMode();
+        this.navBar = new Navigation(mdle, configuration, fixedNavDiv, PageMode.MODULE, path);
         computeModulesData();
     }
 
@@ -196,7 +200,13 @@
                 ? HtmlTree.HEADER()
                 : bodyTree;
         addTop(htmlTree);
-        addNavLinks(true, htmlTree);
+        navBar.setDisplaySummaryModuleDescLink(!utils.getFullBody(mdle).isEmpty() && !configuration.nocomment);
+        navBar.setDisplaySummaryModulesLink(display(requires) || display(indirectModules));
+        navBar.setDisplaySummaryPackagesLink(display(packages) || display(indirectPackages)
+                || display(indirectOpenPackages));
+        navBar.setDisplaySummaryServicesLink(displayServices(uses, usesTrees) || displayServices(provides.keySet(), providesTrees));
+        navBar.setUserHeader(getUserHeaderFooter(true));
+        htmlTree.addContent(navBar.getContent(true));
         if (configuration.allowTag(HtmlTag.HEADER)) {
             bodyTree.addContent(htmlTree);
         }
@@ -914,47 +924,6 @@
     }
 
     /**
-     * Add summary details to the navigation bar.
-     *
-     * @param subDiv the content tree to which the summary detail links will be added
-     */
-    @Override
-    protected void addSummaryDetailLinks(Content subDiv) {
-        Content div = HtmlTree.DIV(getNavSummaryLinks());
-        subDiv.addContent(div);
-    }
-
-    /**
-     * Get summary links for navigation bar.
-     *
-     * @return the content tree for the navigation summary links
-     */
-    protected Content getNavSummaryLinks() {
-        Content li = HtmlTree.LI(contents.moduleSubNavLabel);
-        li.addContent(Contents.SPACE);
-        Content ulNav = HtmlTree.UL(HtmlStyle.subNavList, li);
-        Content liNav = new HtmlTree(HtmlTag.LI);
-        liNav.addContent(!utils.getFullBody(mdle).isEmpty() && !configuration.nocomment
-                ? links.createLink(SectionName.MODULE_DESCRIPTION, contents.navModuleDescription)
-                : contents.navModuleDescription);
-        addNavGap(liNav);
-        liNav.addContent((display(requires) || display(indirectModules))
-                ? links.createLink(SectionName.MODULES, contents.navModules)
-                : contents.navModules);
-        addNavGap(liNav);
-        liNav.addContent((display(packages)
-                || display(indirectPackages) || display(indirectOpenPackages))
-                ? links.createLink(SectionName.PACKAGES, contents.navPackages)
-                : contents.navPackages);
-        addNavGap(liNav);
-        liNav.addContent((displayServices(uses, usesTrees) || displayServices(provides.keySet(), providesTrees))
-                ? links.createLink(SectionName.SERVICES, contents.navServices)
-                : contents.navServices);
-        ulNav.addContent(liNav);
-        return ulNav;
-    }
-
-    /**
      * {@inheritDoc}
      */
     @Override
@@ -975,7 +944,8 @@
         Content htmlTree = (configuration.allowTag(HtmlTag.FOOTER))
                 ? HtmlTree.FOOTER()
                 : contentTree;
-        addNavLinks(false, htmlTree);
+        navBar.setUserFooter(getUserHeaderFooter(false));
+        htmlTree.addContent(navBar.getContent(false));
         addBottom(htmlTree);
         if (configuration.allowTag(HtmlTag.FOOTER)) {
             contentTree.addContent(htmlTree);
@@ -1017,15 +987,4 @@
             li.addContent(deprDiv);
         }
     }
-
-    /**
-     * Get this module link.
-     *
-     * @return a content tree for the module link
-     */
-    @Override
-    protected Content getNavLinkModule() {
-        Content li = HtmlTree.LI(HtmlStyle.navBarCell1Rev, contents.moduleLabel);
-        return li;
-    }
 }
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/NestedClassWriterImpl.java	Mon Apr 09 08:34:30 2018 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/NestedClassWriterImpl.java	Tue Apr 10 13:58:47 2018 -0700
@@ -37,7 +37,7 @@
 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlConstants;
 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
-import jdk.javadoc.internal.doclets.formats.html.markup.Links;
+import jdk.javadoc.internal.doclets.formats.html.markup.Navigation;
 import jdk.javadoc.internal.doclets.formats.html.markup.StringContent;
 import jdk.javadoc.internal.doclets.toolkit.Content;
 import jdk.javadoc.internal.doclets.toolkit.MemberSummaryWriter;
@@ -205,31 +205,4 @@
     protected Content getDeprecatedLink(Element member) {
         return writer.getQualifiedClassLink(LinkInfoImpl.Kind.MEMBER, member);
     }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    protected Content getNavSummaryLink(TypeElement typeElement, boolean link) {
-        if (link) {
-            if (typeElement == null) {
-                return links.createLink(
-                        SectionName.NESTED_CLASS_SUMMARY,
-                        contents.navNested);
-            } else {
-                return links.createLink(
-                        SectionName.NESTED_CLASSES_INHERITANCE,
-                        utils.getFullyQualifiedName(typeElement), contents.navNested);
-            }
-        } else {
-            return contents.navNested;
-        }
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    protected void addNavDetailLink(boolean link, Content liNav) {
-    }
 }
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageIndexWriter.java	Mon Apr 09 08:34:30 2018 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageIndexWriter.java	Tue Apr 10 13:58:47 2018 -0700
@@ -209,7 +209,8 @@
                 ? HtmlTree.HEADER()
                 : body;
         addTop(tree);
-        addNavLinks(true, tree);
+        navBar.setUserHeader(getUserHeaderFooter(true));
+        tree.addContent(navBar.getContent(true));
         if (configuration.allowTag(HtmlTag.HEADER)) {
             body.addContent(tree);
         }
@@ -226,7 +227,8 @@
         Content tree = (configuration.allowTag(HtmlTag.FOOTER))
                 ? HtmlTree.FOOTER()
                 : body;
-        addNavLinks(false, tree);
+        navBar.setUserFooter(getUserHeaderFooter(false));
+        tree.addContent(navBar.getContent(false));
         addBottom(tree);
         if (configuration.allowTag(HtmlTag.FOOTER)) {
             body.addContent(tree);
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageTreeWriter.java	Mon Apr 09 08:34:30 2018 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageTreeWriter.java	Tue Apr 10 13:58:47 2018 -0700
@@ -31,6 +31,8 @@
 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag;
 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
+import jdk.javadoc.internal.doclets.formats.html.markup.Navigation;
+import jdk.javadoc.internal.doclets.formats.html.markup.Navigation.PageMode;
 import jdk.javadoc.internal.doclets.toolkit.Content;
 import jdk.javadoc.internal.doclets.toolkit.util.ClassTree;
 import jdk.javadoc.internal.doclets.toolkit.util.DocFileIOException;
@@ -57,6 +59,8 @@
      */
     protected PackageElement packageElement;
 
+    private final Navigation navBar;
+
     /**
      * Constructor.
      * @param configuration the configuration
@@ -67,6 +71,7 @@
         super(configuration, path,
               new ClassTree(configuration.typeElementCatalog.allClasses(packageElement), configuration));
         this.packageElement = packageElement;
+        this.navBar = new Navigation(packageElement, configuration, fixedNavDiv, PageMode.TREE, path);
     }
 
     /**
@@ -118,7 +123,8 @@
         HtmlTree tree = (configuration.allowTag(HtmlTag.FOOTER))
                 ? HtmlTree.FOOTER()
                 : body;
-        addNavLinks(false, tree);
+        navBar.setUserFooter(getUserHeaderFooter(false));
+        tree.addContent(navBar.getContent(false));
         addBottom(tree);
         if (configuration.allowTag(HtmlTag.FOOTER)) {
             body.addContent(tree);
@@ -139,7 +145,11 @@
                 ? HtmlTree.HEADER()
                 : bodyTree;
         addTop(htmlTree);
-        addNavLinks(true, htmlTree);
+        Content linkContent = getModuleLink(utils.elementUtils.getModuleOf(packageElement),
+                contents.moduleLabel);
+        navBar.setNavLinkModule(linkContent);
+        navBar.setUserHeader(getUserHeaderFooter(true));
+        htmlTree.addContent(navBar.getContent(true));
         if (configuration.allowTag(HtmlTag.HEADER)) {
             bodyTree.addContent(htmlTree);
         }
@@ -160,30 +170,4 @@
         ul.addContent(getNavLinkMainTree(configuration.getText("doclet.All_Packages")));
         div.addContent(ul);
     }
-
-    /**
-     * Get the module link.
-     *
-     * @return a content tree for the module link
-     */
-    @Override
-    protected Content getNavLinkModule() {
-        Content linkContent = getModuleLink(utils.elementUtils.getModuleOf(packageElement),
-                contents.moduleLabel);
-        Content li = HtmlTree.LI(linkContent);
-        return li;
-    }
-
-    /**
-     * Get link to the package summary page for the package of this tree.
-     *
-     * @return a content tree for the package link
-     */
-    @Override
-    protected Content getNavLinkPackage() {
-        Content linkContent = links.createLink(DocPaths.PACKAGE_SUMMARY,
-                contents.packageLabel);
-        Content li = HtmlTree.LI(linkContent);
-        return li;
-    }
 }
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageUseWriter.java	Mon Apr 09 08:34:30 2018 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageUseWriter.java	Tue Apr 10 13:58:47 2018 -0700
@@ -38,7 +38,8 @@
 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag;
 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
-import jdk.javadoc.internal.doclets.formats.html.markup.Links;
+import jdk.javadoc.internal.doclets.formats.html.markup.Navigation;
+import jdk.javadoc.internal.doclets.formats.html.markup.Navigation.PageMode;
 import jdk.javadoc.internal.doclets.formats.html.markup.StringContent;
 import jdk.javadoc.internal.doclets.toolkit.Content;
 import jdk.javadoc.internal.doclets.toolkit.util.ClassUseMapper;
@@ -63,6 +64,7 @@
     final SortedMap<String, Set<TypeElement>> usingPackageToUsedClasses = new TreeMap<>();
     protected HtmlTree mainTree = HtmlTree.MAIN();
     final String packageUseTableSummary;
+    private final Navigation navBar;
 
     /**
      * Constructor.
@@ -100,6 +102,7 @@
 
         packageUseTableSummary = resources.getText("doclet.Use_Table_Summary",
                 resources.getText("doclet.packages"));
+        this.navBar = new Navigation(packageElement, configuration, fixedNavDiv, PageMode.USE, path);
     }
 
     /**
@@ -140,7 +143,8 @@
         HtmlTree tree = (configuration.allowTag(HtmlTag.FOOTER))
                 ? HtmlTree.FOOTER()
                 : body;
-        addNavLinks(false, tree);
+        navBar.setUserFooter(getUserHeaderFooter(false));
+        tree.addContent(navBar.getContent(false));
         addBottom(tree);
         if (configuration.allowTag(HtmlTag.FOOTER)) {
             body.addContent(tree);
@@ -249,7 +253,11 @@
                 ? HtmlTree.HEADER()
                 : bodyTree;
         addTop(htmlTree);
-        addNavLinks(true, htmlTree);
+        Content linkContent = getModuleLink(utils.elementUtils.getModuleOf(packageElement),
+                contents.moduleLabel);
+        navBar.setNavLinkModule(linkContent);
+        navBar.setUserHeader(getUserHeaderFooter(true));
+        htmlTree.addContent(navBar.getContent(true));
         if (configuration.allowTag(HtmlTag.HEADER)) {
             bodyTree.addContent(htmlTree);
         }
@@ -267,54 +275,4 @@
         }
         return bodyTree;
     }
-
-    /**
-     * Get the module link.
-     *
-     * @return a content tree for the module link
-     */
-    @Override
-    protected Content getNavLinkModule() {
-        Content linkContent = getModuleLink(utils.elementUtils.getModuleOf(packageElement),
-                contents.moduleLabel);
-        Content li = HtmlTree.LI(linkContent);
-        return li;
-    }
-
-    /**
-     * Get this package link.
-     *
-     * @return a content tree for the package link
-     */
-    @Override
-    protected Content getNavLinkPackage() {
-        Content linkContent = links.createLink(DocPaths.PACKAGE_SUMMARY,
-                contents.packageLabel);
-        Content li = HtmlTree.LI(linkContent);
-        return li;
-    }
-
-    /**
-     * Get the use link.
-     *
-     * @return a content tree for the use link
-     */
-    @Override
-    protected Content getNavLinkClassUse() {
-        Content li = HtmlTree.LI(HtmlStyle.navBarCell1Rev, contents.useLabel);
-        return li;
-    }
-
-    /**
-     * Get the tree link.
-     *
-     * @return a content tree for the tree link
-     */
-    @Override
-    protected Content getNavLinkTree() {
-        Content linkContent = links.createLink(DocPaths.PACKAGE_TREE,
-                contents.treeLabel);
-        Content li = HtmlTree.LI(linkContent);
-        return li;
-    }
 }
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageWriterImpl.java	Mon Apr 09 08:34:30 2018 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageWriterImpl.java	Tue Apr 10 13:58:47 2018 -0700
@@ -40,12 +40,13 @@
 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag;
 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
+import jdk.javadoc.internal.doclets.formats.html.markup.Navigation;
+import jdk.javadoc.internal.doclets.formats.html.markup.Navigation.PageMode;
 import jdk.javadoc.internal.doclets.formats.html.markup.StringContent;
 import jdk.javadoc.internal.doclets.toolkit.Content;
 import jdk.javadoc.internal.doclets.toolkit.PackageSummaryWriter;
 import jdk.javadoc.internal.doclets.toolkit.util.CommentHelper;
 import jdk.javadoc.internal.doclets.toolkit.util.DocFileIOException;
-import jdk.javadoc.internal.doclets.toolkit.util.DocPath;
 import jdk.javadoc.internal.doclets.toolkit.util.DocPaths;
 
 /**
@@ -79,6 +80,8 @@
      */
     protected HtmlTree sectionTree = HtmlTree.SECTION();
 
+    private final Navigation navBar;
+
     /**
      * Constructor to construct PackageWriter object and to generate
      * "package-summary.html" file in the respective package directory.
@@ -95,6 +98,7 @@
                 configuration.docPaths.forPackage(packageElement)
                 .resolve(DocPaths.PACKAGE_SUMMARY));
         this.packageElement = packageElement;
+        this.navBar = new Navigation(packageElement, configuration, fixedNavDiv, PageMode.PACKAGE, path);
     }
 
     /**
@@ -107,7 +111,11 @@
                 ? HtmlTree.HEADER()
                 : bodyTree;
         addTop(htmlTree);
-        addNavLinks(true, htmlTree);
+        Content linkContent = getModuleLink(utils.elementUtils.getModuleOf(packageElement),
+                contents.moduleLabel);
+        navBar.setNavLinkModule(linkContent);
+        navBar.setUserHeader(getUserHeaderFooter(true));
+        htmlTree.addContent(navBar.getContent(true));
         if (configuration.allowTag(HtmlTag.HEADER)) {
             bodyTree.addContent(htmlTree);
         }
@@ -346,7 +354,8 @@
         Content htmlTree = (configuration.allowTag(HtmlTag.FOOTER))
                 ? HtmlTree.FOOTER()
                 : contentTree;
-        addNavLinks(false, htmlTree);
+        navBar.setUserFooter(getUserHeaderFooter(false));
+        htmlTree.addContent(navBar.getContent(false));
         addBottom(htmlTree);
         if (configuration.allowTag(HtmlTag.FOOTER)) {
             contentTree.addContent(htmlTree);
@@ -361,55 +370,4 @@
         printHtmlDocument(configuration.metakeywords.getMetaKeywords(packageElement),
                 true, contentTree);
     }
-
-    /**
-     * Get "Use" link for this pacakge in the navigation bar.
-     *
-     * @return a content tree for the class use link
-     */
-    @Override
-    protected Content getNavLinkClassUse() {
-        Content useLink = links.createLink(DocPaths.PACKAGE_USE,
-                contents.useLabel, "", "");
-        Content li = HtmlTree.LI(useLink);
-        return li;
-    }
-
-    /**
-     * Get "Tree" link in the navigation bar. This will be link to the package
-     * tree file.
-     *
-     * @return a content tree for the tree link
-     */
-    @Override
-    protected Content getNavLinkTree() {
-        Content useLink = links.createLink(DocPaths.PACKAGE_TREE,
-                contents.treeLabel, "", "");
-        Content li = HtmlTree.LI(useLink);
-        return li;
-    }
-
-    /**
-     * Get the module link.
-     *
-     * @return a content tree for the module link
-     */
-    @Override
-    protected Content getNavLinkModule() {
-        Content linkContent = getModuleLink(utils.elementUtils.getModuleOf(packageElement),
-                contents.moduleLabel);
-        Content li = HtmlTree.LI(linkContent);
-        return li;
-    }
-
-    /**
-     * Highlight "Package" in the navigation bar, as this is the package page.
-     *
-     * @return a content tree for the package link
-     */
-    @Override
-    protected Content getNavLinkPackage() {
-        Content li = HtmlTree.LI(HtmlStyle.navBarCell1Rev, contents.packageLabel);
-        return li;
-    }
 }
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PropertyWriterImpl.java	Mon Apr 09 08:34:30 2018 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PropertyWriterImpl.java	Tue Apr 10 13:58:47 2018 -0700
@@ -37,7 +37,7 @@
 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag;
 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
-import jdk.javadoc.internal.doclets.formats.html.markup.Links;
+import jdk.javadoc.internal.doclets.formats.html.markup.Navigation;
 import jdk.javadoc.internal.doclets.formats.html.markup.StringContent;
 import jdk.javadoc.internal.doclets.toolkit.Content;
 import jdk.javadoc.internal.doclets.toolkit.MemberSummaryWriter;
@@ -324,38 +324,4 @@
         return writer.getDocLink(LinkInfoImpl.Kind.MEMBER, member,
                 utils.getFullyQualifiedName(member));
     }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    protected Content getNavSummaryLink(TypeElement typeElement, boolean link) {
-        if (link) {
-            if (typeElement == null) {
-                return links.createLink(
-                        SectionName.PROPERTY_SUMMARY,
-                        contents.navProperty);
-            } else {
-                return links.createLink(
-                        SectionName.PROPERTIES_INHERITANCE,
-                        configuration.getClassName(typeElement), contents.navProperty);
-            }
-        } else {
-            return contents.navProperty;
-        }
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    protected void addNavDetailLink(boolean link, Content liNav) {
-        if (link) {
-            liNav.addContent(links.createLink(
-                    SectionName.PROPERTY_DETAIL,
-                    contents.navProperty));
-        } else {
-            liNav.addContent(contents.navProperty);
-        }
-    }
 }
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SerializedFormWriterImpl.java	Mon Apr 09 08:34:30 2018 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SerializedFormWriterImpl.java	Tue Apr 10 13:58:47 2018 -0700
@@ -33,6 +33,8 @@
 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag;
 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
+import jdk.javadoc.internal.doclets.formats.html.markup.Navigation;
+import jdk.javadoc.internal.doclets.formats.html.markup.Navigation.PageMode;
 import jdk.javadoc.internal.doclets.formats.html.markup.StringContent;
 import jdk.javadoc.internal.doclets.toolkit.Content;
 import jdk.javadoc.internal.doclets.toolkit.SerializedFormWriter;
@@ -59,12 +61,15 @@
      */
     private HtmlTree mainTree = HtmlTree.MAIN();
 
+    private final Navigation navBar;
+
     /**
      * @param configuration the configuration data for the doclet
      */
     public SerializedFormWriterImpl(HtmlConfiguration configuration) {
         super(configuration, DocPaths.SERIALIZED_FORM);
         visibleClasses = configuration.getIncludedTypeElements();
+        this.navBar = new Navigation(null, configuration, fixedNavDiv, PageMode.SERIALIZEDFORM, path);
     }
 
     /**
@@ -79,7 +84,8 @@
                 ? HtmlTree.HEADER()
                 : bodyTree;
         addTop(htmlTree);
-        addNavLinks(true, htmlTree);
+        navBar.setUserHeader(getUserHeaderFooter(true));
+        htmlTree.addContent(navBar.getContent(true));
         if (configuration.allowTag(HtmlTag.HEADER)) {
             bodyTree.addContent(htmlTree);
         }
@@ -261,7 +267,8 @@
         Content htmlTree = (configuration.allowTag(HtmlTag.FOOTER))
                 ? HtmlTree.FOOTER()
                 : serializedTree;
-        addNavLinks(false, htmlTree);
+        navBar.setUserFooter(getUserHeaderFooter(false));
+        htmlTree.addContent(navBar.getContent(false));
         addBottom(htmlTree);
         if (configuration.allowTag(HtmlTag.FOOTER)) {
             serializedTree.addContent(htmlTree);
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SingleIndexWriter.java	Mon Apr 09 08:34:30 2018 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SingleIndexWriter.java	Tue Apr 10 13:58:47 2018 -0700
@@ -97,7 +97,8 @@
                 ? HtmlTree.HEADER()
                 : body;
         addTop(htmlTree);
-        addNavLinks(true, htmlTree);
+        navBar.setUserHeader(getUserHeaderFooter(true));
+        htmlTree.addContent(navBar.getContent(true));
         if (configuration.allowTag(HtmlTag.HEADER)) {
             body.addContent(htmlTree);
         }
@@ -123,7 +124,8 @@
         if (configuration.allowTag(HtmlTag.FOOTER)) {
             htmlTree = HtmlTree.FOOTER();
         }
-        addNavLinks(false, htmlTree);
+        navBar.setUserFooter(getUserHeaderFooter(false));
+        htmlTree.addContent(navBar.getContent(false));
         addBottom(htmlTree);
         if (configuration.allowTag(HtmlTag.FOOTER)) {
             body.addContent(htmlTree);
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SplitIndexWriter.java	Mon Apr 09 08:34:30 2018 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SplitIndexWriter.java	Tue Apr 10 13:58:47 2018 -0700
@@ -125,7 +125,8 @@
                 ? HtmlTree.HEADER()
                 : body;
         addTop(htmlTree);
-        addNavLinks(true, htmlTree);
+        navBar.setUserHeader(getUserHeaderFooter(true));
+        htmlTree.addContent(navBar.getContent(true));
         if (configuration.allowTag(HtmlTag.HEADER)) {
             body.addContent(htmlTree);
         }
@@ -145,7 +146,8 @@
         if (configuration.allowTag(HtmlTag.FOOTER)) {
             htmlTree = HtmlTree.FOOTER();
         }
-        addNavLinks(false, htmlTree);
+        navBar.setUserFooter(getUserHeaderFooter(false));
+        htmlTree.addContent(navBar.getContent(false));
         addBottom(htmlTree);
         if (configuration.allowTag(HtmlTag.FOOTER)) {
             body.addContent(htmlTree);
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/TreeWriter.java	Mon Apr 09 08:34:30 2018 -0700
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/TreeWriter.java	Tue Apr 10 13:58:47 2018 -0700
@@ -33,7 +33,8 @@
 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTag;
 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree;
-import jdk.javadoc.internal.doclets.formats.html.markup.Links;
+import jdk.javadoc.internal.doclets.formats.html.markup.Navigation;
+import jdk.javadoc.internal.doclets.formats.html.markup.Navigation.PageMode;
 import jdk.javadoc.internal.doclets.formats.html.markup.StringContent;
 import jdk.javadoc.internal.doclets.toolkit.Content;
 import jdk.javadoc.internal.doclets.toolkit.util.ClassTree;
@@ -68,6 +69,8 @@
      */
     private final boolean classesOnly;
 
+    private final Navigation navBar;
+
     /**
      * Constructor to construct TreeWriter object.
      *
@@ -79,6 +82,7 @@
         super(configuration, filename, classtree);
         packages = configuration.packages;
         classesOnly = packages.isEmpty();
+        this.navBar = new Navigation(null, configuration, fixedNavDiv, PageMode.TREE, path);
     }
 
     /**
@@ -127,7 +131,8 @@
         } else {
             htmlTree = body;
         }
-        addNavLinks(false, htmlTree);
+        navBar.setUserFooter(getUserHeaderFooter(false));
+        htmlTree.addContent(navBar.getContent(false));
         addBottom(htmlTree);
         if (configuration.allowTag(HtmlTag.FOOTER)) {
             body.addContent(htmlTree);
@@ -186,7 +191,8 @@
                 ? HtmlTree.HEADER()
                 : bodyTree;
         addTop(htmlTree);
-        addNavLinks(true, htmlTree);
+        navBar.setUserHeader(getUserHeaderFooter(true));
+        htmlTree.addContent(navBar.getContent(true));
         if (configuration.allowTag(HtmlTag.HEADER)) {
             bodyTree.addContent(htmlTree);
         }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Navigation.java	Tue Apr 10 13:58:47 2018 -0700
@@ -0,0 +1,1089 @@
+/*
+ * Copyright (c) 2018, 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.javadoc.internal.doclets.formats.html.markup;
+
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Deque;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.SortedSet;
+
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.ModuleElement;
+import javax.lang.model.element.PackageElement;
+import javax.lang.model.element.TypeElement;
+
+import jdk.javadoc.internal.doclets.formats.html.AbstractMemberWriter;
+import jdk.javadoc.internal.doclets.formats.html.Contents;
+import jdk.javadoc.internal.doclets.formats.html.HtmlConfiguration;
+import jdk.javadoc.internal.doclets.formats.html.SectionName;
+import jdk.javadoc.internal.doclets.toolkit.Content;
+import jdk.javadoc.internal.doclets.toolkit.builders.MemberSummaryBuilder;
+import jdk.javadoc.internal.doclets.toolkit.util.DocFile;
+import jdk.javadoc.internal.doclets.toolkit.util.DocLink;
+import jdk.javadoc.internal.doclets.toolkit.util.DocPath;
+import jdk.javadoc.internal.doclets.toolkit.util.DocPaths;
+import jdk.javadoc.internal.doclets.toolkit.util.VisibleMemberMap;
+
+/**
+ * Factory for navigation bar.
+ *
+ * <p>
+ * <b>This is NOT part of any supported API. If you write code that depends on this, you do so at
+ * your own risk. This code and its internal interfaces are subject to change or deletion without
+ * notice.</b>
+ */
+public class Navigation {
+
+    private final HtmlConfiguration configuration;
+    private final Element element;
+    private final Contents contents;
+    private final DocPath path;
+    private final DocPath pathToRoot;
+    private final Links links;
+    private final HtmlTree fixedNavDiv;
+    private final PageMode documentedPage;
+    private Content navLinkModule;
+    private Content navLinkPackage;
+    private Content navLinkClass;
+    private MemberSummaryBuilder memberSummaryBuilder;
+    private boolean displaySummaryModuleDescLink;
+    private boolean displaySummaryModulesLink;
+    private boolean displaySummaryPackagesLink;
+    private boolean displaySummaryServicesLink;
+    private final Map<Position, Deque<Content>> topBottomNavContents;
+    private Content userHeader;
+    private Content userFooter;
+    private final String rowListTitle;
+    private final Content searchLabel;
+    private static final Script FIXED_NAV_SCRIPT = new Script("<!--\n"
+            + "$('.navPadding').css('padding-top', $('.fixedNav').css(\"height\"));\n"
+            + "//-->\n");
+
+    public enum PageMode {
+        CLASS,
+        CONSTANTVALUES,
+        DEPRECATED,
+        DOCFILE,
+        HELP,
+        INDEX,
+        MODULE,
+        OVERVIEW,
+        PACKAGE,
+        SERIALIZEDFORM,
+        TREE,
+        USE;
+    }
+
+    enum Position {
+        BOTTOM("allclasses_navbar_bottom", HtmlConstants.START_OF_BOTTOM_NAVBAR, HtmlConstants.END_OF_BOTTOM_NAVBAR),
+        TOP("allclasses_navbar_top", HtmlConstants.START_OF_TOP_NAVBAR, HtmlConstants.END_OF_TOP_NAVBAR);
+
+        final String allClassesLinkId;
+        final Content startOfNav;
+        final Content endOfNav;
+
+        Position(String allClassesLinkId, Content startOfNav, Content endOfNav) {
+            this.allClassesLinkId = allClassesLinkId;
+            this.startOfNav = startOfNav;
+            this.endOfNav = endOfNav;
+        }
+
+        String allClassesLinkId() {
+            return allClassesLinkId;
+        }
+
+        Content startOfNav() {
+            return startOfNav;
+        }
+
+        Content endOfNav() {
+            return endOfNav;
+        }
+
+        Script allClassesLinkScript() {
+            return new Script("<!--\n"
+                    + "  allClassesLink = document.getElementById(")
+                    .appendStringLiteral(allClassesLinkId)
+                    .append(");\n"
+                            + "  if(window==top) {\n"
+                            + "    allClassesLink.style.display = \"block\";\n"
+                            + "  }\n"
+                            + "  else {\n"
+                            + "    allClassesLink.style.display = \"none\";\n"
+                            + "  }\n"
+                            + "  //-->\n");
+        }
+    }
+
+    /**
+     * Creates a {@code Navigation} object for a specific file, to be written in a specific HTML
+     * version.
+     *
+     * @param element element being documented. null if its not an element documentation page
+     * @param configuration the configuration object
+     * @param fixedNavDiv the fixed navigation for the header navigation
+     * @param page the kind of page being documented
+     * @param path the DocPath object
+     */
+    public Navigation(Element element, HtmlConfiguration configuration, HtmlTree fixedNavDiv,
+            PageMode page, DocPath path) {
+        this.configuration = configuration;
+        this.element = element;
+        this.fixedNavDiv = fixedNavDiv;
+        this.contents = configuration.contents;
+        this.documentedPage = page;
+        this.path = path;
+        this.pathToRoot = path.parent().invert();
+        this.links = new Links(path, configuration.htmlVersion);
+        this.topBottomNavContents = new HashMap<>();
+        this.rowListTitle = configuration.getText("doclet.Navigation");
+        this.searchLabel = configuration.getContent("doclet.search");
+        populateNavContents(Position.TOP);
+        populateNavContents(Position.BOTTOM);
+    }
+
+    /**
+     * Populate the navigation contents for top and bottom navigation
+     *
+     * @param position the position of the navigation bar on the page
+     */
+    private void populateNavContents(Position position) {
+        Deque<Content> queue = new ArrayDeque<>();
+        Content skipNavLinks = configuration.getContent("doclet.Skip_navigation_links");
+        switch (position) {
+            case TOP:
+                queue.addLast(links.createAnchor(SectionName.NAVBAR_TOP));
+                queue.addLast(links.createLink(SectionName.SKIP_NAVBAR_TOP, skipNavLinks,
+                        skipNavLinks.toString(), ""));
+                queue.addLast(links.createAnchor(SectionName.NAVBAR_TOP_FIRSTROW));
+                queue.addLast(links.createAnchor(SectionName.SKIP_NAVBAR_TOP));
+                topBottomNavContents.put(position, queue);
+                break;
+            case BOTTOM:
+                queue.addLast(links.createAnchor(SectionName.NAVBAR_BOTTOM));
+                queue.addLast(links.createLink(SectionName.SKIP_NAVBAR_BOTTOM, skipNavLinks,
+                        skipNavLinks.toString(), ""));
+                queue.addLast(links.createAnchor(SectionName.NAVBAR_BOTTOM_FIRSTROW));
+                queue.addLast(links.createAnchor(SectionName.SKIP_NAVBAR_BOTTOM));
+                topBottomNavContents.put(position, queue);
+                break;
+            default:
+                break;
+        }
+    }
+
+    public Navigation setNavLinkModule(Content navLinkModule) {
+        this.navLinkModule = navLinkModule;
+        return this;
+    }
+
+    public Navigation setNavLinkPackage(Content navLinkPackage) {
+        this.navLinkPackage = navLinkPackage;
+        return this;
+    }
+
+    public Navigation setNavLinkClass(Content navLinkClass) {
+        this.navLinkClass = navLinkClass;
+        return this;
+    }
+
+    public Navigation setMemberSummaryBuilder(MemberSummaryBuilder memberSummaryBuilder) {
+        this.memberSummaryBuilder = memberSummaryBuilder;
+        return this;
+    }
+
+    public Navigation setDisplaySummaryModuleDescLink(boolean displaySummaryModuleDescLink) {
+        this.displaySummaryModuleDescLink = displaySummaryModuleDescLink;
+        return this;
+    }
+
+    public Navigation setDisplaySummaryModulesLink(boolean displaySummaryModulesLink) {
+        this.displaySummaryModulesLink = displaySummaryModulesLink;
+        return this;
+    }
+
+    public Navigation setDisplaySummaryPackagesLink(boolean displaySummaryPackagesLink) {
+        this.displaySummaryPackagesLink = displaySummaryPackagesLink;
+        return this;
+    }
+
+    public Navigation setDisplaySummaryServicesLink(boolean displaySummaryServicesLink) {
+        this.displaySummaryServicesLink = displaySummaryServicesLink;
+        return this;
+    }
+
+    public Navigation setUserHeader(Content userHeader) {
+        this.userHeader = userHeader;
+        return this;
+    }
+
+    public Navigation setUserFooter(Content userFooter) {
+        this.userFooter = userFooter;
+        return this;
+    }
+
+    /**
+     * Add the links for the main navigation.
+     *
+     * @param tree the content tree to which the main navigation will added
+     */
+    private void addMainNavLinks(Content tree) {
+        switch (documentedPage) {
+            case OVERVIEW:
+                addActivePageLink(tree, contents.overviewLabel, configuration.createoverview);
+                addModuleLink(tree);
+                addPackageLink(tree);
+                addPageLabel(tree, contents.classLabel, true);
+                addPageLabel(tree, contents.useLabel, configuration.classuse);
+                addTreeLink(tree);
+                addDeprecatedLink(tree);
+                addIndexLink(tree);
+                addHelpLink(tree);
+                break;
+            case MODULE:
+                addOverviewLink(tree);
+                addActivePageLink(tree, contents.moduleLabel, configuration.showModules);
+                addPackageLink(tree);
+                addPageLabel(tree, contents.classLabel, true);
+                addPageLabel(tree, contents.useLabel, configuration.classuse);
+                addTreeLink(tree);
+                addDeprecatedLink(tree);
+                addIndexLink(tree);
+                addHelpLink(tree);
+                break;
+            case PACKAGE:
+                addOverviewLink(tree);
+                addModuleOfElementLink(tree);
+                addActivePageLink(tree, contents.packageLabel, true);
+                addPageLabel(tree, contents.classLabel, true);
+                if (configuration.classuse) {
+                    addContentToTree(tree, links.createLink(DocPaths.PACKAGE_USE,
+                            contents.useLabel, "", ""));
+                }
+                if (configuration.createtree) {
+                    addContentToTree(tree, links.createLink(DocPaths.PACKAGE_TREE,
+                            contents.treeLabel, "", ""));
+                }
+                addDeprecatedLink(tree);
+                addIndexLink(tree);
+                addHelpLink(tree);
+                break;
+            case CLASS:
+                addOverviewLink(tree);
+                addModuleOfElementLink(tree);
+                addPackageSummaryLink(tree);
+                addActivePageLink(tree, contents.classLabel, true);
+                if (configuration.classuse) {
+                    addContentToTree(tree, links.createLink(DocPaths.CLASS_USE.resolve(path.basename()),
+                            contents.useLabel));
+                }
+                if (configuration.createtree) {
+                    addContentToTree(tree, links.createLink(DocPaths.PACKAGE_TREE,
+                            contents.treeLabel, "", ""));
+                }
+                addDeprecatedLink(tree);
+                addIndexLink(tree);
+                addHelpLink(tree);
+                break;
+            case USE:
+                addOverviewLink(tree);
+                addModuleOfElementLink(tree);
+                if (element instanceof PackageElement) {
+                    addPackageSummaryLink(tree);
+                    addPageLabel(tree, contents.classLabel, true);
+                } else {
+                    addPackageOfElementLink(tree);
+                    addContentToTree(tree, navLinkClass);
+                }
+                addActivePageLink(tree, contents.useLabel, configuration.classuse);
+                if (element instanceof PackageElement) {
+                    addContentToTree(tree, links.createLink(DocPaths.PACKAGE_TREE, contents.treeLabel));
+                } else {
+                    addContentToTree(tree, configuration.utils.isEnclosingPackageIncluded((TypeElement) element)
+                            ? links.createLink(DocPath.parent.resolve(DocPaths.PACKAGE_TREE), contents.treeLabel)
+                            : links.createLink(pathToRoot.resolve(DocPaths.OVERVIEW_TREE), contents.treeLabel));
+                }
+                addDeprecatedLink(tree);
+                addIndexLink(tree);
+                addHelpLink(tree);
+                break;
+            case TREE:
+                addOverviewLink(tree);
+                if (element == null) {
+                    addPageLabel(tree, contents.moduleLabel, configuration.showModules);
+                    addPageLabel(tree, contents.packageLabel, true);
+                } else {
+                    addModuleOfElementLink(tree);
+                    addPackageSummaryLink(tree);
+                }
+                addPageLabel(tree, contents.classLabel, true);
+                addPageLabel(tree, contents.useLabel, configuration.classuse);
+                addActivePageLink(tree, contents.treeLabel, configuration.createtree);
+                addDeprecatedLink(tree);
+                addIndexLink(tree);
+                addHelpLink(tree);
+                break;
+            case DEPRECATED:
+            case INDEX:
+            case HELP:
+                addOverviewLink(tree);
+                addModuleLink(tree);
+                addPackageLink(tree);
+                addPageLabel(tree, contents.classLabel, true);
+                addPageLabel(tree, contents.useLabel, configuration.classuse);
+                addTreeLink(tree);
+                if (documentedPage == PageMode.DEPRECATED) {
+                    addActivePageLink(tree, contents.deprecatedLabel, !(configuration.nodeprecated
+                            || configuration.nodeprecatedlist));
+                } else {
+                    addDeprecatedLink(tree);
+                }
+                if (documentedPage == PageMode.INDEX) {
+                    addActivePageLink(tree, contents.indexLabel, configuration.createindex);
+                } else {
+                    addIndexLink(tree);
+                }
+                if (documentedPage == PageMode.HELP) {
+                    addActivePageLink(tree, contents.helpLabel, !configuration.nohelp);
+                } else {
+                    addHelpLink(tree);
+                }
+                break;
+            case CONSTANTVALUES:
+            case SERIALIZEDFORM:
+                addOverviewLink(tree);
+                addModuleLink(tree);
+                addPackageLink(tree);
+                addPageLabel(tree, contents.classLabel, true);
+                addPageLabel(tree, contents.useLabel, configuration.classuse);
+                addTreeLink(tree);
+                addDeprecatedLink(tree);
+                addIndexLink(tree);
+                addHelpLink(tree);
+                break;
+            case DOCFILE:
+                addOverviewLink(tree);
+                addModuleOfElementLink(tree);
+                addContentToTree(tree, navLinkPackage);
+                addPageLabel(tree, contents.classLabel, true);
+                addPageLabel(tree, contents.useLabel, configuration.classuse);
+                addTreeLink(tree);
+                addDeprecatedLink(tree);
+                addIndexLink(tree);
+                addHelpLink(tree);
+                break;
+            default:
+                break;
+        }
+    }
+
+    /**
+     * Add the summary links to the sub-navigation.
+     *
+     * @param tree the content tree to which the sub-navigation will added
+     */
+    private void addSummaryLinks(Content tree) {
+        List<Content> listContents = new ArrayList<>();
+        switch (documentedPage) {
+            case CLASS:
+                if (element.getKind() == ElementKind.ANNOTATION_TYPE) {
+                    addAnnotationTypeSummaryLink("doclet.navField",
+                            VisibleMemberMap.Kind.ANNOTATION_TYPE_FIELDS, listContents);
+                    addAnnotationTypeSummaryLink("doclet.navAnnotationTypeRequiredMember",
+                            VisibleMemberMap.Kind.ANNOTATION_TYPE_MEMBER_REQUIRED, listContents);
+                    addAnnotationTypeSummaryLink("doclet.navAnnotationTypeOptionalMember",
+                            VisibleMemberMap.Kind.ANNOTATION_TYPE_MEMBER_OPTIONAL, listContents);
+                } else {
+                    TypeElement typeElement = (TypeElement) element;
+                    for (VisibleMemberMap.Kind kind : VisibleMemberMap.Kind.summarySet) {
+                        if (kind == VisibleMemberMap.Kind.ENUM_CONSTANTS && !configuration.utils.isEnum(typeElement)) {
+                            continue;
+                        }
+                        if (kind == VisibleMemberMap.Kind.CONSTRUCTORS && configuration.utils.isEnum(typeElement)) {
+                            continue;
+                        }
+                        AbstractMemberWriter writer
+                                = ((AbstractMemberWriter) memberSummaryBuilder.getMemberSummaryWriter(kind));
+                        if (writer == null) {
+                            addContentToList(listContents,
+                                    contents.getContent(VisibleMemberMap.Kind.getNavLinkLabels(kind)));
+                        } else {
+                            addTypeSummaryLink(memberSummaryBuilder.members(kind),
+                                    memberSummaryBuilder.getVisibleMemberMap(kind), listContents);
+                        }
+                    }
+                }
+                if (!listContents.isEmpty()) {
+                    Content li = HtmlTree.LI(contents.summaryLabel);
+                    li.addContent(Contents.SPACE);
+                    tree.addContent(li);
+                    addListToNav(listContents, tree);
+                }
+                break;
+            case MODULE:
+                if (displaySummaryModuleDescLink) {
+                    addContentToList(listContents,
+                            links.createLink(SectionName.MODULE_DESCRIPTION, contents.navModuleDescription));
+                } else {
+                    addContentToList(listContents, contents.navModuleDescription);
+                }
+                if (displaySummaryModulesLink) {
+                    addContentToList(listContents,
+                            links.createLink(SectionName.MODULES, contents.navModules));
+                } else {
+                    addContentToList(listContents, contents.navModules);
+                }
+                if (displaySummaryPackagesLink) {
+                    addContentToList(listContents,
+                            links.createLink(SectionName.PACKAGES, contents.navPackages));
+                } else {
+                    addContentToList(listContents, contents.navPackages);
+                }
+                if (displaySummaryServicesLink) {
+                    addContentToList(listContents,
+                            links.createLink(SectionName.SERVICES, contents.navServices));
+                } else {
+                    addContentToList(listContents, contents.navServices);
+                }
+                if (!listContents.isEmpty()) {
+                    Content li = HtmlTree.LI(contents.moduleSubNavLabel);
+                    li.addContent(Contents.SPACE);
+                    tree.addContent(li);
+                    addListToNav(listContents, tree);
+                }
+                break;
+            default:
+                break;
+        }
+    }
+
+    /**
+     * Add the navigation summary link.
+     *
+     * @param members members to be linked
+     * @param visibleMemberMap the visible inherited members map
+     * @param listContents the list of contents
+     */
+    private void addTypeSummaryLink(SortedSet<? extends Element> members,
+            VisibleMemberMap visibleMemberMap, List<Content> listContents) {
+        if (!members.isEmpty()) {
+            addTypeSummaryLink(null, visibleMemberMap.kind, true, listContents);
+            return;
+        }
+
+        SortedSet<TypeElement> visibleClasses = visibleMemberMap.getVisibleClasses();
+        for (TypeElement t : visibleClasses) {
+            if (!configuration.getVisibleMemberMap(t, visibleMemberMap.kind).getLeafMembers().isEmpty()) {
+                addTypeSummaryLink(null, visibleMemberMap.kind, true, listContents);
+                return;
+            }
+        }
+        addTypeSummaryLink(null, visibleMemberMap.kind, false, listContents);
+    }
+
+    /**
+     * Add the navigation Type summary link.
+     *
+     * @param typeElement the Type being documented
+     * @param kind the kind of member being documented
+     * @param link true if the members are listed and need to be linked
+     * @param listContents the list of contents to which the summary will be added
+     */
+    private void addTypeSummaryLink(TypeElement typeElement, VisibleMemberMap.Kind kind, boolean link,
+            List<Content> listContents) {
+        switch (kind) {
+            case CONSTRUCTORS:
+                if (link) {
+                    addContentToList(listContents, links.createLink(SectionName.CONSTRUCTOR_SUMMARY,
+                            contents.navConstructor));
+                } else {
+                    addContentToList(listContents, contents.navConstructor);
+                }
+                break;
+            case ENUM_CONSTANTS:
+                if (link) {
+                    if (typeElement == null) {
+                        addContentToList(listContents, links.createLink(SectionName.ENUM_CONSTANT_SUMMARY,
+                                contents.navEnum));
+                    } else {
+                        addContentToList(listContents, links.createLink(
+                                SectionName.ENUM_CONSTANTS_INHERITANCE,
+                                configuration.getClassName(typeElement), contents.navEnum));
+                    }
+                } else {
+                    addContentToList(listContents, contents.navEnum);
+                }
+                break;
+            case FIELDS:
+                if (link) {
+                    if (typeElement == null) {
+                        addContentToList(listContents,
+                                links.createLink(SectionName.FIELD_SUMMARY, contents.navField));
+                    } else {
+                        addContentToList(listContents, links.createLink(SectionName.FIELDS_INHERITANCE,
+                                configuration.getClassName(typeElement), contents.navField));
+                    }
+                } else {
+                    addContentToList(listContents, contents.navField);
+                }
+                break;
+            case METHODS:
+                if (link) {
+                    if (typeElement == null) {
+                        addContentToList(listContents,
+                                links.createLink(SectionName.METHOD_SUMMARY, contents.navMethod));
+                    } else {
+                        addContentToList(listContents, links.createLink(SectionName.METHODS_INHERITANCE,
+                                configuration.getClassName(typeElement), contents.navMethod));
+                    }
+                } else {
+                    addContentToList(listContents, contents.navMethod);
+                }
+                break;
+            case INNER_CLASSES:
+                if (link) {
+                    if (typeElement == null) {
+                        addContentToList(listContents,
+                                links.createLink(SectionName.NESTED_CLASS_SUMMARY, contents.navNested));
+                    } else {
+                        addContentToList(listContents, links.createLink(SectionName.NESTED_CLASSES_INHERITANCE,
+                                configuration.utils.getFullyQualifiedName(typeElement), contents.navNested));
+                    }
+                } else {
+                    addContentToList(listContents, contents.navNested);
+                }
+                break;
+            case PROPERTIES:
+                if (link) {
+                    if (typeElement == null) {
+                        addContentToList(listContents,
+                                links.createLink(SectionName.PROPERTY_SUMMARY, contents.navProperty));
+                    } else {
+                        addContentToList(listContents, links.createLink(SectionName.PROPERTIES_INHERITANCE,
+                                configuration.getClassName(typeElement), contents.navProperty));
+                    }
+                } else {
+                    addContentToList(listContents, contents.navProperty);
+                }
+                break;
+            default:
+                break;
+        }
+    }
+
+    /**
+     * Add the navigation Type summary link.
+     *
+     * @param label the label to be added
+     * @param type the kind of member being documented
+     * @param listContents the list of contents to which the summary will be added
+     */
+    private void addAnnotationTypeSummaryLink(String label, VisibleMemberMap.Kind type, List<Content> listContents) {
+        AbstractMemberWriter writer = ((AbstractMemberWriter) memberSummaryBuilder.
+                getMemberSummaryWriter(type));
+        if (writer == null) {
+            addContentToList(listContents, contents.getContent(label));
+        } else {
+            boolean link = !memberSummaryBuilder.getVisibleMemberMap(type).noVisibleMembers();
+            switch (type) {
+                case ANNOTATION_TYPE_FIELDS:
+                    if (link) {
+                        addContentToList(listContents, links.createLink(SectionName.ANNOTATION_TYPE_FIELD_SUMMARY,
+                                contents.navField));
+                    } else {
+                        addContentToList(listContents, contents.navField);
+                    }
+                    break;
+                case ANNOTATION_TYPE_MEMBER_REQUIRED:
+                    if (link) {
+                        addContentToList(listContents, links.createLink(
+                                SectionName.ANNOTATION_TYPE_REQUIRED_ELEMENT_SUMMARY,
+                                contents.navAnnotationTypeRequiredMember));
+                    } else {
+                        addContentToList(listContents, contents.navAnnotationTypeRequiredMember);
+                    }
+                    break;
+                case ANNOTATION_TYPE_MEMBER_OPTIONAL:
+                    if (link) {
+                        addContentToList(listContents, links.createLink(
+                                SectionName.ANNOTATION_TYPE_OPTIONAL_ELEMENT_SUMMARY,
+                                contents.navAnnotationTypeOptionalMember));
+                    } else {
+                        addContentToList(listContents, contents.navAnnotationTypeOptionalMember);
+                    }
+                    break;
+                default:
+                    break;
+            }
+        }
+    }
+
+    /**
+     * Add the detail links to sub-navigation.
+     *
+     * @param tree the content tree to which the links will be added
+     */
+    private void addDetailLinks(Content tree) {
+        switch (documentedPage) {
+            case CLASS:
+                List<Content> listContents = new ArrayList<>();
+                if (element.getKind() == ElementKind.ANNOTATION_TYPE) {
+                    addAnnotationTypeDetailLink(listContents);
+                } else {
+                    TypeElement typeElement = (TypeElement) element;
+                    for (VisibleMemberMap.Kind kind : VisibleMemberMap.Kind.detailSet) {
+                        AbstractMemberWriter writer
+                                = ((AbstractMemberWriter) memberSummaryBuilder.
+                                        getMemberSummaryWriter(kind));
+                        if (kind == VisibleMemberMap.Kind.ENUM_CONSTANTS && !configuration.utils.isEnum(typeElement)) {
+                            continue;
+                        }
+                        if (kind == VisibleMemberMap.Kind.CONSTRUCTORS && configuration.utils.isEnum(typeElement)) {
+                            continue;
+                        }
+                        if (writer == null) {
+                            addContentToList(listContents, contents.getContent(VisibleMemberMap.Kind.getNavLinkLabels(kind)));
+                        } else {
+                            addTypeDetailLink(kind, !memberSummaryBuilder.members(kind).isEmpty(), listContents);
+                        }
+                    }
+                }
+                if (!listContents.isEmpty()) {
+                    Content li = HtmlTree.LI(contents.detailLabel);
+                    li.addContent(Contents.SPACE);
+                    tree.addContent(li);
+                    addListToNav(listContents, tree);
+                }
+                break;
+            default:
+                break;
+        }
+    }
+
+    /**
+     * Add the navigation Type detail link.
+     *
+     * @param kind the kind of member being documented
+     * @param link true if the members are listed and need to be linked
+     * @param listContents the list of contents to which the detail will be added.
+     */
+    protected void addTypeDetailLink(VisibleMemberMap.Kind kind, boolean link, List<Content> listContents) {
+        switch (kind) {
+            case CONSTRUCTORS:
+                if (link) {
+                    addContentToList(listContents, links.createLink(SectionName.CONSTRUCTOR_DETAIL, contents.navConstructor));
+                } else {
+                    addContentToList(listContents, contents.navConstructor);
+                }
+                break;
+            case ENUM_CONSTANTS:
+                if (link) {
+                    addContentToList(listContents, links.createLink(SectionName.ENUM_CONSTANT_DETAIL, contents.navEnum));
+                } else {
+                    addContentToList(listContents, contents.navEnum);
+                }
+                break;
+            case FIELDS:
+                if (link) {
+                    addContentToList(listContents, links.createLink(SectionName.FIELD_DETAIL, contents.navField));
+                } else {
+                    addContentToList(listContents, contents.navField);
+                }
+                break;
+            case METHODS:
+                if (link) {
+                    addContentToList(listContents, links.createLink(SectionName.METHOD_DETAIL, contents.navMethod));
+                } else {
+                    addContentToList(listContents, contents.navMethod);
+                }
+                break;
+            case PROPERTIES:
+                if (link) {
+                    addContentToList(listContents, links.createLink(SectionName.PROPERTY_DETAIL, contents.navProperty));
+                } else {
+                    addContentToList(listContents, contents.navProperty);
+                }
+                break;
+            default:
+                break;
+        }
+    }
+
+    /**
+     * Add the navigation Annotation Type detail link.
+     *
+     * @param listContents the list of contents to which the annotation detail will be added.
+     */
+    protected void addAnnotationTypeDetailLink(List<Content> listContents) {
+        TypeElement annotationType = (TypeElement) element;
+        AbstractMemberWriter writerField
+                = ((AbstractMemberWriter) memberSummaryBuilder.
+                        getMemberSummaryWriter(VisibleMemberMap.Kind.ANNOTATION_TYPE_FIELDS));
+        AbstractMemberWriter writerOptional
+                = ((AbstractMemberWriter) memberSummaryBuilder.
+                        getMemberSummaryWriter(VisibleMemberMap.Kind.ANNOTATION_TYPE_MEMBER_OPTIONAL));
+        AbstractMemberWriter writerRequired
+                = ((AbstractMemberWriter) memberSummaryBuilder.
+                        getMemberSummaryWriter(VisibleMemberMap.Kind.ANNOTATION_TYPE_MEMBER_REQUIRED));
+        if (writerField != null) {
+            addAnnotationTypeDetailLink(VisibleMemberMap.Kind.ANNOTATION_TYPE_FIELDS,
+                    !configuration.utils.getAnnotationFields(annotationType).isEmpty(),
+                    listContents);
+        } else {
+            addContentToList(listContents, contents.navField);
+        }
+        if (writerOptional != null) {
+            addAnnotationTypeDetailLink(VisibleMemberMap.Kind.ANNOTATION_TYPE_MEMBER_OPTIONAL,
+                    !annotationType.getAnnotationMirrors().isEmpty(), listContents);
+        } else if (writerRequired != null) {
+            addAnnotationTypeDetailLink(VisibleMemberMap.Kind.ANNOTATION_TYPE_MEMBER_REQUIRED,
+                    !annotationType.getAnnotationMirrors().isEmpty(), listContents);
+        } else {
+            addContentToList(listContents, contents.navAnnotationTypeMember);
+        }
+    }
+
+    /**
+     * Add the navigation Annotation Type detail link.
+     *
+     * @param type the kind of member being documented
+     * @param link true if the member details need to be linked
+     * @param listContents the list of contents to which the annotation detail will be added.
+     */
+    protected void addAnnotationTypeDetailLink(VisibleMemberMap.Kind type, boolean link, List<Content> listContents) {
+        switch (type) {
+            case ANNOTATION_TYPE_FIELDS:
+                if (link) {
+                    addContentToList(listContents, links.createLink(SectionName.ANNOTATION_TYPE_FIELD_DETAIL,
+                            contents.navField));
+                } else {
+                    addContentToList(listContents, contents.navField);
+                }
+                break;
+            case ANNOTATION_TYPE_MEMBER_REQUIRED:
+            case ANNOTATION_TYPE_MEMBER_OPTIONAL:
+                if (link) {
+                    addContentToList(listContents, links.createLink(SectionName.ANNOTATION_TYPE_ELEMENT_DETAIL,
+                            contents.navAnnotationTypeMember));
+                } else {
+                    addContentToList(listContents, contents.navAnnotationTypeMember);
+                }
+                break;
+            default:
+                break;
+        }
+    }
+
+    private void addContentToList(List<Content> listContents, Content tree) {
+        listContents.add(HtmlTree.LI(tree));
+    }
+
+    private void addContentToTree(Content tree, Content content) {
+        tree.addContent(HtmlTree.LI(content));
+    }
+
+    private void addListToNav(List<Content> listContents, Content tree) {
+        int count = 0;
+        for (Content liContent : listContents) {
+            if (count < listContents.size() - 1) {
+                liContent.addContent(Contents.SPACE);
+                liContent.addContent("|");
+                liContent.addContent(Contents.SPACE);
+            }
+            tree.addContent(liContent);
+            count++;
+        }
+    }
+
+    private void addActivePageLink(Content tree, Content label, boolean display) {
+        if (display) {
+            tree.addContent(HtmlTree.LI(HtmlStyle.navBarCell1Rev, label));
+        }
+    }
+
+    private void addPageLabel(Content tree, Content label, boolean display) {
+        if (display) {
+            tree.addContent(HtmlTree.LI(label));
+        }
+    }
+
+    private void addOverviewLink(Content tree) {
+        if (configuration.createoverview) {
+            tree.addContent(HtmlTree.LI(links.createLink(pathToRoot.resolve(DocPaths.overviewSummary(configuration.frames)),
+                    contents.overviewLabel, "", "")));
+        }
+    }
+
+    private void addModuleLink(Content tree) {
+        if (configuration.showModules) {
+            if (configuration.modules.size() == 1) {
+                ModuleElement mdle = configuration.modules.first();
+                boolean included = configuration.utils.isIncluded(mdle);
+                tree.addContent(HtmlTree.LI((included)
+                        ? links.createLink(pathToRoot.resolve(configuration.docPaths.moduleSummary(mdle)), contents.moduleLabel, "", "")
+                        : contents.moduleLabel));
+            } else if (!configuration.modules.isEmpty()) {
+                addPageLabel(tree, contents.moduleLabel, true);
+            }
+        }
+    }
+
+    private void addModuleOfElementLink(Content tree) {
+        if (configuration.showModules) {
+            tree.addContent(HtmlTree.LI(navLinkModule));
+        }
+    }
+
+    private void addPackageLink(Content tree) {
+        if (configuration.packages.size() == 1) {
+            PackageElement packageElement = configuration.packages.first();
+            boolean included = packageElement != null && configuration.utils.isIncluded(packageElement);
+            if (!included) {
+                for (PackageElement p : configuration.packages) {
+                    if (p.equals(packageElement)) {
+                        included = true;
+                        break;
+                    }
+                }
+            }
+            if (included || packageElement == null) {
+                tree.addContent(HtmlTree.LI(links.createLink(
+                        pathToRoot.resolve(configuration.docPaths.forPackage(packageElement).resolve(DocPaths.PACKAGE_SUMMARY)),
+                        contents.packageLabel)));
+            } else {
+                DocLink crossPkgLink = configuration.extern.getExternalLink(
+                        configuration.utils.getPackageName(packageElement), pathToRoot,
+                        DocPaths.PACKAGE_SUMMARY.getPath());
+                if (crossPkgLink != null) {
+                    tree.addContent(HtmlTree.LI(links.createLink(crossPkgLink, contents.packageLabel)));
+                } else {
+                    tree.addContent(HtmlTree.LI(contents.packageLabel));
+                }
+            }
+        } else if (!configuration.packages.isEmpty()) {
+            addPageLabel(tree, contents.packageLabel, true);
+        }
+    }
+
+    private void addPackageOfElementLink(Content tree) {
+        tree.addContent(HtmlTree.LI(links.createLink(DocPath.parent.resolve(DocPaths.PACKAGE_SUMMARY),
+                contents.packageLabel)));
+    }
+
+    private void addPackageSummaryLink(Content tree) {
+        tree.addContent(HtmlTree.LI(links.createLink(DocPaths.PACKAGE_SUMMARY, contents.packageLabel)));
+    }
+
+    private void addTreeLink(Content tree) {
+        if (configuration.createtree) {
+            List<PackageElement> packages = new ArrayList<>(configuration.getSpecifiedPackageElements());
+            DocPath docPath = packages.size() == 1 && configuration.getSpecifiedTypeElements().isEmpty()
+                    ? pathToRoot.resolve(configuration.docPaths.forPackage(packages.get(0)).resolve(DocPaths.PACKAGE_TREE))
+                    : pathToRoot.resolve(DocPaths.OVERVIEW_TREE);
+            tree.addContent(HtmlTree.LI(links.createLink(docPath, contents.treeLabel, "", "")));
+        }
+    }
+
+    private void addDeprecatedLink(Content tree) {
+        if (!(configuration.nodeprecated || configuration.nodeprecatedlist)) {
+            tree.addContent(HtmlTree.LI(links.createLink(pathToRoot.resolve(DocPaths.DEPRECATED_LIST),
+                    contents.deprecatedLabel, "", "")));
+        }
+    }
+
+    private void addIndexLink(Content tree) {
+        if (configuration.createindex) {
+            tree.addContent(HtmlTree.LI(links.createLink(pathToRoot.resolve(
+                    (configuration.splitindex
+                            ? DocPaths.INDEX_FILES.resolve(DocPaths.indexN(1))
+                            : DocPaths.INDEX_ALL)),
+                    contents.indexLabel, "", "")));
+        }
+    }
+
+    private void addHelpLink(Content tree) {
+        if (!configuration.nohelp) {
+            String helpfile = configuration.helpfile;
+            DocPath helpfilenm;
+            if (helpfile.isEmpty()) {
+                helpfilenm = DocPaths.HELP_DOC;
+            } else {
+                DocFile file = DocFile.createFileForInput(configuration, helpfile);
+                helpfilenm = DocPath.create(file.getName());
+            }
+            tree.addContent(HtmlTree.LI(links.createLink(pathToRoot.resolve(helpfilenm),
+                    contents.helpLabel, "", "")));
+        }
+    }
+
+    /**
+     * Add "FRAMES" link, to switch to the frame version of the output.
+     *
+     * @param tree the content tree to which the link will be added
+     */
+    private void addNavShowLists(Content tree) {
+        DocLink dl = new DocLink(pathToRoot.resolve(DocPaths.INDEX), path.getPath(), null);
+        Content framesContent = links.createLink(dl, contents.framesLabel, "", "_top");
+        tree.addContent(HtmlTree.LI(framesContent));
+    }
+
+    /**
+     * Add "NO FRAMES" link, to switch to the non-frame version of the output.
+     *
+     * @param tree the content tree to which the link will be added
+     */
+    private void addNavHideLists(Content tree) {
+        Content noFramesContent = links.createLink(path.basename(), contents.noFramesLabel, "", "_top");
+        tree.addContent(HtmlTree.LI(noFramesContent));
+    }
+
+    private void addNavLinkClassIndex(Content tree) {
+        Content allClassesContent = links.createLink(pathToRoot.resolve(
+                DocPaths.AllClasses(configuration.frames)),
+                contents.allClassesLabel, "", "");
+        tree.addContent(HtmlTree.LI(allClassesContent));
+    }
+
+    private void addSearch(Content tree) {
+        String searchValueId = "search";
+        String reset = "reset";
+        HtmlTree inputText = HtmlTree.INPUT("text", searchValueId, searchValueId);
+        HtmlTree inputReset = HtmlTree.INPUT(reset, reset, reset);
+        HtmlTree liInput = HtmlTree.LI(HtmlTree.LABEL(searchValueId, searchLabel));
+        liInput.addContent(inputText);
+        liInput.addContent(inputReset);
+        HtmlTree ulSearch = HtmlTree.UL(HtmlStyle.navListSearch, liInput);
+        tree.addContent(ulSearch);
+    }
+
+    private void addAllClassesLinkScript(Content tree, boolean top) {
+        Content div = HtmlTree.DIV(top
+                ? Position.TOP.allClassesLinkScript().asContent()
+                : Position.BOTTOM.allClassesLinkScript().asContent());
+        Content div_noscript = HtmlTree.DIV(contents.noScriptMessage);
+        Content noScript = HtmlTree.NOSCRIPT(div_noscript);
+        div.addContent(noScript);
+        tree.addContent(div);
+    }
+
+    private void addFixedNavScript(Content tree) {
+        tree.addContent(FIXED_NAV_SCRIPT.asContent());
+    }
+
+    /**
+     * Get the navigation content.
+     *
+     * @param top true if the top navigation bar is to be printed
+     * @return the navigation contents
+     */
+    public Content getContent(boolean top) {
+        Content contentTree = new ContentBuilder();
+        if (!configuration.nonavbar) {
+            Deque<Content> queue;
+            Content tree = (configuration.htmlVersion == HtmlVersion.HTML5)
+                    ? HtmlTree.NAV()
+                    : contentTree;
+            HtmlTree navDiv = new HtmlTree(HtmlTag.DIV);
+            if (top) {
+                queue = topBottomNavContents.get(Position.TOP);
+                fixedNavDiv.addContent(Position.TOP.startOfNav());
+                navDiv.setStyle(HtmlStyle.topNav);
+            } else {
+                queue = topBottomNavContents.get(Position.BOTTOM);
+                tree.addContent(Position.BOTTOM.startOfNav());
+                navDiv.setStyle(HtmlStyle.bottomNav);
+            }
+            navDiv.addContent(queue.poll());
+            HtmlTree skipLinkDiv = HtmlTree.DIV(HtmlStyle.skipNav, queue.poll());
+            navDiv.addContent(skipLinkDiv);
+            navDiv.addContent(queue.poll());
+            HtmlTree navList = new HtmlTree(HtmlTag.UL);
+            navList.setStyle(HtmlStyle.navList);
+            navList.addAttr(HtmlAttr.TITLE, rowListTitle);
+            fixedNavDiv.setStyle(HtmlStyle.fixedNav);
+            addMainNavLinks(navList);
+            navDiv.addContent(navList);
+            Content aboutDiv = HtmlTree.DIV(HtmlStyle.aboutLanguage, top ? userHeader : userFooter);
+            navDiv.addContent(aboutDiv);
+            if (top) {
+                fixedNavDiv.addContent(navDiv);
+            } else {
+                tree.addContent(navDiv);
+            }
+            HtmlTree subDiv = new HtmlTree(HtmlTag.DIV);
+            subDiv.setStyle(HtmlStyle.subNav);
+            HtmlTree ulFrames = new HtmlTree(HtmlTag.UL);
+            ulFrames.setStyle(HtmlStyle.navList);
+            if (!configuration.nonavbar) {
+                if (configuration.frames) {
+                    addNavShowLists(ulFrames);
+                    addNavHideLists(ulFrames);
+                }
+            }
+            subDiv.addContent(ulFrames);
+            HtmlTree ulAllClasses = new HtmlTree(HtmlTag.UL);
+            ulAllClasses.setStyle(HtmlStyle.navList);
+            ulAllClasses.addAttr(HtmlAttr.ID, top
+                    ? Position.TOP.allClassesLinkId()
+                    : Position.BOTTOM.allClassesLinkId());
+            addNavLinkClassIndex(ulAllClasses);
+            subDiv.addContent(ulAllClasses);
+            if (top && configuration.createindex) {
+                addSearch(subDiv);
+            }
+            addAllClassesLinkScript(subDiv, top);
+            HtmlTree div = new HtmlTree(HtmlTag.DIV);
+            // Add the summary links if present.
+            HtmlTree ulNavSummary = new HtmlTree(HtmlTag.UL);
+            ulNavSummary.setStyle(HtmlStyle.subNavList);
+            addSummaryLinks(ulNavSummary);
+            div.addContent(ulNavSummary);
+            // Add the detail links if present.
+            HtmlTree ulNavDetail = new HtmlTree(HtmlTag.UL);
+            ulNavDetail.setStyle(HtmlStyle.subNavList);
+            addDetailLinks(ulNavDetail);
+            div.addContent(ulNavDetail);
+            subDiv.addContent(div);
+            subDiv.addContent(queue.poll());
+            if (top) {
+                fixedNavDiv.addContent(subDiv);
+                fixedNavDiv.addContent(Position.TOP.endOfNav());
+                tree.addContent(fixedNavDiv);
+                HtmlTree paddingDiv = HtmlTree.DIV(HtmlStyle.navPadding, Contents.SPACE);
+                tree.addContent(paddingDiv);
+                addFixedNavScript(tree);
+            } else {
+                tree.addContent(subDiv);
+                tree.addContent(Position.BOTTOM.endOfNav());
+            }
+            return tree;
+        }
+        return contentTree;
+    }
+}
--- a/test/TestCommon.gmk	Mon Apr 09 08:34:30 2018 -0700
+++ b/test/TestCommon.gmk	Tue Apr 10 13:58:47 2018 -0700
@@ -446,7 +446,7 @@
 JTREG_BASIC_OPTIONS += -e:JDK8_HOME=${JT_JAVA}
 # Give aot tests access to Visual Studio installation
 ifneq ($(VS120COMNTOOLS), )
-  JTREG_BASIC_OPTIONS += -e:VS120COMNTOOLS=$(shell $(GETMIXEDPATH) "$(VS120COMNTOOLS)")
+  JTREG_BASIC_OPTIONS += -e:VS120COMNTOOLS="$(shell $(GETMIXEDPATH) "$(patsubst %\,%,$(VS120COMNTOOLS))")"
 endif
 # Set other vm and test options
 JTREG_TEST_OPTIONS += $(JAVA_ARGS:%=-javaoptions:%) $(JAVA_VM_ARGS:%=-vmoption:%)
--- a/test/jdk/java/util/Collection/IteratorMicroBenchmark.java	Mon Apr 09 08:34:30 2018 -0700
+++ b/test/jdk/java/util/Collection/IteratorMicroBenchmark.java	Tue Apr 10 13:58:47 2018 -0700
@@ -36,6 +36,7 @@
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Deque;
+import java.util.HashMap;
 import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
@@ -55,6 +56,7 @@
 import java.util.concurrent.ThreadLocalRandom;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.LongAdder;
+import java.util.function.UnaryOperator;
 import java.util.regex.Pattern;
 import java.util.stream.Stream;
 
@@ -75,6 +77,13 @@
         public Job(String name) { this.name = name; }
         public String name() { return name; }
         public abstract void work() throws Throwable;
+        public void run() {
+            try { work(); }
+            catch (Throwable ex) {
+                // current job cannot always be deduced from stacktrace.
+                throw new RuntimeException("Job failed: " + name(), ex);
+            }
+        }
     }
 
     final int iterations;
@@ -102,6 +111,7 @@
     static void forceFullGc() {
         CountDownLatch finalizeDone = new CountDownLatch(1);
         WeakReference<?> ref = new WeakReference<Object>(new Object() {
+            @SuppressWarnings("deprecation")
             protected void finalize() { finalizeDone.countDown(); }});
         try {
             for (int i = 0; i < 10; i++) {
@@ -123,7 +133,7 @@
      * compiling everything worth compiling.
      * Returns array of average times per job per run.
      */
-    long[] time0(List<Job> jobs) throws Throwable {
+    long[] time0(List<Job> jobs) {
         final int size = jobs.size();
         long[] nanoss = new long[size];
         for (int i = 0; i < size; i++) {
@@ -132,7 +142,7 @@
             long totalTime;
             int runs = 0;
             long startTime = System.nanoTime();
-            do { job.work(); runs++; }
+            do { job.run(); runs++; }
             while ((totalTime = System.nanoTime() - startTime) < warmupNanos);
             nanoss[i] = totalTime/runs;
         }
@@ -211,10 +221,6 @@
             System.out.println("the answer");
     }
 
-    private static <T> List<T> asSubList(List<T> list) {
-        return list.subList(0, list.size());
-    }
-
     private static <T> Iterable<T> backwards(final List<T> list) {
         return new Iterable<T>() {
             public Iterator<T> iterator() {
@@ -241,11 +247,32 @@
         new IteratorMicroBenchmark(args).run();
     }
 
+    HashMap<Class<?>, String> goodClassName = new HashMap<>();
+
+    String goodClassName(Class<?> klazz) {
+        return goodClassName.computeIfAbsent(
+            klazz,
+            k -> {
+                String simple = k.getSimpleName();
+                return (simple.equals("SubList")) // too simple!
+                    ? k.getName().replaceFirst(".*\\.", "")
+                    : simple;
+            });
+    }
+
+    static List<Integer> makeSubList(List<Integer> list) {
+        final ThreadLocalRandom rnd = ThreadLocalRandom.current();
+        int size = list.size();
+        if (size <= 2) return list.subList(0, size);
+        List<Integer> subList = list.subList(rnd.nextInt(0, 2),
+                                             size - rnd.nextInt(0, 2));
+        List<Integer> copy = new ArrayList<>(list);
+        subList.clear();
+        subList.addAll(copy);
+        return subList;
+    }
+
     void run() throws Throwable {
-//         System.out.printf(
-//             "iterations=%d size=%d, warmup=%1g, filter=\"%s\"%n",
-//             iterations, size, warmupSeconds, nameFilter);
-
         final ArrayList<Integer> al = new ArrayList<>(size);
 
         // Populate collections with random data
@@ -265,10 +292,14 @@
 
         ArrayList<Job> jobs = Stream.<Collection<Integer>>of(
                 al, ad, abq,
+                makeSubList(new ArrayList<>(al)),
                 new LinkedList<>(al),
+                makeSubList(new LinkedList<>(al)),
                 new PriorityQueue<>(al),
                 new Vector<>(al),
+                makeSubList(new Vector<>(al)),
                 new CopyOnWriteArrayList<>(al),
+                makeSubList(new CopyOnWriteArrayList<>(al)),
                 new ConcurrentLinkedQueue<>(al),
                 new ConcurrentLinkedDeque<>(al),
                 new LinkedBlockingQueue<>(al),
@@ -294,16 +325,25 @@
     Stream<Job> jobs(Collection<Integer> x) {
         return concatStreams(
             collectionJobs(x),
+
             (x instanceof Deque)
             ? dequeJobs((Deque<Integer>)x)
             : Stream.empty(),
+
             (x instanceof List)
             ? listJobs((List<Integer>)x)
             : Stream.empty());
     }
 
+    Object sneakyAdder(int[] sneakySum) {
+        return new Object() {
+            public int hashCode() { throw new AssertionError(); }
+            public boolean equals(Object z) {
+                sneakySum[0] += (int) z; return false; }};
+    }
+
     Stream<Job> collectionJobs(Collection<Integer> x) {
-        String klazz = x.getClass().getSimpleName();
+        final String klazz = goodClassName(x.getClass());
         return Stream.of(
             new Job(klazz + " iterate for loop") {
                 public void work() throws Throwable {
@@ -345,22 +385,28 @@
             new Job(klazz + " contains") {
                 public void work() throws Throwable {
                     int[] sum = new int[1];
-                    Object y = new Object() {
-                        public boolean equals(Object z) {
-                            sum[0] += (int) z; return false; }};
+                    Object sneakyAdder = sneakyAdder(sum);
                     for (int i = 0; i < iterations; i++) {
                         sum[0] = 0;
-                        if (x.contains(y)) throw new AssertionError();
+                        if (x.contains(sneakyAdder)) throw new AssertionError();
+                        check.sum(sum[0]);}}},
+            new Job(klazz + " containsAll") {
+                public void work() throws Throwable {
+                    int[] sum = new int[1];
+                    Collection<Object> sneakyAdderCollection =
+                        Collections.singleton(sneakyAdder(sum));
+                    for (int i = 0; i < iterations; i++) {
+                        sum[0] = 0;
+                        if (x.containsAll(sneakyAdderCollection))
+                            throw new AssertionError();
                         check.sum(sum[0]);}}},
             new Job(klazz + " remove(Object)") {
                 public void work() throws Throwable {
                     int[] sum = new int[1];
-                    Object y = new Object() {
-                        public boolean equals(Object z) {
-                            sum[0] += (int) z; return false; }};
+                    Object sneakyAdder = sneakyAdder(sum);
                     for (int i = 0; i < iterations; i++) {
                         sum[0] = 0;
-                        if (x.remove(y)) throw new AssertionError();
+                        if (x.remove(sneakyAdder)) throw new AssertionError();
                         check.sum(sum[0]);}}},
             new Job(klazz + " forEach") {
                 public void work() throws Throwable {
@@ -446,7 +492,7 @@
     }
 
     Stream<Job> dequeJobs(Deque<Integer> x) {
-        String klazz = x.getClass().getSimpleName();
+        String klazz = goodClassName(x.getClass());
         return Stream.of(
             new Job(klazz + " descendingIterator() loop") {
                 public void work() throws Throwable {
@@ -466,48 +512,50 @@
     }
 
     Stream<Job> listJobs(List<Integer> x) {
-        String klazz = x.getClass().getSimpleName();
+        final String klazz = goodClassName(x.getClass());
         return Stream.of(
-            new Job(klazz + " subList toArray()") {
+            new Job(klazz + " listIterator forward loop") {
                 public void work() throws Throwable {
-                    int size = x.size();
                     for (int i = 0; i < iterations; i++) {
-                        int total = Stream.of(x.subList(0, size / 2),
-                                              x.subList(size / 2, size))
-                            .mapToInt(subList -> {
-                                int sum = 0;
-                                for (Object o : subList.toArray())
-                                    sum += (Integer) o;
-                                return sum; })
-                            .sum();
-                        check.sum(total);}}},
-            new Job(klazz + " subList toArray(a)") {
+                        int sum = 0;
+                        ListIterator<Integer> it = x.listIterator();
+                        while (it.hasNext())
+                            sum += it.next();
+                        check.sum(sum);}}},
+            new Job(klazz + " listIterator backward loop") {
                 public void work() throws Throwable {
-                    int size = x.size();
+                    for (int i = 0; i < iterations; i++) {
+                        int sum = 0;
+                        ListIterator<Integer> it = x.listIterator(x.size());
+                        while (it.hasPrevious())
+                            sum += it.previous();
+                        check.sum(sum);}}},
+            new Job(klazz + " indexOf") {
+                public void work() throws Throwable {
+                    int[] sum = new int[1];
+                    Object sneakyAdder = sneakyAdder(sum);
                     for (int i = 0; i < iterations; i++) {
-                        int total = Stream.of(x.subList(0, size / 2),
-                                              x.subList(size / 2, size))
-                            .mapToInt(subList -> {
-                                int sum = 0;
-                                Integer[] a = new Integer[subList.size()];
-                                for (Object o : subList.toArray(a))
-                                    sum += (Integer) o;
-                                return sum; })
-                            .sum();
-                        check.sum(total);}}},
-            new Job(klazz + " subList toArray(empty)") {
+                        sum[0] = 0;
+                        if (x.indexOf(sneakyAdder) != -1)
+                            throw new AssertionError();
+                        check.sum(sum[0]);}}},
+            new Job(klazz + " lastIndexOf") {
                 public void work() throws Throwable {
-                    int size = x.size();
-                    Integer[] empty = new Integer[0];
+                    int[] sum = new int[1];
+                    Object sneakyAdder = sneakyAdder(sum);
                     for (int i = 0; i < iterations; i++) {
-                        int total = Stream.of(x.subList(0, size / 2),
-                                              x.subList(size / 2, size))
-                            .mapToInt(subList -> {
-                                int sum = 0;
-                                for (Object o : subList.toArray(empty))
-                                    sum += (Integer) o;
-                                return sum; })
-                            .sum();
-                        check.sum(total);}}});
+                        sum[0] = 0;
+                        if (x.lastIndexOf(sneakyAdder) != -1)
+                            throw new AssertionError();
+                        check.sum(sum[0]);}}},
+            new Job(klazz + " replaceAll") {
+                public void work() throws Throwable {
+                    int[] sum = new int[1];
+                    UnaryOperator<Integer> sneakyAdder =
+                        x -> { sum[0] += x; return x; };
+                    for (int i = 0; i < iterations; i++) {
+                        sum[0] = 0;
+                        x.replaceAll(sneakyAdder);
+                        check.sum(sum[0]);}}});
     }
 }
--- a/test/jdk/java/util/Collection/RemoveMicroBenchmark.java	Mon Apr 09 08:34:30 2018 -0700
+++ b/test/jdk/java/util/Collection/RemoveMicroBenchmark.java	Tue Apr 10 13:58:47 2018 -0700
@@ -27,7 +27,7 @@
  * @run main RemoveMicroBenchmark iterations=1 size=8 warmup=0
  */
 
-import static java.util.stream.Collectors.toList;
+import static java.util.stream.Collectors.toCollection;
 
 import java.lang.ref.WeakReference;
 import java.util.ArrayDeque;
@@ -35,6 +35,7 @@
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Deque;
+import java.util.HashMap;
 import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
@@ -47,6 +48,7 @@
 import java.util.concurrent.BlockingQueue;
 import java.util.concurrent.ConcurrentLinkedDeque;
 import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.LinkedBlockingDeque;
 import java.util.concurrent.LinkedBlockingQueue;
@@ -55,7 +57,7 @@
 import java.util.concurrent.ThreadLocalRandom;
 import java.util.concurrent.TimeUnit;
 import java.util.regex.Pattern;
-import java.util.function.Supplier;
+import java.util.stream.Stream;
 
 /**
  * Usage: [iterations=N] [size=N] [filter=REGEXP] [warmup=SECONDS]
@@ -72,25 +74,38 @@
         public Job(String name) { this.name = name; }
         public String name() { return name; }
         public abstract void work() throws Throwable;
+        public void run() {
+            try { work(); }
+            catch (Throwable ex) {
+                // current job cannot always be deduced from stacktrace.
+                throw new RuntimeException("Job failed: " + name(), ex);
+            }
+        }
     }
 
     final int iterations;
     final int size;             // number of elements in collections
     final double warmupSeconds;
     final long warmupNanos;
-    final Pattern filter;       // select subset of Jobs to run
+    final Pattern nameFilter;   // select subset of Jobs to run
     final boolean reverse;      // reverse order of Jobs
     final boolean shuffle;      // randomize order of Jobs
 
+    final ArrayList<Integer> elements; // contains size random Integers
+
     RemoveMicroBenchmark(String[] args) {
         iterations    = intArg(args, "iterations", 10_000);
         size          = intArg(args, "size", 1000);
         warmupSeconds = doubleArg(args, "warmup", 7.0);
-        filter        = patternArg(args, "filter");
+        nameFilter    = patternArg(args, "filter");
         reverse       = booleanArg(args, "reverse");
         shuffle       = booleanArg(args, "shuffle");
 
         warmupNanos = (long) (warmupSeconds * (1000L * 1000L * 1000L));
+
+        elements = ThreadLocalRandom.current().ints(size)
+            .mapToObj(x -> x)
+            .collect(toCollection(ArrayList::new));
     }
 
     // --------------- GC finalization infrastructure ---------------
@@ -99,6 +114,7 @@
     static void forceFullGc() {
         CountDownLatch finalizeDone = new CountDownLatch(1);
         WeakReference<?> ref = new WeakReference<Object>(new Object() {
+            @SuppressWarnings("deprecation")
             protected void finalize() { finalizeDone.countDown(); }});
         try {
             for (int i = 0; i < 10; i++) {
@@ -120,7 +136,7 @@
      * compiling everything worth compiling.
      * Returns array of average times per job per run.
      */
-    long[] time0(List<Job> jobs) throws Throwable {
+    long[] time0(List<Job> jobs) {
         final int size = jobs.size();
         long[] nanoss = new long[size];
         for (int i = 0; i < size; i++) {
@@ -129,7 +145,7 @@
             long totalTime;
             int runs = 0;
             long startTime = System.nanoTime();
-            do { job.work(); runs++; }
+            do { job.run(); runs++; }
             while ((totalTime = System.nanoTime() - startTime) < warmupNanos);
             nanoss[i] = totalTime/runs;
         }
@@ -203,22 +219,11 @@
         throw new IllegalArgumentException(val);
     }
 
-    private static List<Job> filter(Pattern filter, List<Job> jobs) {
-        return (filter == null) ? jobs
-            : jobs.stream()
-            .filter(job -> filter.matcher(job.name()).find())
-            .collect(toList());
-    }
-
     private static void deoptimize(int sum) {
         if (sum == 42)
             System.out.println("the answer");
     }
 
-    private static <T> List<T> asSubList(List<T> list) {
-        return list.subList(0, list.size());
-    }
-
     private static <T> Iterable<T> backwards(final List<T> list) {
         return new Iterable<T>() {
             public Iterator<T> iterator() {
@@ -245,66 +250,99 @@
         new RemoveMicroBenchmark(args).run();
     }
 
-    void run() throws Throwable {
-//         System.out.printf(
-//             "iterations=%d size=%d, warmup=%1g, filter=\"%s\"%n",
-//             iterations, size, warmupSeconds, filter);
+    HashMap<Class<?>, String> goodClassName = new HashMap<>();
 
-        final ArrayList<Integer> al = new ArrayList<>(size);
+    String goodClassName(Class<?> klazz) {
+        return goodClassName.computeIfAbsent(
+            klazz,
+            k -> {
+                String simple = k.getSimpleName();
+                return (simple.equals("SubList")) // too simple!
+                    ? k.getName().replaceFirst(".*\\.", "")
+                    : simple;
+            });
+    }
 
-        // Populate collections with random data
+    static List<Integer> makeSubList(List<Integer> list) {
         final ThreadLocalRandom rnd = ThreadLocalRandom.current();
-        for (int i = 0; i < size; i++)
-            al.add(rnd.nextInt(size));
+        int size = rnd.nextInt(4);
+        for (int i = size; i--> 0; )
+            list.add(rnd.nextInt());
+        int index = rnd.nextInt(size + 1);
+        return list.subList(index, index);
+    }
 
-        ArrayList<Job> jobs = new ArrayList<>();
+    private static <T> List<T> asSubList(List<T> list) {
+        return list.subList(0, list.size());
+    }
+
+    @SafeVarargs @SuppressWarnings("varargs")
+    private <T> Stream<T> concatStreams(Stream<T> ... streams) {
+        return Stream.of(streams).flatMap(s -> s);
+    }
 
-        List.<Collection<Integer>>of(
-            new ArrayList<>(),
-            new LinkedList<>(),
-            new Vector<>(),
-            new ArrayDeque<>(),
-            new PriorityQueue<>(),
-            new ArrayBlockingQueue<>(al.size()),
-            new ConcurrentLinkedQueue<>(),
-            new ConcurrentLinkedDeque<>(),
-            new LinkedBlockingQueue<>(),
-            new LinkedBlockingDeque<>(),
-            new LinkedTransferQueue<>(),
-            new PriorityBlockingQueue<>()).forEach(
-                x -> {
-                    String klazz = x.getClass().getSimpleName();
-                    jobs.addAll(collectionJobs(klazz, () -> x, al));
-                    if (x instanceof Queue) {
-                        Queue<Integer> queue = (Queue<Integer>) x;
-                        jobs.addAll(queueJobs(klazz, () -> queue, al));
-                    }
-                    if (x instanceof Deque) {
-                        Deque<Integer> deque = (Deque<Integer>) x;
-                        jobs.addAll(dequeJobs(klazz, () -> deque, al));
-                    }
-                    if (x instanceof BlockingQueue) {
-                        BlockingQueue<Integer> q = (BlockingQueue<Integer>) x;
-                        jobs.addAll(blockingQueueJobs(klazz, () -> q, al));
-                    }
-                    if (x instanceof BlockingDeque) {
-                        BlockingDeque<Integer> q = (BlockingDeque<Integer>) x;
-                        jobs.addAll(blockingDequeJobs(klazz, () -> q, al));
-                    }
-                    if (x instanceof List) {
-                        List<Integer> list = (List<Integer>) x;
-                        jobs.addAll(
-                            collectionJobs(
-                                klazz + " subList",
-                                () -> list.subList(0, x.size()),
-                                al));
-                    }
-                });
+    Class<?> topLevelClass(Object x) {
+        for (Class<?> k = x.getClass();; ) {
+            Class<?> enclosing = k.getEnclosingClass();
+            if (enclosing == null)
+                return k;
+            k = enclosing;
+        }
+    }
+
+    void run() throws Throwable {
+        ArrayList<Job> jobs = Stream.<Collection<Integer>>of(
+                new ArrayList<>(),
+                makeSubList(new ArrayList<>()),
+                new LinkedList<>(),
+                makeSubList(new LinkedList<>()),
+                new Vector<>(),
+                makeSubList(new Vector<>()),
+                new CopyOnWriteArrayList<>(),
+                makeSubList(new CopyOnWriteArrayList<>()),
+                new ArrayDeque<>(),
+                new PriorityQueue<>(),
+                new ArrayBlockingQueue<>(elements.size()),
+                new ConcurrentLinkedQueue<>(),
+                new ConcurrentLinkedDeque<>(),
+                new LinkedBlockingQueue<>(),
+                new LinkedBlockingDeque<>(),
+                new LinkedTransferQueue<>(),
+                new PriorityBlockingQueue<>())
+            .flatMap(x -> jobs(x))
+            .filter(job ->
+                nameFilter == null || nameFilter.matcher(job.name()).find())
+            .collect(toCollection(ArrayList::new));
 
         if (reverse) Collections.reverse(jobs);
         if (shuffle) Collections.shuffle(jobs);
 
-        time(filter(filter, jobs));
+        time(jobs);
+    }
+
+    Stream<Job> jobs(Collection<Integer> x) {
+        return concatStreams(
+            collectionJobs(x),
+
+            (CopyOnWriteArrayList.class.isAssignableFrom(topLevelClass(x)))
+            ? Stream.empty()
+            : iteratorRemoveJobs(x),
+
+            (x instanceof Queue)
+            ? queueJobs((Queue<Integer>)x)
+            : Stream.empty(),
+
+            (x instanceof Deque)
+            ? dequeJobs((Deque<Integer>)x)
+            : Stream.empty(),
+
+            (x instanceof BlockingQueue)
+            ? blockingQueueJobs((BlockingQueue<Integer>)x)
+            : Stream.empty(),
+
+            (x instanceof BlockingDeque)
+            ? blockingDequeJobs((BlockingDeque<Integer>)x)
+            : Stream.empty());
     }
 
     Collection<Integer> universeRecorder(int[] sum) {
@@ -323,75 +361,81 @@
             }};
     }
 
-    List<Job> collectionJobs(
-        String description,
-        Supplier<Collection<Integer>> supplier,
-        ArrayList<Integer> al) {
-        return List.of(
-            new Job(description + " removeIf") {
+    Stream<Job> collectionJobs(Collection<Integer> x) {
+        final String klazz = goodClassName(x.getClass());
+        return Stream.of(
+            new Job(klazz + " removeIf") {
                 public void work() throws Throwable {
-                    Collection<Integer> x = supplier.get();
                     int[] sum = new int[1];
                     for (int i = 0; i < iterations; i++) {
                         sum[0] = 0;
-                        x.addAll(al);
+                        x.addAll(elements);
                         x.removeIf(n -> { sum[0] += n; return true; });
                         check.sum(sum[0]);}}},
-            new Job(description + " removeIf rnd-two-pass") {
+            new Job(klazz + " removeIf rnd-two-pass") {
                 public void work() throws Throwable {
                     ThreadLocalRandom rnd = ThreadLocalRandom.current();
-                    Collection<Integer> x = supplier.get();
                     int[] sum = new int[1];
                     for (int i = 0; i < iterations; i++) {
                         sum[0] = 0;
-                        x.addAll(al);
+                        x.addAll(elements);
                         x.removeIf(n -> {
                             boolean b = rnd.nextBoolean();
                             if (b) sum[0] += n;
                             return b; });
                         x.removeIf(n -> { sum[0] += n; return true; });
                         check.sum(sum[0]);}}},
-            new Job(description + " removeAll") {
+            new Job(klazz + " removeAll") {
                 public void work() throws Throwable {
-                    Collection<Integer> x = supplier.get();
                     int[] sum = new int[1];
                     Collection<Integer> universe = universeRecorder(sum);
                     for (int i = 0; i < iterations; i++) {
                         sum[0] = 0;
-                        x.addAll(al);
+                        x.addAll(elements);
                         x.removeAll(universe);
                         check.sum(sum[0]);}}},
-            new Job(description + " retainAll") {
+            new Job(klazz + " retainAll") {
                 public void work() throws Throwable {
-                    Collection<Integer> x = supplier.get();
                     int[] sum = new int[1];
                     Collection<Integer> empty = emptyRecorder(sum);
                     for (int i = 0; i < iterations; i++) {
                         sum[0] = 0;
-                        x.addAll(al);
+                        x.addAll(elements);
                         x.retainAll(empty);
                         check.sum(sum[0]);}}},
-            new Job(description + " Iterator.remove") {
+            new Job(klazz + " clear") {
                 public void work() throws Throwable {
-                    Collection<Integer> x = supplier.get();
                     int[] sum = new int[1];
                     for (int i = 0; i < iterations; i++) {
                         sum[0] = 0;
-                        x.addAll(al);
+                        x.addAll(elements);
+                        x.forEach(e -> sum[0] += e);
+                        x.clear();
+                        check.sum(sum[0]);}}});
+    }
+
+    Stream<Job> iteratorRemoveJobs(Collection<Integer> x) {
+        final String klazz = goodClassName(x.getClass());
+        return Stream.of(
+             new Job(klazz + " Iterator.remove") {
+                public void work() throws Throwable {
+                    int[] sum = new int[1];
+                    for (int i = 0; i < iterations; i++) {
+                        sum[0] = 0;
+                        x.addAll(elements);
                         Iterator<Integer> it = x.iterator();
                         while (it.hasNext()) {
                             sum[0] += it.next();
                             it.remove();
                         }
                         check.sum(sum[0]);}}},
-            new Job(description + " Iterator.remove-rnd-two-pass") {
+            new Job(klazz + " Iterator.remove-rnd-two-pass") {
                 public void work() throws Throwable {
                     ThreadLocalRandom rnd = ThreadLocalRandom.current();
-                    Collection<Integer> x = supplier.get();
                     int[] sum = new int[1];
                     for (int i = 0; i < iterations; i++) {
                         sum[0] = 0;
-                        x.addAll(al);
+                        x.addAll(elements);
                         for (Iterator<Integer> it = x.iterator();
                              it.hasNext(); ) {
                             Integer e = it.next();
@@ -405,129 +449,103 @@
                             sum[0] += it.next();
                             it.remove();
                         }
-                        check.sum(sum[0]);}}},
-            new Job(description + " clear") {
-                public void work() throws Throwable {
-                    Collection<Integer> x = supplier.get();
-                    int[] sum = new int[1];
-                    for (int i = 0; i < iterations; i++) {
-                        sum[0] = 0;
-                        x.addAll(al);
-                        x.forEach(e -> sum[0] += e);
-                        x.clear();
                         check.sum(sum[0]);}}});
     }
 
-    List<Job> queueJobs(
-        String description,
-        Supplier<Queue<Integer>> supplier,
-        ArrayList<Integer> al) {
-        return List.of(
-            new Job(description + " poll()") {
+    Stream<Job> queueJobs(Queue<Integer> x) {
+        final String klazz = goodClassName(x.getClass());
+        return Stream.of(
+            new Job(klazz + " poll()") {
                 public void work() throws Throwable {
-                    Queue<Integer> x = supplier.get();
                     int[] sum = new int[1];
                     for (int i = 0; i < iterations; i++) {
                         sum[0] = 0;
-                        x.addAll(al);
+                        x.addAll(elements);
                         for (Integer e; (e = x.poll()) != null; )
                             sum[0] += e;
                         check.sum(sum[0]);}}});
     }
 
-    List<Job> dequeJobs(
-        String description,
-        Supplier<Deque<Integer>> supplier,
-        ArrayList<Integer> al) {
-        return List.of(
-            new Job(description + " descendingIterator().remove") {
+    Stream<Job> dequeJobs(Deque<Integer> x) {
+        final String klazz = goodClassName(x.getClass());
+        return Stream.of(
+            new Job(klazz + " descendingIterator().remove") {
                 public void work() throws Throwable {
-                    Deque<Integer> x = supplier.get();
                     int[] sum = new int[1];
                     for (int i = 0; i < iterations; i++) {
                         sum[0] = 0;
-                        x.addAll(al);
+                        x.addAll(elements);
                         Iterator<Integer> it = x.descendingIterator();
                         while (it.hasNext()) {
                             sum[0] += it.next();
                             it.remove();
                         }
                         check.sum(sum[0]);}}},
-            new Job(description + " pollFirst()") {
+            new Job(klazz + " pollFirst()") {
                 public void work() throws Throwable {
-                    Deque<Integer> x = supplier.get();
                     int[] sum = new int[1];
                     for (int i = 0; i < iterations; i++) {
                         sum[0] = 0;
-                        x.addAll(al);
+                        x.addAll(elements);
                         for (Integer e; (e = x.pollFirst()) != null; )
                             sum[0] += e;
                         check.sum(sum[0]);}}},
-            new Job(description + " pollLast()") {
+            new Job(klazz + " pollLast()") {
                 public void work() throws Throwable {
-                    Deque<Integer> x = supplier.get();
                     int[] sum = new int[1];
                     for (int i = 0; i < iterations; i++) {
                         sum[0] = 0;
-                        x.addAll(al);
+                        x.addAll(elements);
                         for (Integer e; (e = x.pollLast()) != null; )
                             sum[0] += e;
                         check.sum(sum[0]);}}});
     }
 
-    List<Job> blockingQueueJobs(
-        String description,
-        Supplier<BlockingQueue<Integer>> supplier,
-        ArrayList<Integer> al) {
-        return List.of(
-            new Job(description + " drainTo(sink)") {
+    Stream<Job> blockingQueueJobs(BlockingQueue<Integer> x) {
+        final String klazz = goodClassName(x.getClass());
+        return Stream.of(
+            new Job(klazz + " drainTo(sink)") {
                 public void work() throws Throwable {
-                    BlockingQueue<Integer> x = supplier.get();
                     ArrayList<Integer> sink = new ArrayList<>();
                     int[] sum = new int[1];
                     for (int i = 0; i < iterations; i++) {
                         sum[0] = 0;
                         sink.clear();
-                        x.addAll(al);
+                        x.addAll(elements);
                         x.drainTo(sink);
                         sink.forEach(e -> sum[0] += e);
                         check.sum(sum[0]);}}},
-            new Job(description + " drainTo(sink, n)") {
+            new Job(klazz + " drainTo(sink, n)") {
                 public void work() throws Throwable {
-                    BlockingQueue<Integer> x = supplier.get();
                     ArrayList<Integer> sink = new ArrayList<>();
                     int[] sum = new int[1];
                     for (int i = 0; i < iterations; i++) {
                         sum[0] = 0;
                         sink.clear();
-                        x.addAll(al);
-                        x.drainTo(sink, al.size());
+                        x.addAll(elements);
+                        x.drainTo(sink, elements.size());
                         sink.forEach(e -> sum[0] += e);
                         check.sum(sum[0]);}}});
     }
 
-    List<Job> blockingDequeJobs(
-        String description,
-        Supplier<BlockingDeque<Integer>> supplier,
-        ArrayList<Integer> al) {
-        return List.of(
-            new Job(description + " timed pollFirst()") {
+    Stream<Job> blockingDequeJobs(BlockingDeque<Integer> x) {
+        final String klazz = goodClassName(x.getClass());
+        return Stream.of(
+            new Job(klazz + " timed pollFirst()") {
                 public void work() throws Throwable {
-                    BlockingDeque<Integer> x = supplier.get();
                     int[] sum = new int[1];
                     for (int i = 0; i < iterations; i++) {
                         sum[0] = 0;
-                        x.addAll(al);
+                        x.addAll(elements);
                         for (Integer e; (e = x.pollFirst(0L, TimeUnit.DAYS)) != null; )
                             sum[0] += e;
                         check.sum(sum[0]);}}},
-            new Job(description + " timed pollLast()") {
+            new Job(klazz + " timed pollLast()") {
                 public void work() throws Throwable {
-                    BlockingDeque<Integer> x = supplier.get();
                     int[] sum = new int[1];
                     for (int i = 0; i < iterations; i++) {
                         sum[0] = 0;
-                        x.addAll(al);
+                        x.addAll(elements);
                         for (Integer e; (e = x.pollLast(0L, TimeUnit.DAYS)) != null; )
                             sum[0] += e;
                         check.sum(sum[0]);}}});
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/util/concurrent/ConcurrentHashMap/WhiteBox.java	Tue Apr 10 13:58:47 2018 -0700
@@ -0,0 +1,155 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute 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.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * Written by Martin Buchholz with assistance from members of JCP
+ * JSR-166 Expert Group and released to the public domain, as
+ * explained at http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+/*
+ * @test
+ * @modules java.base/java.util.concurrent:open
+ * @run testng WhiteBox
+ * @summary White box tests of implementation details
+ */
+
+import static org.testng.Assert.*;
+import org.testng.annotations.Test;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ThreadLocalRandom;
+
+@Test
+public class WhiteBox {
+    final ThreadLocalRandom rnd = ThreadLocalRandom.current();
+    final VarHandle TABLE, NEXTTABLE, SIZECTL;
+
+    WhiteBox() throws ReflectiveOperationException {
+        Class<?> mClass = ConcurrentHashMap.class;
+        String nodeClassName = mClass.getName() + "$Node";
+        Class<?> nodeClass = Class.forName(nodeClassName);
+        Class<?> nodeArrayClass = Class.forName("[L" + nodeClassName + ";");
+        MethodHandles.Lookup lookup
+            = MethodHandles.privateLookupIn(mClass, MethodHandles.lookup());
+        TABLE = lookup.findVarHandle(mClass, "table", nodeArrayClass);
+        NEXTTABLE = lookup.findVarHandle(mClass, "nextTable", nodeArrayClass);
+        SIZECTL = lookup.findVarHandle(mClass, "sizeCtl", int.class);
+    }
+
+    Object[] table(ConcurrentHashMap m) { return (Object[]) TABLE.getVolatile(m); }
+    Object[] nextTable(ConcurrentHashMap m) { return (Object[]) NEXTTABLE.getVolatile(m); }
+    int sizeCtl(ConcurrentHashMap m) { return (int) SIZECTL.getVolatile(m); }
+
+    @Test
+    public void defaultConstructor() {
+        ConcurrentHashMap m = new ConcurrentHashMap();
+        assertNull(table(m));
+        assertEquals(sizeCtl(m), 0);
+        assertResizeNotInProgress(m);
+    }
+
+    @Test
+    public void shouldNotResizeWhenInitialCapacityProvided() {
+        int initialCapacity = rnd.nextInt(1, 100);
+        Object[] initialTable = null;
+        ConcurrentHashMap m = new ConcurrentHashMap(initialCapacity);
+
+        // table is lazily initialized
+        assertNull(table(m));
+        int expectedInitialTableLength = sizeCtl(m);
+
+        assertInvariants(m);
+        for (int i = 0; i < initialCapacity; i++) {
+            m.put(i * 100 + rnd.nextInt(100), i);
+            if (i == 0)
+                initialTable = table(m);
+            else
+                assertSame(table(m), initialTable);
+            assertInvariants(m);
+        }
+        assertEquals(initialTable.length, expectedInitialTableLength);
+    }
+
+    byte[] serialBytes(Object o) {
+        try {
+            ByteArrayOutputStream bos = new ByteArrayOutputStream();
+            ObjectOutputStream oos = new ObjectOutputStream(bos);
+            oos.writeObject(o);
+            oos.flush();
+            oos.close();
+            return bos.toByteArray();
+        } catch (Exception fail) {
+            throw new AssertionError(fail);
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    <T> T serialClone(T o) {
+        try {
+            ObjectInputStream ois = new ObjectInputStream
+                (new ByteArrayInputStream(serialBytes(o)));
+            T clone = (T) ois.readObject();
+            assertNotSame(o, clone);
+            assertSame(o.getClass(), clone.getClass());
+            return clone;
+        } catch (Exception fail) {
+            throw new AssertionError(fail);
+        }
+    }
+
+    @Test
+    public void testSerialization() {
+        assertInvariants(serialClone(new ConcurrentHashMap()));
+
+        ConcurrentHashMap m = new ConcurrentHashMap(rnd.nextInt(100));
+        m.put(1, 1);
+        ConcurrentHashMap clone = serialClone(m);
+        assertInvariants(clone);
+        assertNotSame(table(m), table(clone));
+        assertEquals(m, clone);
+        assertResizeNotInProgress(m);
+        assertResizeNotInProgress(clone);
+    }
+
+    /** Checks conditions which should always be true. */
+    void assertInvariants(ConcurrentHashMap m) {
+        if (!m.isEmpty())
+            assertNotNull(table(m));
+    }
+
+    void assertResizeNotInProgress(ConcurrentHashMap m) {
+        assertTrue(sizeCtl(m) >= 0);
+        assertNull(nextTable(m));
+    }
+}
--- a/test/jdk/java/util/concurrent/ConcurrentLinkedQueue/WhiteBox.java	Mon Apr 09 08:34:30 2018 -0700
+++ b/test/jdk/java/util/concurrent/ConcurrentLinkedQueue/WhiteBox.java	Tue Apr 10 13:58:47 2018 -0700
@@ -338,6 +338,7 @@
         }
     }
 
+    @Test
     public void testSerialization() {
         ConcurrentLinkedQueue q = serialClone(new ConcurrentLinkedQueue());
         assertInvariants(q);
--- a/test/jdk/java/util/concurrent/Executors/PrivilegedCallables.java	Mon Apr 09 08:34:30 2018 -0700
+++ b/test/jdk/java/util/concurrent/Executors/PrivilegedCallables.java	Tue Apr 10 13:58:47 2018 -0700
@@ -101,8 +101,7 @@
         final Policy policy = new Policy();
         Policy.setPolicy(policy);
         policy.setPermissions(new RuntimePermission("getClassLoader"),
-                              new RuntimePermission("setContextClassLoader"),
-                              new RuntimePermission("stopThread"));
+                              new RuntimePermission("setContextClassLoader"));
         System.setSecurityManager(new SecurityManager());
 
         testPrivileged();
--- a/test/jdk/java/util/concurrent/LinkedTransferQueue/WhiteBox.java	Mon Apr 09 08:34:30 2018 -0700
+++ b/test/jdk/java/util/concurrent/LinkedTransferQueue/WhiteBox.java	Tue Apr 10 13:58:47 2018 -0700
@@ -361,6 +361,7 @@
         }
     }
 
+    @Test
     public void testSerialization() {
         LinkedTransferQueue q = serialClone(new LinkedTransferQueue());
         assertInvariants(q);
--- a/test/jdk/java/util/concurrent/tck/Collection8Test.java	Mon Apr 09 08:34:30 2018 -0700
+++ b/test/jdk/java/util/concurrent/tck/Collection8Test.java	Tue Apr 10 13:58:47 2018 -0700
@@ -35,6 +35,7 @@
 import static java.util.concurrent.TimeUnit.HOURS;
 import static java.util.concurrent.TimeUnit.MILLISECONDS;
 
+import java.util.ArrayDeque;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -46,6 +47,7 @@
 import java.util.List;
 import java.util.NoSuchElementException;
 import java.util.Queue;
+import java.util.Set;
 import java.util.Spliterator;
 import java.util.concurrent.BlockingDeque;
 import java.util.concurrent.BlockingQueue;
@@ -86,8 +88,9 @@
 
     Object bomb() {
         return new Object() {
-            public boolean equals(Object x) { throw new AssertionError(); }
-            public int hashCode() { throw new AssertionError(); }
+            @Override public boolean equals(Object x) { throw new AssertionError(); }
+            @Override public int hashCode() { throw new AssertionError(); }
+            @Override public String toString() { throw new AssertionError(); }
         };
     }
 
@@ -119,6 +122,23 @@
         assertTrue(c.isEmpty());
         assertEquals(0, c.size());
         assertEquals("[]", c.toString());
+        if (c instanceof List<?>) {
+            List x = (List) c;
+            assertEquals(1, x.hashCode());
+            assertEquals(x, Collections.emptyList());
+            assertEquals(Collections.emptyList(), x);
+            assertEquals(-1, x.indexOf(impl.makeElement(86)));
+            assertEquals(-1, x.lastIndexOf(impl.makeElement(99)));
+            assertThrows(
+                IndexOutOfBoundsException.class,
+                () -> x.get(0),
+                () -> x.set(0, impl.makeElement(42)));
+        }
+        else if (c instanceof Set<?>) {
+            assertEquals(0, c.hashCode());
+            assertEquals(c, Collections.emptySet());
+            assertEquals(Collections.emptySet(), c);
+        }
         {
             Object[] a = c.toArray();
             assertEquals(0, a.length);
@@ -279,6 +299,16 @@
                 () -> d.pop(),
                 () -> d.descendingIterator().next());
         }
+        if (c instanceof List) {
+            List x = (List) c;
+            assertThrows(
+                NoSuchElementException.class,
+                () -> x.iterator().next(),
+                () -> x.listIterator().next(),
+                () -> x.listIterator(0).next(),
+                () -> x.listIterator().previous(),
+                () -> x.listIterator(0).previous());
+        }
     }
 
     public void testRemoveIf() {
@@ -904,6 +934,31 @@
         }
     }
 
+    public void testCollectionCopies() throws Exception {
+        ThreadLocalRandom rnd = ThreadLocalRandom.current();
+        Collection c = impl.emptyCollection();
+        for (int n = rnd.nextInt(4); n--> 0; )
+            c.add(impl.makeElement(rnd.nextInt()));
+        assertEquals(c, c);
+        if (c instanceof List)
+            assertCollectionsEquals(c, new ArrayList(c));
+        else if (c instanceof Set)
+            assertCollectionsEquals(c, new HashSet(c));
+        else if (c instanceof Deque)
+            assertCollectionsEquivalent(c, new ArrayDeque(c));
+
+        Collection clone = cloneableClone(c);
+        if (clone != null) {
+            assertSame(c.getClass(), clone.getClass());
+            assertCollectionsEquivalent(c, clone);
+        }
+        try {
+            Collection serialClone = serialClonePossiblyFailing(c);
+            assertSame(c.getClass(), serialClone.getClass());
+            assertCollectionsEquivalent(c, serialClone);
+        } catch (java.io.NotSerializableException acceptable) {}
+    }
+
 //     public void testCollection8DebugFail() {
 //         fail(impl.klazz().getSimpleName());
 //     }
--- a/test/jdk/java/util/concurrent/tck/CopyOnWriteArrayListTest.java	Mon Apr 09 08:34:30 2018 -0700
+++ b/test/jdk/java/util/concurrent/tck/CopyOnWriteArrayListTest.java	Tue Apr 10 13:58:47 2018 -0700
@@ -36,12 +36,13 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.Iterator;
-import java.util.LinkedList;
 import java.util.List;
 import java.util.ListIterator;
 import java.util.NoSuchElementException;
 import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.concurrent.ThreadLocalRandom;
 
 import junit.framework.Test;
 
@@ -61,7 +62,12 @@
         }
         class SubListImplementation extends Implementation {
             public List emptyCollection() {
-                return super.emptyCollection().subList(0, 0);
+                List list = super.emptyCollection();
+                ThreadLocalRandom rnd = ThreadLocalRandom.current();
+                if (rnd.nextBoolean())
+                    list.add(makeElement(rnd.nextInt()));
+                int i = rnd.nextInt(list.size() + 1);
+                return list.subList(i, i);
             }
         }
         return newTestSuite(
@@ -70,67 +76,67 @@
                 CollectionTest.testSuite(new SubListImplementation()));
     }
 
-    static CopyOnWriteArrayList<Integer> populatedArray(int n) {
-        CopyOnWriteArrayList<Integer> a = new CopyOnWriteArrayList<>();
-        assertTrue(a.isEmpty());
+    static CopyOnWriteArrayList<Integer> populatedList(int n) {
+        CopyOnWriteArrayList<Integer> list = new CopyOnWriteArrayList<>();
+        assertTrue(list.isEmpty());
         for (int i = 0; i < n; i++)
-            a.add(i);
-        assertFalse(a.isEmpty());
-        assertEquals(n, a.size());
-        return a;
+            list.add(i);
+        assertEquals(n <= 0, list.isEmpty());
+        assertEquals(n, list.size());
+        return list;
     }
 
-    static CopyOnWriteArrayList<Integer> populatedArray(Integer[] elements) {
-        CopyOnWriteArrayList<Integer> a = new CopyOnWriteArrayList<>();
-        assertTrue(a.isEmpty());
+    static CopyOnWriteArrayList<Integer> populatedList(Integer[] elements) {
+        CopyOnWriteArrayList<Integer> list = new CopyOnWriteArrayList<>();
+        assertTrue(list.isEmpty());
         for (Integer element : elements)
-            a.add(element);
-        assertFalse(a.isEmpty());
-        assertEquals(elements.length, a.size());
-        return a;
+            list.add(element);
+        assertFalse(list.isEmpty());
+        assertEquals(elements.length, list.size());
+        return list;
     }
 
     /**
      * a new list is empty
      */
     public void testConstructor() {
-        CopyOnWriteArrayList a = new CopyOnWriteArrayList();
-        assertTrue(a.isEmpty());
+        List list = new CopyOnWriteArrayList();
+        assertTrue(list.isEmpty());
     }
 
     /**
      * new list contains all elements of initializing array
      */
     public void testConstructor2() {
-        Integer[] ints = new Integer[SIZE];
+        Integer[] elts = new Integer[SIZE];
         for (int i = 0; i < SIZE - 1; ++i)
-            ints[i] = new Integer(i);
-        CopyOnWriteArrayList a = new CopyOnWriteArrayList(ints);
+            elts[i] = i;
+        List list = new CopyOnWriteArrayList(elts);
         for (int i = 0; i < SIZE; ++i)
-            assertEquals(ints[i], a.get(i));
+            assertEquals(elts[i], list.get(i));
     }
 
     /**
      * new list contains all elements of initializing collection
      */
     public void testConstructor3() {
-        Integer[] ints = new Integer[SIZE];
+        Integer[] elts = new Integer[SIZE];
         for (int i = 0; i < SIZE - 1; ++i)
-            ints[i] = new Integer(i);
-        CopyOnWriteArrayList a = new CopyOnWriteArrayList(Arrays.asList(ints));
+            elts[i] = i;
+        List list = new CopyOnWriteArrayList(Arrays.asList(elts));
         for (int i = 0; i < SIZE; ++i)
-            assertEquals(ints[i], a.get(i));
+            assertEquals(elts[i], list.get(i));
     }
 
     /**
      * addAll adds each element from the given collection, including duplicates
      */
     public void testAddAll() {
-        CopyOnWriteArrayList full = populatedArray(3);
-        assertTrue(full.addAll(Arrays.asList(three, four, five)));
-        assertEquals(6, full.size());
-        assertTrue(full.addAll(Arrays.asList(three, four, five)));
-        assertEquals(9, full.size());
+        List list = populatedList(3);
+        assertTrue(list.addAll(Arrays.asList(three, four, five)));
+        assertEquals(6, list.size());
+        assertTrue(list.addAll(Arrays.asList(three, four, five)));
+        assertEquals(9, list.size());
     }
 
     /**
@@ -138,46 +144,46 @@
      * already exist in the List
      */
     public void testAddAllAbsent() {
-        CopyOnWriteArrayList full = populatedArray(3);
+        CopyOnWriteArrayList list = populatedList(3);
         // "one" is duplicate and will not be added
-        assertEquals(2, full.addAllAbsent(Arrays.asList(three, four, one)));
-        assertEquals(5, full.size());
-        assertEquals(0, full.addAllAbsent(Arrays.asList(three, four, one)));
-        assertEquals(5, full.size());
+        assertEquals(2, list.addAllAbsent(Arrays.asList(three, four, one)));
+        assertEquals(5, list.size());
+        assertEquals(0, list.addAllAbsent(Arrays.asList(three, four, one)));
+        assertEquals(5, list.size());
     }
 
     /**
      * addIfAbsent will not add the element if it already exists in the list
      */
     public void testAddIfAbsent() {
-        CopyOnWriteArrayList full = populatedArray(SIZE);
-        full.addIfAbsent(one);
-        assertEquals(SIZE, full.size());
+        CopyOnWriteArrayList list = populatedList(SIZE);
+        list.addIfAbsent(one);
+        assertEquals(SIZE, list.size());
     }
 
     /**
      * addIfAbsent adds the element when it does not exist in the list
      */
     public void testAddIfAbsent2() {
-        CopyOnWriteArrayList full = populatedArray(SIZE);
-        full.addIfAbsent(three);
-        assertTrue(full.contains(three));
+        CopyOnWriteArrayList list = populatedList(SIZE);
+        list.addIfAbsent(three);
+        assertTrue(list.contains(three));
     }
 
     /**
      * clear removes all elements from the list
      */
     public void testClear() {
-        CopyOnWriteArrayList full = populatedArray(SIZE);
-        full.clear();
-        assertEquals(0, full.size());
+        List list = populatedList(SIZE);
+        list.clear();
+        assertEquals(0, list.size());
     }
 
     /**
      * Cloned list is equal
      */
     public void testClone() {
-        CopyOnWriteArrayList l1 = populatedArray(SIZE);
+        CopyOnWriteArrayList l1 = populatedList(SIZE);
         CopyOnWriteArrayList l2 = (CopyOnWriteArrayList)(l1.clone());
         assertEquals(l1, l2);
         l1.clear();
@@ -188,33 +194,33 @@
      * contains is true for added elements
      */
     public void testContains() {
-        CopyOnWriteArrayList full = populatedArray(3);
-        assertTrue(full.contains(one));
-        assertFalse(full.contains(five));
+        List list = populatedList(3);
+        assertTrue(list.contains(one));
+        assertFalse(list.contains(five));
     }
 
     /**
      * adding at an index places it in the indicated index
      */
     public void testAddIndex() {
-        CopyOnWriteArrayList full = populatedArray(3);
-        full.add(0, m1);
-        assertEquals(4, full.size());
-        assertEquals(m1, full.get(0));
-        assertEquals(zero, full.get(1));
+        List list = populatedList(3);
+        list.add(0, m1);
+        assertEquals(4, list.size());
+        assertEquals(m1, list.get(0));
+        assertEquals(zero, list.get(1));
 
-        full.add(2, m2);
-        assertEquals(5, full.size());
-        assertEquals(m2, full.get(2));
-        assertEquals(two, full.get(4));
+        list.add(2, m2);
+        assertEquals(5, list.size());
+        assertEquals(m2, list.get(2));
+        assertEquals(two, list.get(4));
     }
 
     /**
      * lists with same elements are equal and have same hashCode
      */
     public void testEquals() {
-        CopyOnWriteArrayList a = populatedArray(3);
-        CopyOnWriteArrayList b = populatedArray(3);
+        List a = populatedList(3);
+        List b = populatedList(3);
         assertTrue(a.equals(b));
         assertTrue(b.equals(a));
         assertTrue(a.containsAll(b));
@@ -239,15 +245,15 @@
      * containsAll returns true for collections with subset of elements
      */
     public void testContainsAll() {
-        CopyOnWriteArrayList full = populatedArray(3);
-        assertTrue(full.containsAll(Arrays.asList()));
-        assertTrue(full.containsAll(Arrays.asList(one)));
-        assertTrue(full.containsAll(Arrays.asList(one, two)));
-        assertFalse(full.containsAll(Arrays.asList(one, two, six)));
-        assertFalse(full.containsAll(Arrays.asList(six)));
+        List list = populatedList(3);
+        assertTrue(list.containsAll(Arrays.asList()));
+        assertTrue(list.containsAll(Arrays.asList(one)));
+        assertTrue(list.containsAll(Arrays.asList(one, two)));
+        assertFalse(list.containsAll(Arrays.asList(one, two, six)));
+        assertFalse(list.containsAll(Arrays.asList(six)));
 
         try {
-            full.containsAll(null);
+            list.containsAll(null);
             shouldThrow();
         } catch (NullPointerException success) {}
     }
@@ -256,37 +262,81 @@
      * get returns the value at the given index
      */
     public void testGet() {
-        CopyOnWriteArrayList full = populatedArray(3);
-        assertEquals(0, full.get(0));
+        List list = populatedList(3);
+        assertEquals(0, list.get(0));
     }
 
     /**
-     * indexOf gives the index for the given object
+     * indexOf(Object) returns the index of the first occurrence of the
+     * specified element in this list, or -1 if this list does not
+     * contain the element
      */
     public void testIndexOf() {
-        CopyOnWriteArrayList full = populatedArray(3);
-        assertEquals(1, full.indexOf(one));
-        assertEquals(-1, full.indexOf("puppies"));
+        List list = populatedList(3);
+        assertEquals(-1, list.indexOf(-42));
+        int size = list.size();
+        for (int i = 0; i < size; i++) {
+            assertEquals(i, list.indexOf(i));
+            assertEquals(i, list.subList(0, size).indexOf(i));
+            assertEquals(i, list.subList(0, i + 1).indexOf(i));
+            assertEquals(-1, list.subList(0, i).indexOf(i));
+            assertEquals(0, list.subList(i, size).indexOf(i));
+            assertEquals(-1, list.subList(i + 1, size).indexOf(i));
+        }
+
+        list.add(1);
+        assertEquals(1, list.indexOf(1));
+        assertEquals(1, list.subList(0, size + 1).indexOf(1));
+        assertEquals(0, list.subList(1, size + 1).indexOf(1));
+        assertEquals(size - 2, list.subList(2, size + 1).indexOf(1));
+        assertEquals(0, list.subList(size, size + 1).indexOf(1));
+        assertEquals(-1, list.subList(size + 1, size + 1).indexOf(1));
     }
 
     /**
-     * indexOf gives the index based on the given index
-     * at which to start searching
+     * indexOf(E, int) returns the index of the first occurrence of the
+     * specified element in this list, searching forwards from index,
+     * or returns -1 if the element is not found
      */
     public void testIndexOf2() {
-        CopyOnWriteArrayList full = populatedArray(3);
-        assertEquals(1, full.indexOf(one, 0));
-        assertEquals(-1, full.indexOf(one, 2));
+        CopyOnWriteArrayList list = populatedList(3);
+        int size = list.size();
+        assertEquals(-1, list.indexOf(-42, 0));
+
+        // we might expect IOOBE, but spec says otherwise
+        assertEquals(-1, list.indexOf(0, size));
+        assertEquals(-1, list.indexOf(0, Integer.MAX_VALUE));
+
+        assertThrows(
+            IndexOutOfBoundsException.class,
+            () -> list.indexOf(0, -1),
+            () -> list.indexOf(0, Integer.MIN_VALUE));
+
+        for (int i = 0; i < size; i++) {
+            assertEquals(i, list.indexOf(i, 0));
+            assertEquals(i, list.indexOf(i, i));
+            assertEquals(-1, list.indexOf(i, i + 1));
+        }
+
+        list.add(1);
+        assertEquals(1, list.indexOf(1, 0));
+        assertEquals(1, list.indexOf(1, 1));
+        assertEquals(size, list.indexOf(1, 2));
+        assertEquals(size, list.indexOf(1, size));
     }
 
     /**
      * isEmpty returns true when empty, else false
      */
     public void testIsEmpty() {
-        CopyOnWriteArrayList empty = new CopyOnWriteArrayList();
-        CopyOnWriteArrayList full = populatedArray(SIZE);
+        List empty = new CopyOnWriteArrayList();
         assertTrue(empty.isEmpty());
+        assertTrue(empty.subList(0, 0).isEmpty());
+
+        List full = populatedList(SIZE);
         assertFalse(full.isEmpty());
+        assertTrue(full.subList(0, 0).isEmpty());
+        assertTrue(full.subList(SIZE, SIZE).isEmpty());
     }
 
     /**
@@ -305,7 +355,7 @@
         for (int i = 0; i < SIZE; i++)
             elements[i] = i;
         shuffle(elements);
-        Collection<Integer> full = populatedArray(elements);
+        Collection<Integer> full = populatedList(elements);
 
         Iterator it = full.iterator();
         for (int j = 0; j < SIZE; j++) {
@@ -327,8 +377,8 @@
      * iterator.remove throws UnsupportedOperationException
      */
     public void testIteratorRemove() {
-        CopyOnWriteArrayList full = populatedArray(SIZE);
-        Iterator it = full.iterator();
+        CopyOnWriteArrayList list = populatedList(SIZE);
+        Iterator it = list.iterator();
         it.next();
         try {
             it.remove();
@@ -341,42 +391,78 @@
      */
     public void testToString() {
         assertEquals("[]", new CopyOnWriteArrayList().toString());
-        CopyOnWriteArrayList full = populatedArray(3);
-        String s = full.toString();
+        List list = populatedList(3);
+        String s = list.toString();
         for (int i = 0; i < 3; ++i)
             assertTrue(s.contains(String.valueOf(i)));
-        assertEquals(new ArrayList(full).toString(),
-                     full.toString());
+        assertEquals(new ArrayList(list).toString(),
+                     list.toString());
     }
 
     /**
-     * lastIndexOf returns the index for the given object
+     * lastIndexOf(Object) returns the index of the last occurrence of
+     * the specified element in this list, or -1 if this list does not
+     * contain the element
      */
     public void testLastIndexOf1() {
-        CopyOnWriteArrayList full = populatedArray(3);
-        full.add(one);
-        full.add(three);
-        assertEquals(3, full.lastIndexOf(one));
-        assertEquals(-1, full.lastIndexOf(six));
+        List list = populatedList(3);
+        assertEquals(-1, list.lastIndexOf(-42));
+        int size = list.size();
+        for (int i = 0; i < size; i++) {
+            assertEquals(i, list.lastIndexOf(i));
+            assertEquals(i, list.subList(0, size).lastIndexOf(i));
+            assertEquals(i, list.subList(0, i + 1).lastIndexOf(i));
+            assertEquals(-1, list.subList(0, i).lastIndexOf(i));
+            assertEquals(0, list.subList(i, size).lastIndexOf(i));
+            assertEquals(-1, list.subList(i + 1, size).lastIndexOf(i));
+        }
+
+        list.add(1);
+        assertEquals(size, list.lastIndexOf(1));
+        assertEquals(size, list.subList(0, size + 1).lastIndexOf(1));
+        assertEquals(1, list.subList(0, size).lastIndexOf(1));
+        assertEquals(0, list.subList(1, 2).lastIndexOf(1));
+        assertEquals(-1, list.subList(0, 1).indexOf(1));
     }
 
     /**
-     * lastIndexOf returns the index from the given starting point
+     * lastIndexOf(E, int) returns the index of the last occurrence of the
+     * specified element in this list, searching backwards from index, or
+     * returns -1 if the element is not found
      */
     public void testLastIndexOf2() {
-        CopyOnWriteArrayList full = populatedArray(3);
-        full.add(one);
-        full.add(three);
-        assertEquals(3, full.lastIndexOf(one, 4));
-        assertEquals(-1, full.lastIndexOf(three, 3));
+        CopyOnWriteArrayList list = populatedList(3);
+
+        // we might expect IOOBE, but spec says otherwise
+        assertEquals(-1, list.lastIndexOf(0, -1));
+
+        int size = list.size();
+        assertThrows(
+            IndexOutOfBoundsException.class,
+            () -> list.lastIndexOf(0, size),
+            () -> list.lastIndexOf(0, Integer.MAX_VALUE));
+
+        for (int i = 0; i < size; i++) {
+            assertEquals(i, list.lastIndexOf(i, i));
+            assertEquals(list.indexOf(i), list.lastIndexOf(i, i));
+            if (i > 0)
+                assertEquals(-1, list.lastIndexOf(i, i - 1));
+        }
+        list.add(one);
+        list.add(three);
+        assertEquals(1, list.lastIndexOf(one, 1));
+        assertEquals(1, list.lastIndexOf(one, 2));
+        assertEquals(3, list.lastIndexOf(one, 3));
+        assertEquals(3, list.lastIndexOf(one, 4));
+        assertEquals(-1, list.lastIndexOf(three, 3));
     }
 
     /**
      * listIterator traverses all elements
      */
     public void testListIterator1() {
-        CopyOnWriteArrayList full = populatedArray(SIZE);
-        ListIterator i = full.listIterator();
+        List list = populatedList(SIZE);
+        ListIterator i = list.listIterator();
         int j;
         for (j = 0; i.hasNext(); j++)
             assertEquals(j, i.next());
@@ -387,8 +473,8 @@
      * listIterator only returns those elements after the given index
      */
     public void testListIterator2() {
-        CopyOnWriteArrayList full = populatedArray(3);
-        ListIterator i = full.listIterator(1);
+        List list = populatedList(3);
+        ListIterator i = list.listIterator(1);
         int j;
         for (j = 0; i.hasNext(); j++)
             assertEquals(j + 1, i.next());
@@ -401,10 +487,10 @@
     public void testRemove_int() {
         int SIZE = 3;
         for (int i = 0; i < SIZE; i++) {
-            CopyOnWriteArrayList full = populatedArray(SIZE);
-            assertEquals(i, full.remove(i));
-            assertEquals(SIZE - 1, full.size());
-            assertFalse(full.contains(new Integer(i)));
+            List list = populatedList(SIZE);
+            assertEquals(i, list.remove(i));
+            assertEquals(SIZE - 1, list.size());
+            assertFalse(list.contains(new Integer(i)));
         }
     }
 
@@ -414,11 +500,11 @@
     public void testRemove_Object() {
         int SIZE = 3;
         for (int i = 0; i < SIZE; i++) {
-            CopyOnWriteArrayList full = populatedArray(SIZE);
-            assertFalse(full.remove(new Integer(-42)));
-            assertTrue(full.remove(new Integer(i)));
-            assertEquals(SIZE - 1, full.size());
-            assertFalse(full.contains(new Integer(i)));
+            List list = populatedList(SIZE);
+            assertFalse(list.remove(new Integer(-42)));
+            assertTrue(list.remove(new Integer(i)));
+            assertEquals(SIZE - 1, list.size());
+            assertFalse(list.contains(new Integer(i)));
         }
         CopyOnWriteArrayList x = new CopyOnWriteArrayList(Arrays.asList(4, 5, 6));
         assertTrue(x.remove(new Integer(6)));
@@ -434,30 +520,34 @@
      * removeAll removes all elements from the given collection
      */
     public void testRemoveAll() {
-        CopyOnWriteArrayList full = populatedArray(3);
-        assertTrue(full.removeAll(Arrays.asList(one, two)));
-        assertEquals(1, full.size());
-        assertFalse(full.removeAll(Arrays.asList(one, two)));
-        assertEquals(1, full.size());
+        List list = populatedList(3);
+        assertTrue(list.removeAll(Arrays.asList(one, two)));
+        assertEquals(1, list.size());
+        assertFalse(list.removeAll(Arrays.asList(one, two)));
+        assertEquals(1, list.size());
     }
 
     /**
      * set changes the element at the given index
      */
     public void testSet() {
-        CopyOnWriteArrayList full = populatedArray(3);
-        assertEquals(2, full.set(2, four));
-        assertEquals(4, full.get(2));
+        List list = populatedList(3);
+        assertEquals(2, list.set(2, four));
+        assertEquals(4, list.get(2));
     }
 
     /**
      * size returns the number of elements
      */
     public void testSize() {
-        CopyOnWriteArrayList empty = new CopyOnWriteArrayList();
-        CopyOnWriteArrayList full = populatedArray(SIZE);
+        List empty = new CopyOnWriteArrayList();
+        assertEquals(0, empty.size());
+        assertEquals(0, empty.subList(0, 0).size());
+
+        List full = populatedList(SIZE);
         assertEquals(SIZE, full.size());
-        assertEquals(0, empty.size());
+        assertEquals(0, full.subList(0, 0).size());
+        assertEquals(0, full.subList(SIZE, SIZE).size());
     }
 
     /**
@@ -473,7 +563,7 @@
         for (int i = 0; i < SIZE; i++)
             elements[i] = i;
         shuffle(elements);
-        Collection<Integer> full = populatedArray(elements);
+        Collection<Integer> full = populatedList(elements);
 
         assertTrue(Arrays.equals(elements, full.toArray()));
         assertSame(Object[].class, full.toArray().getClass());
@@ -501,7 +591,7 @@
         for (int i = 0; i < SIZE; i++)
             elements[i] = i;
         shuffle(elements);
-        Collection<Integer> full = populatedArray(elements);
+        Collection<Integer> full = populatedList(elements);
 
         Arrays.fill(a, 42);
         assertTrue(Arrays.equals(elements, full.toArray(a)));
@@ -527,7 +617,7 @@
      * sublists contains elements at indexes offset from their base
      */
     public void testSubList() {
-        CopyOnWriteArrayList a = populatedArray(10);
+        List a = populatedList(10);
         assertTrue(a.subList(1,1).isEmpty());
         for (int j = 0; j < 9; ++j) {
             for (int i = j ; i < 10; ++i) {
@@ -544,6 +634,11 @@
         assertEquals(a.get(4), m1);
         s.clear();
         assertEquals(7, a.size());
+
+        assertThrows(
+            IndexOutOfBoundsException.class,
+            () -> s.get(0),
+            () -> s.set(0, 42));
     }
 
     // Exception tests
@@ -553,231 +648,72 @@
      * can not store the objects inside the list
      */
     public void testToArray_ArrayStoreException() {
-        CopyOnWriteArrayList c = new CopyOnWriteArrayList();
-        c.add("zfasdfsdf");
-        c.add("asdadasd");
-        try {
-            c.toArray(new Long[5]);
-            shouldThrow();
-        } catch (ArrayStoreException success) {}
-    }
-
-    /**
-     * get throws an IndexOutOfBoundsException on a negative index
-     */
-    public void testGet1_IndexOutOfBoundsException() {
-        CopyOnWriteArrayList c = populatedArray(5);
-        List[] lists = { c, c.subList(1, c.size() - 1) };
-        for (List list : lists) {
-            try {
-                list.get(-1);
-                shouldThrow();
-            } catch (IndexOutOfBoundsException success) {}
-        }
-    }
-
-    /**
-     * get throws an IndexOutOfBoundsException on a too high index
-     */
-    public void testGet2_IndexOutOfBoundsException() {
-        CopyOnWriteArrayList c = populatedArray(5);
-        List[] lists = { c, c.subList(1, c.size() - 1) };
-        for (List list : lists) {
-            try {
-                list.get(list.size());
-                shouldThrow();
-            } catch (IndexOutOfBoundsException success) {}
-        }
-    }
-
-    /**
-     * set throws an IndexOutOfBoundsException on a negative index
-     */
-    public void testSet1_IndexOutOfBoundsException() {
-        CopyOnWriteArrayList c = populatedArray(5);
-        List[] lists = { c, c.subList(1, c.size() - 1) };
-        for (List list : lists) {
-            try {
-                list.set(-1, "qwerty");
-                shouldThrow();
-            } catch (IndexOutOfBoundsException success) {}
-        }
+        List list = new CopyOnWriteArrayList();
+        // Integers are not auto-converted to Longs
+        list.add(86);
+        list.add(99);
+        assertThrows(
+            ArrayStoreException.class,
+            () -> list.toArray(new Long[0]),
+            () -> list.toArray(new Long[5]));
     }
 
-    /**
-     * set throws an IndexOutOfBoundsException on a too high index
-     */
-    public void testSet2() {
-        CopyOnWriteArrayList c = populatedArray(5);
-        List[] lists = { c, c.subList(1, c.size() - 1) };
-        for (List list : lists) {
-            try {
-                list.set(list.size(), "qwerty");
-                shouldThrow();
-            } catch (IndexOutOfBoundsException success) {}
-        }
-    }
+    void testIndexOutOfBoundsException(List list) {
+        int size = list.size();
+        assertThrows(
+            IndexOutOfBoundsException.class,
+            () -> list.get(-1),
+            () -> list.get(size),
+            () -> list.set(-1, "qwerty"),
+            () -> list.set(size, "qwerty"),
+            () -> list.add(-1, "qwerty"),
+            () -> list.add(size + 1, "qwerty"),
+            () -> list.remove(-1),
+            () -> list.remove(size),
+            () -> list.addAll(-1, Collections.emptyList()),
+            () -> list.addAll(size + 1, Collections.emptyList()),
+            () -> list.listIterator(-1),
+            () -> list.listIterator(size + 1),
+            () -> list.subList(-1, size),
+            () -> list.subList(0, size + 1));
 
-    /**
-     * add throws an IndexOutOfBoundsException on a negative index
-     */
-    public void testAdd1_IndexOutOfBoundsException() {
-        CopyOnWriteArrayList c = populatedArray(5);
-        List[] lists = { c, c.subList(1, c.size() - 1) };
-        for (List list : lists) {
-            try {
-                list.add(-1, "qwerty");
-                shouldThrow();
-            } catch (IndexOutOfBoundsException success) {}
-        }
-    }
-
-    /**
-     * add throws an IndexOutOfBoundsException on a too high index
-     */
-    public void testAdd2_IndexOutOfBoundsException() {
-        CopyOnWriteArrayList c = populatedArray(5);
-        List[] lists = { c, c.subList(1, c.size() - 1) };
-        for (List list : lists) {
-            try {
-                list.add(list.size() + 1, "qwerty");
-                shouldThrow();
-            } catch (IndexOutOfBoundsException success) {}
-        }
-    }
-
-    /**
-     * remove throws an IndexOutOfBoundsException on a negative index
-     */
-    public void testRemove1_IndexOutOfBounds() {
-        CopyOnWriteArrayList c = populatedArray(5);
-        List[] lists = { c, c.subList(1, c.size() - 1) };
-        for (List list : lists) {
-            try {
-                list.remove(-1);
-                shouldThrow();
-            } catch (IndexOutOfBoundsException success) {}
-        }
+        // Conversely, operations that must not throw
+        list.addAll(0, Collections.emptyList());
+        list.addAll(size, Collections.emptyList());
+        list.add(0, "qwerty");
+        list.add(list.size(), "qwerty");
+        list.get(0);
+        list.get(list.size() - 1);
+        list.set(0, "azerty");
+        list.set(list.size() - 1, "azerty");
+        list.listIterator(0);
+        list.listIterator(list.size());
+        list.subList(0, list.size());
+        list.remove(list.size() - 1);
     }
 
     /**
-     * remove throws an IndexOutOfBoundsException on a too high index
-     */
-    public void testRemove2_IndexOutOfBounds() {
-        CopyOnWriteArrayList c = populatedArray(5);
-        List[] lists = { c, c.subList(1, c.size() - 1) };
-        for (List list : lists) {
-            try {
-                list.remove(list.size());
-                shouldThrow();
-            } catch (IndexOutOfBoundsException success) {}
-        }
-    }
-
-    /**
-     * addAll throws an IndexOutOfBoundsException on a negative index
+     * IndexOutOfBoundsException is thrown when specified
      */
-    public void testAddAll1_IndexOutOfBoundsException() {
-        CopyOnWriteArrayList c = populatedArray(5);
-        List[] lists = { c, c.subList(1, c.size() - 1) };
-        for (List list : lists) {
-            try {
-                list.addAll(-1, new LinkedList());
-                shouldThrow();
-            } catch (IndexOutOfBoundsException success) {}
-        }
-    }
-
-    /**
-     * addAll throws an IndexOutOfBoundsException on a too high index
-     */
-    public void testAddAll2_IndexOutOfBoundsException() {
-        CopyOnWriteArrayList c = populatedArray(5);
-        List[] lists = { c, c.subList(1, c.size() - 1) };
-        for (List list : lists) {
-            try {
-                list.addAll(list.size() + 1, new LinkedList());
-                shouldThrow();
-            } catch (IndexOutOfBoundsException success) {}
-        }
-    }
-
-    /**
-     * listIterator throws an IndexOutOfBoundsException on a negative index
-     */
-    public void testListIterator1_IndexOutOfBoundsException() {
-        CopyOnWriteArrayList c = populatedArray(5);
-        List[] lists = { c, c.subList(1, c.size() - 1) };
-        for (List list : lists) {
-            try {
-                list.listIterator(-1);
-                shouldThrow();
-            } catch (IndexOutOfBoundsException success) {}
-        }
-    }
+    public void testIndexOutOfBoundsException() {
+        ThreadLocalRandom rnd = ThreadLocalRandom.current();
+        List x = populatedList(rnd.nextInt(5));
+        testIndexOutOfBoundsException(x);
 
-    /**
-     * listIterator throws an IndexOutOfBoundsException on a too high index
-     */
-    public void testListIterator2_IndexOutOfBoundsException() {
-        CopyOnWriteArrayList c = populatedArray(5);
-        List[] lists = { c, c.subList(1, c.size() - 1) };
-        for (List list : lists) {
-            try {
-                list.listIterator(list.size() + 1);
-                shouldThrow();
-            } catch (IndexOutOfBoundsException success) {}
-        }
-    }
-
-    /**
-     * subList throws an IndexOutOfBoundsException on a negative index
-     */
-    public void testSubList1_IndexOutOfBoundsException() {
-        CopyOnWriteArrayList c = populatedArray(5);
-        List[] lists = { c, c.subList(1, c.size() - 1) };
-        for (List list : lists) {
-            try {
-                list.subList(-1, list.size());
-                shouldThrow();
-            } catch (IndexOutOfBoundsException success) {}
-        }
-    }
-
-    /**
-     * subList throws an IndexOutOfBoundsException on a too high index
-     */
-    public void testSubList2_IndexOutOfBoundsException() {
-        CopyOnWriteArrayList c = populatedArray(5);
-        List[] lists = { c, c.subList(1, c.size() - 1) };
-        for (List list : lists) {
-            try {
-                list.subList(0, list.size() + 1);
-                shouldThrow();
-            } catch (IndexOutOfBoundsException success) {}
-        }
-    }
-
-    /**
-     * subList throws IndexOutOfBoundsException when the second index
-     * is lower then the first
-     */
-    public void testSubList3_IndexOutOfBoundsException() {
-        CopyOnWriteArrayList c = populatedArray(5);
-        List[] lists = { c, c.subList(1, c.size() - 1) };
-        for (List list : lists) {
-            try {
-                list.subList(list.size() - 1, 1);
-                shouldThrow();
-            } catch (IndexOutOfBoundsException success) {}
-        }
+        int start = rnd.nextInt(x.size() + 1);
+        int end = rnd.nextInt(start, x.size() + 1);
+        assertThrows(
+            IndexOutOfBoundsException.class,
+            () -> x.subList(start, start - 1));
+        List subList = x.subList(start, end);
+        testIndexOutOfBoundsException(x);
     }
 
     /**
      * a deserialized/reserialized list equals original
      */
     public void testSerialization() throws Exception {
-        List x = populatedArray(SIZE);
+        List x = populatedList(SIZE);
         List y = serialClone(x);
 
         assertNotSame(x, y);
--- a/test/jdk/java/util/concurrent/tck/CopyOnWriteArraySetTest.java	Mon Apr 09 08:34:30 2018 -0700
+++ b/test/jdk/java/util/concurrent/tck/CopyOnWriteArraySetTest.java	Tue Apr 10 13:58:47 2018 -0700
@@ -49,7 +49,16 @@
         main(suite(), args);
     }
     public static Test suite() {
-        return new TestSuite(CopyOnWriteArraySetTest.class);
+        class Implementation implements CollectionImplementation {
+            public Class<?> klazz() { return CopyOnWriteArraySet.class; }
+            public Set emptyCollection() { return new CopyOnWriteArraySet(); }
+            public Object makeElement(int i) { return i; }
+            public boolean isConcurrent() { return true; }
+            public boolean permitsNulls() { return true; }
+        }
+        return newTestSuite(
+                CopyOnWriteArraySetTest.class,
+                CollectionTest.testSuite(new Implementation()));
     }
 
     static CopyOnWriteArraySet<Integer> populatedSet(int n) {
--- a/test/jdk/java/util/concurrent/tck/JSR166TestCase.java	Mon Apr 09 08:34:30 2018 -0700
+++ b/test/jdk/java/util/concurrent/tck/JSR166TestCase.java	Tue Apr 10 13:58:47 2018 -0700
@@ -93,11 +93,14 @@
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Date;
+import java.util.Deque;
 import java.util.Enumeration;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.NoSuchElementException;
 import java.util.PropertyPermission;
+import java.util.Set;
 import java.util.concurrent.BlockingQueue;
 import java.util.concurrent.Callable;
 import java.util.concurrent.CountDownLatch;
@@ -475,6 +478,7 @@
     public static boolean atLeastJava8()  { return JAVA_CLASS_VERSION >= 52.0; }
     public static boolean atLeastJava9()  { return JAVA_CLASS_VERSION >= 53.0; }
     public static boolean atLeastJava10() { return JAVA_CLASS_VERSION >= 54.0; }
+    public static boolean atLeastJava11() { return JAVA_CLASS_VERSION >= 55.0; }
 
     /**
      * Collects all JSR166 unit tests as one suite.
@@ -1473,26 +1477,6 @@
         }
     }
 
-    public abstract class RunnableShouldThrow implements Runnable {
-        protected abstract void realRun() throws Throwable;
-
-        final Class<?> exceptionClass;
-
-        <T extends Throwable> RunnableShouldThrow(Class<T> exceptionClass) {
-            this.exceptionClass = exceptionClass;
-        }
-
-        public final void run() {
-            try {
-                realRun();
-                threadShouldThrow(exceptionClass.getSimpleName());
-            } catch (Throwable t) {
-                if (! exceptionClass.isInstance(t))
-                    threadUnexpectedException(t);
-            }
-        }
-    }
-
     public abstract class ThreadShouldThrow extends Thread {
         protected abstract void realRun() throws Throwable;
 
@@ -2098,4 +2082,42 @@
         assertEquals(savedCompletedTaskCount, p.getCompletedTaskCount());
         assertEquals(savedQueueSize, p.getQueue().size());
     }
+
+    void assertCollectionsEquals(Collection<?> x, Collection<?> y) {
+        assertEquals(x, y);
+        assertEquals(y, x);
+        assertEquals(x.isEmpty(), y.isEmpty());
+        assertEquals(x.size(), y.size());
+        if (x instanceof List) {
+            assertEquals(x.toString(), y.toString());
+        }
+        if (x instanceof List || x instanceof Set) {
+            assertEquals(x.hashCode(), y.hashCode());
+        }
+        if (x instanceof List || x instanceof Deque) {
+            assertTrue(Arrays.equals(x.toArray(), y.toArray()));
+            assertTrue(Arrays.equals(x.toArray(new Object[0]),
+                                     y.toArray(new Object[0])));
+        }
+    }
+
+    /**
+     * A weaker form of assertCollectionsEquals which does not insist
+     * that the two collections satisfy Object#equals(Object), since
+     * they may use identity semantics as Deques do.
+     */
+    void assertCollectionsEquivalent(Collection<?> x, Collection<?> y) {
+        if (x instanceof List || x instanceof Set)
+            assertCollectionsEquals(x, y);
+        else {
+            assertEquals(x.isEmpty(), y.isEmpty());
+            assertEquals(x.size(), y.size());
+            assertEquals(new HashSet(x), new HashSet(y));
+            if (x instanceof Deque) {
+                assertTrue(Arrays.equals(x.toArray(), y.toArray()));
+                assertTrue(Arrays.equals(x.toArray(new Object[0]),
+                                         y.toArray(new Object[0])));
+            }
+        }
+    }
 }
--- a/test/jdk/java/util/concurrent/tck/LinkedListTest.java	Mon Apr 09 08:34:30 2018 -0700
+++ b/test/jdk/java/util/concurrent/tck/LinkedListTest.java	Tue Apr 10 13:58:47 2018 -0700
@@ -37,7 +37,9 @@
 import java.util.Collection;
 import java.util.Iterator;
 import java.util.LinkedList;
+import java.util.List;
 import java.util.NoSuchElementException;
+import java.util.concurrent.ThreadLocalRandom;
 
 import junit.framework.Test;
 
@@ -49,14 +51,19 @@
     public static Test suite() {
         class Implementation implements CollectionImplementation {
             public Class<?> klazz() { return LinkedList.class; }
-            public Collection emptyCollection() { return new LinkedList(); }
+            public List emptyCollection() { return new LinkedList(); }
             public Object makeElement(int i) { return i; }
             public boolean isConcurrent() { return false; }
             public boolean permitsNulls() { return true; }
         }
         class SubListImplementation extends Implementation {
-            public Collection emptyCollection() {
-                return new LinkedList().subList(0, 0);
+            public List emptyCollection() {
+                List list = super.emptyCollection();
+                ThreadLocalRandom rnd = ThreadLocalRandom.current();
+                if (rnd.nextBoolean())
+                    list.add(makeElement(rnd.nextInt()));
+                int i = rnd.nextInt(list.size() + 1);
+                return list.subList(i, i);
             }
         }
         return newTestSuite(
--- a/test/jdk/java/util/concurrent/tck/VectorTest.java	Mon Apr 09 08:34:30 2018 -0700
+++ b/test/jdk/java/util/concurrent/tck/VectorTest.java	Tue Apr 10 13:58:47 2018 -0700
@@ -32,8 +32,13 @@
  * http://creativecommons.org/publicdomain/zero/1.0/
  */
 
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
 import java.util.Vector;
-import java.util.List;
+import java.util.concurrent.ThreadLocalRandom;
 
 import junit.framework.Test;
 
@@ -52,7 +57,12 @@
         }
         class SubListImplementation extends Implementation {
             public List emptyCollection() {
-                return super.emptyCollection().subList(0, 0);
+                List list = super.emptyCollection();
+                ThreadLocalRandom rnd = ThreadLocalRandom.current();
+                if (rnd.nextBoolean())
+                    list.add(makeElement(rnd.nextInt()));
+                int i = rnd.nextInt(list.size() + 1);
+                return list.subList(i, i);
             }
         }
         return newTestSuite(
@@ -61,6 +71,393 @@
                 CollectionTest.testSuite(new SubListImplementation()));
     }
 
+    static Vector<Integer> populatedList(int n) {
+        Vector<Integer> list = new Vector<>();
+        assertTrue(list.isEmpty());
+        for (int i = 0; i < n; i++)
+            list.add(i);
+        assertEquals(n <= 0, list.isEmpty());
+        assertEquals(n, list.size());
+        return list;
+    }
+
+    /**
+     * addAll adds each element from the given collection, including duplicates
+     */
+    public void testAddAll() {
+        List list = populatedList(3);
+        assertTrue(list.addAll(Arrays.asList(three, four, five)));
+        assertEquals(6, list.size());
+        assertTrue(list.addAll(Arrays.asList(three, four, five)));
+        assertEquals(9, list.size());
+    }
+
+    /**
+     * clear removes all elements from the list
+     */
+    public void testClear() {
+        List list = populatedList(SIZE);
+        list.clear();
+        assertEquals(0, list.size());
+    }
+
+    /**
+     * Cloned list is equal
+     */
+    public void testClone() {
+        Vector l1 = populatedList(SIZE);
+        Vector l2 = (Vector)(l1.clone());
+        assertEquals(l1, l2);
+        l1.clear();
+        assertFalse(l1.equals(l2));
+    }
+
+    /**
+     * contains is true for added elements
+     */
+    public void testContains() {
+        List list = populatedList(3);
+        assertTrue(list.contains(one));
+        assertFalse(list.contains(five));
+    }
+
+    /**
+     * adding at an index places it in the indicated index
+     */
+    public void testAddIndex() {
+        List list = populatedList(3);
+        list.add(0, m1);
+        assertEquals(4, list.size());
+        assertEquals(m1, list.get(0));
+        assertEquals(zero, list.get(1));
+
+        list.add(2, m2);
+        assertEquals(5, list.size());
+        assertEquals(m2, list.get(2));
+        assertEquals(two, list.get(4));
+    }
+
+    /**
+     * lists with same elements are equal and have same hashCode
+     */
+    public void testEquals() {
+        List a = populatedList(3);
+        List b = populatedList(3);
+        assertTrue(a.equals(b));
+        assertTrue(b.equals(a));
+        assertTrue(a.containsAll(b));
+        assertTrue(b.containsAll(a));
+        assertEquals(a.hashCode(), b.hashCode());
+        a.add(m1);
+        assertFalse(a.equals(b));
+        assertFalse(b.equals(a));
+        assertTrue(a.containsAll(b));
+        assertFalse(b.containsAll(a));
+        b.add(m1);
+        assertTrue(a.equals(b));
+        assertTrue(b.equals(a));
+        assertTrue(a.containsAll(b));
+        assertTrue(b.containsAll(a));
+        assertEquals(a.hashCode(), b.hashCode());
+
+        assertFalse(a.equals(null));
+    }
+
+    /**
+     * containsAll returns true for collections with subset of elements
+     */
+    public void testContainsAll() {
+        List list = populatedList(3);
+        assertTrue(list.containsAll(Arrays.asList()));
+        assertTrue(list.containsAll(Arrays.asList(one)));
+        assertTrue(list.containsAll(Arrays.asList(one, two)));
+        assertFalse(list.containsAll(Arrays.asList(one, two, six)));
+        assertFalse(list.containsAll(Arrays.asList(six)));
+
+        try {
+            list.containsAll(null);
+            shouldThrow();
+        } catch (NullPointerException success) {}
+    }
+
+    /**
+     * get returns the value at the given index
+     */
+    public void testGet() {
+        List list = populatedList(3);
+        assertEquals(0, list.get(0));
+    }
+
+    /**
+     * indexOf(Object) returns the index of the first occurrence of the
+     * specified element in this list, or -1 if this list does not
+     * contain the element
+     */
+    public void testIndexOf() {
+        List list = populatedList(3);
+        assertEquals(-1, list.indexOf(-42));
+        int size = list.size();
+        for (int i = 0; i < size; i++) {
+            assertEquals(i, list.indexOf(i));
+            assertEquals(i, list.subList(0, size).indexOf(i));
+            assertEquals(i, list.subList(0, i + 1).indexOf(i));
+            assertEquals(-1, list.subList(0, i).indexOf(i));
+            assertEquals(0, list.subList(i, size).indexOf(i));
+            assertEquals(-1, list.subList(i + 1, size).indexOf(i));
+        }
+
+        list.add(1);
+        assertEquals(1, list.indexOf(1));
+        assertEquals(1, list.subList(0, size + 1).indexOf(1));
+        assertEquals(0, list.subList(1, size + 1).indexOf(1));
+        assertEquals(size - 2, list.subList(2, size + 1).indexOf(1));
+        assertEquals(0, list.subList(size, size + 1).indexOf(1));
+        assertEquals(-1, list.subList(size + 1, size + 1).indexOf(1));
+    }
+
+    /**
+     * indexOf(E, int) returns the index of the first occurrence of the
+     * specified element in this list, searching forwards from index,
+     * or returns -1 if the element is not found
+     */
+    public void testIndexOf2() {
+        Vector list = populatedList(3);
+        int size = list.size();
+        assertEquals(-1, list.indexOf(-42, 0));
+
+        // we might expect IOOBE, but spec says otherwise
+        assertEquals(-1, list.indexOf(0, size));
+        assertEquals(-1, list.indexOf(0, Integer.MAX_VALUE));
+
+        assertThrows(
+            IndexOutOfBoundsException.class,
+            () -> list.indexOf(0, -1),
+            () -> list.indexOf(0, Integer.MIN_VALUE));
+
+        for (int i = 0; i < size; i++) {
+            assertEquals(i, list.indexOf(i, 0));
+            assertEquals(i, list.indexOf(i, i));
+            assertEquals(-1, list.indexOf(i, i + 1));
+        }
+
+        list.add(1);
+        assertEquals(1, list.indexOf(1, 0));
+        assertEquals(1, list.indexOf(1, 1));
+        assertEquals(size, list.indexOf(1, 2));
+        assertEquals(size, list.indexOf(1, size));
+    }
+
+    /**
+     * isEmpty returns true when empty, else false
+     */
+    public void testIsEmpty() {
+        List empty = new Vector();
+        assertTrue(empty.isEmpty());
+        assertTrue(empty.subList(0, 0).isEmpty());
+
+        List full = populatedList(SIZE);
+        assertFalse(full.isEmpty());
+        assertTrue(full.subList(0, 0).isEmpty());
+        assertTrue(full.subList(SIZE, SIZE).isEmpty());
+    }
+
+    /**
+     * iterator of empty collection has no elements
+     */
+    public void testEmptyIterator() {
+        Collection c = new Vector();
+        assertIteratorExhausted(c.iterator());
+    }
+
+    /**
+     * lastIndexOf(Object) returns the index of the last occurrence of
+     * the specified element in this list, or -1 if this list does not
+     * contain the element
+     */
+    public void testLastIndexOf1() {
+        List list = populatedList(3);
+        assertEquals(-1, list.lastIndexOf(-42));
+        int size = list.size();
+        for (int i = 0; i < size; i++) {
+            assertEquals(i, list.lastIndexOf(i));
+            assertEquals(i, list.subList(0, size).lastIndexOf(i));
+            assertEquals(i, list.subList(0, i + 1).lastIndexOf(i));
+            assertEquals(-1, list.subList(0, i).lastIndexOf(i));
+            assertEquals(0, list.subList(i, size).lastIndexOf(i));
+            assertEquals(-1, list.subList(i + 1, size).lastIndexOf(i));
+        }
+
+        list.add(1);
+        assertEquals(size, list.lastIndexOf(1));
+        assertEquals(size, list.subList(0, size + 1).lastIndexOf(1));
+        assertEquals(1, list.subList(0, size).lastIndexOf(1));
+        assertEquals(0, list.subList(1, 2).lastIndexOf(1));
+        assertEquals(-1, list.subList(0, 1).indexOf(1));
+    }
+
+    /**
+     * lastIndexOf(E, int) returns the index of the last occurrence of the
+     * specified element in this list, searching backwards from index, or
+     * returns -1 if the element is not found
+     */
+    public void testLastIndexOf2() {
+        Vector list = populatedList(3);
+
+        // we might expect IOOBE, but spec says otherwise
+        assertEquals(-1, list.lastIndexOf(0, -1));
+
+        int size = list.size();
+        assertThrows(
+            IndexOutOfBoundsException.class,
+            () -> list.lastIndexOf(0, size),
+            () -> list.lastIndexOf(0, Integer.MAX_VALUE));
+
+        for (int i = 0; i < size; i++) {
+            assertEquals(i, list.lastIndexOf(i, i));
+            assertEquals(list.indexOf(i), list.lastIndexOf(i, i));
+            if (i > 0)
+                assertEquals(-1, list.lastIndexOf(i, i - 1));
+        }
+        list.add(one);
+        list.add(three);
+        assertEquals(1, list.lastIndexOf(one, 1));
+        assertEquals(1, list.lastIndexOf(one, 2));
+        assertEquals(3, list.lastIndexOf(one, 3));
+        assertEquals(3, list.lastIndexOf(one, 4));
+        assertEquals(-1, list.lastIndexOf(three, 3));
+    }
+
+    /**
+     * size returns the number of elements
+     */
+    public void testSize() {
+        List empty = new Vector();
+        assertEquals(0, empty.size());
+        assertEquals(0, empty.subList(0, 0).size());
+
+        List full = populatedList(SIZE);
+        assertEquals(SIZE, full.size());
+        assertEquals(0, full.subList(0, 0).size());
+        assertEquals(0, full.subList(SIZE, SIZE).size());
+    }
+
+    /**
+     * sublists contains elements at indexes offset from their base
+     */
+    public void testSubList() {
+        List a = populatedList(10);
+        assertTrue(a.subList(1,1).isEmpty());
+        for (int j = 0; j < 9; ++j) {
+            for (int i = j ; i < 10; ++i) {
+                List b = a.subList(j,i);
+                for (int k = j; k < i; ++k) {
+                    assertEquals(new Integer(k), b.get(k-j));
+                }
+            }
+        }
+
+        List s = a.subList(2, 5);
+        assertEquals(3, s.size());
+        s.set(2, m1);
+        assertEquals(a.get(4), m1);
+        s.clear();
+        assertEquals(7, a.size());
+
+        assertThrows(
+            IndexOutOfBoundsException.class,
+            () -> s.get(0),
+            () -> s.set(0, 42));
+    }
+
+    /**
+     * toArray throws an ArrayStoreException when the given array
+     * can not store the objects inside the list
+     */
+    public void testToArray_ArrayStoreException() {
+        List list = new Vector();
+        // Integers are not auto-converted to Longs
+        list.add(86);
+        list.add(99);
+        assertThrows(
+            ArrayStoreException.class,
+            () -> list.toArray(new Long[0]),
+            () -> list.toArray(new Long[5]));
+    }
+
+    void testIndexOutOfBoundsException(List list) {
+        int size = list.size();
+        assertThrows(
+            IndexOutOfBoundsException.class,
+            () -> list.get(-1),
+            () -> list.get(size),
+            () -> list.set(-1, "qwerty"),
+            () -> list.set(size, "qwerty"),
+            () -> list.add(-1, "qwerty"),
+            () -> list.add(size + 1, "qwerty"),
+            () -> list.remove(-1),
+            () -> list.remove(size),
+            () -> list.addAll(-1, Collections.emptyList()),
+            () -> list.addAll(size + 1, Collections.emptyList()),
+            () -> list.listIterator(-1),
+            () -> list.listIterator(size + 1),
+            () -> list.subList(-1, size),
+            () -> list.subList(0, size + 1));
+
+        // Conversely, operations that must not throw
+        list.addAll(0, Collections.emptyList());
+        list.addAll(size, Collections.emptyList());
+        list.add(0, "qwerty");
+        list.add(list.size(), "qwerty");
+        list.get(0);
+        list.get(list.size() - 1);
+        list.set(0, "azerty");
+        list.set(list.size() - 1, "azerty");
+        list.listIterator(0);
+        list.listIterator(list.size());
+        list.subList(0, list.size());
+        list.remove(list.size() - 1);
+    }
+
+    /**
+     * IndexOutOfBoundsException is thrown when specified
+     */
+    public void testIndexOutOfBoundsException() {
+        ThreadLocalRandom rnd = ThreadLocalRandom.current();
+        List x = populatedList(rnd.nextInt(5));
+        testIndexOutOfBoundsException(x);
+
+        int start = rnd.nextInt(x.size() + 1);
+        int end = rnd.nextInt(start, x.size() + 1);
+
+        // Vector#subList spec deviates slightly from List#subList spec
+        assertThrows(
+            IllegalArgumentException.class,
+            () -> x.subList(start, start - 1));
+
+        List subList = x.subList(start, end);
+        testIndexOutOfBoundsException(x);
+    }
+
+    /**
+     * a deserialized/reserialized list equals original
+     */
+    public void testSerialization() throws Exception {
+        List x = populatedList(SIZE);
+        List y = serialClone(x);
+
+        assertNotSame(x, y);
+        assertEquals(x.size(), y.size());
+        assertEquals(x.toString(), y.toString());
+        assertTrue(Arrays.equals(x.toArray(), y.toArray()));
+        assertEquals(x, y);
+        assertEquals(y, x);
+        while (!x.isEmpty()) {
+            assertFalse(y.isEmpty());
+            assertEquals(x.remove(0), y.remove(0));
+        }
+        assertTrue(y.isEmpty());
+    }
+
     /**
      * tests for setSize()
      */
--- a/test/jdk/java/util/regex/RegExTest.java	Mon Apr 09 08:34:30 2018 -0700
+++ b/test/jdk/java/util/regex/RegExTest.java	Tue Apr 10 13:58:47 2018 -0700
@@ -4683,6 +4683,9 @@
         if (p.test("1234")) {
             failCount++;
         }
+        if (!p.test("word1234")) {
+            failCount++;
+        }
         report("Pattern.asPredicate");
     }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/sun/security/krb5/auto/NonAscii.java	Tue Apr 10 13:58:47 2018 -0700
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2018, 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 8200152
+ * @summary KerberosString should use UTF-8 by default
+ * @library /test/lib
+ * @compile -XDignore.symbol.file NonAscii.java
+ * @run main jdk.test.lib.FileInstaller TestHosts TestHosts
+ * @run main/othervm -Djdk.net.hosts.file=TestHosts NonAscii
+ * @run main/othervm/fail -Djdk.net.hosts.file=TestHosts
+ *                        -Dsun.security.krb5.msinterop.kstring=false
+ *                        NonAscii
+ * @run main/othervm/fail -Djdk.net.hosts.file=TestHosts
+ *                        -Dsun.security.krb5.msinterop.kstring=no
+ *                        NonAscii
+ */
+
+public class NonAscii {
+    public static void main(String[] args) throws Exception {
+        String name = "ab\u00e7";
+        char[] password = "password".toCharArray();
+        new OneKDC(null).addPrincipal(name, password);
+        Context.fromUserPass(name, password, false);
+    }
+}
--- a/test/langtools/jdk/javadoc/doclet/testModules/TestModuleServicesLink.java	Mon Apr 09 08:34:30 2018 -0700
+++ b/test/langtools/jdk/javadoc/doclet/testModules/TestModuleServicesLink.java	Tue Apr 10 13:58:47 2018 -0700
@@ -23,7 +23,7 @@
 
 /*
  * @test
- * @bug 8185151
+ * @bug 8185151 8196200
  * @summary test that navigation summary links are not linked when there are no dependencies
  * @modules jdk.compiler/com.sun.tools.javac.api
  *          jdk.compiler/com.sun.tools.javac.main
@@ -69,10 +69,10 @@
         checkExit(Exit.OK);
 
         checkOutput("m/module-summary.html", true,
-                "<a href=\"#module.description\">Description</a>&nbsp;|"
-                + "&nbsp;Modules&nbsp;|"
-                + "&nbsp;<a href=\"#packages.summary\">Packages</a>&nbsp;|"
-                + "&nbsp;<a href=\"#services.summary\">Services</a>");
+                "<li><a href=\"#module.description\">Description</a>&nbsp;|&nbsp;</li>\n"
+                + "<li>Modules&nbsp;|&nbsp;</li>\n"
+                + "<li><a href=\"#packages.summary\">Packages</a>&nbsp;|&nbsp;</li>\n"
+                + "<li><a href=\"#services.summary\">Services</a></li>");
 
     }
 
@@ -93,10 +93,10 @@
         checkExit(Exit.OK);
 
         checkOutput("m/module-summary.html", true,
-                "<a href=\"#module.description\">Description</a>&nbsp;|"
-                + "&nbsp;Modules&nbsp;|"
-                + "&nbsp;<a href=\"#packages.summary\">Packages</a>&nbsp;|"
-                + "&nbsp;<a href=\"#services.summary\">Services</a>");
+                "<li><a href=\"#module.description\">Description</a>&nbsp;|&nbsp;</li>\n"
+                + "<li>Modules&nbsp;|&nbsp;</li>\n"
+                + "<li><a href=\"#packages.summary\">Packages</a>&nbsp;|&nbsp;</li>\n"
+                + "<li><a href=\"#services.summary\">Services</a></li>");
 
     }
 
@@ -115,9 +115,10 @@
         checkExit(Exit.OK);
 
         checkOutput("m/module-summary.html", true,
-                "Description&nbsp;|&nbsp;Modules&nbsp;|"
-                + "&nbsp;<a href=\"#packages.summary\">Packages</a>&nbsp;|"
-                + "&nbsp;Services");
+                "<li>Description&nbsp;|&nbsp;</li>\n"
+                + "<li>Modules&nbsp;|&nbsp;</li>\n"
+                + "<li><a href=\"#packages.summary\">Packages</a>&nbsp;|&nbsp;</li>\n"
+                + "<li>Services</li>");
     }
 
 }
--- a/test/langtools/jdk/javadoc/doclet/testModules/TestModules.java	Mon Apr 09 08:34:30 2018 -0700
+++ b/test/langtools/jdk/javadoc/doclet/testModules/TestModules.java	Tue Apr 10 13:58:47 2018 -0700
@@ -26,7 +26,7 @@
  * @bug 8154119 8154262 8156077 8157987 8154261 8154817 8135291 8155995 8162363
  *      8168766 8168688 8162674 8160196 8175799 8174974 8176778 8177562 8175218
  *      8175823 8166306 8178043 8181622 8183511 8169819 8074407 8183037 8191464
-        8164407 8192007 8182765
+        8164407 8192007 8182765 8196200
  * @summary Test modules support in javadoc.
  * @author bpatel
  * @library ../lib
@@ -940,9 +940,10 @@
         checkOutput("moduleA/module-summary.html", true,
                 "<ul class=\"subNavList\">\n"
                 + "<li>Module:&nbsp;</li>\n"
-                + "<li><a href=\"#module.description\">Description</a>&nbsp;|&nbsp;<a "
-                + "href=\"#modules.summary\">Modules</a>&nbsp;|&nbsp;<a href=\"#packages.summary\">"
-                + "Packages</a>&nbsp;|&nbsp;Services</li>\n"
+                + "<li><a href=\"#module.description\">Description</a>&nbsp;|&nbsp;</li>\n"
+                + "<li><a href=\"#modules.summary\">Modules</a>&nbsp;|&nbsp;</li>\n"
+                + "<li><a href=\"#packages.summary\">Packages</a>&nbsp;|&nbsp;</li>\n"
+                + "<li>Services</li>\n"
                 + "</ul>",
                 "<!-- ============ MODULES SUMMARY =========== -->\n"
                 + "<a id=\"modules.summary\">\n"
@@ -964,9 +965,10 @@
                 + "</td>\n"
                 + "</tr>");
         checkOutput("moduleB/module-summary.html", true,
-                "<li><a href=\"#module.description\">Description</a>&nbsp;|&nbsp;Modules&nbsp;|&nbsp;"
-                + "<a href=\"#packages.summary\">Packages</a>&nbsp;|&nbsp;<a href=\"#services.summary\">"
-                + "Services</a></li>",
+                "<li><a href=\"#module.description\">Description</a>&nbsp;|&nbsp;</li>\n"
+                + "<li>Modules&nbsp;|&nbsp;</li>\n"
+                + "<li><a href=\"#packages.summary\">Packages</a>&nbsp;|&nbsp;</li>\n"
+                + "<li><a href=\"#services.summary\">Services</a></li>",
                 "<!-- ============ PACKAGES SUMMARY =========== -->\n"
                 + "<a id=\"packages.summary\">\n"
                 + "<!--   -->\n"
@@ -1180,8 +1182,10 @@
                 + " Package Link: <a href=\"moduletags/testpkgmdltags/package-summary.html\"><code>testpkgmdltags</code></a>.<br></div>\n"
                 + "</td>");
         checkOutput("moduleA/module-summary.html", true,
-                "<li><a href=\"#module.description\">Description</a>&nbsp;|&nbsp;<a href=\"#modules.summary\">"
-                + "Modules</a>&nbsp;|&nbsp;<a href=\"#packages.summary\">Packages</a>&nbsp;|&nbsp;Services</li>",
+                "<li><a href=\"#module.description\">Description</a>&nbsp;|&nbsp;</li>\n"
+                + "<li><a href=\"#modules.summary\">Modules</a>&nbsp;|&nbsp;</li>\n"
+                + "<li><a href=\"#packages.summary\">Packages</a>&nbsp;|&nbsp;</li>\n"
+                + "<li>Services</li>",
                 "<th class=\"colFirst\" scope=\"row\"><a href=\"../moduleB/module-summary.html\">moduleB</a></th>\n"
                 + "<td class=\"colLast\"><a href=\"../moduleB/testpkgmdlB/package-summary.html\">testpkgmdlB</a></td>\n");
         checkOutput("moduleB/module-summary.html", true,
@@ -1189,8 +1193,10 @@
                 + "<td class=\"colLast\">\n"
                 + "<div class=\"block\">With a test description for uses.</div>\n</td>\n");
         checkOutput("moduletags/module-summary.html", true,
-                "<li><a href=\"#module.description\">Description</a>&nbsp;|&nbsp;<a href=\"#modules.summary\">Modules"
-                + "</a>&nbsp;|&nbsp;<a href=\"#packages.summary\">Packages</a>&nbsp;|&nbsp;Services</li>",
+                "<li><a href=\"#module.description\">Description</a>&nbsp;|&nbsp;</li>\n"
+                + "<li><a href=\"#modules.summary\">Modules</a>&nbsp;|&nbsp;</li>\n"
+                + "<li><a href=\"#packages.summary\">Packages</a>&nbsp;|&nbsp;</li>\n"
+                + "<li>Services</li>",
                 "<table class=\"requiresSummary\">\n"
                 + "<caption><span>Indirect Requires</span><span class=\"tabEnd\">&nbsp;</span></caption>",
                 "<td class=\"colFirst\">transitive</td>\n"
@@ -1267,8 +1273,10 @@
                 "<th class=\"colFirst\" scope=\"row\"><a href=\"testpkgmdlA/package-summary.html\">testpkgmdlA</a></th>\n"
                 + "<td class=\"colLast\">&nbsp;</td>");
         checkOutput("moduleB/module-summary.html", found,
-                "<li><a href=\"#module.description\">Description</a>&nbsp;|&nbsp;Modules&nbsp;|&nbsp;"
-                + "<a href=\"#packages.summary\">Packages</a>&nbsp;|&nbsp;<a href=\"#services.summary\">Services</a></li>",
+                "<li><a href=\"#module.description\">Description</a>&nbsp;|&nbsp;</li>\n"
+                + "<li>Modules&nbsp;|&nbsp;</li>\n"
+                + "<li><a href=\"#packages.summary\">Packages</a>&nbsp;|&nbsp;</li>\n"
+                + "<li><a href=\"#services.summary\">Services</a></li>",
                 "<th class=\"colFirst\" scope=\"row\"><a href=\"testpkgmdlB/package-summary.html\">testpkgmdlB</a></th>\n"
                 + "<td class=\"colLast\">&nbsp;</td>",
                 "<table class=\"packagesSummary\">\n"
@@ -1329,8 +1337,10 @@
                 + "<td class=\"colSecond\">None</td>\n"
                 + "<td class=\"colLast\">&nbsp;</td>");
         checkOutput("moduleB/module-summary.html", found,
-                "<li><a href=\"#module.description\">Description</a>&nbsp;|&nbsp;<a href=\"#modules.summary\">"
-                + "Modules</a>&nbsp;|&nbsp;<a href=\"#packages.summary\">Packages</a>&nbsp;|&nbsp;<a href=\"#services.summary\">Services</a></li>",
+                "<li><a href=\"#module.description\">Description</a>&nbsp;|&nbsp;</li>\n"
+                + "<li><a href=\"#modules.summary\">Modules</a>&nbsp;|&nbsp;</li>\n"
+                + "<li><a href=\"#packages.summary\">Packages</a>&nbsp;|&nbsp;</li>\n"
+                + "<li><a href=\"#services.summary\">Services</a></li>",
                 "<th class=\"colFirst\" scope=\"row\"><a href=\"testpkgmdlB/package-summary.html\">testpkgmdlB</a></th>\n"
                 + "<td class=\"colSecond\">None</td>\n"
                 + "<td class=\"colSecond\">All Modules</td>\n"
--- a/test/langtools/jdk/javadoc/doclet/testNavigation/TestNavigation.java	Mon Apr 09 08:34:30 2018 -0700
+++ b/test/langtools/jdk/javadoc/doclet/testNavigation/TestNavigation.java	Tue Apr 10 13:58:47 2018 -0700
@@ -24,24 +24,36 @@
 /*
  * @test
  * @bug      4131628 4664607 7025314 8023700 7198273 8025633 8026567 8081854 8150188 8151743 8196027 8182765
+ *           8196200
  * @summary  Make sure the Next/Prev Class links iterate through all types.
  *           Make sure the navagation is 2 columns, not 3.
  * @author   jamieh
- * @library  ../lib
+ * @library  /tools/lib ../lib
  * @modules jdk.javadoc/jdk.javadoc.internal.tool
- * @build    JavadocTester
+ * @build    toolbox.ToolBox JavadocTester
  * @run main TestNavigation
  */
 
+import java.io.IOException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+import toolbox.*;
+
 public class TestNavigation extends JavadocTester {
 
+    public final ToolBox tb;
     public static void main(String... args) throws Exception {
         TestNavigation tester = new TestNavigation();
-        tester.runTests();
+        tester.runTests(m -> new Object[] { Paths.get(m.getName()) });
+    }
+
+    public TestNavigation() {
+        tb = new ToolBox();
     }
 
     @Test
-    void test() {
+    void test(Path ignore) {
         javadoc("-d", "out",
                 "-overview", testSrc("overview.html"),
                 "-sourcepath", testSrc,
@@ -96,7 +108,7 @@
     }
 
     @Test
-    void test_html4() {
+    void test_html4(Path ignore) {
         javadoc("-d", "out-html4",
                 "-html4",
                 "-overview", testSrc("overview.html"),
@@ -135,7 +147,7 @@
 
     // Test for checking additional padding to offset the fixed navigation bar in HTML5.
     @Test
-    void test1() {
+    void test1(Path ignore) {
         javadoc("-d", "out-1",
                 "-html5",
                 "-sourcepath", testSrc,
@@ -167,7 +179,7 @@
 
     // Test to make sure that no extra padding for nav bar gets generated if -nonavbar is specified for HTML4.
     @Test
-    void test2() {
+    void test2(Path ignore) {
         javadoc("-d", "out-2",
                 "-nonavbar",
                 "-sourcepath", testSrc,
@@ -197,7 +209,7 @@
 
     // Test to make sure that no extra padding for nav bar gets generated if -nonavbar is specified for HTML5.
     @Test
-    void test3() {
+    void test3(Path ignore) {
         javadoc("-d", "out-3",
                 "-html5",
                 "-nonavbar",
@@ -227,4 +239,89 @@
                 + "</script>\n"
                 + "</nav>");
     }
+
+    @Test
+    void test4(Path base) throws IOException {
+        Path src = base.resolve("src");
+        tb.writeJavaFiles(src,
+                "package pkg1; public class A {\n"
+                + "    /**\n"
+                + "     * Class with members.\n"
+                + "     */\n"
+                + "    public static class X {\n"
+                + "        /**\n"
+                + "         * A ctor\n"
+                + "         */\n"
+                + "        public X() {\n"
+                + "        }\n"
+                + "        /**\n"
+                + "         * A field\n"
+                + "         */\n"
+                + "        public int field;\n"
+                + "        /**\n"
+                + "         * A method\n"
+                + "         */\n"
+                + "        public void method() {\n"
+                + "        }\n"
+                + "        /**\n"
+                + "         * An inner class\n"
+                + "         */\n"
+                + "        public static class IC {\n"
+                + "        }\n"
+                + "    }\n"
+                + "    /**\n"
+                + "     * Class with all inherited members.\n"
+                + "     */\n"
+                + "    public static class Y extends X {\n"
+                + "    }\n"
+                + "}");
+
+        tb.writeJavaFiles(src,
+                "package pkg1; public class C {\n"
+                + "}");
+
+        tb.writeJavaFiles(src,
+                "package pkg1; public interface InterfaceWithNoMembers {\n"
+                + "}");
+
+        javadoc("-d", "out-4",
+                "-sourcepath", src.toString(),
+                "pkg1");
+        checkExit(Exit.OK);
+
+        checkOrder("pkg1/A.X.html",
+                "Summary",
+                "<li><a href=\"#nested.class.summary\">Nested</a>&nbsp;|&nbsp;</li>",
+                "<li><a href=\"#field.summary\">Field</a>&nbsp;|&nbsp;</li>",
+                "<li><a href=\"#constructor.summary\">Constr</a>&nbsp;|&nbsp;</li>",
+                "<li><a href=\"#method.summary\">Method</a></li>");
+
+        checkOrder("pkg1/A.Y.html",
+                "Summary",
+                "<li><a href=\"#nested.class.summary\">Nested</a>&nbsp;|&nbsp;</li>",
+                "<li><a href=\"#field.summary\">Field</a>&nbsp;|&nbsp;</li>",
+                "<li><a href=\"#constructor.summary\">Constr</a>&nbsp;|&nbsp;</li>",
+                "<li><a href=\"#method.summary\">Method</a></li>");
+
+        checkOrder("pkg1/A.X.IC.html",
+                "Summary",
+                "<li>Nested&nbsp;|&nbsp;</li>",
+                "<li>Field&nbsp;|&nbsp;</li>",
+                "<li><a href=\"#constructor.summary\">Constr</a>&nbsp;|&nbsp;</li>",
+                "<li><a href=\"#method.summary\">Method</a></li>");
+
+        checkOrder("pkg1/C.html",
+                "Summary",
+                "<li>Nested&nbsp;|&nbsp;</li>",
+                "<li>Field&nbsp;|&nbsp;</li>",
+                "<li><a href=\"#constructor.summary\">Constr</a>&nbsp;|&nbsp;</li>",
+                "<li><a href=\"#method.summary\">Method</a></li>");
+
+        checkOrder("pkg1/InterfaceWithNoMembers.html",
+                "Summary",
+                "<li>Nested&nbsp;|&nbsp;</li>",
+                "<li>Field&nbsp;|&nbsp;</li>",
+                "<li>Constr&nbsp;|&nbsp;</li>",
+                "<li>Method</li>");
+    }
 }