changeset 48279:4b3760787150 lambda-leftovers

manual merge
author mcimadamore
date Wed, 06 Dec 2017 11:39:23 +0000
parents 78af27007264 6c4bdbf90897
children 6dd657f5585d
files src/java.base/share/classes/jdk/internal/util/jar/VersionedStream.java src/jdk.compiler/share/classes/com/sun/tools/javac/code/Source.java src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symtab.java src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties test/jdk/jdk/internal/misc/JavaLangAccess/NewUnsafeString.java test/langtools/tools/javac/6302184/T6302184.java test/langtools/tools/javac/6302184/T6302184.out
diffstat 172 files changed, 4027 insertions(+), 2228 deletions(-) [+]
line wrap: on
line diff
--- a/.hgtags	Thu Nov 30 22:05:19 2017 +0100
+++ b/.hgtags	Wed Dec 06 11:39:23 2017 +0000
@@ -458,3 +458,4 @@
 e6278add9ff28fab70fe1cc4c1d65f7363dc9445 jdk-10+31
 a2008587c13fa05fa2dbfcb09fe987576fbedfd1 jdk-10+32
 bbd692ad4fa300ecca7939ffbe3b1d5e52a28cc6 jdk-10+33
+89deac44e51517841491ba86ff44aa82a5ca96b3 jdk-10+34
--- a/doc/testing.html	Thu Nov 30 22:05:19 2017 +0100
+++ b/doc/testing.html	Wed Dec 06 11:39:23 2017 +0000
@@ -57,6 +57,7 @@
 <h3 id="gtest">Gtest</h3>
 <p>Since the Hotspot Gtest suite is so quick, the default is to run all tests. This is specified by just <code>gtest</code>, or as a fully qualified test descriptor <code>gtest:all</code>.</p>
 <p>If you want, you can single out an individual test or a group of tests, for instance <code>gtest:LogDecorations</code> or <code>gtest:LogDecorations.level_test_vm</code>. This can be particularly useful if you want to run a shaky test repeatedly.</p>
+<p>For Gtest, there is a separate test suite for each JVM variant. The JVM variant is defined by adding <code>/&lt;variant&gt;</code> to the test descriptor, e.g. <code>gtest:Log/client</code>. If you specify no variant, gtest will run once for each JVM variant present (e.g. server, client). So if you only have the server JVM present, then <code>gtest:all</code> will be equivalent to <code>gtest:all/server</code>.</p>
 <h2 id="test-results-and-summary">Test results and summary</h2>
 <p>At the end of the test run, a summary of all tests run will be presented. This will have a consistent look, regardless of what test suites were used. This is a sample summary:</p>
 <pre><code>==============================
--- a/doc/testing.md	Thu Nov 30 22:05:19 2017 +0100
+++ b/doc/testing.md	Wed Dec 06 11:39:23 2017 +0000
@@ -81,6 +81,12 @@
 instance `gtest:LogDecorations` or `gtest:LogDecorations.level_test_vm`. This
 can be particularly useful if you want to run a shaky test repeatedly.
 
+For Gtest, there is a separate test suite for each JVM variant. The JVM variant
+is defined by adding `/<variant>` to the test descriptor, e.g.
+`gtest:Log/client`. If you specify no variant, gtest will run once for each JVM
+variant present (e.g. server, client). So if you only have the server JVM
+present, then `gtest:all` will be equivalent to `gtest:all/server`.
+
 ## Test results and summary
 
 At the end of the test run, a summary of all tests run will be presented. This
--- a/make/CompileJavaModules.gmk	Thu Nov 30 22:05:19 2017 +0100
+++ b/make/CompileJavaModules.gmk	Wed Dec 06 11:39:23 2017 +0000
@@ -300,7 +300,9 @@
 
 ################################################################################
 
-java.xml_SETUP := GENERATE_JDKBYTECODE_NOWARNINGS
+java.xml_ADD_JAVAC_FLAGS += -Xdoclint:all/protected \
+    '-Xdoclint/package:$(call CommaList, javax.xml.catalog javax.xml.datatype \
+    javax.xml.transform javax.xml.validation javax.xml.xpath)'
 java.xml_CLEAN += .properties
 
 ################################################################################
--- a/make/InitSupport.gmk	Thu Nov 30 22:05:19 2017 +0100
+++ b/make/InitSupport.gmk	Wed Dec 06 11:39:23 2017 +0000
@@ -279,7 +279,9 @@
           # generated files.
           ifeq ($$(MAKE_RESTARTS),)
             ifeq ($$(words $$(matching_confs)), 1)
-              $$(info Building configuration '$$(matching_confs)' (matching CONF=$$(CONF)))
+              ifneq ($$(findstring $$(LOG_LEVEL), info debug trace),)
+                $$(info Building configuration '$$(matching_confs)' (matching CONF=$$(CONF)))
+              endif
             else
               $$(info Building these configurations (matching CONF=$$(CONF)):)
               $$(foreach var, $$(matching_confs), $$(info * $$(var)))
--- a/make/RunTests.gmk	Thu Nov 30 22:05:19 2017 +0100
+++ b/make/RunTests.gmk	Wed Dec 06 11:39:23 2017 +0000
@@ -68,6 +68,7 @@
 TEST_RESULTS_DIR := $(OUTPUTDIR)/test-results
 TEST_SUPPORT_DIR := $(OUTPUTDIR)/test-support
 TEST_SUMMARY := $(TEST_RESULTS_DIR)/test-summary.txt
+TEST_LAST_IDS := $(TEST_SUPPORT_DIR)/test-last-ids.txt
 
 ifeq ($(CUSTOM_ROOT), )
   JTREG_TOPDIR := $(TOPDIR)
@@ -87,6 +88,9 @@
       -timeoutHandlerTimeout:0
 endif
 
+GTEST_LAUNCHER_DIRS := $(patsubst %/gtestLauncher, %, $(wildcard $(TEST_IMAGE_DIR)/hotspot/gtest/*/gtestLauncher))
+GTEST_VARIANTS := $(strip $(patsubst $(TEST_IMAGE_DIR)/hotspot/gtest/%, %, $(GTEST_LAUNCHER_DIRS)))
+
 ################################################################################
 # Parse control variables
 ################################################################################
@@ -165,16 +169,23 @@
 # Helper function to determine if a test specification is a Gtest test
 #
 # It is a Gtest test if it is either "gtest", or "gtest:" followed by an optional
-# test filter string.
+# test filter string, and an optional "/<variant>" to select a specific JVM
+# variant. If no variant is specified, all found variants are tested.
 define ParseGtestTestSelection
   $(if $(filter gtest%, $1), \
     $(if $(filter gtest, $1), \
-      gtest:all \
+      $(addprefix gtest:all/, $(GTEST_VARIANTS)) \
     , \
-      $(if $(filter gtest:, $1), \
-        gtest:all \
+      $(if $(strip $(or $(filter gtest/%, $1) $(filter gtest:/%, $1))), \
+        $(patsubst gtest:/%, gtest:all/%, $(patsubst gtest/%, gtest:/%, $1)) \
       , \
-        $1 \
+        $(if $(filter gtest:%, $1), \
+          $(if $(findstring /, $1), \
+            $1 \
+          , \
+            $(addprefix $1/, $(GTEST_VARIANTS)) \
+          ) \
+        ) \
       ) \
     ) \
   )
@@ -228,7 +239,8 @@
   $(if $(findstring :, $(TEST_NAME)), \
     $(if $(filter :%, $(TEST_NAME)), \
       $(eval TEST_GROUP := $(patsubst :%, %, $(TEST_NAME))) \
-      $(eval TEST_ROOTS := $(JTREG_TESTROOTS)) \
+      $(eval TEST_ROOTS := $(foreach test_root, $(JTREG_TESTROOTS), \
+          $(call CleanupJtregPath, $(test_root)))) \
     , \
       $(eval TEST_PATH := $(word 1, $(subst :, $(SPACE), $(TEST_NAME)))) \
       $(eval TEST_GROUP := $(word 2, $(subst :, $(SPACE), $(TEST_NAME)))) \
@@ -251,6 +263,15 @@
   )
 endef
 
+# Helper function to determine if a test specification is a special test
+#
+# It is a special test if it is "special:" followed by a test name.
+define ParseSpecialTestSelection
+  $(if $(filter special:%, $1), \
+    $1 \
+  )
+endef
+
 ifeq ($(TEST), )
   $(info No test selection given in TEST!)
   $(info Please use e.g. 'run-test TEST=tier1' or 'run-test-tier1')
@@ -270,6 +291,9 @@
     $(eval PARSED_TESTS += $(call ParseJtregTestSelection, $(test))) \
   ) \
   $(if $(strip $(PARSED_TESTS)), , \
+    $(eval PARSED_TESTS += $(call ParseSpecialTestSelection, $(test))) \
+  ) \
+  $(if $(strip $(PARSED_TESTS)), , \
     $(eval UNKNOWN_TEST := $(test)) \
   ) \
   $(eval TESTS_TO_RUN += $(PARSED_TESTS)) \
@@ -316,8 +340,14 @@
 define SetupRunGtestTestBody
   $1_TEST_RESULTS_DIR := $$(TEST_RESULTS_DIR)/$1
   $1_TEST_SUPPORT_DIR := $$(TEST_SUPPORT_DIR)/$1
+  $1_EXITCODE := $$($1_TEST_RESULTS_DIR)/exitcode.txt
 
-  $1_TEST_NAME := $$(strip $$(patsubst gtest:%, %, $$($1_TEST)))
+  $1_VARIANT :=  $$(lastword $$(subst /, , $$($1_TEST)))
+  ifeq ($$(filter $$($1_VARIANT), $$(GTEST_VARIANTS)), )
+    $$(error Invalid gtest variant '$$($1_VARIANT)'. Valid variants: $$(GTEST_VARIANTS))
+  endif
+  $1_TEST_NAME := $$(strip $$(patsubst %/$$($1_VARIANT), %, \
+      $$(patsubst gtest:%, %, $$($1_TEST))))
   ifneq ($$($1_TEST_NAME), all)
     $1_GTEST_FILTER := --gtest_filter=$$($1_TEST_NAME)*
   endif
@@ -331,11 +361,14 @@
 	$$(call LogWarn, Running test '$$($1_TEST)')
 	$$(call MakeDir, $$($1_TEST_RESULTS_DIR) $$($1_TEST_SUPPORT_DIR))
 	$$(call ExecuteWithLog, $$($1_TEST_SUPPORT_DIR)/gtest, \
-	    $$(FIXPATH) $$(TEST_IMAGE_DIR)/hotspot/gtest/server/gtestLauncher \
-	    -jdk $(JDK_IMAGE_DIR) $$($1_GTEST_FILTER) \
-	    --gtest_output=xml:$$($1_TEST_RESULTS_DIR)/gtest.xml \
-	    $$($1_GTEST_REPEAT) $$(GTEST_OPTIONS) $$(GTEST_VM_OPTIONS) \
-	    > >($(TEE) $$($1_TEST_RESULTS_DIR)/gtest.txt) || true )
+	    $$(FIXPATH) $$(TEST_IMAGE_DIR)/hotspot/gtest/$$($1_VARIANT)/gtestLauncher \
+	         -jdk $(JDK_IMAGE_DIR) $$($1_GTEST_FILTER) \
+	         --gtest_output=xml:$$($1_TEST_RESULTS_DIR)/gtest.xml \
+	         $$($1_GTEST_REPEAT) $$(GTEST_OPTIONS) $$(GTEST_VM_OPTIONS) \
+	        > >($(TEE) $$($1_TEST_RESULTS_DIR)/gtest.txt) \
+	    && $$(ECHO) $$$$? > $$($1_EXITCODE) \
+	    || $$(ECHO) $$$$? > $$($1_EXITCODE) \
+	)
 
   $1_RESULT_FILE := $$($1_TEST_RESULTS_DIR)/gtest.txt
 
@@ -343,7 +376,7 @@
 	$$(call LogWarn, Finished running test '$$($1_TEST)')
 	$$(call LogWarn, Test report is stored in $$(strip \
 	    $$(subst $$(TOPDIR)/, , $$($1_TEST_RESULTS_DIR))))
-	$$(if  $$(wildcard $$($1_RESULT_FILE)), \
+	$$(if $$(wildcard $$($1_RESULT_FILE)), \
 	  $$(eval $1_TOTAL := $$(shell $$(AWK) '/==========.* tests? from .* \
 	      test cases? ran/ { print $$$$2 }' $$($1_RESULT_FILE))) \
 	  $$(if $$($1_TOTAL), , $$(eval $1_TOTAL := 0)) \
@@ -398,6 +431,7 @@
 define SetupRunJtregTestBody
   $1_TEST_RESULTS_DIR := $$(TEST_RESULTS_DIR)/$1
   $1_TEST_SUPPORT_DIR := $$(TEST_SUPPORT_DIR)/$1
+  $1_EXITCODE := $$($1_TEST_RESULTS_DIR)/exitcode.txt
 
   $1_TEST_NAME := $$(strip $$(patsubst jtreg:%, %, $$($1_TEST)))
 
@@ -505,7 +539,10 @@
 	        -workDir:$$($1_TEST_SUPPORT_DIR) \
 	        $$(JTREG_OPTIONS) \
 	        $$(JTREG_FAILURE_HANDLER_OPTIONS) \
-	        $$($1_TEST_NAME) || true )
+	        $$($1_TEST_NAME) \
+	    && $$(ECHO) $$$$? > $$($1_EXITCODE) \
+	    || $$(ECHO) $$$$? > $$($1_EXITCODE) \
+	)
 
   $1_RESULT_FILE := $$($1_TEST_RESULTS_DIR)/text/stats.txt
 
@@ -513,7 +550,7 @@
 	$$(call LogWarn, Finished running test '$$($1_TEST)')
 	$$(call LogWarn, Test report is stored in $$(strip \
 	    $$(subst $$(TOPDIR)/, , $$($1_TEST_RESULTS_DIR))))
-	$$(if  $$(wildcard $$($1_RESULT_FILE)), \
+	$$(if $$(wildcard $$($1_RESULT_FILE)), \
 	  $$(eval $1_PASSED := $$(shell $$(AWK) '{ gsub(/[,;]/, ""); \
 	      for (i=1; i<=NF; i++) { if ($$$$i == "passed:") \
 	      print $$$$(i+1) } }' $$($1_RESULT_FILE))) \
@@ -540,6 +577,69 @@
   TARGETS += $1
 endef
 
+################################################################################
+
+### Rules for special tests
+
+SetupRunSpecialTest = $(NamedParamsMacroTemplate)
+define SetupRunSpecialTestBody
+  $1_TEST_RESULTS_DIR := $$(TEST_RESULTS_DIR)/$1
+  $1_TEST_SUPPORT_DIR := $$(TEST_SUPPORT_DIR)/$1
+  $1_EXITCODE := $$($1_TEST_RESULTS_DIR)/exitcode.txt
+
+  $1_FULL_TEST_NAME := $$(strip $$(patsubst special:%, %, $$($1_TEST)))
+  ifneq ($$(findstring :, $$($1_FULL_TEST_NAME)), )
+    $1_TEST_NAME := $$(firstword $$(subst :, ,$$($1_FULL_TEST_NAME)))
+    $1_TEST_ARGS := $$(strip $$(patsubst special:$$($1_TEST_NAME):%, %, $$($1_TEST)))
+  else
+    $1_TEST_NAME := $$($1_FULL_TEST_NAME)
+    $1_TEST_ARGS :=
+  endif
+
+  ifeq ($$($1_TEST_NAME), hotspot-internal)
+    $1_TEST_COMMAND_LINE := \
+        $$(JDK_IMAGE_DIR)/bin/java -XX:+ExecuteInternalVMTests \
+        -XX:+ShowMessageBoxOnError -version
+  else ifeq ($$($1_TEST_NAME), failure-handler)
+    $1_TEST_COMMAND_LINE := \
+        ($(CD) $(TOPDIR)/make/test && $(MAKE) $(MAKE_ARGS) -f \
+        BuildFailureHandler.gmk test)
+  else ifeq ($$($1_TEST_NAME), make)
+    $1_TEST_COMMAND_LINE := \
+        ($(CD) $(TOPDIR)/test/make && $(MAKE) $(MAKE_ARGS) -f \
+        TestMake.gmk $$($1_TEST_ARGS))
+  else
+    $$(error Invalid special test specification: $$($1_TEST_NAME))
+  endif
+
+  run-test-$1:
+	$$(call LogWarn)
+	$$(call LogWarn, Running test '$$($1_TEST)')
+	$$(call MakeDir, $$($1_TEST_RESULTS_DIR) $$($1_TEST_SUPPORT_DIR))
+	$$(call ExecuteWithLog, $$($1_TEST_SUPPORT_DIR)/test-execution, \
+	    $$($1_TEST_COMMAND_LINE) \
+	        > >($(TEE) $$($1_TEST_RESULTS_DIR)/test-output.txt) \
+	    && $$(ECHO) $$$$? > $$($1_EXITCODE) \
+	    || $$(ECHO) $$$$? > $$($1_EXITCODE) \
+	)
+
+  $1_RESULT_FILE := $$($1_TEST_RESULTS_DIR)/gtest.txt
+
+  # We can not parse the various "special" tests.
+  parse-test-$1: run-test-$1
+	$$(call LogWarn, Finished running test '$$($1_TEST)')
+	$$(call LogWarn, Test report is stored in $$(strip \
+	    $$(subst $$(TOPDIR)/, , $$($1_TEST_RESULTS_DIR))))
+	$$(call LogWarn, Warning: Special test results are not properly parsed!)
+	$$(eval $1_PASSED := 0)
+	$$(eval $1_FAILED := 0)
+	$$(eval $1_ERROR := 0)
+	$$(eval $1_TOTAL := 0)
+
+  $1: run-test-$1 parse-test-$1
+
+  TARGETS += $1
+endef
 
 ################################################################################
 # Setup and execute make rules for all selected tests
@@ -552,10 +652,13 @@
 UseJtregTestHandler = \
   $(if $(filter jtreg:%, $1), true)
 
+UseSpecialTestHandler = \
+  $(if $(filter special:%, $1), true)
+
 # Now process each test to run and setup a proper make rule
 $(foreach test, $(TESTS_TO_RUN), \
   $(eval TEST_ID := $(shell $(ECHO) $(strip $(test)) | \
-      $(TR) -cs '[a-z][A-Z][0-9]\n' '_')) \
+      $(TR) -cs '[a-z][A-Z][0-9]\n' '[_*1000]')) \
   $(eval ALL_TEST_IDS += $(TEST_ID)) \
   $(if $(call UseCustomTestHandler, $(test)), \
     $(eval $(call SetupRunCustomTest, $(TEST_ID), \
@@ -572,6 +675,11 @@
         TEST := $(test), \
     )) \
   ) \
+  $(if $(call UseSpecialTestHandler, $(test)), \
+    $(eval $(call SetupRunSpecialTest, $(TEST_ID), \
+        TEST := $(test), \
+    )) \
+  ) \
 )
 
 # Sort also removes duplicates, so if there is any we'll get fewer words.
@@ -592,6 +700,8 @@
         # Create and print a table of the result of all tests run
 	$(RM) $(TEST_SUMMARY).old 2> /dev/null
 	$(MV) $(TEST_SUMMARY) $(TEST_SUMMARY).old 2> /dev/null || true
+	$(RM) $(TEST_LAST_IDS).old 2> /dev/null
+	$(MV) $(TEST_LAST_IDS) $(TEST_LAST_IDS).old 2> /dev/null || true
 	$(ECHO) >> $(TEST_SUMMARY) ==============================
 	$(ECHO) >> $(TEST_SUMMARY) Test summary
 	$(ECHO) >> $(TEST_SUMMARY) ==============================
@@ -599,8 +709,9 @@
 	    TEST TOTAL PASS FAIL ERROR " "
 	$(foreach test, $(TESTS_TO_RUN), \
 	  $(eval TEST_ID := $(shell $(ECHO) $(strip $(test)) | \
-	      $(TR) -cs '[a-z][A-Z][0-9]\n' '_')) \
-	  $(eval NAME_PATTERN := $(shell $(ECHO) $(test) | $(TR) -c \\n _)) \
+	      $(TR) -cs '[a-z][A-Z][0-9]\n' '[_*1000]')) \
+	    $(ECHO) >> $(TEST_LAST_IDS) $(TEST_ID) $(NEWLINE) \
+	  $(eval NAME_PATTERN := $(shell $(ECHO) $(test) | $(TR) -c '\n' '[_*1000]')) \
 	  $(if $(filter __________________________________________________%, $(NAME_PATTERN)), \
 	    $(eval TEST_NAME := ) \
 	    $(PRINTF) >> $(TEST_SUMMARY) "%2s %-49s\n" "  " "$(test)"  $(NEWLINE) \
--- a/make/autoconf/basics.m4	Thu Nov 30 22:05:19 2017 +0100
+++ b/make/autoconf/basics.m4	Wed Dec 06 11:39:23 2017 +0000
@@ -1092,10 +1092,6 @@
     # We can build without it.
     LDD="true"
   fi
-  BASIC_PATH_PROGS(OTOOL, otool)
-  if test "x$OTOOL" = "x"; then
-    OTOOL="true"
-  fi
   BASIC_PATH_PROGS(READELF, [greadelf readelf])
   BASIC_PATH_PROGS(DOT, dot)
   BASIC_PATH_PROGS(HG, hg)
--- a/make/autoconf/boot-jdk.m4	Thu Nov 30 22:05:19 2017 +0100
+++ b/make/autoconf/boot-jdk.m4	Wed Dec 06 11:39:23 2017 +0000
@@ -353,9 +353,6 @@
 
   AC_MSG_CHECKING([flags for boot jdk java command] )
 
-  # Disable special log output when a debug build is used as Boot JDK...
-  ADD_JVM_ARG_IF_OK([-XX:-PrintVMOptions -XX:-UnlockDiagnosticVMOptions -XX:-LogVMOutput],boot_jdk_jvmargs,[$JAVA])
-
   # Force en-US environment
   ADD_JVM_ARG_IF_OK([-Duser.language=en -Duser.country=US],boot_jdk_jvmargs,[$JAVA])
 
--- a/make/autoconf/generated-configure.sh	Thu Nov 30 22:05:19 2017 +0100
+++ b/make/autoconf/generated-configure.sh	Wed Dec 06 11:39:23 2017 +0000
@@ -818,6 +818,8 @@
 DUMPBIN
 RC
 MT
+INSTALL_NAME_TOOL
+OTOOL
 LIPO
 ac_ct_AR
 AR
@@ -932,7 +934,6 @@
 HG
 DOT
 READELF
-OTOOL
 LDD
 ZIPEXE
 UNZIP
@@ -1277,7 +1278,6 @@
 UNZIP
 ZIPEXE
 LDD
-OTOOL
 READELF
 DOT
 HG
@@ -1310,6 +1310,8 @@
 AS
 AR
 LIPO
+OTOOL
+INSTALL_NAME_TOOL
 STRIP
 NM
 GNM
@@ -2226,7 +2228,6 @@
   UNZIP       Override default value for UNZIP
   ZIPEXE      Override default value for ZIPEXE
   LDD         Override default value for LDD
-  OTOOL       Override default value for OTOOL
   READELF     Override default value for READELF
   DOT         Override default value for DOT
   HG          Override default value for HG
@@ -2260,6 +2261,9 @@
   AS          Override default value for AS
   AR          Override default value for AR
   LIPO        Override default value for LIPO
+  OTOOL       Override default value for OTOOL
+  INSTALL_NAME_TOOL
+              Override default value for INSTALL_NAME_TOOL
   STRIP       Override default value for STRIP
   NM          Override default value for NM
   GNM         Override default value for GNM
@@ -5155,7 +5159,7 @@
 #CUSTOM_AUTOCONF_INCLUDE
 
 # Do not change or remove the following line, it is needed for consistency checks:
-DATE_WHEN_GENERATED=1511359342
+DATE_WHEN_GENERATED=1512479382
 
 ###############################################################################
 #
@@ -22126,206 +22130,6 @@
   # Publish this variable in the help.
 
 
-  if [ -z "${OTOOL+x}" ]; then
-    # The variable is not set by user, try to locate tool using the code snippet
-    for ac_prog in otool
-do
-  # Extract the first word of "$ac_prog", so it can be a program name with args.
-set dummy $ac_prog; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_OTOOL+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  case $OTOOL in
-  [\\/]* | ?:[\\/]*)
-  ac_cv_path_OTOOL="$OTOOL" # Let the user override the test with a path.
-  ;;
-  *)
-  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-    for ac_exec_ext in '' $ac_executable_extensions; do
-  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
-    ac_cv_path_OTOOL="$as_dir/$ac_word$ac_exec_ext"
-    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
-    break 2
-  fi
-done
-  done
-IFS=$as_save_IFS
-
-  ;;
-esac
-fi
-OTOOL=$ac_cv_path_OTOOL
-if test -n "$OTOOL"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL" >&5
-$as_echo "$OTOOL" >&6; }
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-
-  test -n "$OTOOL" && break
-done
-
-  else
-    # The variable is set, but is it from the command line or the environment?
-
-    # Try to remove the string !OTOOL! from our list.
-    try_remove_var=${CONFIGURE_OVERRIDDEN_VARIABLES//!OTOOL!/}
-    if test "x$try_remove_var" = "x$CONFIGURE_OVERRIDDEN_VARIABLES"; then
-      # If it failed, the variable was not from the command line. Ignore it,
-      # but warn the user (except for BASH, which is always set by the calling BASH).
-      if test "xOTOOL" != xBASH; then
-        { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Ignoring value of OTOOL from the environment. Use command line variables instead." >&5
-$as_echo "$as_me: WARNING: Ignoring value of OTOOL from the environment. Use command line variables instead." >&2;}
-      fi
-      # Try to locate tool using the code snippet
-      for ac_prog in otool
-do
-  # Extract the first word of "$ac_prog", so it can be a program name with args.
-set dummy $ac_prog; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_OTOOL+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  case $OTOOL in
-  [\\/]* | ?:[\\/]*)
-  ac_cv_path_OTOOL="$OTOOL" # Let the user override the test with a path.
-  ;;
-  *)
-  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-    for ac_exec_ext in '' $ac_executable_extensions; do
-  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
-    ac_cv_path_OTOOL="$as_dir/$ac_word$ac_exec_ext"
-    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
-    break 2
-  fi
-done
-  done
-IFS=$as_save_IFS
-
-  ;;
-esac
-fi
-OTOOL=$ac_cv_path_OTOOL
-if test -n "$OTOOL"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL" >&5
-$as_echo "$OTOOL" >&6; }
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-
-  test -n "$OTOOL" && break
-done
-
-    else
-      # If it succeeded, then it was overridden by the user. We will use it
-      # for the tool.
-
-      # First remove it from the list of overridden variables, so we can test
-      # for unknown variables in the end.
-      CONFIGURE_OVERRIDDEN_VARIABLES="$try_remove_var"
-
-      # Check if we try to supply an empty value
-      if test "x$OTOOL" = x; then
-        { $as_echo "$as_me:${as_lineno-$LINENO}: Setting user supplied tool OTOOL= (no value)" >&5
-$as_echo "$as_me: Setting user supplied tool OTOOL= (no value)" >&6;}
-        { $as_echo "$as_me:${as_lineno-$LINENO}: checking for OTOOL" >&5
-$as_echo_n "checking for OTOOL... " >&6; }
-        { $as_echo "$as_me:${as_lineno-$LINENO}: result: disabled" >&5
-$as_echo "disabled" >&6; }
-      else
-        # Check if the provided tool contains a complete path.
-        tool_specified="$OTOOL"
-        tool_basename="${tool_specified##*/}"
-        if test "x$tool_basename" = "x$tool_specified"; then
-          # A command without a complete path is provided, search $PATH.
-          { $as_echo "$as_me:${as_lineno-$LINENO}: Will search for user supplied tool OTOOL=$tool_basename" >&5
-$as_echo "$as_me: Will search for user supplied tool OTOOL=$tool_basename" >&6;}
-          # Extract the first word of "$tool_basename", so it can be a program name with args.
-set dummy $tool_basename; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_OTOOL+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  case $OTOOL in
-  [\\/]* | ?:[\\/]*)
-  ac_cv_path_OTOOL="$OTOOL" # Let the user override the test with a path.
-  ;;
-  *)
-  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-    for ac_exec_ext in '' $ac_executable_extensions; do
-  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
-    ac_cv_path_OTOOL="$as_dir/$ac_word$ac_exec_ext"
-    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
-    break 2
-  fi
-done
-  done
-IFS=$as_save_IFS
-
-  ;;
-esac
-fi
-OTOOL=$ac_cv_path_OTOOL
-if test -n "$OTOOL"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL" >&5
-$as_echo "$OTOOL" >&6; }
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-
-          if test "x$OTOOL" = x; then
-            as_fn_error $? "User supplied tool $tool_basename could not be found" "$LINENO" 5
-          fi
-        else
-          # Otherwise we believe it is a complete path. Use it as it is.
-          { $as_echo "$as_me:${as_lineno-$LINENO}: Will use user supplied tool OTOOL=$tool_specified" >&5
-$as_echo "$as_me: Will use user supplied tool OTOOL=$tool_specified" >&6;}
-          { $as_echo "$as_me:${as_lineno-$LINENO}: checking for OTOOL" >&5
-$as_echo_n "checking for OTOOL... " >&6; }
-          if test ! -x "$tool_specified"; then
-            { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5
-$as_echo "not found" >&6; }
-            as_fn_error $? "User supplied tool OTOOL=$tool_specified does not exist or is not executable" "$LINENO" 5
-          fi
-          { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tool_specified" >&5
-$as_echo "$tool_specified" >&6; }
-        fi
-      fi
-    fi
-
-  fi
-
-
-  if test "x$OTOOL" = "x"; then
-    OTOOL="true"
-  fi
-
-
-  # Publish this variable in the help.
-
-
   if [ -z "${READELF+x}" ]; then
     # The variable is not set by user, try to locate tool using the code snippet
     for ac_prog in greadelf readelf
@@ -39588,6 +39392,986 @@
     fi
   fi
 
+
+
+
+  # Publish this variable in the help.
+
+
+  if [ -z "${OTOOL+x}" ]; then
+    # The variable is not set by user, try to locate tool using the code snippet
+    for ac_prog in otool
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_OTOOL+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $OTOOL in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_OTOOL="$OTOOL" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_path_OTOOL="$as_dir/$ac_word$ac_exec_ext"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+OTOOL=$ac_cv_path_OTOOL
+if test -n "$OTOOL"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL" >&5
+$as_echo "$OTOOL" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$OTOOL" && break
+done
+
+  else
+    # The variable is set, but is it from the command line or the environment?
+
+    # Try to remove the string !OTOOL! from our list.
+    try_remove_var=${CONFIGURE_OVERRIDDEN_VARIABLES//!OTOOL!/}
+    if test "x$try_remove_var" = "x$CONFIGURE_OVERRIDDEN_VARIABLES"; then
+      # If it failed, the variable was not from the command line. Ignore it,
+      # but warn the user (except for BASH, which is always set by the calling BASH).
+      if test "xOTOOL" != xBASH; then
+        { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Ignoring value of OTOOL from the environment. Use command line variables instead." >&5
+$as_echo "$as_me: WARNING: Ignoring value of OTOOL from the environment. Use command line variables instead." >&2;}
+      fi
+      # Try to locate tool using the code snippet
+      for ac_prog in otool
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_OTOOL+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $OTOOL in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_OTOOL="$OTOOL" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_path_OTOOL="$as_dir/$ac_word$ac_exec_ext"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+OTOOL=$ac_cv_path_OTOOL
+if test -n "$OTOOL"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL" >&5
+$as_echo "$OTOOL" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$OTOOL" && break
+done
+
+    else
+      # If it succeeded, then it was overridden by the user. We will use it
+      # for the tool.
+
+      # First remove it from the list of overridden variables, so we can test
+      # for unknown variables in the end.
+      CONFIGURE_OVERRIDDEN_VARIABLES="$try_remove_var"
+
+      # Check if we try to supply an empty value
+      if test "x$OTOOL" = x; then
+        { $as_echo "$as_me:${as_lineno-$LINENO}: Setting user supplied tool OTOOL= (no value)" >&5
+$as_echo "$as_me: Setting user supplied tool OTOOL= (no value)" >&6;}
+        { $as_echo "$as_me:${as_lineno-$LINENO}: checking for OTOOL" >&5
+$as_echo_n "checking for OTOOL... " >&6; }
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: disabled" >&5
+$as_echo "disabled" >&6; }
+      else
+        # Check if the provided tool contains a complete path.
+        tool_specified="$OTOOL"
+        tool_basename="${tool_specified##*/}"
+        if test "x$tool_basename" = "x$tool_specified"; then
+          # A command without a complete path is provided, search $PATH.
+          { $as_echo "$as_me:${as_lineno-$LINENO}: Will search for user supplied tool OTOOL=$tool_basename" >&5
+$as_echo "$as_me: Will search for user supplied tool OTOOL=$tool_basename" >&6;}
+          # Extract the first word of "$tool_basename", so it can be a program name with args.
+set dummy $tool_basename; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_OTOOL+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $OTOOL in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_OTOOL="$OTOOL" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_path_OTOOL="$as_dir/$ac_word$ac_exec_ext"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+OTOOL=$ac_cv_path_OTOOL
+if test -n "$OTOOL"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL" >&5
+$as_echo "$OTOOL" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+          if test "x$OTOOL" = x; then
+            as_fn_error $? "User supplied tool $tool_basename could not be found" "$LINENO" 5
+          fi
+        else
+          # Otherwise we believe it is a complete path. Use it as it is.
+          { $as_echo "$as_me:${as_lineno-$LINENO}: Will use user supplied tool OTOOL=$tool_specified" >&5
+$as_echo "$as_me: Will use user supplied tool OTOOL=$tool_specified" >&6;}
+          { $as_echo "$as_me:${as_lineno-$LINENO}: checking for OTOOL" >&5
+$as_echo_n "checking for OTOOL... " >&6; }
+          if test ! -x "$tool_specified"; then
+            { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5
+$as_echo "not found" >&6; }
+            as_fn_error $? "User supplied tool OTOOL=$tool_specified does not exist or is not executable" "$LINENO" 5
+          fi
+          { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tool_specified" >&5
+$as_echo "$tool_specified" >&6; }
+        fi
+      fi
+    fi
+
+  fi
+
+
+
+  if test "x$OTOOL" = x; then
+    as_fn_error $? "Could not find required tool for OTOOL" "$LINENO" 5
+  fi
+
+
+
+  # Only process if variable expands to non-empty
+
+  if test "x$OTOOL" != x; then
+    if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then
+
+  # First separate the path from the arguments. This will split at the first
+  # space.
+  complete="$OTOOL"
+  path="${complete%% *}"
+  tmp="$complete EOL"
+  arguments="${tmp#* }"
+
+  # Input might be given as Windows format, start by converting to
+  # unix format.
+  new_path=`$CYGPATH -u "$path"`
+
+  # Now try to locate executable using which
+  new_path=`$WHICH "$new_path" 2> /dev/null`
+  # bat and cmd files are not always considered executable in cygwin causing which
+  # to not find them
+  if test "x$new_path" = x \
+      && test "x`$ECHO \"$path\" | $GREP -i -e \"\\.bat$\" -e \"\\.cmd$\"`" != x \
+      && test "x`$LS \"$path\" 2>/dev/null`" != x; then
+    new_path=`$CYGPATH -u "$path"`
+  fi
+  if test "x$new_path" = x; then
+    # Oops. Which didn't find the executable.
+    # The splitting of arguments from the executable at a space might have been incorrect,
+    # since paths with space are more likely in Windows. Give it another try with the whole
+    # argument.
+    path="$complete"
+    arguments="EOL"
+    new_path=`$CYGPATH -u "$path"`
+    new_path=`$WHICH "$new_path" 2> /dev/null`
+    # bat and cmd files are not always considered executable in cygwin causing which
+    # to not find them
+    if test "x$new_path" = x \
+        && test "x`$ECHO \"$path\" | $GREP -i -e \"\\.bat$\" -e \"\\.cmd$\"`" != x \
+        && test "x`$LS \"$path\" 2>/dev/null`" != x; then
+      new_path=`$CYGPATH -u "$path"`
+    fi
+    if test "x$new_path" = x; then
+      # It's still not found. Now this is an unrecoverable error.
+      { $as_echo "$as_me:${as_lineno-$LINENO}: The path of OTOOL, which resolves as \"$complete\", is not found." >&5
+$as_echo "$as_me: The path of OTOOL, which resolves as \"$complete\", is not found." >&6;}
+      has_space=`$ECHO "$complete" | $GREP " "`
+      if test "x$has_space" != x; then
+        { $as_echo "$as_me:${as_lineno-$LINENO}: You might be mixing spaces in the path and extra arguments, which is not allowed." >&5
+$as_echo "$as_me: You might be mixing spaces in the path and extra arguments, which is not allowed." >&6;}
+      fi
+      as_fn_error $? "Cannot locate the the path of OTOOL" "$LINENO" 5
+    fi
+  fi
+
+  # Cygwin tries to hide some aspects of the Windows file system, such that binaries are
+  # named .exe but called without that suffix. Therefore, "foo" and "foo.exe" are considered
+  # the same file, most of the time (as in "test -f"). But not when running cygpath -s, then
+  # "foo.exe" is OK but "foo" is an error.
+  #
+  # This test is therefore slightly more accurate than "test -f" to check for file presence.
+  # It is also a way to make sure we got the proper file name for the real test later on.
+  test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null`
+  if test "x$test_shortpath" = x; then
+    # Short path failed, file does not exist as specified.
+    # Try adding .exe or .cmd
+    if test -f "${new_path}.exe"; then
+      input_to_shortpath="${new_path}.exe"
+    elif test -f "${new_path}.cmd"; then
+      input_to_shortpath="${new_path}.cmd"
+    else
+      { $as_echo "$as_me:${as_lineno-$LINENO}: The path of OTOOL, which resolves as \"$new_path\", is invalid." >&5
+$as_echo "$as_me: The path of OTOOL, which resolves as \"$new_path\", is invalid." >&6;}
+      { $as_echo "$as_me:${as_lineno-$LINENO}: Neither \"$new_path\" nor \"$new_path.exe/cmd\" can be found" >&5
+$as_echo "$as_me: Neither \"$new_path\" nor \"$new_path.exe/cmd\" can be found" >&6;}
+      as_fn_error $? "Cannot locate the the path of OTOOL" "$LINENO" 5
+    fi
+  else
+    input_to_shortpath="$new_path"
+  fi
+
+  # Call helper function which possibly converts this using DOS-style short mode.
+  # If so, the updated path is stored in $new_path.
+  new_path="$input_to_shortpath"
+
+  input_path="$input_to_shortpath"
+  # Check if we need to convert this using DOS-style short mode. If the path
+  # contains just simple characters, use it. Otherwise (spaces, weird characters),
+  # take no chances and rewrite it.
+  # Note: m4 eats our [], so we need to use [ and ] instead.
+  has_forbidden_chars=`$ECHO "$input_path" | $GREP [^-._/a-zA-Z0-9]`
+  if test "x$has_forbidden_chars" != x; then
+    # Now convert it to mixed DOS-style, short mode (no spaces, and / instead of \)
+    shortmode_path=`$CYGPATH -s -m -a "$input_path"`
+    path_after_shortmode=`$CYGPATH -u "$shortmode_path"`
+    if test "x$path_after_shortmode" != "x$input_to_shortpath"; then
+      # Going to short mode and back again did indeed matter. Since short mode is
+      # case insensitive, let's make it lowercase to improve readability.
+      shortmode_path=`$ECHO "$shortmode_path" | $TR 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+      # Now convert it back to Unix-style (cygpath)
+      input_path=`$CYGPATH -u "$shortmode_path"`
+      new_path="$input_path"
+    fi
+  fi
+
+  test_cygdrive_prefix=`$ECHO $input_path | $GREP ^/cygdrive/`
+  if test "x$test_cygdrive_prefix" = x; then
+    # As a simple fix, exclude /usr/bin since it's not a real path.
+    if test "x`$ECHO $input_to_shortpath | $GREP ^/usr/bin/`" = x; then
+      # The path is in a Cygwin special directory (e.g. /home). We need this converted to
+      # a path prefixed by /cygdrive for fixpath to work.
+      new_path="$CYGWIN_ROOT_PATH$input_path"
+    fi
+  fi
+
+  # remove trailing .exe if any
+  new_path="${new_path/%.exe/}"
+
+    elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then
+
+  # First separate the path from the arguments. This will split at the first
+  # space.
+  complete="$OTOOL"
+  path="${complete%% *}"
+  tmp="$complete EOL"
+  arguments="${tmp#* }"
+
+  # Input might be given as Windows format, start by converting to
+  # unix format.
+  new_path="$path"
+
+  windows_path="$new_path"
+  if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then
+    unix_path=`$CYGPATH -u "$windows_path"`
+    new_path="$unix_path"
+  elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then
+    unix_path=`$ECHO "$windows_path" | $SED -e 's,^\\(.\\):,/\\1,g' -e 's,\\\\,/,g'`
+    new_path="$unix_path"
+  fi
+
+
+  # Now try to locate executable using which
+  new_path=`$WHICH "$new_path" 2> /dev/null`
+
+  if test "x$new_path" = x; then
+    # Oops. Which didn't find the executable.
+    # The splitting of arguments from the executable at a space might have been incorrect,
+    # since paths with space are more likely in Windows. Give it another try with the whole
+    # argument.
+    path="$complete"
+    arguments="EOL"
+    new_path="$path"
+
+  windows_path="$new_path"
+  if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then
+    unix_path=`$CYGPATH -u "$windows_path"`
+    new_path="$unix_path"
+  elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then
+    unix_path=`$ECHO "$windows_path" | $SED -e 's,^\\(.\\):,/\\1,g' -e 's,\\\\,/,g'`
+    new_path="$unix_path"
+  fi
+
+
+    new_path=`$WHICH "$new_path" 2> /dev/null`
+    # bat and cmd files are not always considered executable in MSYS causing which
+    # to not find them
+    if test "x$new_path" = x \
+        && test "x`$ECHO \"$path\" | $GREP -i -e \"\\.bat$\" -e \"\\.cmd$\"`" != x \
+        && test "x`$LS \"$path\" 2>/dev/null`" != x; then
+      new_path="$path"
+
+  windows_path="$new_path"
+  if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then
+    unix_path=`$CYGPATH -u "$windows_path"`
+    new_path="$unix_path"
+  elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then
+    unix_path=`$ECHO "$windows_path" | $SED -e 's,^\\(.\\):,/\\1,g' -e 's,\\\\,/,g'`
+    new_path="$unix_path"
+  fi
+
+    fi
+
+    if test "x$new_path" = x; then
+      # It's still not found. Now this is an unrecoverable error.
+      { $as_echo "$as_me:${as_lineno-$LINENO}: The path of OTOOL, which resolves as \"$complete\", is not found." >&5
+$as_echo "$as_me: The path of OTOOL, which resolves as \"$complete\", is not found." >&6;}
+      has_space=`$ECHO "$complete" | $GREP " "`
+      if test "x$has_space" != x; then
+        { $as_echo "$as_me:${as_lineno-$LINENO}: You might be mixing spaces in the path and extra arguments, which is not allowed." >&5
+$as_echo "$as_me: You might be mixing spaces in the path and extra arguments, which is not allowed." >&6;}
+      fi
+      as_fn_error $? "Cannot locate the the path of OTOOL" "$LINENO" 5
+    fi
+  fi
+
+  # Now new_path has a complete unix path to the binary
+  if test "x`$ECHO $new_path | $GREP ^/bin/`" != x; then
+    # Keep paths in /bin as-is, but remove trailing .exe if any
+    new_path="${new_path/%.exe/}"
+    # Do not save /bin paths to all_fixpath_prefixes!
+  else
+    # Not in mixed or Windows style, start by that.
+    new_path=`cmd //c echo $new_path`
+
+  input_path="$new_path"
+  # Check if we need to convert this using DOS-style short mode. If the path
+  # contains just simple characters, use it. Otherwise (spaces, weird characters),
+  # take no chances and rewrite it.
+  # Note: m4 eats our [], so we need to use [ and ] instead.
+  has_forbidden_chars=`$ECHO "$input_path" | $GREP [^-_/:a-zA-Z0-9]`
+  if test "x$has_forbidden_chars" != x; then
+    # Now convert it to mixed DOS-style, short mode (no spaces, and / instead of \)
+    new_path=`cmd /c "for %A in (\"$input_path\") do @echo %~sA"|$TR \\\\\\\\ / | $TR 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+  fi
+
+    # Output is in $new_path
+
+  windows_path="$new_path"
+  if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then
+    unix_path=`$CYGPATH -u "$windows_path"`
+    new_path="$unix_path"
+  elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then
+    unix_path=`$ECHO "$windows_path" | $SED -e 's,^\\(.\\):,/\\1,g' -e 's,\\\\,/,g'`
+    new_path="$unix_path"
+  fi
+
+    # remove trailing .exe if any
+    new_path="${new_path/%.exe/}"
+
+    # Save the first 10 bytes of this path to the storage, so fixpath can work.
+    all_fixpath_prefixes=("${all_fixpath_prefixes[@]}" "${new_path:0:10}")
+  fi
+
+    else
+      # We're on a unix platform. Hooray! :)
+      # First separate the path from the arguments. This will split at the first
+      # space.
+      complete="$OTOOL"
+      path="${complete%% *}"
+      tmp="$complete EOL"
+      arguments="${tmp#* }"
+
+      # Cannot rely on the command "which" here since it doesn't always work.
+      is_absolute_path=`$ECHO "$path" | $GREP ^/`
+      if test -z "$is_absolute_path"; then
+        # Path to executable is not absolute. Find it.
+        IFS_save="$IFS"
+        IFS=:
+        for p in $PATH; do
+          if test -f "$p/$path" && test -x "$p/$path"; then
+            new_path="$p/$path"
+            break
+          fi
+        done
+        IFS="$IFS_save"
+      else
+        # This is an absolute path, we can use it without further modifications.
+        new_path="$path"
+      fi
+
+      if test "x$new_path" = x; then
+        { $as_echo "$as_me:${as_lineno-$LINENO}: The path of OTOOL, which resolves as \"$complete\", is not found." >&5
+$as_echo "$as_me: The path of OTOOL, which resolves as \"$complete\", is not found." >&6;}
+        has_space=`$ECHO "$complete" | $GREP " "`
+        if test "x$has_space" != x; then
+          { $as_echo "$as_me:${as_lineno-$LINENO}: This might be caused by spaces in the path, which is not allowed." >&5
+$as_echo "$as_me: This might be caused by spaces in the path, which is not allowed." >&6;}
+        fi
+        as_fn_error $? "Cannot locate the the path of OTOOL" "$LINENO" 5
+      fi
+    fi
+
+    # Now join together the path and the arguments once again
+    if test "x$arguments" != xEOL; then
+      new_complete="$new_path ${arguments% *}"
+    else
+      new_complete="$new_path"
+    fi
+
+    if test "x$complete" != "x$new_complete"; then
+      OTOOL="$new_complete"
+      { $as_echo "$as_me:${as_lineno-$LINENO}: Rewriting OTOOL to \"$new_complete\"" >&5
+$as_echo "$as_me: Rewriting OTOOL to \"$new_complete\"" >&6;}
+    fi
+  fi
+
+
+
+
+  # Publish this variable in the help.
+
+
+  if [ -z "${INSTALL_NAME_TOOL+x}" ]; then
+    # The variable is not set by user, try to locate tool using the code snippet
+    for ac_prog in install_name_tool
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_INSTALL_NAME_TOOL+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $INSTALL_NAME_TOOL in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_INSTALL_NAME_TOOL="$INSTALL_NAME_TOOL" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_path_INSTALL_NAME_TOOL="$as_dir/$ac_word$ac_exec_ext"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+INSTALL_NAME_TOOL=$ac_cv_path_INSTALL_NAME_TOOL
+if test -n "$INSTALL_NAME_TOOL"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL_NAME_TOOL" >&5
+$as_echo "$INSTALL_NAME_TOOL" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$INSTALL_NAME_TOOL" && break
+done
+
+  else
+    # The variable is set, but is it from the command line or the environment?
+
+    # Try to remove the string !INSTALL_NAME_TOOL! from our list.
+    try_remove_var=${CONFIGURE_OVERRIDDEN_VARIABLES//!INSTALL_NAME_TOOL!/}
+    if test "x$try_remove_var" = "x$CONFIGURE_OVERRIDDEN_VARIABLES"; then
+      # If it failed, the variable was not from the command line. Ignore it,
+      # but warn the user (except for BASH, which is always set by the calling BASH).
+      if test "xINSTALL_NAME_TOOL" != xBASH; then
+        { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Ignoring value of INSTALL_NAME_TOOL from the environment. Use command line variables instead." >&5
+$as_echo "$as_me: WARNING: Ignoring value of INSTALL_NAME_TOOL from the environment. Use command line variables instead." >&2;}
+      fi
+      # Try to locate tool using the code snippet
+      for ac_prog in install_name_tool
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_INSTALL_NAME_TOOL+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $INSTALL_NAME_TOOL in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_INSTALL_NAME_TOOL="$INSTALL_NAME_TOOL" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_path_INSTALL_NAME_TOOL="$as_dir/$ac_word$ac_exec_ext"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+INSTALL_NAME_TOOL=$ac_cv_path_INSTALL_NAME_TOOL
+if test -n "$INSTALL_NAME_TOOL"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL_NAME_TOOL" >&5
+$as_echo "$INSTALL_NAME_TOOL" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$INSTALL_NAME_TOOL" && break
+done
+
+    else
+      # If it succeeded, then it was overridden by the user. We will use it
+      # for the tool.
+
+      # First remove it from the list of overridden variables, so we can test
+      # for unknown variables in the end.
+      CONFIGURE_OVERRIDDEN_VARIABLES="$try_remove_var"
+
+      # Check if we try to supply an empty value
+      if test "x$INSTALL_NAME_TOOL" = x; then
+        { $as_echo "$as_me:${as_lineno-$LINENO}: Setting user supplied tool INSTALL_NAME_TOOL= (no value)" >&5
+$as_echo "$as_me: Setting user supplied tool INSTALL_NAME_TOOL= (no value)" >&6;}
+        { $as_echo "$as_me:${as_lineno-$LINENO}: checking for INSTALL_NAME_TOOL" >&5
+$as_echo_n "checking for INSTALL_NAME_TOOL... " >&6; }
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: disabled" >&5
+$as_echo "disabled" >&6; }
+      else
+        # Check if the provided tool contains a complete path.
+        tool_specified="$INSTALL_NAME_TOOL"
+        tool_basename="${tool_specified##*/}"
+        if test "x$tool_basename" = "x$tool_specified"; then
+          # A command without a complete path is provided, search $PATH.
+          { $as_echo "$as_me:${as_lineno-$LINENO}: Will search for user supplied tool INSTALL_NAME_TOOL=$tool_basename" >&5
+$as_echo "$as_me: Will search for user supplied tool INSTALL_NAME_TOOL=$tool_basename" >&6;}
+          # Extract the first word of "$tool_basename", so it can be a program name with args.
+set dummy $tool_basename; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_INSTALL_NAME_TOOL+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $INSTALL_NAME_TOOL in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_INSTALL_NAME_TOOL="$INSTALL_NAME_TOOL" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_path_INSTALL_NAME_TOOL="$as_dir/$ac_word$ac_exec_ext"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+  ;;
+esac
+fi
+INSTALL_NAME_TOOL=$ac_cv_path_INSTALL_NAME_TOOL
+if test -n "$INSTALL_NAME_TOOL"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL_NAME_TOOL" >&5
+$as_echo "$INSTALL_NAME_TOOL" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+          if test "x$INSTALL_NAME_TOOL" = x; then
+            as_fn_error $? "User supplied tool $tool_basename could not be found" "$LINENO" 5
+          fi
+        else
+          # Otherwise we believe it is a complete path. Use it as it is.
+          { $as_echo "$as_me:${as_lineno-$LINENO}: Will use user supplied tool INSTALL_NAME_TOOL=$tool_specified" >&5
+$as_echo "$as_me: Will use user supplied tool INSTALL_NAME_TOOL=$tool_specified" >&6;}
+          { $as_echo "$as_me:${as_lineno-$LINENO}: checking for INSTALL_NAME_TOOL" >&5
+$as_echo_n "checking for INSTALL_NAME_TOOL... " >&6; }
+          if test ! -x "$tool_specified"; then
+            { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5
+$as_echo "not found" >&6; }
+            as_fn_error $? "User supplied tool INSTALL_NAME_TOOL=$tool_specified does not exist or is not executable" "$LINENO" 5
+          fi
+          { $as_echo "$as_me:${as_lineno-$LINENO}: result: $tool_specified" >&5
+$as_echo "$tool_specified" >&6; }
+        fi
+      fi
+    fi
+
+  fi
+
+
+
+  if test "x$INSTALL_NAME_TOOL" = x; then
+    as_fn_error $? "Could not find required tool for INSTALL_NAME_TOOL" "$LINENO" 5
+  fi
+
+
+
+  # Only process if variable expands to non-empty
+
+  if test "x$INSTALL_NAME_TOOL" != x; then
+    if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then
+
+  # First separate the path from the arguments. This will split at the first
+  # space.
+  complete="$INSTALL_NAME_TOOL"
+  path="${complete%% *}"
+  tmp="$complete EOL"
+  arguments="${tmp#* }"
+
+  # Input might be given as Windows format, start by converting to
+  # unix format.
+  new_path=`$CYGPATH -u "$path"`
+
+  # Now try to locate executable using which
+  new_path=`$WHICH "$new_path" 2> /dev/null`
+  # bat and cmd files are not always considered executable in cygwin causing which
+  # to not find them
+  if test "x$new_path" = x \
+      && test "x`$ECHO \"$path\" | $GREP -i -e \"\\.bat$\" -e \"\\.cmd$\"`" != x \
+      && test "x`$LS \"$path\" 2>/dev/null`" != x; then
+    new_path=`$CYGPATH -u "$path"`
+  fi
+  if test "x$new_path" = x; then
+    # Oops. Which didn't find the executable.
+    # The splitting of arguments from the executable at a space might have been incorrect,
+    # since paths with space are more likely in Windows. Give it another try with the whole
+    # argument.
+    path="$complete"
+    arguments="EOL"
+    new_path=`$CYGPATH -u "$path"`
+    new_path=`$WHICH "$new_path" 2> /dev/null`
+    # bat and cmd files are not always considered executable in cygwin causing which
+    # to not find them
+    if test "x$new_path" = x \
+        && test "x`$ECHO \"$path\" | $GREP -i -e \"\\.bat$\" -e \"\\.cmd$\"`" != x \
+        && test "x`$LS \"$path\" 2>/dev/null`" != x; then
+      new_path=`$CYGPATH -u "$path"`
+    fi
+    if test "x$new_path" = x; then
+      # It's still not found. Now this is an unrecoverable error.
+      { $as_echo "$as_me:${as_lineno-$LINENO}: The path of INSTALL_NAME_TOOL, which resolves as \"$complete\", is not found." >&5
+$as_echo "$as_me: The path of INSTALL_NAME_TOOL, which resolves as \"$complete\", is not found." >&6;}
+      has_space=`$ECHO "$complete" | $GREP " "`
+      if test "x$has_space" != x; then
+        { $as_echo "$as_me:${as_lineno-$LINENO}: You might be mixing spaces in the path and extra arguments, which is not allowed." >&5
+$as_echo "$as_me: You might be mixing spaces in the path and extra arguments, which is not allowed." >&6;}
+      fi
+      as_fn_error $? "Cannot locate the the path of INSTALL_NAME_TOOL" "$LINENO" 5
+    fi
+  fi
+
+  # Cygwin tries to hide some aspects of the Windows file system, such that binaries are
+  # named .exe but called without that suffix. Therefore, "foo" and "foo.exe" are considered
+  # the same file, most of the time (as in "test -f"). But not when running cygpath -s, then
+  # "foo.exe" is OK but "foo" is an error.
+  #
+  # This test is therefore slightly more accurate than "test -f" to check for file presence.
+  # It is also a way to make sure we got the proper file name for the real test later on.
+  test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null`
+  if test "x$test_shortpath" = x; then
+    # Short path failed, file does not exist as specified.
+    # Try adding .exe or .cmd
+    if test -f "${new_path}.exe"; then
+      input_to_shortpath="${new_path}.exe"
+    elif test -f "${new_path}.cmd"; then
+      input_to_shortpath="${new_path}.cmd"
+    else
+      { $as_echo "$as_me:${as_lineno-$LINENO}: The path of INSTALL_NAME_TOOL, which resolves as \"$new_path\", is invalid." >&5
+$as_echo "$as_me: The path of INSTALL_NAME_TOOL, which resolves as \"$new_path\", is invalid." >&6;}
+      { $as_echo "$as_me:${as_lineno-$LINENO}: Neither \"$new_path\" nor \"$new_path.exe/cmd\" can be found" >&5
+$as_echo "$as_me: Neither \"$new_path\" nor \"$new_path.exe/cmd\" can be found" >&6;}
+      as_fn_error $? "Cannot locate the the path of INSTALL_NAME_TOOL" "$LINENO" 5
+    fi
+  else
+    input_to_shortpath="$new_path"
+  fi
+
+  # Call helper function which possibly converts this using DOS-style short mode.
+  # If so, the updated path is stored in $new_path.
+  new_path="$input_to_shortpath"
+
+  input_path="$input_to_shortpath"
+  # Check if we need to convert this using DOS-style short mode. If the path
+  # contains just simple characters, use it. Otherwise (spaces, weird characters),
+  # take no chances and rewrite it.
+  # Note: m4 eats our [], so we need to use [ and ] instead.
+  has_forbidden_chars=`$ECHO "$input_path" | $GREP [^-._/a-zA-Z0-9]`
+  if test "x$has_forbidden_chars" != x; then
+    # Now convert it to mixed DOS-style, short mode (no spaces, and / instead of \)
+    shortmode_path=`$CYGPATH -s -m -a "$input_path"`
+    path_after_shortmode=`$CYGPATH -u "$shortmode_path"`
+    if test "x$path_after_shortmode" != "x$input_to_shortpath"; then
+      # Going to short mode and back again did indeed matter. Since short mode is
+      # case insensitive, let's make it lowercase to improve readability.
+      shortmode_path=`$ECHO "$shortmode_path" | $TR 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+      # Now convert it back to Unix-style (cygpath)
+      input_path=`$CYGPATH -u "$shortmode_path"`
+      new_path="$input_path"
+    fi
+  fi
+
+  test_cygdrive_prefix=`$ECHO $input_path | $GREP ^/cygdrive/`
+  if test "x$test_cygdrive_prefix" = x; then
+    # As a simple fix, exclude /usr/bin since it's not a real path.
+    if test "x`$ECHO $input_to_shortpath | $GREP ^/usr/bin/`" = x; then
+      # The path is in a Cygwin special directory (e.g. /home). We need this converted to
+      # a path prefixed by /cygdrive for fixpath to work.
+      new_path="$CYGWIN_ROOT_PATH$input_path"
+    fi
+  fi
+
+  # remove trailing .exe if any
+  new_path="${new_path/%.exe/}"
+
+    elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then
+
+  # First separate the path from the arguments. This will split at the first
+  # space.
+  complete="$INSTALL_NAME_TOOL"
+  path="${complete%% *}"
+  tmp="$complete EOL"
+  arguments="${tmp#* }"
+
+  # Input might be given as Windows format, start by converting to
+  # unix format.
+  new_path="$path"
+
+  windows_path="$new_path"
+  if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then
+    unix_path=`$CYGPATH -u "$windows_path"`
+    new_path="$unix_path"
+  elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then
+    unix_path=`$ECHO "$windows_path" | $SED -e 's,^\\(.\\):,/\\1,g' -e 's,\\\\,/,g'`
+    new_path="$unix_path"
+  fi
+
+
+  # Now try to locate executable using which
+  new_path=`$WHICH "$new_path" 2> /dev/null`
+
+  if test "x$new_path" = x; then
+    # Oops. Which didn't find the executable.
+    # The splitting of arguments from the executable at a space might have been incorrect,
+    # since paths with space are more likely in Windows. Give it another try with the whole
+    # argument.
+    path="$complete"
+    arguments="EOL"
+    new_path="$path"
+
+  windows_path="$new_path"
+  if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then
+    unix_path=`$CYGPATH -u "$windows_path"`
+    new_path="$unix_path"
+  elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then
+    unix_path=`$ECHO "$windows_path" | $SED -e 's,^\\(.\\):,/\\1,g' -e 's,\\\\,/,g'`
+    new_path="$unix_path"
+  fi
+
+
+    new_path=`$WHICH "$new_path" 2> /dev/null`
+    # bat and cmd files are not always considered executable in MSYS causing which
+    # to not find them
+    if test "x$new_path" = x \
+        && test "x`$ECHO \"$path\" | $GREP -i -e \"\\.bat$\" -e \"\\.cmd$\"`" != x \
+        && test "x`$LS \"$path\" 2>/dev/null`" != x; then
+      new_path="$path"
+
+  windows_path="$new_path"
+  if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then
+    unix_path=`$CYGPATH -u "$windows_path"`
+    new_path="$unix_path"
+  elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then
+    unix_path=`$ECHO "$windows_path" | $SED -e 's,^\\(.\\):,/\\1,g' -e 's,\\\\,/,g'`
+    new_path="$unix_path"
+  fi
+
+    fi
+
+    if test "x$new_path" = x; then
+      # It's still not found. Now this is an unrecoverable error.
+      { $as_echo "$as_me:${as_lineno-$LINENO}: The path of INSTALL_NAME_TOOL, which resolves as \"$complete\", is not found." >&5
+$as_echo "$as_me: The path of INSTALL_NAME_TOOL, which resolves as \"$complete\", is not found." >&6;}
+      has_space=`$ECHO "$complete" | $GREP " "`
+      if test "x$has_space" != x; then
+        { $as_echo "$as_me:${as_lineno-$LINENO}: You might be mixing spaces in the path and extra arguments, which is not allowed." >&5
+$as_echo "$as_me: You might be mixing spaces in the path and extra arguments, which is not allowed." >&6;}
+      fi
+      as_fn_error $? "Cannot locate the the path of INSTALL_NAME_TOOL" "$LINENO" 5
+    fi
+  fi
+
+  # Now new_path has a complete unix path to the binary
+  if test "x`$ECHO $new_path | $GREP ^/bin/`" != x; then
+    # Keep paths in /bin as-is, but remove trailing .exe if any
+    new_path="${new_path/%.exe/}"
+    # Do not save /bin paths to all_fixpath_prefixes!
+  else
+    # Not in mixed or Windows style, start by that.
+    new_path=`cmd //c echo $new_path`
+
+  input_path="$new_path"
+  # Check if we need to convert this using DOS-style short mode. If the path
+  # contains just simple characters, use it. Otherwise (spaces, weird characters),
+  # take no chances and rewrite it.
+  # Note: m4 eats our [], so we need to use [ and ] instead.
+  has_forbidden_chars=`$ECHO "$input_path" | $GREP [^-_/:a-zA-Z0-9]`
+  if test "x$has_forbidden_chars" != x; then
+    # Now convert it to mixed DOS-style, short mode (no spaces, and / instead of \)
+    new_path=`cmd /c "for %A in (\"$input_path\") do @echo %~sA"|$TR \\\\\\\\ / | $TR 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+  fi
+
+    # Output is in $new_path
+
+  windows_path="$new_path"
+  if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then
+    unix_path=`$CYGPATH -u "$windows_path"`
+    new_path="$unix_path"
+  elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then
+    unix_path=`$ECHO "$windows_path" | $SED -e 's,^\\(.\\):,/\\1,g' -e 's,\\\\,/,g'`
+    new_path="$unix_path"
+  fi
+
+    # remove trailing .exe if any
+    new_path="${new_path/%.exe/}"
+
+    # Save the first 10 bytes of this path to the storage, so fixpath can work.
+    all_fixpath_prefixes=("${all_fixpath_prefixes[@]}" "${new_path:0:10}")
+  fi
+
+    else
+      # We're on a unix platform. Hooray! :)
+      # First separate the path from the arguments. This will split at the first
+      # space.
+      complete="$INSTALL_NAME_TOOL"
+      path="${complete%% *}"
+      tmp="$complete EOL"
+      arguments="${tmp#* }"
+
+      # Cannot rely on the command "which" here since it doesn't always work.
+      is_absolute_path=`$ECHO "$path" | $GREP ^/`
+      if test -z "$is_absolute_path"; then
+        # Path to executable is not absolute. Find it.
+        IFS_save="$IFS"
+        IFS=:
+        for p in $PATH; do
+          if test -f "$p/$path" && test -x "$p/$path"; then
+            new_path="$p/$path"
+            break
+          fi
+        done
+        IFS="$IFS_save"
+      else
+        # This is an absolute path, we can use it without further modifications.
+        new_path="$path"
+      fi
+
+      if test "x$new_path" = x; then
+        { $as_echo "$as_me:${as_lineno-$LINENO}: The path of INSTALL_NAME_TOOL, which resolves as \"$complete\", is not found." >&5
+$as_echo "$as_me: The path of INSTALL_NAME_TOOL, which resolves as \"$complete\", is not found." >&6;}
+        has_space=`$ECHO "$complete" | $GREP " "`
+        if test "x$has_space" != x; then
+          { $as_echo "$as_me:${as_lineno-$LINENO}: This might be caused by spaces in the path, which is not allowed." >&5
+$as_echo "$as_me: This might be caused by spaces in the path, which is not allowed." >&6;}
+        fi
+        as_fn_error $? "Cannot locate the the path of INSTALL_NAME_TOOL" "$LINENO" 5
+      fi
+    fi
+
+    # Now join together the path and the arguments once again
+    if test "x$arguments" != xEOL; then
+      new_complete="$new_path ${arguments% *}"
+    else
+      new_complete="$new_path"
+    fi
+
+    if test "x$complete" != "x$new_complete"; then
+      INSTALL_NAME_TOOL="$new_complete"
+      { $as_echo "$as_me:${as_lineno-$LINENO}: Rewriting INSTALL_NAME_TOOL to \"$new_complete\"" >&5
+$as_echo "$as_me: Rewriting INSTALL_NAME_TOOL to \"$new_complete\"" >&6;}
+    fi
+  fi
+
   fi
 
   if test "x$TOOLCHAIN_TYPE" = xmicrosoft; then
@@ -64486,17 +65270,18 @@
     { $as_echo "$as_me:${as_lineno-$LINENO}: result: $BUNDLE_FREETYPE" >&5
 $as_echo "$BUNDLE_FREETYPE" >&6; }
 
-  fi # end freetype needed
-
-  FREETYPE_LICENSE=""
-  if test "x$with_freetype_license" = "xyes"; then
-    as_fn_error $? "--with-freetype-license must have a value" "$LINENO" 5
-  elif test "x$with_freetype_license" != "x"; then
-    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for freetype license" >&5
+    if test "x$BUNDLE_FREETYPE" = xyes; then
+      FREETYPE_LICENSE=""
+      { $as_echo "$as_me:${as_lineno-$LINENO}: checking for freetype license" >&5
 $as_echo_n "checking for freetype license... " >&6; }
-    { $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_freetype_license" >&5
+      if test "x$with_freetype_license" = "xyes"; then
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+        as_fn_error $? "--with-freetype-license must have a value" "$LINENO" 5
+      elif test "x$with_freetype_license" != "x"; then
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_freetype_license" >&5
 $as_echo "$with_freetype_license" >&6; }
-    FREETYPE_LICENSE="$with_freetype_license"
+        FREETYPE_LICENSE="$with_freetype_license"
 
   # Only process if variable expands to non-empty
 
@@ -64629,10 +65414,154 @@
     fi
   fi
 
-    if test ! -f "$FREETYPE_LICENSE"; then
-      as_fn_error $? "$FREETYPE_LICENSE cannot be found" "$LINENO" 5
-    fi
-  fi
+        if test ! -f "$FREETYPE_LICENSE"; then
+          as_fn_error $? "$FREETYPE_LICENSE cannot be found" "$LINENO" 5
+        fi
+      else
+        if test "x$with_freetype" != "x" && test -f $with_freetype/freetype.md; then
+          FREETYPE_LICENSE="$with_freetype/freetype.md"
+          { $as_echo "$as_me:${as_lineno-$LINENO}: result: $FREETYPE_LICENSE" >&5
+$as_echo "$FREETYPE_LICENSE" >&6; }
+
+  # Only process if variable expands to non-empty
+
+  if test "x$FREETYPE_LICENSE" != x; then
+    if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then
+
+  # Input might be given as Windows format, start by converting to
+  # unix format.
+  path="$FREETYPE_LICENSE"
+  new_path=`$CYGPATH -u "$path"`
+
+  # Cygwin tries to hide some aspects of the Windows file system, such that binaries are
+  # named .exe but called without that suffix. Therefore, "foo" and "foo.exe" are considered
+  # the same file, most of the time (as in "test -f"). But not when running cygpath -s, then
+  # "foo.exe" is OK but "foo" is an error.
+  #
+  # This test is therefore slightly more accurate than "test -f" to check for file precense.
+  # It is also a way to make sure we got the proper file name for the real test later on.
+  test_shortpath=`$CYGPATH -s -m "$new_path" 2> /dev/null`
+  if test "x$test_shortpath" = x; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: The path of FREETYPE_LICENSE, which resolves as \"$path\", is invalid." >&5
+$as_echo "$as_me: The path of FREETYPE_LICENSE, which resolves as \"$path\", is invalid." >&6;}
+    as_fn_error $? "Cannot locate the the path of FREETYPE_LICENSE" "$LINENO" 5
+  fi
+
+  # Call helper function which possibly converts this using DOS-style short mode.
+  # If so, the updated path is stored in $new_path.
+
+  input_path="$new_path"
+  # Check if we need to convert this using DOS-style short mode. If the path
+  # contains just simple characters, use it. Otherwise (spaces, weird characters),
+  # take no chances and rewrite it.
+  # Note: m4 eats our [], so we need to use [ and ] instead.
+  has_forbidden_chars=`$ECHO "$input_path" | $GREP [^-._/a-zA-Z0-9]`
+  if test "x$has_forbidden_chars" != x; then
+    # Now convert it to mixed DOS-style, short mode (no spaces, and / instead of \)
+    shortmode_path=`$CYGPATH -s -m -a "$input_path"`
+    path_after_shortmode=`$CYGPATH -u "$shortmode_path"`
+    if test "x$path_after_shortmode" != "x$input_to_shortpath"; then
+      # Going to short mode and back again did indeed matter. Since short mode is
+      # case insensitive, let's make it lowercase to improve readability.
+      shortmode_path=`$ECHO "$shortmode_path" | $TR 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+      # Now convert it back to Unix-style (cygpath)
+      input_path=`$CYGPATH -u "$shortmode_path"`
+      new_path="$input_path"
+    fi
+  fi
+
+  test_cygdrive_prefix=`$ECHO $input_path | $GREP ^/cygdrive/`
+  if test "x$test_cygdrive_prefix" = x; then
+    # As a simple fix, exclude /usr/bin since it's not a real path.
+    if test "x`$ECHO $new_path | $GREP ^/usr/bin/`" = x; then
+      # The path is in a Cygwin special directory (e.g. /home). We need this converted to
+      # a path prefixed by /cygdrive for fixpath to work.
+      new_path="$CYGWIN_ROOT_PATH$input_path"
+    fi
+  fi
+
+
+  if test "x$path" != "x$new_path"; then
+    FREETYPE_LICENSE="$new_path"
+    { $as_echo "$as_me:${as_lineno-$LINENO}: Rewriting FREETYPE_LICENSE to \"$new_path\"" >&5
+$as_echo "$as_me: Rewriting FREETYPE_LICENSE to \"$new_path\"" >&6;}
+  fi
+
+    elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then
+
+  path="$FREETYPE_LICENSE"
+  has_colon=`$ECHO $path | $GREP ^.:`
+  new_path="$path"
+  if test "x$has_colon" = x; then
+    # Not in mixed or Windows style, start by that.
+    new_path=`cmd //c echo $path`
+  fi
+
+
+  input_path="$new_path"
+  # Check if we need to convert this using DOS-style short mode. If the path
+  # contains just simple characters, use it. Otherwise (spaces, weird characters),
+  # take no chances and rewrite it.
+  # Note: m4 eats our [], so we need to use [ and ] instead.
+  has_forbidden_chars=`$ECHO "$input_path" | $GREP [^-_/:a-zA-Z0-9]`
+  if test "x$has_forbidden_chars" != x; then
+    # Now convert it to mixed DOS-style, short mode (no spaces, and / instead of \)
+    new_path=`cmd /c "for %A in (\"$input_path\") do @echo %~sA"|$TR \\\\\\\\ / | $TR 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+  fi
+
+
+  windows_path="$new_path"
+  if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then
+    unix_path=`$CYGPATH -u "$windows_path"`
+    new_path="$unix_path"
+  elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys"; then
+    unix_path=`$ECHO "$windows_path" | $SED -e 's,^\\(.\\):,/\\1,g' -e 's,\\\\,/,g'`
+    new_path="$unix_path"
+  fi
+
+  if test "x$path" != "x$new_path"; then
+    FREETYPE_LICENSE="$new_path"
+    { $as_echo "$as_me:${as_lineno-$LINENO}: Rewriting FREETYPE_LICENSE to \"$new_path\"" >&5
+$as_echo "$as_me: Rewriting FREETYPE_LICENSE to \"$new_path\"" >&6;}
+  fi
+
+  # Save the first 10 bytes of this path to the storage, so fixpath can work.
+  all_fixpath_prefixes=("${all_fixpath_prefixes[@]}" "${new_path:0:10}")
+
+    else
+      # We're on a unix platform. Hooray! :)
+      path="$FREETYPE_LICENSE"
+      has_space=`$ECHO "$path" | $GREP " "`
+      if test "x$has_space" != x; then
+        { $as_echo "$as_me:${as_lineno-$LINENO}: The path of FREETYPE_LICENSE, which resolves as \"$path\", is invalid." >&5
+$as_echo "$as_me: The path of FREETYPE_LICENSE, which resolves as \"$path\", is invalid." >&6;}
+        as_fn_error $? "Spaces are not allowed in this path." "$LINENO" 5
+      fi
+
+      # Use eval to expand a potential ~
+      eval path="$path"
+      if test ! -f "$path" && test ! -d "$path"; then
+        as_fn_error $? "The path of FREETYPE_LICENSE, which resolves as \"$path\", is not found." "$LINENO" 5
+      fi
+
+      if test -d "$path"; then
+        FREETYPE_LICENSE="`cd "$path"; $THEPWDCMD -L`"
+      else
+        dir="`$DIRNAME "$path"`"
+        base="`$BASENAME "$path"`"
+        FREETYPE_LICENSE="`cd "$dir"; $THEPWDCMD -L`/$base"
+      fi
+    fi
+  fi
+
+        else
+          { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+        fi
+      fi
+    fi
+
+  fi # end freetype needed
 
 
 
@@ -65334,23 +66263,6 @@
 fi
 
 
-  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for which libpng to use" >&5
-$as_echo_n "checking for which libpng to use... " >&6; }
-
-  # default is bundled
-  DEFAULT_LIBPNG=bundled
-  # if user didn't specify, use DEFAULT_LIBPNG
-  if test "x${with_libpng}" = "x"; then
-    with_libpng=${DEFAULT_LIBPNG}
-  fi
-
-  if test "x${with_libpng}" = "xbundled"; then
-    USE_EXTERNAL_LIBPNG=false
-    PNG_CFLAGS=""
-    PNG_LIBS=""
-    { $as_echo "$as_me:${as_lineno-$LINENO}: result: bundled" >&5
-$as_echo "bundled" >&6; }
-  elif test "x${with_libpng}" = "xsystem"; then
 
 pkg_failed=no
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for PNG" >&5
@@ -65418,6 +66330,23 @@
 $as_echo "yes" >&6; }
 	LIBPNG_FOUND=yes
 fi
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for which libpng to use" >&5
+$as_echo_n "checking for which libpng to use... " >&6; }
+
+  # default is bundled
+  DEFAULT_LIBPNG=bundled
+  # if user didn't specify, use DEFAULT_LIBPNG
+  if test "x${with_libpng}" = "x"; then
+    with_libpng=${DEFAULT_LIBPNG}
+  fi
+
+  if test "x${with_libpng}" = "xbundled"; then
+    USE_EXTERNAL_LIBPNG=false
+    PNG_CFLAGS=""
+    PNG_LIBS=""
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: bundled" >&5
+$as_echo "bundled" >&6; }
+  elif test "x${with_libpng}" = "xsystem"; then
     if test "x${LIBPNG_FOUND}" = "xyes"; then
       # PKG_CHECK_MODULES will set PNG_CFLAGS and PNG_LIBS
       USE_EXTERNAL_LIBPNG=true
@@ -65515,6 +66444,40 @@
       USE_EXTERNAL_LIBZ=true
       { $as_echo "$as_me:${as_lineno-$LINENO}: result: system" >&5
 $as_echo "system" >&6; }
+
+      if test "x$USE_EXTERNAL_LIBPNG" != "xtrue"; then
+        # If we use bundled libpng, we must verify that we have a proper zlib.
+        # For instance zlib-ng has had issues with inflateValidate().
+        { $as_echo "$as_me:${as_lineno-$LINENO}: checking for system zlib functionality" >&5
+$as_echo_n "checking for system zlib functionality... " >&6; }
+        cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include "zlib.h"
+int
+main ()
+{
+
+                #if ZLIB_VERNUM >= 0x1281
+                  inflateValidate(NULL, 0);
+                #endif
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5
+$as_echo "ok" >&6; }
+else
+
+                { $as_echo "$as_me:${as_lineno-$LINENO}: result: not ok" >&5
+$as_echo "not ok" >&6; }
+                as_fn_error $? "System zlib not working correctly" "$LINENO" 5
+
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+      fi
     else
       { $as_echo "$as_me:${as_lineno-$LINENO}: result: system not found" >&5
 $as_echo "system not found" >&6; }
@@ -66416,23 +67379,6 @@
   { $as_echo "$as_me:${as_lineno-$LINENO}: checking flags for boot jdk java command " >&5
 $as_echo_n "checking flags for boot jdk java command ... " >&6; }
 
-  # Disable special log output when a debug build is used as Boot JDK...
-
-  $ECHO "Check if jvm arg is ok: -XX:-PrintVMOptions -XX:-UnlockDiagnosticVMOptions -XX:-LogVMOutput" >&5
-  $ECHO "Command: $JAVA -XX:-PrintVMOptions -XX:-UnlockDiagnosticVMOptions -XX:-LogVMOutput -version" >&5
-  OUTPUT=`$JAVA -XX:-PrintVMOptions -XX:-UnlockDiagnosticVMOptions -XX:-LogVMOutput -version 2>&1`
-  FOUND_WARN=`$ECHO "$OUTPUT" | $GREP -i warn`
-  FOUND_VERSION=`$ECHO $OUTPUT | $GREP " version \""`
-  if test "x$FOUND_VERSION" != x && test "x$FOUND_WARN" = x; then
-    boot_jdk_jvmargs="$boot_jdk_jvmargs -XX:-PrintVMOptions -XX:-UnlockDiagnosticVMOptions -XX:-LogVMOutput"
-    JVM_ARG_OK=true
-  else
-    $ECHO "Arg failed:" >&5
-    $ECHO "$OUTPUT" >&5
-    JVM_ARG_OK=false
-  fi
-
-
   # Force en-US environment
 
   $ECHO "Check if jvm arg is ok: -Duser.language=en -Duser.country=US" >&5
--- a/make/autoconf/lib-bundled.m4	Thu Nov 30 22:05:19 2017 +0100
+++ b/make/autoconf/lib-bundled.m4	Wed Dec 06 11:39:23 2017 +0000
@@ -113,6 +113,7 @@
   AC_ARG_WITH(libpng, [AS_HELP_STRING([--with-libpng],
      [use libpng from build system or OpenJDK source (system, bundled) @<:@bundled@:>@])])
 
+  PKG_CHECK_MODULES(PNG, libpng, [LIBPNG_FOUND=yes], [LIBPNG_FOUND=no])
   AC_MSG_CHECKING([for which libpng to use])
 
   # default is bundled
@@ -128,7 +129,6 @@
     PNG_LIBS=""
     AC_MSG_RESULT([bundled])
   elif test "x${with_libpng}" = "xsystem"; then
-    PKG_CHECK_MODULES(PNG, libpng, [LIBPNG_FOUND=yes], [LIBPNG_FOUND=no])
     if test "x${LIBPNG_FOUND}" = "xyes"; then
       # PKG_CHECK_MODULES will set PNG_CFLAGS and PNG_LIBS
       USE_EXTERNAL_LIBPNG=true
@@ -183,6 +183,24 @@
     if test "x${ZLIB_FOUND}" = "xyes"; then
       USE_EXTERNAL_LIBZ=true
       AC_MSG_RESULT([system])
+
+      if test "x$USE_EXTERNAL_LIBPNG" != "xtrue"; then
+        # If we use bundled libpng, we must verify that we have a proper zlib.
+        # For instance zlib-ng has had issues with inflateValidate().
+        AC_MSG_CHECKING([for system zlib functionality])
+        AC_COMPILE_IFELSE(
+            [AC_LANG_PROGRAM([#include "zlib.h"], [
+                #if ZLIB_VERNUM >= 0x1281
+                  inflateValidate(NULL, 0);
+                #endif
+            ])],
+            [AC_MSG_RESULT([ok])],
+            [
+                AC_MSG_RESULT([not ok])
+                AC_MSG_ERROR([System zlib not working correctly])
+            ]
+        )
+      fi
     else
       AC_MSG_RESULT([system not found])
       AC_MSG_ERROR([--with-zlib=system specified, but no zlib found!])
--- a/make/autoconf/lib-freetype.m4	Thu Nov 30 22:05:19 2017 +0100
+++ b/make/autoconf/lib-freetype.m4	Wed Dec 06 11:39:23 2017 +0000
@@ -443,21 +443,32 @@
     fi
     AC_MSG_RESULT([$BUNDLE_FREETYPE])
 
+    if test "x$BUNDLE_FREETYPE" = xyes; then
+      FREETYPE_LICENSE=""
+      AC_MSG_CHECKING([for freetype license])
+      if test "x$with_freetype_license" = "xyes"; then
+        AC_MSG_RESULT([no])
+        AC_MSG_ERROR([--with-freetype-license must have a value])
+      elif test "x$with_freetype_license" != "x"; then
+        AC_MSG_RESULT([$with_freetype_license])
+        FREETYPE_LICENSE="$with_freetype_license"
+        BASIC_FIXUP_PATH(FREETYPE_LICENSE)
+        if test ! -f "$FREETYPE_LICENSE"; then
+          AC_MSG_ERROR([$FREETYPE_LICENSE cannot be found])
+        fi
+      else
+        if test "x$with_freetype" != "x" && test -f $with_freetype/freetype.md; then
+          FREETYPE_LICENSE="$with_freetype/freetype.md"
+          AC_MSG_RESULT([$FREETYPE_LICENSE])
+          BASIC_FIXUP_PATH(FREETYPE_LICENSE)
+        else
+          AC_MSG_RESULT([no])
+        fi
+      fi
+    fi
+
   fi # end freetype needed
 
-  FREETYPE_LICENSE=""
-  if test "x$with_freetype_license" = "xyes"; then
-    AC_MSG_ERROR([--with-freetype-license must have a value])
-  elif test "x$with_freetype_license" != "x"; then
-    AC_MSG_CHECKING([for freetype license])
-    AC_MSG_RESULT([$with_freetype_license])
-    FREETYPE_LICENSE="$with_freetype_license"
-    BASIC_FIXUP_PATH(FREETYPE_LICENSE)
-    if test ! -f "$FREETYPE_LICENSE"; then
-      AC_MSG_ERROR([$FREETYPE_LICENSE cannot be found])
-    fi
-  fi
-
   AC_SUBST(FREETYPE_BUNDLE_LIB_PATH)
   AC_SUBST(FREETYPE_CFLAGS)
   AC_SUBST(FREETYPE_LIBS)
--- a/make/autoconf/spec.gmk.in	Thu Nov 30 22:05:19 2017 +0100
+++ b/make/autoconf/spec.gmk.in	Wed Dec 06 11:39:23 2017 +0000
@@ -293,6 +293,7 @@
 FREETYPE_CFLAGS:=@FREETYPE_CFLAGS@
 FREETYPE_BUNDLE_LIB_PATH=@FREETYPE_BUNDLE_LIB_PATH@
 FREETYPE_LICENSE=@FREETYPE_LICENSE@
+FONTCONFIG_CFLAGS:=@FONTCONFIG_CFLAGS@
 CUPS_CFLAGS:=@CUPS_CFLAGS@
 ALSA_LIBS:=@ALSA_LIBS@
 ALSA_CFLAGS:=@ALSA_CFLAGS@
@@ -471,6 +472,7 @@
 STRIP:=@STRIP@
 
 LIPO:=@LIPO@
+INSTALL_NAME_TOOL:=@INSTALL_NAME_TOOL@
 
 # Options to linker to specify a mapfile.
 # (Note absence of := assignment, because we do not want to evaluate the macro body here)
--- a/make/autoconf/toolchain.m4	Thu Nov 30 22:05:19 2017 +0100
+++ b/make/autoconf/toolchain.m4	Wed Dec 06 11:39:23 2017 +0000
@@ -628,6 +628,10 @@
   if test "x$OPENJDK_TARGET_OS" = "xmacosx"; then
     BASIC_PATH_PROGS(LIPO, lipo)
     BASIC_FIXUP_EXECUTABLE(LIPO)
+    BASIC_REQUIRE_PROGS(OTOOL, otool)
+    BASIC_FIXUP_EXECUTABLE(OTOOL)
+    BASIC_REQUIRE_PROGS(INSTALL_NAME_TOOL, install_name_tool)
+    BASIC_FIXUP_EXECUTABLE(INSTALL_NAME_TOOL)
   fi
 
   if test "x$TOOLCHAIN_TYPE" = xmicrosoft; then
--- a/make/conf/jib-profiles.js	Thu Nov 30 22:05:19 2017 +0100
+++ b/make/conf/jib-profiles.js	Wed Dec 06 11:39:23 2017 +0000
@@ -429,7 +429,7 @@
         "macosx-x64": {
             target_os: "macosx",
             target_cpu: "x64",
-            dependencies: ["devkit"],
+            dependencies: ["devkit", "freetype"],
             configure_args: concat(common.configure_args_64bit, "--with-zlib=system",
                 "--with-macosx-version-max=10.7.0"),
         },
@@ -662,21 +662,6 @@
         }
     });
 
-    // The windows ri profile needs to add the freetype license file
-    profilesRiFreetype = {
-        "windows-x86-ri": {
-            configure_args: "--with-freetype-license="
-                + input.get("freetype", "install_path")
-                + "/freetype-2.7.1-v120-x86/freetype.md"
-        },
-        "windows-x64-ri": {
-            configure_args: "--with-freetype-license="
-                + input.get("freetype", "install_path")
-                + "/freetype-2.7.1-v120-x64/freetype.md"
-        }
-    };
-    profiles = concatObjects(profiles, profilesRiFreetype);
-
     // Profiles used to run tests. Used in JPRT and Mach 5.
     var testOnlyProfiles = {
         "run-test-jprt": {
@@ -788,6 +773,12 @@
     var boot_jdk_platform = (input.build_os == "macosx" ? "osx" : input.build_os)
         + "-" + input.build_cpu;
 
+    var freetype_version = {
+        windows_x64: "2.7.1-v120+1.1",
+        windows_x86: "2.7.1-v120+1.1",
+        macosx_x64: "2.7.1-Xcode6.3-MacOSX10.9+1.0"
+    }[input.target_platform];
+
     var dependencies = {
 
         boot_jdk: {
@@ -852,7 +843,7 @@
         freetype: {
             organization: common.organization,
             ext: "tar.gz",
-            revision: "2.7.1-v120+1.0",
+            revision: freetype_version,
             module: "freetype-" + input.target_platform
         },
 
--- a/make/copy/Copy-java.desktop.gmk	Thu Nov 30 22:05:19 2017 +0100
+++ b/make/copy/Copy-java.desktop.gmk	Wed Dec 06 11:39:23 2017 +0000
@@ -44,7 +44,8 @@
 ################################################################################
 
 ifneq ($(FREETYPE_BUNDLE_LIB_PATH), )
-  # We need to bundle the freetype library, so it will be available at runtime as well as link time.
+  # We need to bundle the freetype library, so it will be available at runtime
+  # as well as link time.
   #
   # NB: Default freetype build system uses -h linker option and
   # result .so contains hardcoded library name that is later
@@ -61,10 +62,10 @@
   #
   #TODO: rework this to avoid hardcoding library name in the makefile
   #
-  ifeq ($(OPENJDK_TARGET_OS), windows)
+  ifneq ($(filter $(OPENJDK_TARGET_OS), linux solaris), )
+    FREETYPE_TARGET_LIB := $(LIB_DST_DIR)/$(call SHARED_LIBRARY,freetype).6
+  else
     FREETYPE_TARGET_LIB := $(LIB_DST_DIR)/$(call SHARED_LIBRARY,freetype)
-  else
-    FREETYPE_TARGET_LIB := $(LIB_DST_DIR)/$(call SHARED_LIBRARY,freetype).6
   endif
 
   # We can't use $(install-file) in this rule because it preserves symbolic links and
--- a/make/lib/Awt2dLibraries.gmk	Thu Nov 30 22:05:19 2017 +0100
+++ b/make/lib/Awt2dLibraries.gmk	Wed Dec 06 11:39:23 2017 +0000
@@ -658,7 +658,7 @@
 
 $(eval $(call SetupNativeCompilation,BUILD_LIBFONTMANAGER, \
     LIBRARY := fontmanager, \
-    OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE), \
+    OUTPUT_DIR := $(SUPPORT_OUTPUTDIR)/native/$(MODULE)/libfontmanager, \
     SRC := $(LIBFONTMANAGER_SRC), \
     EXCLUDE_FILES := $(LIBFONTMANAGER_EXCLUDE_FILES) \
         AccelGlyphCache.c, \
@@ -702,6 +702,21 @@
     OBJECT_DIR := $(SUPPORT_OUTPUTDIR)/native/$(MODULE)/libfontmanager, \
 ))
 
+$(INSTALL_LIBRARIES_HERE)/$(call SHARED_LIBRARY,fontmanager): $(BUILD_LIBFONTMANAGER_TARGET)
+	$(install-file)
+        ifneq ($(FREETYPE_BUNDLE_LIB_PATH), )
+          ifeq ($(OPENJDK_TARGET_OS), macosx)
+            # If bundling freetype on macosx, we need to rewrite the rpath location
+            # in the libfontmanager library to point to the bundled location
+	    $(INSTALL_NAME_TOOL) -change \
+	        `$(OTOOL) -D $(FREETYPE_BUNDLE_LIB_PATH)/$(call SHARED_LIBRARY,freetype) | $(TAIL) -n1` \
+	        '@rpath/$(call SHARED_LIBRARY,freetype)' \
+	        $@
+          endif
+        endif
+
+BUILD_LIBFONTMANAGER += $(INSTALL_LIBRARIES_HERE)/$(call SHARED_LIBRARY,fontmanager)
+
 $(BUILD_LIBFONTMANAGER): $(BUILD_LIBAWT)
 
 ifneq (, $(findstring $(OPENJDK_TARGET_OS), solaris aix))
--- a/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp	Thu Nov 30 22:05:19 2017 +0100
+++ b/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp	Wed Dec 06 11:39:23 2017 +0000
@@ -148,6 +148,16 @@
       PrefetchCopyIntervalInBytes = 32760;
   }
 
+  if (AllocatePrefetchDistance !=-1 && (AllocatePrefetchDistance & 7)) {
+    warning("AllocatePrefetchDistance must be multiple of 8");
+    AllocatePrefetchDistance &= ~7;
+  }
+
+  if (AllocatePrefetchStepSize & 7) {
+    warning("AllocatePrefetchStepSize must be multiple of 8");
+    AllocatePrefetchStepSize &= ~7;
+  }
+
   if (SoftwarePrefetchHintDistance != -1 &&
        (SoftwarePrefetchHintDistance & 7)) {
     warning("SoftwarePrefetchHintDistance must be -1, or a multiple of 8");
--- a/src/java.base/share/classes/java/lang/Class.java	Thu Nov 30 22:05:19 2017 +0100
+++ b/src/java.base/share/classes/java/lang/Class.java	Wed Dec 06 11:39:23 2017 +0000
@@ -53,12 +53,11 @@
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.HashMap;
-import java.util.HashSet;
 import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
-import java.util.Set;
 import java.util.StringJoiner;
 
 import jdk.internal.HotSpotIntrinsicCandidate;
@@ -1771,7 +1770,7 @@
         if (sm != null) {
             checkMemberAccess(sm, Member.PUBLIC, Reflection.getCallerClass(), true);
         }
-        return copyFields(privateGetPublicFields(null));
+        return copyFields(privateGetPublicFields());
     }
 
 
@@ -3026,7 +3025,7 @@
     // Returns an array of "root" fields. These Field objects must NOT
     // be propagated to the outside world, but must instead be copied
     // via ReflectionFactory.copyField.
-    private Field[] privateGetPublicFields(Set<Class<?>> traversedInterfaces) {
+    private Field[] privateGetPublicFields() {
         Field[] res;
         ReflectionData<T> rd = reflectionData();
         if (rd != null) {
@@ -3034,35 +3033,25 @@
             if (res != null) return res;
         }
 
-        // No cached value available; compute value recursively.
-        // Traverse in correct order for getField().
-        List<Field> fields = new ArrayList<>();
-        if (traversedInterfaces == null) {
-            traversedInterfaces = new HashSet<>();
+        // Use a linked hash set to ensure order is preserved and
+        // fields from common super interfaces are not duplicated
+        LinkedHashSet<Field> fields = new LinkedHashSet<>();
+
+        // Local fields
+        addAll(fields, privateGetDeclaredFields(true));
+
+        // Direct superinterfaces, recursively
+        for (Class<?> si : getInterfaces()) {
+            addAll(fields, si.privateGetPublicFields());
         }
 
-        // Local fields
-        Field[] tmp = privateGetDeclaredFields(true);
-        addAll(fields, tmp);
-
-        // Direct superinterfaces, recursively
-        for (Class<?> c : getInterfaces()) {
-            if (!traversedInterfaces.contains(c)) {
-                traversedInterfaces.add(c);
-                addAll(fields, c.privateGetPublicFields(traversedInterfaces));
-            }
+        // Direct superclass, recursively
+        Class<?> sc = getSuperclass();
+        if (sc != null) {
+            addAll(fields, sc.privateGetPublicFields());
         }
 
-        // Direct superclass, recursively
-        if (!isInterface()) {
-            Class<?> c = getSuperclass();
-            if (c != null) {
-                addAll(fields, c.privateGetPublicFields(traversedInterfaces));
-            }
-        }
-
-        res = new Field[fields.size()];
-        fields.toArray(res);
+        res = fields.toArray(new Field[0]);
         if (rd != null) {
             rd.publicFields = res;
         }
--- a/src/java.base/share/classes/java/lang/ClassLoader.java	Thu Nov 30 22:05:19 2017 +0100
+++ b/src/java.base/share/classes/java/lang/ClassLoader.java	Wed Dec 06 11:39:23 2017 +0000
@@ -30,6 +30,7 @@
 import java.io.UncheckedIOException;
 import java.io.File;
 import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
 import java.net.URL;
 import java.security.AccessController;
 import java.security.AccessControlContext;
@@ -1867,7 +1868,7 @@
      * to be the system class loader. During construction, the class loader
      * should take great care to avoid calling {@code getSystemClassLoader()}.
      * If circular initialization of the system class loader is detected then
-     * an unspecified error or exception is thrown.
+     * an {@code IllegalStateException} is thrown.
      *
      * @implNote The system property to override the system class loader is not
      * examined until the VM is almost fully initialized. Code that executes
@@ -1918,8 +1919,8 @@
                 // the system class loader is the built-in app class loader during startup
                 return getBuiltinAppClassLoader();
             case 3:
-                String msg = "getSystemClassLoader should only be called after VM booted";
-                throw new InternalError(msg);
+                String msg = "getSystemClassLoader cannot be called during the system class loader instantiation";
+                throw new IllegalStateException(msg);
             case 4:
                 // system fully initialized
                 assert VM.isBooted() && scl != null;
@@ -1969,7 +1970,17 @@
                                            .getDeclaredConstructor(ClassLoader.class);
                 scl = (ClassLoader) ctor.newInstance(builtinLoader);
             } catch (Exception e) {
-                throw new Error(e);
+                Throwable cause = e;
+                if (e instanceof InvocationTargetException) {
+                    cause = e.getCause();
+                    if (cause instanceof Error) {
+                        throw (Error) cause;
+                    }
+                }
+                if (cause instanceof RuntimeException) {
+                    throw (RuntimeException) cause;
+                }
+                throw new Error(cause.getMessage(), cause);
             }
         } else {
             scl = builtinLoader;
--- a/src/java.base/share/classes/java/lang/String.java	Thu Nov 30 22:05:19 2017 +0100
+++ b/src/java.base/share/classes/java/lang/String.java	Wed Dec 06 11:39:23 2017 +0000
@@ -645,19 +645,6 @@
         this(builder, null);
     }
 
-   /*
-    * Package private constructor which shares value array for speed.
-    * this constructor is always expected to be called with share==true.
-    * a separate constructor is needed because we already have a public
-    * String(char[]) constructor that makes a copy of the given char[].
-    */
-    // TBD: this is kept for package internal use (Thread/System),
-    // should be removed if they all have a byte[] version
-    String(char[] val, boolean share) {
-        // assert share : "unshared not supported";
-        this(val, 0, val.length, null);
-    }
-
     /**
      * Returns the length of this string.
      * The length is equal to the number of <a href="Character.html#unicode">Unicode
--- a/src/java.base/share/classes/java/lang/System.java	Thu Nov 30 22:05:19 2017 +0100
+++ b/src/java.base/share/classes/java/lang/System.java	Wed Dec 06 11:39:23 2017 +0000
@@ -63,8 +63,8 @@
 import jdk.internal.reflect.CallerSensitive;
 import jdk.internal.reflect.Reflection;
 import jdk.internal.HotSpotIntrinsicCandidate;
-import jdk.internal.misc.JavaLangAccess;;
-import jdk.internal.misc.SharedSecrets;;
+import jdk.internal.misc.JavaLangAccess;
+import jdk.internal.misc.SharedSecrets;
 import jdk.internal.misc.VM;
 import jdk.internal.logger.LoggerFinderLoader;
 import jdk.internal.logger.LazyLoggers;
@@ -2109,9 +2109,6 @@
             public void registerShutdownHook(int slot, boolean registerShutdownInProgress, Runnable hook) {
                 Shutdown.add(slot, registerShutdownInProgress, hook);
             }
-            public String newStringUnsafe(char[] chars) {
-                return new String(chars, true);
-            }
             public Thread newThreadWithAcc(Runnable target, AccessControlContext acc) {
                 return new Thread(target, acc);
             }
--- a/src/java.base/share/classes/java/util/Collection.java	Thu Nov 30 22:05:19 2017 +0100
+++ b/src/java.base/share/classes/java/util/Collection.java	Wed Dec 06 11:39:23 2017 +0000
@@ -54,19 +54,15 @@
  * constructors) but all of the general-purpose {@code Collection}
  * implementations in the Java platform libraries comply.
  *
- * <p>The "destructive" methods contained in this interface, that is, the
- * methods that modify the collection on which they operate, are specified to
- * throw {@code UnsupportedOperationException} if this collection does not
- * support the operation.  If this is the case, these methods may, but are not
- * required to, throw an {@code UnsupportedOperationException} if the
- * invocation would have no effect on the collection.  For example, invoking
- * the {@link #addAll(Collection)} method on an unmodifiable collection may,
- * but is not required to, throw the exception if the collection to be added
- * is empty.
+ * <p>Certain methods are specified to be
+ * <i>optional</i>. If a collection implementation doesn't implement a
+ * particular operation, it should define the corresponding method to throw
+ * {@code UnsupportedOperationException}. Such methods are marked "optional
+ * operation" in method specifications of the collections interfaces.
  *
- * <p><a id="optional-restrictions">
- * Some collection implementations have restrictions on the elements that
- * they may contain.</a>  For example, some implementations prohibit null elements,
+ * <p><a id="optional-restrictions"></a>Some collection implementations
+ * have restrictions on the elements that they may contain.
+ * For example, some implementations prohibit null elements,
  * and some have restrictions on the types of their elements.  Attempting to
  * add an ineligible element throws an unchecked exception, typically
  * {@code NullPointerException} or {@code ClassCastException}.  Attempting
@@ -111,6 +107,86 @@
  * methods. Implementations may optionally handle the self-referential scenario,
  * however most current implementations do not do so.
  *
+ * <h2><a id="view">View Collections</a></h2>
+ *
+ * <p>Most collections manage storage for elements they contain. By contrast, <i>view
+ * collections</i> themselves do not store elements, but instead they rely on a
+ * backing collection to store the actual elements. Operations that are not handled
+ * by the view collection itself are delegated to the backing collection. Examples of
+ * view collections include the wrapper collections returned by methods such as
+ * {@link Collections#checkedCollection Collections.checkedCollection},
+ * {@link Collections#synchronizedCollection Collections.synchronizedCollection}, and
+ * {@link Collections#unmodifiableCollection Collections.unmodifiableCollection}.
+ * Other examples of view collections include collections that provide a
+ * different representation of the same elements, for example, as
+ * provided by {@link List#subList List.subList},
+ * {@link NavigableSet#subSet NavigableSet.subSet}, or
+ * {@link Map#entrySet Map.entrySet}.
+ * Any changes made to the backing collection are visible in the view collection.
+ * Correspondingly, any changes made to the view collection &mdash; if changes
+ * are permitted &mdash; are written through to the backing collection.
+ * Although they technically aren't collections, instances of
+ * {@link Iterator} and {@link ListIterator} can also allow modifications
+ * to be written through to the backing collection, and in some cases,
+ * modifications to the backing collection will be visible to the Iterator
+ * during iteration.
+ *
+ * <h2><a id="unmodifiable">Unmodifiable Collections</a></h2>
+ *
+ * <p>Certain methods of this interface are considered "destructive" and are called
+ * "mutator" methods in that they modify the group of objects contained within
+ * the collection on which they operate. They can be specified to throw
+ * {@code UnsupportedOperationException} if this collection implementation
+ * does not support the operation. Such methods should (but are not required
+ * to) throw an {@code UnsupportedOperationException} if the invocation would
+ * have no effect on the collection. For example, consider a collection that
+ * does not support the {@link #add add} operation. What will happen if the
+ * {@link #addAll addAll} method is invoked on this collection, with an empty
+ * collection as the argument? The addition of zero elements has no effect,
+ * so it is permissible for this collection simply to do nothing and not to throw
+ * an exception. However, it is recommended that such cases throw an exception
+ * unconditionally, as throwing only in certain cases can lead to
+ * programming errors.
+ *
+ * <p>An <i>unmodifiable collection</i> is a collection, all of whose
+ * mutator methods (as defined above) are specified to throw
+ * {@code UnsupportedOperationException}. Such a collection thus cannot be
+ * modified by calling any methods on it. For a collection to be properly
+ * unmodifiable, any view collections derived from it must also be unmodifiable.
+ * For example, if a List is unmodifiable, the List returned by
+ * {@link List#subList List.subList} is also unmodifiable.
+ *
+ * <p>An unmodifiable collection is not necessarily immutable. If the
+ * contained elements are mutable, the entire collection is clearly
+ * mutable, even though it might be unmodifiable. For example, consider
+ * two unmodifiable lists containing mutable elements. The result of calling
+ * {@code list1.equals(list2)} might differ from one call to the next if
+ * the elements had been mutated, even though both lists are unmodifiable.
+ * However, if an unmodifiable collection contains all immutable elements,
+ * it can be considered effectively immutable.
+ *
+ * <h2><a id="unmodview">Unmodifiable View Collections</a></h2>
+ *
+ * <p>An <i>unmodifiable view collection</i> is a collection that is unmodifiable
+ * and that is also a view onto a backing collection. Its mutator methods throw
+ * {@code UnsupportedOperationException}, as described above, while
+ * reading and querying methods are delegated to the backing collection.
+ * The effect is to provide read-only access to the backing collection.
+ * This is useful for a component to provide users with read access to
+ * an internal collection, while preventing them from modifying such
+ * collections unexpectedly. Examples of unmodifiable view collections
+ * are those returned by the
+ * {@link Collections#unmodifiableCollection Collections.unmodifiableCollection},
+ * {@link Collections#unmodifiableList Collections.unmodifiableList}, and
+ * related methods.
+ *
+ * <p>Note that changes to the backing collection might still be possible,
+ * and if they occur, they are visible through the unmodifiable view. Thus,
+ * an unmodifiable view collection is not necessarily immutable. However,
+ * if the backing collection of an unmodifiable view is effectively immutable,
+ * or if the only reference to the backing collection is through an
+ * unmodifiable view, the view can be considered effectively immutable.
+ *
  * <p>This interface is a member of the
  * <a href="{@docRoot}/java/util/package-summary.html#CollectionsFramework">
  * Java Collections Framework</a>.
@@ -192,7 +268,8 @@
      * Returns an array containing all of the elements in this collection.
      * If this collection makes any guarantees as to what order its elements
      * are returned by its iterator, this method must return the elements in
-     * the same order.
+     * the same order. The returned array's {@linkplain Class#getComponentType
+     * runtime component type} is {@code Object}.
      *
      * <p>The returned array will be "safe" in that no references to it are
      * maintained by this collection.  (In other words, this method must
@@ -202,7 +279,8 @@
      * <p>This method acts as bridge between array-based and collection-based
      * APIs.
      *
-     * @return an array containing all of the elements in this collection
+     * @return an array, whose {@linkplain Class#getComponentType runtime component
+     * type} is {@code Object}, containing all of the elements in this collection
      */
     Object[] toArray();
 
@@ -239,14 +317,14 @@
      * Note that {@code toArray(new Object[0])} is identical in function to
      * {@code toArray()}.
      *
-     * @param <T> the runtime type of the array to contain the collection
+     * @param <T> the component type of the array to contain the collection
      * @param a the array into which the elements of this collection are to be
      *        stored, if it is big enough; otherwise, a new array of the same
      *        runtime type is allocated for this purpose.
      * @return an array containing all of the elements in this collection
-     * @throws ArrayStoreException if the runtime type of the specified array
-     *         is not a supertype of the runtime type of every element in
-     *         this collection
+     * @throws ArrayStoreException if the runtime type of any element in this
+     *         collection is not assignable to the {@linkplain Class#getComponentType
+     *         runtime component type} of the specified array
      * @throws NullPointerException if the specified array is null
      */
     <T> T[] toArray(T[] a);
--- a/src/java.base/share/classes/java/util/Collections.java	Thu Nov 30 22:05:19 2017 +0100
+++ b/src/java.base/share/classes/java/util/Collections.java	Wed Dec 06 11:39:23 2017 +0000
@@ -989,9 +989,8 @@
     // Unmodifiable Wrappers
 
     /**
-     * Returns an unmodifiable view of the specified collection.  This method
-     * allows modules to provide users with "read-only" access to internal
-     * collections.  Query operations on the returned collection "read through"
+     * Returns an <a href="Collection.html#unmodview">unmodifiable view</a> of the
+     * specified collection. Query operations on the returned collection "read through"
      * to the specified collection, and attempts to modify the returned
      * collection, whether direct or via its iterator, result in an
      * {@code UnsupportedOperationException}.<p>
@@ -1102,9 +1101,8 @@
     }
 
     /**
-     * Returns an unmodifiable view of the specified set.  This method allows
-     * modules to provide users with "read-only" access to internal sets.
-     * Query operations on the returned set "read through" to the specified
+     * Returns an <a href="Collection.html#unmodview">unmodifiable view</a> of the
+     * specified set. Query operations on the returned set "read through" to the specified
      * set, and attempts to modify the returned set, whether direct or via its
      * iterator, result in an {@code UnsupportedOperationException}.<p>
      *
@@ -1132,9 +1130,8 @@
     }
 
     /**
-     * Returns an unmodifiable view of the specified sorted set.  This method
-     * allows modules to provide users with "read-only" access to internal
-     * sorted sets.  Query operations on the returned sorted set "read
+     * Returns an <a href="Collection.html#unmodview">unmodifiable view</a> of the
+     * specified sorted set. Query operations on the returned sorted set "read
      * through" to the specified sorted set.  Attempts to modify the returned
      * sorted set, whether direct, via its iterator, or via its
      * {@code subSet}, {@code headSet}, or {@code tailSet} views, result in
@@ -1180,9 +1177,8 @@
     }
 
     /**
-     * Returns an unmodifiable view of the specified navigable set.  This method
-     * allows modules to provide users with "read-only" access to internal
-     * navigable sets.  Query operations on the returned navigable set "read
+     * Returns an <a href="Collection.html#unmodview">unmodifiable view</a> of the
+     * specified navigable set. Query operations on the returned navigable set "read
      * through" to the specified navigable set.  Attempts to modify the returned
      * navigable set, whether direct, via its iterator, or via its
      * {@code subSet}, {@code headSet}, or {@code tailSet} views, result in
@@ -1269,9 +1265,8 @@
     }
 
     /**
-     * Returns an unmodifiable view of the specified list.  This method allows
-     * modules to provide users with "read-only" access to internal
-     * lists.  Query operations on the returned list "read through" to the
+     * Returns an <a href="Collection.html#unmodview">unmodifiable view</a> of the
+     * specified list. Query operations on the returned list "read through" to the
      * specified list, and attempts to modify the returned list, whether
      * direct or via its iterator, result in an
      * {@code UnsupportedOperationException}.<p>
@@ -1415,9 +1410,8 @@
     }
 
     /**
-     * Returns an unmodifiable view of the specified map.  This method
-     * allows modules to provide users with "read-only" access to internal
-     * maps.  Query operations on the returned map "read through"
+     * Returns an <a href="Collection.html#unmodview">unmodifiable view</a> of the
+     * specified map. Query operations on the returned map "read through"
      * to the specified map, and attempts to modify the returned
      * map, whether direct or via its collection views, result in an
      * {@code UnsupportedOperationException}.<p>
@@ -1765,9 +1759,8 @@
     }
 
     /**
-     * Returns an unmodifiable view of the specified sorted map.  This method
-     * allows modules to provide users with "read-only" access to internal
-     * sorted maps.  Query operations on the returned sorted map "read through"
+     * Returns an <a href="Collection.html#unmodview">unmodifiable view</a> of the
+     * specified sorted map. Query operations on the returned sorted map "read through"
      * to the specified sorted map.  Attempts to modify the returned
      * sorted map, whether direct, via its collection views, or via its
      * {@code subMap}, {@code headMap}, or {@code tailMap} views, result in
@@ -1809,9 +1802,8 @@
     }
 
     /**
-     * Returns an unmodifiable view of the specified navigable map.  This method
-     * allows modules to provide users with "read-only" access to internal
-     * navigable maps.  Query operations on the returned navigable map "read
+     * Returns an <a href="Collection.html#unmodview">unmodifiable view</a> of the
+     * specified navigable map. Query operations on the returned navigable map "read
      * through" to the specified navigable map.  Attempts to modify the returned
      * navigable map, whether direct, via its collection views, or via its
      * {@code subMap}, {@code headMap}, or {@code tailMap} views, result in
--- a/src/java.base/share/classes/java/util/List.java	Thu Nov 30 22:05:19 2017 +0100
+++ b/src/java.base/share/classes/java/util/List.java	Wed Dec 06 11:39:23 2017 +0000
@@ -87,15 +87,16 @@
  * Such exceptions are marked as "optional" in the specification for this
  * interface.
  *
- * <h2><a id="immutable">Immutable List Static Factory Methods</a></h2>
- * <p>The {@link List#of(Object...) List.of()} static factory methods
- * provide a convenient way to create immutable lists. The {@code List}
+ * <h2><a id="unmodifiable">Unmodifiable Lists</a></h2>
+ * <p>The {@link List#of(Object...) List.of} and
+ * {@link List#copyOf List.copyOf} static factory methods
+ * provide a convenient way to create unmodifiable lists. The {@code List}
  * instances created by these methods have the following characteristics:
  *
  * <ul>
- * <li>They are <em>structurally immutable</em>. Elements cannot be added, removed,
- * or replaced. Calling any mutator method will always cause
- * {@code UnsupportedOperationException} to be thrown.
+ * <li>They are <a href="Collection.html#unmodifiable"><i>unmodifiable</i></a>. Elements cannot
+ * be added, removed, or replaced. Calling any mutator method on the List
+ * will always cause {@code UnsupportedOperationException} to be thrown.
  * However, if the contained elements are themselves mutable,
  * this may cause the List's contents to appear to change.
  * <li>They disallow {@code null} elements. Attempts to create them with
@@ -777,9 +778,9 @@
     }
 
     /**
-     * Returns an immutable list containing zero elements.
+     * Returns an unmodifiable list containing zero elements.
      *
-     * See <a href="#immutable">Immutable List Static Factory Methods</a> for details.
+     * See <a href="#unmodifiable">Unmodifiable Lists</a> for details.
      *
      * @param <E> the {@code List}'s element type
      * @return an empty {@code List}
@@ -791,9 +792,9 @@
     }
 
     /**
-     * Returns an immutable list containing one element.
+     * Returns an unmodifiable list containing one element.
      *
-     * See <a href="#immutable">Immutable List Static Factory Methods</a> for details.
+     * See <a href="#unmodifiable">Unmodifiable Lists</a> for details.
      *
      * @param <E> the {@code List}'s element type
      * @param e1 the single element
@@ -807,9 +808,9 @@
     }
 
     /**
-     * Returns an immutable list containing two elements.
+     * Returns an unmodifiable list containing two elements.
      *
-     * See <a href="#immutable">Immutable List Static Factory Methods</a> for details.
+     * See <a href="#unmodifiable">Unmodifiable Lists</a> for details.
      *
      * @param <E> the {@code List}'s element type
      * @param e1 the first element
@@ -824,9 +825,9 @@
     }
 
     /**
-     * Returns an immutable list containing three elements.
+     * Returns an unmodifiable list containing three elements.
      *
-     * See <a href="#immutable">Immutable List Static Factory Methods</a> for details.
+     * See <a href="#unmodifiable">Unmodifiable Lists</a> for details.
      *
      * @param <E> the {@code List}'s element type
      * @param e1 the first element
@@ -842,9 +843,9 @@
     }
 
     /**
-     * Returns an immutable list containing four elements.
+     * Returns an unmodifiable list containing four elements.
      *
-     * See <a href="#immutable">Immutable List Static Factory Methods</a> for details.
+     * See <a href="#unmodifiable">Unmodifiable Lists</a> for details.
      *
      * @param <E> the {@code List}'s element type
      * @param e1 the first element
@@ -861,9 +862,9 @@
     }
 
     /**
-     * Returns an immutable list containing five elements.
+     * Returns an unmodifiable list containing five elements.
      *
-     * See <a href="#immutable">Immutable List Static Factory Methods</a> for details.
+     * See <a href="#unmodifiable">Unmodifiable Lists</a> for details.
      *
      * @param <E> the {@code List}'s element type
      * @param e1 the first element
@@ -881,9 +882,9 @@
     }
 
     /**
-     * Returns an immutable list containing six elements.
+     * Returns an unmodifiable list containing six elements.
      *
-     * See <a href="#immutable">Immutable List Static Factory Methods</a> for details.
+     * See <a href="#unmodifiable">Unmodifiable Lists</a> for details.
      *
      * @param <E> the {@code List}'s element type
      * @param e1 the first element
@@ -903,9 +904,9 @@
     }
 
     /**
-     * Returns an immutable list containing seven elements.
+     * Returns an unmodifiable list containing seven elements.
      *
-     * See <a href="#immutable">Immutable List Static Factory Methods</a> for details.
+     * See <a href="#unmodifiable">Unmodifiable Lists</a> for details.
      *
      * @param <E> the {@code List}'s element type
      * @param e1 the first element
@@ -926,9 +927,9 @@
     }
 
     /**
-     * Returns an immutable list containing eight elements.
+     * Returns an unmodifiable list containing eight elements.
      *
-     * See <a href="#immutable">Immutable List Static Factory Methods</a> for details.
+     * See <a href="#unmodifiable">Unmodifiable Lists</a> for details.
      *
      * @param <E> the {@code List}'s element type
      * @param e1 the first element
@@ -950,9 +951,9 @@
     }
 
     /**
-     * Returns an immutable list containing nine elements.
+     * Returns an unmodifiable list containing nine elements.
      *
-     * See <a href="#immutable">Immutable List Static Factory Methods</a> for details.
+     * See <a href="#unmodifiable">Unmodifiable Lists</a> for details.
      *
      * @param <E> the {@code List}'s element type
      * @param e1 the first element
@@ -975,9 +976,9 @@
     }
 
     /**
-     * Returns an immutable list containing ten elements.
+     * Returns an unmodifiable list containing ten elements.
      *
-     * See <a href="#immutable">Immutable List Static Factory Methods</a> for details.
+     * See <a href="#unmodifiable">Unmodifiable Lists</a> for details.
      *
      * @param <E> the {@code List}'s element type
      * @param e1 the first element
@@ -1001,8 +1002,8 @@
     }
 
     /**
-     * Returns an immutable list containing an arbitrary number of elements.
-     * See <a href="#immutable">Immutable List Static Factory Methods</a> for details.
+     * Returns an unmodifiable list containing an arbitrary number of elements.
+     * See <a href="#unmodifiable">Unmodifiable Lists</a> for details.
      *
      * @apiNote
      * This method also accepts a single array as an argument. The element type of
@@ -1039,4 +1040,29 @@
                 return new ImmutableCollections.ListN<>(elements);
         }
     }
+
+    /**
+     * Returns an <a href="#unmodifiable">unmodifiable List</a> containing the elements of
+     * the given Collection, in its iteration order. The given Collection must not be null,
+     * and it must not contain any null elements. If the given Collection is subsequently
+     * modified, the returned List will not reflect such modifications.
+     *
+     * @implNote
+     * If the given Collection is an <a href="#unmodifiable">unmodifiable List</a>,
+     * calling copyOf will generally not create a copy.
+     *
+     * @param <E> the {@code List}'s element type
+     * @param coll a {@code Collection} from which elements are drawn, must be non-null
+     * @return a {@code List} containing the elements of the given {@code Collection}
+     * @throws NullPointerException if coll is null, or if it contains any nulls
+     * @since 10
+     */
+    @SuppressWarnings("unchecked")
+    static <E> List<E> copyOf(Collection<? extends E> coll) {
+        if (coll instanceof ImmutableCollections.AbstractImmutableList) {
+            return (List<E>)coll;
+        } else {
+            return (List<E>)List.of(coll.toArray());
+        }
+    }
 }
--- a/src/java.base/share/classes/java/util/Map.java	Thu Nov 30 22:05:19 2017 +0100
+++ b/src/java.base/share/classes/java/util/Map.java	Wed Dec 06 11:39:23 2017 +0000
@@ -110,17 +110,18 @@
  * Implementations may optionally handle the self-referential scenario, however
  * most current implementations do not do so.
  *
- * <h2><a id="immutable">Immutable Map Static Factory Methods</a></h2>
- * <p>The {@link Map#of() Map.of()} and
- * {@link Map#ofEntries(Map.Entry...) Map.ofEntries()}
- * static factory methods provide a convenient way to create immutable maps.
+ * <h2><a id="unmodifiable">Unmodifiable Maps</a></h2>
+ * <p>The {@link Map#of() Map.of},
+ * {@link Map#ofEntries(Map.Entry...) Map.ofEntries}, and
+ * {@link Map#copyOf Map.copyOf}
+ * static factory methods provide a convenient way to create unmodifiable maps.
  * The {@code Map}
  * instances created by these methods have the following characteristics:
  *
  * <ul>
- * <li>They are <em>structurally immutable</em>. Keys and values cannot be added,
- * removed, or updated. Calling any mutator method will always cause
- * {@code UnsupportedOperationException} to be thrown.
+ * <li>They are <a href="Collection.html#unmodifiable"><i>unmodifiable</i></a>. Keys and values
+ * cannot be added, removed, or updated. Calling any mutator method on the Map
+ * will always cause {@code UnsupportedOperationException} to be thrown.
  * However, if the contained keys or values are themselves mutable, this may cause the
  * Map to behave inconsistently or its contents to appear to change.
  * <li>They disallow {@code null} keys and values. Attempts to create them with
@@ -1276,8 +1277,8 @@
     }
 
     /**
-     * Returns an immutable map containing zero mappings.
-     * See <a href="#immutable">Immutable Map Static Factory Methods</a> for details.
+     * Returns an unmodifiable map containing zero mappings.
+     * See <a href="#unmodifiable">Unmodifiable Maps</a> for details.
      *
      * @param <K> the {@code Map}'s key type
      * @param <V> the {@code Map}'s value type
@@ -1290,8 +1291,8 @@
     }
 
     /**
-     * Returns an immutable map containing a single mapping.
-     * See <a href="#immutable">Immutable Map Static Factory Methods</a> for details.
+     * Returns an unmodifiable map containing a single mapping.
+     * See <a href="#unmodifiable">Unmodifiable Maps</a> for details.
      *
      * @param <K> the {@code Map}'s key type
      * @param <V> the {@code Map}'s value type
@@ -1307,8 +1308,8 @@
     }
 
     /**
-     * Returns an immutable map containing two mappings.
-     * See <a href="#immutable">Immutable Map Static Factory Methods</a> for details.
+     * Returns an unmodifiable map containing two mappings.
+     * See <a href="#unmodifiable">Unmodifiable Maps</a> for details.
      *
      * @param <K> the {@code Map}'s key type
      * @param <V> the {@code Map}'s value type
@@ -1327,8 +1328,8 @@
     }
 
     /**
-     * Returns an immutable map containing three mappings.
-     * See <a href="#immutable">Immutable Map Static Factory Methods</a> for details.
+     * Returns an unmodifiable map containing three mappings.
+     * See <a href="#unmodifiable">Unmodifiable Maps</a> for details.
      *
      * @param <K> the {@code Map}'s key type
      * @param <V> the {@code Map}'s value type
@@ -1349,8 +1350,8 @@
     }
 
     /**
-     * Returns an immutable map containing four mappings.
-     * See <a href="#immutable">Immutable Map Static Factory Methods</a> for details.
+     * Returns an unmodifiable map containing four mappings.
+     * See <a href="#unmodifiable">Unmodifiable Maps</a> for details.
      *
      * @param <K> the {@code Map}'s key type
      * @param <V> the {@code Map}'s value type
@@ -1373,8 +1374,8 @@
     }
 
     /**
-     * Returns an immutable map containing five mappings.
-     * See <a href="#immutable">Immutable Map Static Factory Methods</a> for details.
+     * Returns an unmodifiable map containing five mappings.
+     * See <a href="#unmodifiable">Unmodifiable Maps</a> for details.
      *
      * @param <K> the {@code Map}'s key type
      * @param <V> the {@code Map}'s value type
@@ -1399,8 +1400,8 @@
     }
 
     /**
-     * Returns an immutable map containing six mappings.
-     * See <a href="#immutable">Immutable Map Static Factory Methods</a> for details.
+     * Returns an unmodifiable map containing six mappings.
+     * See <a href="#unmodifiable">Unmodifiable Maps</a> for details.
      *
      * @param <K> the {@code Map}'s key type
      * @param <V> the {@code Map}'s value type
@@ -1429,8 +1430,8 @@
     }
 
     /**
-     * Returns an immutable map containing seven mappings.
-     * See <a href="#immutable">Immutable Map Static Factory Methods</a> for details.
+     * Returns an unmodifiable map containing seven mappings.
+     * See <a href="#unmodifiable">Unmodifiable Maps</a> for details.
      *
      * @param <K> the {@code Map}'s key type
      * @param <V> the {@code Map}'s value type
@@ -1461,8 +1462,8 @@
     }
 
     /**
-     * Returns an immutable map containing eight mappings.
-     * See <a href="#immutable">Immutable Map Static Factory Methods</a> for details.
+     * Returns an unmodifiable map containing eight mappings.
+     * See <a href="#unmodifiable">Unmodifiable Maps</a> for details.
      *
      * @param <K> the {@code Map}'s key type
      * @param <V> the {@code Map}'s value type
@@ -1495,8 +1496,8 @@
     }
 
     /**
-     * Returns an immutable map containing nine mappings.
-     * See <a href="#immutable">Immutable Map Static Factory Methods</a> for details.
+     * Returns an unmodifiable map containing nine mappings.
+     * See <a href="#unmodifiable">Unmodifiable Maps</a> for details.
      *
      * @param <K> the {@code Map}'s key type
      * @param <V> the {@code Map}'s value type
@@ -1531,8 +1532,8 @@
     }
 
     /**
-     * Returns an immutable map containing ten mappings.
-     * See <a href="#immutable">Immutable Map Static Factory Methods</a> for details.
+     * Returns an unmodifiable map containing ten mappings.
+     * See <a href="#unmodifiable">Unmodifiable Maps</a> for details.
      *
      * @param <K> the {@code Map}'s key type
      * @param <V> the {@code Map}'s value type
@@ -1569,9 +1570,9 @@
     }
 
     /**
-     * Returns an immutable map containing keys and values extracted from the given entries.
+     * Returns an unmodifiable map containing keys and values extracted from the given entries.
      * The entries themselves are not stored in the map.
-     * See <a href="#immutable">Immutable Map Static Factory Methods</a> for details.
+     * See <a href="#unmodifiable">Unmodifiable Maps</a> for details.
      *
      * @apiNote
      * It is convenient to create the map entries using the {@link Map#entry Map.entry()} method.
@@ -1602,15 +1603,17 @@
     @SafeVarargs
     @SuppressWarnings("varargs")
     static <K, V> Map<K, V> ofEntries(Entry<? extends K, ? extends V>... entries) {
-        if (entries.length == 0) { // implicit null check of entries
+        if (entries.length == 0) { // implicit null check of entries array
             return ImmutableCollections.Map0.instance();
         } else if (entries.length == 1) {
+            // implicit null check of the array slot
             return new ImmutableCollections.Map1<>(entries[0].getKey(),
                                                    entries[0].getValue());
         } else {
             Object[] kva = new Object[entries.length << 1];
             int a = 0;
             for (Entry<? extends K, ? extends V> entry : entries) {
+                // implicit null checks of each array slot
                 kva[a++] = entry.getKey();
                 kva[a++] = entry.getValue();
             }
@@ -1619,7 +1622,7 @@
     }
 
     /**
-     * Returns an immutable {@link Entry} containing the given key and value.
+     * Returns an unmodifiable {@link Entry} containing the given key and value.
      * These entries are suitable for populating {@code Map} instances using the
      * {@link Map#ofEntries Map.ofEntries()} method.
      * The {@code Entry} instances created by this method have the following characteristics:
@@ -1627,7 +1630,7 @@
      * <ul>
      * <li>They disallow {@code null} keys and values. Attempts to create them using a {@code null}
      * key or value result in {@code NullPointerException}.
-     * <li>They are immutable. Calls to {@link Entry#setValue Entry.setValue()}
+     * <li>They are unmodifiable. Calls to {@link Entry#setValue Entry.setValue()}
      * on a returned {@code Entry} result in {@code UnsupportedOperationException}.
      * <li>They are not serializable.
      * <li>They are <a href="../lang/doc-files/ValueBased.html">value-based</a>.
@@ -1655,4 +1658,30 @@
         // KeyValueHolder checks for nulls
         return new KeyValueHolder<>(k, v);
     }
+
+    /**
+     * Returns an <a href="#unmodifiable">unmodifiable Map</a> containing the entries
+     * of the given Map. The given Map must not be null, and it must not contain any
+     * null keys or values. If the given Map is subsequently modified, the returned
+     * Map will not reflect such modifications.
+     *
+     * @implNote
+     * If the given Map is an <a href="#unmodifiable">unmodifiable Map</a>,
+     * calling copyOf will generally not create a copy.
+     *
+     * @param <K> the {@code Map}'s key type
+     * @param <V> the {@code Map}'s value type
+     * @param map a {@code Map} from which entries are drawn, must be non-null
+     * @return a {@code Map} containing the entries of the given {@code Map}
+     * @throws NullPointerException if map is null, or if it contains any null keys or values
+     * @since 10
+     */
+    @SuppressWarnings({"rawtypes","unchecked"})
+    static <K, V> Map<K, V> copyOf(Map<? extends K, ? extends V> map) {
+        if (map instanceof ImmutableCollections.AbstractImmutableMap) {
+            return (Map<K,V>)map;
+        } else {
+            return (Map<K,V>)Map.ofEntries(map.entrySet().toArray(new Entry[0]));
+        }
+    }
 }
--- a/src/java.base/share/classes/java/util/Set.java	Thu Nov 30 22:05:19 2017 +0100
+++ b/src/java.base/share/classes/java/util/Set.java	Wed Dec 06 11:39:23 2017 +0000
@@ -63,15 +63,16 @@
  * Such exceptions are marked as "optional" in the specification for this
  * interface.
  *
- * <h2><a id="immutable">Immutable Set Static Factory Methods</a></h2>
- * <p>The {@link Set#of(Object...) Set.of()} static factory methods
- * provide a convenient way to create immutable sets. The {@code Set}
+ * <h2><a id="unmodifiable">Unmodifiable Sets</a></h2>
+ * <p>The {@link Set#of(Object...) Set.of} and
+ * {@link Set#copyOf Set.copyOf} static factory methods
+ * provide a convenient way to create unmodifiable sets. The {@code Set}
  * instances created by these methods have the following characteristics:
  *
  * <ul>
- * <li>They are <em>structurally immutable</em>. Elements cannot be added or
- * removed. Calling any mutator method will always cause
- * {@code UnsupportedOperationException} to be thrown.
+ * <li>They are <a href="Collection.html#unmodifiable"><i>unmodifiable</i></a>. Elements cannot
+ * be added or removed. Calling any mutator method on the Set
+ * will always cause {@code UnsupportedOperationException} to be thrown.
  * However, if the contained elements are themselves mutable, this may cause the
  * Set to behave inconsistently or its contents to appear to change.
  * <li>They disallow {@code null} elements. Attempts to create them with
@@ -439,8 +440,8 @@
     }
 
     /**
-     * Returns an immutable set containing zero elements.
-     * See <a href="#immutable">Immutable Set Static Factory Methods</a> for details.
+     * Returns an unmodifiable set containing zero elements.
+     * See <a href="#unmodifiable">Unmodifiable Sets</a> for details.
      *
      * @param <E> the {@code Set}'s element type
      * @return an empty {@code Set}
@@ -452,8 +453,8 @@
     }
 
     /**
-     * Returns an immutable set containing one element.
-     * See <a href="#immutable">Immutable Set Static Factory Methods</a> for details.
+     * Returns an unmodifiable set containing one element.
+     * See <a href="#unmodifiable">Unmodifiable Sets</a> for details.
      *
      * @param <E> the {@code Set}'s element type
      * @param e1 the single element
@@ -467,8 +468,8 @@
     }
 
     /**
-     * Returns an immutable set containing two elements.
-     * See <a href="#immutable">Immutable Set Static Factory Methods</a> for details.
+     * Returns an unmodifiable set containing two elements.
+     * See <a href="#unmodifiable">Unmodifiable Sets</a> for details.
      *
      * @param <E> the {@code Set}'s element type
      * @param e1 the first element
@@ -484,8 +485,8 @@
     }
 
     /**
-     * Returns an immutable set containing three elements.
-     * See <a href="#immutable">Immutable Set Static Factory Methods</a> for details.
+     * Returns an unmodifiable set containing three elements.
+     * See <a href="#unmodifiable">Unmodifiable Sets</a> for details.
      *
      * @param <E> the {@code Set}'s element type
      * @param e1 the first element
@@ -502,8 +503,8 @@
     }
 
     /**
-     * Returns an immutable set containing four elements.
-     * See <a href="#immutable">Immutable Set Static Factory Methods</a> for details.
+     * Returns an unmodifiable set containing four elements.
+     * See <a href="#unmodifiable">Unmodifiable Sets</a> for details.
      *
      * @param <E> the {@code Set}'s element type
      * @param e1 the first element
@@ -521,8 +522,8 @@
     }
 
     /**
-     * Returns an immutable set containing five elements.
-     * See <a href="#immutable">Immutable Set Static Factory Methods</a> for details.
+     * Returns an unmodifiable set containing five elements.
+     * See <a href="#unmodifiable">Unmodifiable Sets</a> for details.
      *
      * @param <E> the {@code Set}'s element type
      * @param e1 the first element
@@ -541,8 +542,8 @@
     }
 
     /**
-     * Returns an immutable set containing six elements.
-     * See <a href="#immutable">Immutable Set Static Factory Methods</a> for details.
+     * Returns an unmodifiable set containing six elements.
+     * See <a href="#unmodifiable">Unmodifiable Sets</a> for details.
      *
      * @param <E> the {@code Set}'s element type
      * @param e1 the first element
@@ -563,8 +564,8 @@
     }
 
     /**
-     * Returns an immutable set containing seven elements.
-     * See <a href="#immutable">Immutable Set Static Factory Methods</a> for details.
+     * Returns an unmodifiable set containing seven elements.
+     * See <a href="#unmodifiable">Unmodifiable Sets</a> for details.
      *
      * @param <E> the {@code Set}'s element type
      * @param e1 the first element
@@ -586,8 +587,8 @@
     }
 
     /**
-     * Returns an immutable set containing eight elements.
-     * See <a href="#immutable">Immutable Set Static Factory Methods</a> for details.
+     * Returns an unmodifiable set containing eight elements.
+     * See <a href="#unmodifiable">Unmodifiable Sets</a> for details.
      *
      * @param <E> the {@code Set}'s element type
      * @param e1 the first element
@@ -610,8 +611,8 @@
     }
 
     /**
-     * Returns an immutable set containing nine elements.
-     * See <a href="#immutable">Immutable Set Static Factory Methods</a> for details.
+     * Returns an unmodifiable set containing nine elements.
+     * See <a href="#unmodifiable">Unmodifiable Sets</a> for details.
      *
      * @param <E> the {@code Set}'s element type
      * @param e1 the first element
@@ -635,8 +636,8 @@
     }
 
     /**
-     * Returns an immutable set containing ten elements.
-     * See <a href="#immutable">Immutable Set Static Factory Methods</a> for details.
+     * Returns an unmodifiable set containing ten elements.
+     * See <a href="#unmodifiable">Unmodifiable Sets</a> for details.
      *
      * @param <E> the {@code Set}'s element type
      * @param e1 the first element
@@ -661,8 +662,8 @@
     }
 
     /**
-     * Returns an immutable set containing an arbitrary number of elements.
-     * See <a href="#immutable">Immutable Set Static Factory Methods</a> for details.
+     * Returns an unmodifiable set containing an arbitrary number of elements.
+     * See <a href="#unmodifiable">Unmodifiable Sets</a> for details.
      *
      * @apiNote
      * This method also accepts a single array as an argument. The element type of
@@ -700,4 +701,30 @@
                 return new ImmutableCollections.SetN<>(elements);
         }
     }
+
+    /**
+     * Returns an <a href="#unmodifiable">unmodifiable Set</a> containing the elements
+     * of the given Collection. The given Collection must not be null, and it must not
+     * contain any null elements. If the given Collection contains duplicate elements,
+     * an arbitrary element of the duplicates is preserved. If the given Collection is
+     * subsequently modified, the returned Set will not reflect such modifications.
+     *
+     * @implNote
+     * If the given Collection is an <a href="#unmodifiable">unmodifiable Set</a>,
+     * calling copyOf will generally not create a copy.
+     *
+     * @param <E> the {@code Set}'s element type
+     * @param coll a {@code Collection} from which elements are drawn, must be non-null
+     * @return a {@code Set} containing the elements of the given {@code Collection}
+     * @throws NullPointerException if coll is null, or if it contains any nulls
+     * @since 10
+     */
+    @SuppressWarnings("unchecked")
+    static <E> Set<E> copyOf(Collection<? extends E> coll) {
+        if (coll instanceof ImmutableCollections.AbstractImmutableSet) {
+            return (Set<E>)coll;
+        } else {
+            return (Set<E>)Set.of(new HashSet<>(coll).toArray());
+        }
+    }
 }
--- a/src/java.base/share/classes/java/util/StringJoiner.java	Thu Nov 30 22:05:19 2017 +0100
+++ b/src/java.base/share/classes/java/util/StringJoiner.java	Wed Dec 06 11:39:23 2017 +0000
@@ -24,9 +24,6 @@
  */
 package java.util;
 
-import jdk.internal.misc.JavaLangAccess;
-import jdk.internal.misc.SharedSecrets;
-
 /**
  * {@code StringJoiner} is used to construct a sequence of characters separated
  * by a delimiter and optionally starting with a supplied prefix
@@ -86,8 +83,6 @@
      */
     private String emptyValue;
 
-    private static final JavaLangAccess jla = SharedSecrets.getJavaLangAccess();
-
     /**
      * Constructs a {@code StringJoiner} with no characters in it, with no
      * {@code prefix} or {@code suffix}, and a copy of the supplied
@@ -189,7 +184,7 @@
             }
         }
         k += getChars(suffix, chars, k);
-        return jla.newStringUnsafe(chars);
+        return new String(chars);
     }
 
     /**
@@ -252,7 +247,7 @@
                 elts[i] = null;
             } while (++i < size);
             size = 1;
-            elts[0] = jla.newStringUnsafe(chars);
+            elts[0] = new String(chars);
         }
     }
 
--- a/src/java.base/share/classes/java/util/concurrent/SubmissionPublisher.java	Thu Nov 30 22:05:19 2017 +0100
+++ b/src/java.base/share/classes/java/util/concurrent/SubmissionPublisher.java	Wed Dec 06 11:39:23 2017 +0000
@@ -38,11 +38,15 @@
 import java.lang.invoke.MethodHandles;
 import java.lang.invoke.VarHandle;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 import java.util.concurrent.locks.LockSupport;
 import java.util.function.BiConsumer;
 import java.util.function.BiPredicate;
 import java.util.function.Consumer;
+import static java.util.concurrent.Flow.Publisher;
+import static java.util.concurrent.Flow.Subscriber;
+import static java.util.concurrent.Flow.Subscription;
 
 /**
  * A {@link Flow.Publisher} that asynchronously issues submitted
@@ -74,6 +78,14 @@
  * Flow#defaultBufferSize()} may provide a useful starting point for
  * choosing a capacity based on expected rates, resources, and usages.
  *
+ * <p>A single SubmissionPublisher may be shared among multiple
+ * sources. Actions in a source thread prior to publishing an item or
+ * issuing a signal <a href="package-summary.html#MemoryVisibility">
+ * <i>happen-before</i></a> actions subsequent to the corresponding
+ * access by each subscriber. But reported estimates of lag and demand
+ * are designed for use in monitoring, not for synchronization
+ * control, and may reflect stale or inaccurate views of progress.
+ *
  * <p>Publication methods support different policies about what to do
  * when buffers are saturated. Method {@link #submit(Object) submit}
  * blocks until resources are available. This is simplest, but least
@@ -158,19 +170,27 @@
  * @author Doug Lea
  * @since 9
  */
-public class SubmissionPublisher<T> implements Flow.Publisher<T>,
+public class SubmissionPublisher<T> implements Publisher<T>,
                                                AutoCloseable {
     /*
      * Most mechanics are handled by BufferedSubscription. This class
      * mainly tracks subscribers and ensures sequentiality, by using
-     * built-in synchronization locks across public methods. (Using
+     * built-in synchronization locks across public methods. Using
      * built-in locks works well in the most typical case in which
-     * only one thread submits items).
+     * only one thread submits items. We extend this idea in
+     * submission methods by detecting single-ownership to reduce
+     * producer-consumer synchronization strength.
      */
 
     /** The largest possible power of two array size. */
     static final int BUFFER_CAPACITY_LIMIT = 1 << 30;
 
+    /**
+     * Initial buffer capacity used when maxBufferCapacity is
+     * greater. Must be a power of two.
+     */
+    static final int INITIAL_CAPACITY = 32;
+
     /** Round capacity to power of 2, at most limit. */
     static final int roundCapacity(int cap) {
         int n = cap - 1;
@@ -206,7 +226,7 @@
      * but we expect that subscribing is much less common than
      * publishing. Unsubscribing occurs only during traversal loops,
      * when BufferedSubscription methods return negative values
-     * signifying that they have been disabled.  To reduce
+     * signifying that they have been closed.  To reduce
      * head-of-line blocking, submit and offer methods first call
      * BufferedSubscription.offer on each subscriber, and place
      * saturated ones in retries list (using nextRetry field), and
@@ -216,12 +236,16 @@
 
     /** Run status, updated only within locks */
     volatile boolean closed;
+    /** Set true on first call to subscribe, to initialize possible owner */
+    boolean subscribed;
+    /** The first caller thread to subscribe, or null if thread ever changed */
+    Thread owner;
     /** If non-null, the exception in closeExceptionally */
     volatile Throwable closedException;
 
     // Parameters for constructing BufferedSubscriptions
     final Executor executor;
-    final BiConsumer<? super Flow.Subscriber<? super T>, ? super Throwable> onNextHandler;
+    final BiConsumer<? super Subscriber<? super T>, ? super Throwable> onNextHandler;
     final int maxBufferCapacity;
 
     /**
@@ -245,7 +269,7 @@
      * positive
      */
     public SubmissionPublisher(Executor executor, int maxBufferCapacity,
-                               BiConsumer<? super Flow.Subscriber<? super T>, ? super Throwable> handler) {
+                               BiConsumer<? super Subscriber<? super T>, ? super Throwable> handler) {
         if (executor == null)
             throw new NullPointerException();
         if (maxBufferCapacity <= 0)
@@ -311,12 +335,19 @@
      * @param subscriber the subscriber
      * @throws NullPointerException if subscriber is null
      */
-    public void subscribe(Flow.Subscriber<? super T> subscriber) {
+    public void subscribe(Subscriber<? super T> subscriber) {
         if (subscriber == null) throw new NullPointerException();
+        int max = maxBufferCapacity; // allocate initial array
+        Object[] array = new Object[max < INITIAL_CAPACITY ?
+                                    max : INITIAL_CAPACITY];
         BufferedSubscription<T> subscription =
-            new BufferedSubscription<T>(subscriber, executor,
-                                        onNextHandler, maxBufferCapacity);
+            new BufferedSubscription<T>(subscriber, executor, onNextHandler,
+                                        array, max);
         synchronized (this) {
+            if (!subscribed) {
+                subscribed = true;
+                owner = Thread.currentThread();
+            }
             for (BufferedSubscription<T> b = clients, pred = null;;) {
                 if (b == null) {
                     Throwable ex;
@@ -332,7 +363,7 @@
                     break;
                 }
                 BufferedSubscription<T> next = b.next;
-                if (b.isDisabled()) { // remove
+                if (b.isClosed()) {   // remove
                     b.next = null;    // detach
                     if (pred == null)
                         clients = next;
@@ -351,6 +382,107 @@
     }
 
     /**
+     * Common implementation for all three forms of submit and offer.
+     * Acts as submit if nanos == Long.MAX_VALUE, else offer.
+     */
+    private int doOffer(T item, long nanos,
+                        BiPredicate<Subscriber<? super T>, ? super T> onDrop) {
+        if (item == null) throw new NullPointerException();
+        int lag = 0;
+        boolean complete, unowned;
+        synchronized (this) {
+            Thread t = Thread.currentThread(), o;
+            BufferedSubscription<T> b = clients;
+            if ((unowned = ((o = owner) != t)) && o != null)
+                owner = null;                     // disable bias
+            if (b == null)
+                complete = closed;
+            else {
+                complete = false;
+                boolean cleanMe = false;
+                BufferedSubscription<T> retries = null, rtail = null, next;
+                do {
+                    next = b.next;
+                    int stat = b.offer(item, unowned);
+                    if (stat == 0) {              // saturated; add to retry list
+                        b.nextRetry = null;       // avoid garbage on exceptions
+                        if (rtail == null)
+                            retries = b;
+                        else
+                            rtail.nextRetry = b;
+                        rtail = b;
+                    }
+                    else if (stat < 0)            // closed
+                        cleanMe = true;           // remove later
+                    else if (stat > lag)
+                        lag = stat;
+                } while ((b = next) != null);
+
+                if (retries != null || cleanMe)
+                    lag = retryOffer(item, nanos, onDrop, retries, lag, cleanMe);
+            }
+        }
+        if (complete)
+            throw new IllegalStateException("Closed");
+        else
+            return lag;
+    }
+
+    /**
+     * Helps, (timed) waits for, and/or drops buffers on list; returns
+     * lag or negative drops (for use in offer).
+     */
+    private int retryOffer(T item, long nanos,
+                           BiPredicate<Subscriber<? super T>, ? super T> onDrop,
+                           BufferedSubscription<T> retries, int lag,
+                           boolean cleanMe) {
+        for (BufferedSubscription<T> r = retries; r != null;) {
+            BufferedSubscription<T> nextRetry = r.nextRetry;
+            r.nextRetry = null;
+            if (nanos > 0L)
+                r.awaitSpace(nanos);
+            int stat = r.retryOffer(item);
+            if (stat == 0 && onDrop != null && onDrop.test(r.subscriber, item))
+                stat = r.retryOffer(item);
+            if (stat == 0)
+                lag = (lag >= 0) ? -1 : lag - 1;
+            else if (stat < 0)
+                cleanMe = true;
+            else if (lag >= 0 && stat > lag)
+                lag = stat;
+            r = nextRetry;
+        }
+        if (cleanMe)
+            cleanAndCount();
+        return lag;
+    }
+
+    /**
+     * Returns current list count after removing closed subscribers.
+     * Call only while holding lock.  Used mainly by retryOffer for
+     * cleanup.
+     */
+    private int cleanAndCount() {
+        int count = 0;
+        BufferedSubscription<T> pred = null, next;
+        for (BufferedSubscription<T> b = clients; b != null; b = next) {
+            next = b.next;
+            if (b.isClosed()) {
+                b.next = null;
+                if (pred == null)
+                    clients = next;
+                else
+                    pred.next = next;
+            }
+            else {
+                pred = b;
+                ++count;
+            }
+        }
+        return count;
+    }
+
+    /**
      * Publishes the given item to each current subscriber by
      * asynchronously invoking its {@link Flow.Subscriber#onNext(Object)
      * onNext} method, blocking uninterruptibly while resources for any
@@ -373,55 +505,7 @@
      * @throws RejectedExecutionException if thrown by Executor
      */
     public int submit(T item) {
-        if (item == null) throw new NullPointerException();
-        int lag = 0;
-        boolean complete;
-        synchronized (this) {
-            complete = closed;
-            BufferedSubscription<T> b = clients;
-            if (!complete) {
-                BufferedSubscription<T> pred = null, r = null, rtail = null;
-                while (b != null) {
-                    BufferedSubscription<T> next = b.next;
-                    int stat = b.offer(item);
-                    if (stat < 0) {           // disabled
-                        b.next = null;
-                        if (pred == null)
-                            clients = next;
-                        else
-                            pred.next = next;
-                    }
-                    else {
-                        if (stat > lag)
-                            lag = stat;
-                        else if (stat == 0) { // place on retry list
-                            b.nextRetry = null;
-                            if (rtail == null)
-                                r = b;
-                            else
-                                rtail.nextRetry = b;
-                            rtail = b;
-                        }
-                        pred = b;
-                    }
-                    b = next;
-                }
-                while (r != null) {
-                    BufferedSubscription<T> nextRetry = r.nextRetry;
-                    r.nextRetry = null;
-                    int stat = r.submit(item);
-                    if (stat > lag)
-                        lag = stat;
-                    else if (stat < 0 && clients == r)
-                        clients = r.next; // postpone internal unsubscribes
-                    r = nextRetry;
-                }
-            }
-        }
-        if (complete)
-            throw new IllegalStateException("Closed");
-        else
-            return lag;
+        return doOffer(item, Long.MAX_VALUE, null);
     }
 
     /**
@@ -462,8 +546,8 @@
      * @throws RejectedExecutionException if thrown by Executor
      */
     public int offer(T item,
-                     BiPredicate<Flow.Subscriber<? super T>, ? super T> onDrop) {
-        return doOffer(0L, item, onDrop);
+                     BiPredicate<Subscriber<? super T>, ? super T> onDrop) {
+        return doOffer(item, 0L, onDrop);
     }
 
     /**
@@ -510,71 +594,11 @@
      * @throws RejectedExecutionException if thrown by Executor
      */
     public int offer(T item, long timeout, TimeUnit unit,
-                     BiPredicate<Flow.Subscriber<? super T>, ? super T> onDrop) {
-        return doOffer(unit.toNanos(timeout), item, onDrop);
-    }
-
-    /** Common implementation for both forms of offer */
-    final int doOffer(long nanos, T item,
-                      BiPredicate<Flow.Subscriber<? super T>, ? super T> onDrop) {
-        if (item == null) throw new NullPointerException();
-        int lag = 0, drops = 0;
-        boolean complete;
-        synchronized (this) {
-            complete = closed;
-            BufferedSubscription<T> b = clients;
-            if (!complete) {
-                BufferedSubscription<T> pred = null, r = null, rtail = null;
-                while (b != null) {
-                    BufferedSubscription<T> next = b.next;
-                    int stat = b.offer(item);
-                    if (stat < 0) {
-                        b.next = null;
-                        if (pred == null)
-                            clients = next;
-                        else
-                            pred.next = next;
-                    }
-                    else {
-                        if (stat > lag)
-                            lag = stat;
-                        else if (stat == 0) {
-                            b.nextRetry = null;
-                            if (rtail == null)
-                                r = b;
-                            else
-                                rtail.nextRetry = b;
-                            rtail = b;
-                        }
-                        else if (stat > lag)
-                            lag = stat;
-                        pred = b;
-                    }
-                    b = next;
-                }
-                while (r != null) {
-                    BufferedSubscription<T> nextRetry = r.nextRetry;
-                    r.nextRetry = null;
-                    int stat = (nanos > 0L)
-                        ? r.timedOffer(item, nanos)
-                        : r.offer(item);
-                    if (stat == 0 && onDrop != null &&
-                        onDrop.test(r.subscriber, item))
-                        stat = r.offer(item);
-                    if (stat == 0)
-                        ++drops;
-                    else if (stat > lag)
-                        lag = stat;
-                    else if (stat < 0 && clients == r)
-                        clients = r.next;
-                    r = nextRetry;
-                }
-            }
-        }
-        if (complete)
-            throw new IllegalStateException("Closed");
-        else
-            return (drops > 0) ? -drops : lag;
+                     BiPredicate<Subscriber<? super T>, ? super T> onDrop) {
+        long nanos = unit.toNanos(timeout);
+        // distinguishes from untimed (only wrt interrupt policy)
+        if (nanos == Long.MAX_VALUE) --nanos;
+        return doOffer(item, nanos, onDrop);
     }
 
     /**
@@ -591,6 +615,7 @@
                 // no need to re-check closed here
                 b = clients;
                 clients = null;
+                owner = null;
                 closed = true;
             }
             while (b != null) {
@@ -621,8 +646,9 @@
             synchronized (this) {
                 b = clients;
                 if (!closed) {  // don't clobber racing close
+                    closedException = error;
                     clients = null;
-                    closedException = error;
+                    owner = null;
                     closed = true;
                 }
             }
@@ -662,18 +688,16 @@
      */
     public boolean hasSubscribers() {
         boolean nonEmpty = false;
-        if (!closed) {
-            synchronized (this) {
-                for (BufferedSubscription<T> b = clients; b != null;) {
-                    BufferedSubscription<T> next = b.next;
-                    if (b.isDisabled()) {
-                        b.next = null;
-                        b = clients = next;
-                    }
-                    else {
-                        nonEmpty = true;
-                        break;
-                    }
+        synchronized (this) {
+            for (BufferedSubscription<T> b = clients; b != null;) {
+                BufferedSubscription<T> next = b.next;
+                if (b.isClosed()) {
+                    b.next = null;
+                    b = clients = next;
+                }
+                else {
+                    nonEmpty = true;
+                    break;
                 }
             }
         }
@@ -686,27 +710,9 @@
      * @return the number of current subscribers
      */
     public int getNumberOfSubscribers() {
-        int count = 0;
-        if (!closed) {
-            synchronized (this) {
-                BufferedSubscription<T> pred = null, next;
-                for (BufferedSubscription<T> b = clients; b != null; b = next) {
-                    next = b.next;
-                    if (b.isDisabled()) {
-                        b.next = null;
-                        if (pred == null)
-                            clients = next;
-                        else
-                            pred.next = next;
-                    }
-                    else {
-                        pred = b;
-                        ++count;
-                    }
-                }
-            }
+        synchronized (this) {
+            return cleanAndCount();
         }
-        return count;
     }
 
     /**
@@ -734,13 +740,13 @@
      *
      * @return list of current subscribers
      */
-    public List<Flow.Subscriber<? super T>> getSubscribers() {
-        ArrayList<Flow.Subscriber<? super T>> subs = new ArrayList<>();
+    public List<Subscriber<? super T>> getSubscribers() {
+        ArrayList<Subscriber<? super T>> subs = new ArrayList<>();
         synchronized (this) {
             BufferedSubscription<T> pred = null, next;
             for (BufferedSubscription<T> b = clients; b != null; b = next) {
                 next = b.next;
-                if (b.isDisabled()) {
+                if (b.isClosed()) {
                     b.next = null;
                     if (pred == null)
                         clients = next;
@@ -761,14 +767,14 @@
      * @return true if currently subscribed
      * @throws NullPointerException if subscriber is null
      */
-    public boolean isSubscribed(Flow.Subscriber<? super T> subscriber) {
+    public boolean isSubscribed(Subscriber<? super T> subscriber) {
         if (subscriber == null) throw new NullPointerException();
         if (!closed) {
             synchronized (this) {
                 BufferedSubscription<T> pred = null, next;
                 for (BufferedSubscription<T> b = clients; b != null; b = next) {
                     next = b.next;
-                    if (b.isDisabled()) {
+                    if (b.isClosed()) {
                         b.next = null;
                         if (pred == null)
                             clients = next;
@@ -872,16 +878,15 @@
     }
 
     /** Subscriber for method consume */
-    private static final class ConsumerSubscriber<T>
-        implements Flow.Subscriber<T> {
+    static final class ConsumerSubscriber<T> implements Subscriber<T> {
         final CompletableFuture<Void> status;
         final Consumer<? super T> consumer;
-        Flow.Subscription subscription;
+        Subscription subscription;
         ConsumerSubscriber(CompletableFuture<Void> status,
                            Consumer<? super T> consumer) {
             this.status = status; this.consumer = consumer;
         }
-        public final void onSubscribe(Flow.Subscription subscription) {
+        public final void onSubscribe(Subscription subscription) {
             this.subscription = subscription;
             status.whenComplete((v, e) -> subscription.cancel());
             if (!status.isDone())
@@ -925,634 +930,534 @@
     }
 
     /**
-     * A bounded (ring) buffer with integrated control to start a
-     * consumer task whenever items are available.  The buffer
-     * algorithm is similar to one used inside ForkJoinPool (see its
-     * internal documentation for details) specialized for the case of
-     * at most one concurrent producer and consumer, and power of two
-     * buffer sizes. This allows methods to operate without locks even
-     * while supporting resizing, blocking, task-triggering, and
-     * garbage-free buffers (nulling out elements when consumed),
-     * although supporting these does impose a bit of overhead
-     * compared to plain fixed-size ring buffers.
+     * A resizable array-based ring buffer with integrated control to
+     * start a consumer task whenever items are available.  The buffer
+     * algorithm is specialized for the case of at most one concurrent
+     * producer and consumer, and power of two buffer sizes. It relies
+     * primarily on atomic operations (CAS or getAndSet) at the next
+     * array slot to put or take an element, at the "tail" and "head"
+     * indices written only by the producer and consumer respectively.
      *
-     * The publisher guarantees a single producer via its lock.  We
-     * ensure in this class that there is at most one consumer.  The
-     * request and cancel methods must be fully thread-safe but are
-     * coded to exploit the most common case in which they are only
-     * called by consumers (usually within onNext).
+     * We ensure internally that there is at most one active consumer
+     * task at any given time. The publisher guarantees a single
+     * producer via its lock. Sync among producers and consumers
+     * relies on volatile fields "ctl", "demand", and "waiting" (along
+     * with element access). Other variables are accessed in plain
+     * mode, relying on outer ordering and exclusion, and/or enclosing
+     * them within other volatile accesses. Some atomic operations are
+     * avoided by tracking single threaded ownership by producers (in
+     * the style of biased locking).
      *
-     * Execution control is managed using the ACTIVE ctl bit. We
-     * ensure that a task is active when consumable items (and
-     * usually, SUBSCRIBE, ERROR or COMPLETE signals) are present and
-     * there is demand (unfilled requests).  This is complicated on
-     * the creation side by the possibility of exceptions when trying
-     * to execute tasks. These eventually force DISABLED state, but
-     * sometimes not directly. On the task side, termination (clearing
-     * ACTIVE) that would otherwise race with producers or request()
-     * calls uses the CONSUME keep-alive bit to force a recheck.
-     *
-     * The ctl field also manages run state. When DISABLED, no further
-     * updates are possible. Disabling may be preceded by setting
-     * ERROR or COMPLETE (or both -- ERROR has precedence), in which
-     * case the associated Subscriber methods are invoked, possibly
-     * synchronously if there is no active consumer task (including
-     * cases where execute() failed). The cancel() method is supported
-     * by treating as ERROR but suppressing onError signal.
+     * Execution control and protocol state are managed using field
+     * "ctl".  Methods to subscribe, close, request, and cancel set
+     * ctl bits (mostly using atomic boolean method getAndBitwiseOr),
+     * and ensure that a task is running. (The corresponding consumer
+     * side actions are in method consume.)  To avoid starting a new
+     * task on each action, ctl also includes a keep-alive bit
+     * (ACTIVE) that is refreshed if needed on producer actions.
+     * (Maintaining agreement about keep-alives requires most atomic
+     * updates to be full SC/Volatile strength, which is still much
+     * cheaper than using one task per item.)  Error signals
+     * additionally null out items and/or fields to reduce termination
+     * latency.  The cancel() method is supported by treating as ERROR
+     * but suppressing onError signal.
      *
      * Support for blocking also exploits the fact that there is only
      * one possible waiter. ManagedBlocker-compatible control fields
      * are placed in this class itself rather than in wait-nodes.
-     * Blocking control relies on the "waiter" field. Producers set
-     * the field before trying to block, but must then recheck (via
-     * offer) before parking. Signalling then just unparks and clears
-     * waiter field. If the producer and/or consumer are using a
-     * ForkJoinPool, the producer attempts to help run consumer tasks
-     * via ForkJoinPool.helpAsyncBlocker before blocking.
+     * Blocking control relies on the "waiting" and "waiter"
+     * fields. Producers set them before trying to block. Signalling
+     * unparks and clears fields. If the producer and/or consumer are
+     * using a ForkJoinPool, the producer attempts to help run
+     * consumer tasks via ForkJoinPool.helpAsyncBlocker before
+     * blocking.
      *
-     * This class uses @Contended and heuristic field declaration
-     * ordering to reduce false-sharing-based memory contention among
-     * instances of BufferedSubscription, but it does not currently
-     * attempt to avoid memory contention among buffers. This field
-     * and element packing can hurt performance especially when each
-     * publisher has only one client operating at a high rate.
-     * Addressing this may require allocating substantially more space
-     * than users expect.
+     * Usages of this class may encounter any of several forms of
+     * memory contention. We try to ameliorate across them without
+     * unduly impacting footprints in low-contention usages where it
+     * isn't needed. Buffer arrays start out small and grow only as
+     * needed.  The class uses @Contended and heuristic field
+     * declaration ordering to reduce false-sharing memory contention
+     * across instances of BufferedSubscription (as in, multiple
+     * subscribers per publisher).  We additionally segregate some
+     * fields that would otherwise nearly always encounter cache line
+     * contention among producers and consumers. To reduce contention
+     * across time (vs space), consumers only periodically update
+     * other fields (see method takeItems), at the expense of possibly
+     * staler reporting of lags and demand (bounded at 12.5% == 1/8
+     * capacity) and possibly more atomic operations.
+     *
+     * Other forms of imbalance and slowdowns can occur during startup
+     * when producer and consumer methods are compiled and/or memory
+     * is allocated at different rates.  This is ameliorated by
+     * artificially subdividing some consumer methods, including
+     * isolation of all subscriber callbacks.  This code also includes
+     * typical power-of-two array screening idioms to avoid compilers
+     * generating traps, along with the usual SSA-based inline
+     * assignment coding style. Also, all methods and fields have
+     * default visibility to simplify usage by callers.
      */
     @SuppressWarnings("serial")
     @jdk.internal.vm.annotation.Contended
-    private static final class BufferedSubscription<T>
-        implements Flow.Subscription, ForkJoinPool.ManagedBlocker {
-        // Order-sensitive field declarations
-        long timeout;                      // > 0 if timed wait
-        volatile long demand;              // # unfilled requests
-        int maxCapacity;                   // reduced on OOME
-        int putStat;                       // offer result for ManagedBlocker
+    static final class BufferedSubscription<T>
+        implements Subscription, ForkJoinPool.ManagedBlocker {
+        long timeout;                      // Long.MAX_VALUE if untimed wait
+        int head;                          // next position to take
+        int tail;                          // next position to put
+        final int maxCapacity;             // max buffer size
         volatile int ctl;                  // atomic run state flags
-        volatile int head;                 // next position to take
-        int tail;                          // next position to put
-        Object[] array;                    // buffer: null if disabled
-        Flow.Subscriber<? super T> subscriber; // null if disabled
-        Executor executor;                 // null if disabled
-        BiConsumer<? super Flow.Subscriber<? super T>, ? super Throwable> onNextHandler;
-        volatile Throwable pendingError;   // holds until onError issued
-        volatile Thread waiter;            // blocked producer thread
-        T putItem;                         // for offer within ManagedBlocker
+        Object[] array;                    // buffer
+        final Subscriber<? super T> subscriber;
+        final BiConsumer<? super Subscriber<? super T>, ? super Throwable> onNextHandler;
+        Executor executor;                 // null on error
+        Thread waiter;                     // blocked producer thread
+        Throwable pendingError;            // holds until onError issued
         BufferedSubscription<T> next;      // used only by publisher
         BufferedSubscription<T> nextRetry; // used only by publisher
 
-        // ctl values
-        static final int ACTIVE    = 0x01; // consumer task active
-        static final int CONSUME   = 0x02; // keep-alive for consumer task
-        static final int DISABLED  = 0x04; // final state
-        static final int ERROR     = 0x08; // signal onError then disable
-        static final int SUBSCRIBE = 0x10; // signal onSubscribe
-        static final int COMPLETE  = 0x20; // signal onComplete when done
+        @jdk.internal.vm.annotation.Contended("c") // segregate
+        volatile long demand;              // # unfilled requests
+        @jdk.internal.vm.annotation.Contended("c")
+        volatile int waiting;              // nonzero if producer blocked
+
+        // ctl bit values
+        static final int CLOSED   = 0x01;  // if set, other bits ignored
+        static final int ACTIVE   = 0x02;  // keep-alive for consumer task
+        static final int REQS     = 0x04;  // (possibly) nonzero demand
+        static final int ERROR    = 0x08;  // issues onError when noticed
+        static final int COMPLETE = 0x10;  // issues onComplete when done
+        static final int RUN      = 0x20;  // task is or will be running
+        static final int OPEN     = 0x40;  // true after subscribe
 
         static final long INTERRUPTED = -1L; // timeout vs interrupt sentinel
 
-        /**
-         * Initial buffer capacity used when maxBufferCapacity is
-         * greater. Must be a power of two.
-         */
-        static final int DEFAULT_INITIAL_CAP = 32;
-
-        BufferedSubscription(Flow.Subscriber<? super T> subscriber,
+        BufferedSubscription(Subscriber<? super T> subscriber,
                              Executor executor,
-                             BiConsumer<? super Flow.Subscriber<? super T>,
+                             BiConsumer<? super Subscriber<? super T>,
                              ? super Throwable> onNextHandler,
+                             Object[] array,
                              int maxBufferCapacity) {
             this.subscriber = subscriber;
             this.executor = executor;
             this.onNextHandler = onNextHandler;
+            this.array = array;
             this.maxCapacity = maxBufferCapacity;
-            this.array = new Object[maxBufferCapacity < DEFAULT_INITIAL_CAP ?
-                                    (maxBufferCapacity < 2 ? // at least 2 slots
-                                     2 : maxBufferCapacity) :
-                                    DEFAULT_INITIAL_CAP];
         }
 
-        final boolean isDisabled() {
-            return ctl == DISABLED;
+        // Wrappers for some VarHandle methods
+
+        final boolean weakCasCtl(int cmp, int val) {
+            return CTL.weakCompareAndSet(this, cmp, val);
+        }
+
+        final int getAndBitwiseOrCtl(int bits) {
+            return (int)CTL.getAndBitwiseOr(this, bits);
+        }
+
+        final long subtractDemand(int k) {
+            long n = (long)(-k);
+            return n + (long)DEMAND.getAndAdd(this, n);
+        }
+
+        final boolean casDemand(long cmp, long val) {
+            return DEMAND.compareAndSet(this, cmp, val);
+        }
+
+        // Utilities used by SubmissionPublisher
+
+        /**
+         * Returns true if closed (consumer task may still be running).
+         */
+        final boolean isClosed() {
+            return (ctl & CLOSED) != 0;
         }
 
         /**
-         * Returns estimated number of buffered items, or -1 if
-         * disabled.
+         * Returns estimated number of buffered items, or negative if
+         * closed.
          */
         final int estimateLag() {
-            int n;
-            return (ctl == DISABLED) ? -1 : ((n = tail - head) > 0) ? n : 0;
+            int c = ctl, n = tail - head;
+            return ((c & CLOSED) != 0) ? -1 : (n < 0) ? 0 : n;
+        }
+
+        // Methods for submitting items
+
+        /**
+         * Tries to add item and start consumer task if necessary.
+         * @return negative if closed, 0 if saturated, else estimated lag
+         */
+        final int offer(T item, boolean unowned) {
+            Object[] a;
+            int stat = 0, cap = ((a = array) == null) ? 0 : a.length;
+            int t = tail, i = t & (cap - 1), n = t + 1 - head;
+            if (cap > 0) {
+                boolean added;
+                if (n >= cap && cap < maxCapacity) // resize
+                    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
+                    QA.setRelease(a, i, item);
+                    added = true;
+                }
+                if (added) {
+                    tail = t + 1;
+                    stat = n;
+                }
+            }
+            return startOnOffer(stat);
         }
 
         /**
-         * Tries to add item and start consumer task if necessary.
-         * @return -1 if disabled, 0 if dropped, else estimated lag
+         * Tries to expand buffer and add item, returning true on
+         * success. Currently fails only if out of memory.
          */
-        final int offer(T item) {
-            int h = head, t = tail, cap, size, stat;
-            Object[] a = array;
-            if (a != null && (cap = a.length) > 0 && cap >= (size = t + 1 - h)) {
-                a[(cap - 1) & t] = item;    // relaxed writes OK
-                tail = t + 1;
-                stat = size;
+        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) {
+                try {
+                    newArray = new Object[newCap];
+                } catch (OutOfMemoryError ex) {
+                }
             }
-            else
-                stat = growAndAdd(a, item);
-            return (stat > 0 &&
-                    (ctl & (ACTIVE | CONSUME)) != (ACTIVE | CONSUME)) ?
-                startOnOffer(stat) : stat;
+            if (newArray == null)
+                return false;
+            else {                                // take and move items
+                int newMask = newCap - 1;
+                newArray[t-- & newMask] = item;
+                for (int mask = cap - 1, k = mask; k >= 0; --k) {
+                    Object x = QA.getAndSet(a, t & mask, null);
+                    if (x == null)
+                        break;                    // already consumed
+                    else
+                        newArray[t-- & newMask] = x;
+                }
+                array = newArray;
+                VarHandle.releaseFence();         // release array and slots
+                return true;
+            }
         }
 
         /**
-         * Tries to create or expand buffer, then adds item if possible.
+         * Version of offer for retries (no resize or bias)
          */
-        private int growAndAdd(Object[] a, T item) {
-            boolean alloc;
-            int cap, stat;
-            if ((ctl & (ERROR | DISABLED)) != 0) {
-                cap = 0;
+        final int retryOffer(T item) {
+            Object[] a;
+            int stat = 0, t = tail, h = head, cap;
+            if ((a = array) != null && (cap = a.length) > 0 &&
+                QA.compareAndSet(a, (cap - 1) & t, null, item))
+                stat = (tail = t + 1) - h;
+            return startOnOffer(stat);
+        }
+
+        /**
+         * Tries to start consumer task after offer.
+         * @return negative if now closed, else argument
+         */
+        final int startOnOffer(int stat) {
+            int c; // start or keep alive if requests exist and not active
+            if (((c = ctl) & (REQS | ACTIVE)) == REQS &&
+                ((c = getAndBitwiseOrCtl(RUN | ACTIVE)) & (RUN | CLOSED)) == 0)
+                tryStart();
+            else if ((c & CLOSED) != 0)
                 stat = -1;
-                alloc = false;
-            }
-            else if (a == null || (cap = a.length) <= 0) {
-                cap = 0;
-                stat = 1;
-                alloc = true;
-            }
-            else {
-                VarHandle.fullFence();           // recheck
-                int h = head, t = tail, size = t + 1 - h;
-                if (cap >= size) {
-                    a[(cap - 1) & t] = item;
-                    tail = t + 1;
-                    stat = size;
-                    alloc = false;
-                }
-                else if (cap >= maxCapacity) {
-                    stat = 0;                    // cannot grow
-                    alloc = false;
-                }
-                else {
-                    stat = cap + 1;
-                    alloc = true;
-                }
-            }
-            if (alloc) {
-                int newCap = (cap > 0) ? cap << 1 : 1;
-                if (newCap <= cap)
-                    stat = 0;
-                else {
-                    Object[] newArray = null;
-                    try {
-                        newArray = new Object[newCap];
-                    } catch (Throwable ex) {     // try to cope with OOME
-                    }
-                    if (newArray == null) {
-                        if (cap > 0)
-                            maxCapacity = cap;   // avoid continuous failure
-                        stat = 0;
-                    }
-                    else {
-                        array = newArray;
-                        int t = tail;
-                        int newMask = newCap - 1;
-                        if (a != null && cap > 0) {
-                            int mask = cap - 1;
-                            for (int j = head; j != t; ++j) {
-                                int k = j & mask;
-                                Object x = QA.getAcquire(a, k);
-                                if (x != null && // races with consumer
-                                    QA.compareAndSet(a, k, x, null))
-                                    newArray[j & newMask] = x;
-                            }
-                        }
-                        newArray[t & newMask] = item;
-                        tail = t + 1;
-                    }
-                }
-            }
             return stat;
         }
 
         /**
-         * Spins/helps/blocks while offer returns 0.  Called only if
-         * initial offer return 0.
+         * Tries to start consumer task. Sets error state on failure.
          */
-        final int submit(T item) {
-            int stat;
-            if ((stat = offer(item)) == 0) {
-                putItem = item;
-                timeout = 0L;
-                putStat = 0;
-                ForkJoinPool.helpAsyncBlocker(executor, this);
-                if ((stat = putStat) == 0) {
-                    try {
-                        ForkJoinPool.managedBlock(this);
-                    } catch (InterruptedException ie) {
-                        timeout = INTERRUPTED;
-                    }
-                    stat = putStat;
-                }
-                if (timeout < 0L)
-                    Thread.currentThread().interrupt();
-            }
-            return stat;
-        }
-
-        /**
-         * Timeout version; similar to submit.
-         */
-        final int timedOffer(T item, long nanos) {
-            int stat;
-            if ((stat = offer(item)) == 0 && (timeout = nanos) > 0L) {
-                putItem = item;
-                putStat = 0;
-                ForkJoinPool.helpAsyncBlocker(executor, this);
-                if ((stat = putStat) == 0) {
-                    try {
-                        ForkJoinPool.managedBlock(this);
-                    } catch (InterruptedException ie) {
-                        timeout = INTERRUPTED;
-                    }
-                    stat = putStat;
-                }
-                if (timeout < 0L)
-                    Thread.currentThread().interrupt();
-            }
-            return stat;
-        }
-
-        /**
-         * Tries to start consumer task after offer.
-         * @return -1 if now disabled, else argument
-         */
-        private int startOnOffer(int stat) {
-            for (;;) {
-                Executor e; int c;
-                if ((c = ctl) == DISABLED || (e = executor) == null) {
-                    stat = -1;
-                    break;
-                }
-                else if ((c & ACTIVE) != 0) { // ensure keep-alive
-                    if ((c & CONSUME) != 0 ||
-                        CTL.compareAndSet(this, c, c | CONSUME))
-                        break;
-                }
-                else if (demand == 0L || tail == head)
-                    break;
-                else if (CTL.compareAndSet(this, c, c | (ACTIVE | CONSUME))) {
-                    try {
-                        e.execute(new ConsumerTask<T>(this));
-                        break;
-                    } catch (RuntimeException | Error ex) { // back out
-                        do {} while (((c = ctl) & DISABLED) == 0 &&
-                                     (c & ACTIVE) != 0 &&
-                                     !CTL.weakCompareAndSet
-                                     (this, c, c & ~ACTIVE));
-                        throw ex;
-                    }
-                }
-            }
-            return stat;
-        }
-
-        private void signalWaiter(Thread w) {
-            waiter = null;
-            LockSupport.unpark(w);    // release producer
-        }
-
-        /**
-         * Nulls out most fields, mainly to avoid garbage retention
-         * until publisher unsubscribes, but also to help cleanly stop
-         * upon error by nulling required components.
-         */
-        private void detach() {
-            Thread w = waiter;
-            executor = null;
-            subscriber = null;
-            pendingError = null;
-            signalWaiter(w);
-        }
-
-        /**
-         * Issues error signal, asynchronously if a task is running,
-         * else synchronously.
-         */
-        final void onError(Throwable ex) {
-            for (int c;;) {
-                if (((c = ctl) & (ERROR | DISABLED)) != 0)
-                    break;
-                else if ((c & ACTIVE) != 0) {
-                    pendingError = ex;
-                    if (CTL.compareAndSet(this, c, c | ERROR))
-                        break; // cause consumer task to exit
-                }
-                else if (CTL.compareAndSet(this, c, DISABLED)) {
-                    Flow.Subscriber<? super T> s = subscriber;
-                    if (s != null && ex != null) {
-                        try {
-                            s.onError(ex);
-                        } catch (Throwable ignore) {
-                        }
-                    }
-                    detach();
-                    break;
-                }
+        final void tryStart() {
+            try {
+                Executor e;
+                ConsumerTask<T> task = new ConsumerTask<T>(this);
+                if ((e = executor) != null)   // skip if disabled on error
+                    e.execute(task);
+            } catch (RuntimeException | Error ex) {
+                getAndBitwiseOrCtl(ERROR | CLOSED);
+                throw ex;
             }
         }
 
+        // Signals to consumer tasks
+
         /**
-         * Tries to start consumer task upon a signal or request;
-         * disables on failure.
+         * Sets the given control bits, starting task if not running or closed.
+         * @param bits state bits, assumed to include RUN but not CLOSED
          */
-        private void startOrDisable() {
-            Executor e;
-            if ((e = executor) != null) { // skip if already disabled
-                try {
-                    e.execute(new ConsumerTask<T>(this));
-                } catch (Throwable ex) {  // back out and force signal
-                    for (int c;;) {
-                        if ((c = ctl) == DISABLED || (c & ACTIVE) == 0)
-                            break;
-                        if (CTL.compareAndSet(this, c, c & ~ACTIVE)) {
-                            onError(ex);
-                            break;
-                        }
-                    }
-                }
+        final void startOnSignal(int bits) {
+            if ((ctl & bits) != bits &&
+                (getAndBitwiseOrCtl(bits) & (RUN | CLOSED)) == 0)
+                tryStart();
+        }
+
+        final void onSubscribe() {
+            startOnSignal(RUN | ACTIVE);
+        }
+
+        final void onComplete() {
+            startOnSignal(RUN | ACTIVE | COMPLETE);
+        }
+
+        final void onError(Throwable ex) {
+            int c; Object[] a;      // to null out buffer on async error
+            if (ex != null)
+                pendingError = ex;  // races are OK
+            if (((c = getAndBitwiseOrCtl(ERROR | RUN | ACTIVE)) & CLOSED) == 0) {
+                if ((c & RUN) == 0)
+                    tryStart();
+                else if ((a = array) != null)
+                    Arrays.fill(a, null);
             }
         }
 
-        final void onComplete() {
-            for (int c;;) {
-                if ((c = ctl) == DISABLED)
-                    break;
-                if (CTL.compareAndSet(this, c,
-                                      c | (ACTIVE | CONSUME | COMPLETE))) {
-                    if ((c & ACTIVE) == 0)
-                        startOrDisable();
-                    break;
-                }
-            }
+        public final void cancel() {
+            onError(null);
         }
 
-        final void onSubscribe() {
-            for (int c;;) {
-                if ((c = ctl) == DISABLED)
-                    break;
-                if (CTL.compareAndSet(this, c,
-                                      c | (ACTIVE | CONSUME | SUBSCRIBE))) {
-                    if ((c & ACTIVE) == 0)
-                        startOrDisable();
-                    break;
-                }
-            }
-        }
-
-        /**
-         * Causes consumer task to exit if active (without reporting
-         * onError unless there is already a pending error), and
-         * disables.
-         */
-        public void cancel() {
-            for (int c;;) {
-                if ((c = ctl) == DISABLED)
-                    break;
-                else if ((c & ACTIVE) != 0) {
-                    if (CTL.compareAndSet(this, c,
-                                          c | (CONSUME | ERROR)))
+        public final void request(long n) {
+            if (n > 0L) {
+                for (;;) {
+                    long p = demand, d = p + n;  // saturate
+                    if (casDemand(p, d < p ? Long.MAX_VALUE : d))
                         break;
                 }
-                else if (CTL.compareAndSet(this, c, DISABLED)) {
-                    detach();
-                    break;
-                }
-            }
-        }
-
-        /**
-         * Adds to demand and possibly starts task.
-         */
-        public void request(long n) {
-            if (n > 0L) {
-                for (;;) {
-                    long prev = demand, d;
-                    if ((d = prev + n) < prev) // saturate
-                        d = Long.MAX_VALUE;
-                    if (DEMAND.compareAndSet(this, prev, d)) {
-                        for (int c, h;;) {
-                            if ((c = ctl) == DISABLED)
-                                break;
-                            else if ((c & ACTIVE) != 0) {
-                                if ((c & CONSUME) != 0 ||
-                                    CTL.compareAndSet(this, c, c | CONSUME))
-                                    break;
-                            }
-                            else if ((h = head) != tail) {
-                                if (CTL.compareAndSet(this, c,
-                                                      c | (ACTIVE|CONSUME))) {
-                                    startOrDisable();
-                                    break;
-                                }
-                            }
-                            else if (head == h && tail == h)
-                                break;          // else stale
-                            if (demand == 0L)
-                                break;
-                        }
-                        break;
-                    }
-                }
+                startOnSignal(RUN | ACTIVE | REQS);
             }
             else
                 onError(new IllegalArgumentException(
                             "non-positive subscription request"));
         }
 
-        public final boolean isReleasable() { // for ManagedBlocker
-            T item = putItem;
-            if (item != null) {
-                if ((putStat = offer(item)) == 0)
-                    return false;
-                putItem = null;
-            }
-            return true;
-        }
-
-        public final boolean block() { // for ManagedBlocker
-            T item = putItem;
-            if (item != null) {
-                putItem = null;
-                long nanos = timeout;
-                long deadline = (nanos > 0L) ? System.nanoTime() + nanos : 0L;
-                while ((putStat = offer(item)) == 0) {
-                    if (Thread.interrupted()) {
-                        timeout = INTERRUPTED;
-                        if (nanos > 0L)
-                            break;
-                    }
-                    else if (nanos > 0L &&
-                             (nanos = deadline - System.nanoTime()) <= 0L)
-                        break;
-                    else if (waiter == null)
-                        waiter = Thread.currentThread();
-                    else {
-                        if (nanos > 0L)
-                            LockSupport.parkNanos(this, nanos);
-                        else
-                            LockSupport.park(this);
-                        waiter = null;
-                    }
-                }
-            }
-            waiter = null;
-            return true;
-        }
+        // Consumer task actions
 
         /**
-         * Consumer loop, called from ConsumerTask, or indirectly
-         * when helping during submit.
+         * Consumer loop, called from ConsumerTask, or indirectly when
+         * helping during submit.
          */
         final void consume() {
-            Flow.Subscriber<? super T> s;
-            int h = head;
-            if ((s = subscriber) != null) {           // else disabled
-                for (;;) {
-                    long d = demand;
-                    int c; Object[] a; int n, i; Object x; Thread w;
-                    if (((c = ctl) & (ERROR | SUBSCRIBE | DISABLED)) != 0) {
-                        if (!checkControl(s, c))
-                            break;
+            Subscriber<? super T> s;
+            if ((s = subscriber) != null) {          // hoist checks
+                subscribeOnOpen(s);
+                long d = demand;
+                for (int h = head, t = tail;;) {
+                    int c, taken; boolean empty;
+                    if (((c = ctl) & ERROR) != 0) {
+                        closeOnError(s, null);
+                        break;
                     }
-                    else if ((a = array) == null || h == tail ||
-                             (n = a.length) == 0 ||
-                             (x = QA.getAcquire(a, i = (n - 1) & h)) == null) {
-                        if (!checkEmpty(s, c))
-                            break;
+                    else if ((taken = takeItems(s, d, h)) > 0) {
+                        head = h += taken;
+                        d = subtractDemand(taken);
                     }
-                    else if (d == 0L) {
-                        if (!checkDemand(c))
-                            break;
+                    else if ((empty = (t == h)) && (c & COMPLETE) != 0) {
+                        closeOnComplete(s);          // end of stream
+                        break;
                     }
-                    else if (((c & CONSUME) != 0 ||
-                              CTL.compareAndSet(this, c, c | CONSUME)) &&
-                             QA.compareAndSet(a, i, x, null)) {
-                        HEAD.setRelease(this, ++h);
-                        DEMAND.getAndAdd(this, -1L);
-                        if ((w = waiter) != null)
-                            signalWaiter(w);
-                        try {
-                            @SuppressWarnings("unchecked") T y = (T) x;
-                            s.onNext(y);
-                        } catch (Throwable ex) {
-                            handleOnNext(s, ex);
-                        }
+                    else if ((d = demand) == 0L && (c & REQS) != 0)
+                        weakCasCtl(c, c & ~REQS);    // exhausted demand
+                    else if (d != 0L && (c & REQS) == 0)
+                        weakCasCtl(c, c | REQS);     // new demand
+                    else if (t == (t = tail) && (empty || d == 0L)) {
+                        int bit = ((c & ACTIVE) != 0) ? ACTIVE : RUN;
+                        if (weakCasCtl(c, c & ~bit) && bit == RUN)
+                            break;                   // un-keep-alive or exit
                     }
                 }
             }
         }
 
         /**
-         * Responds to control events in consume().
+         * Consumes some items until unavailable or bound or error.
+         *
+         * @param s subscriber
+         * @param d current demand
+         * @param h current head
+         * @return number taken
          */
-        private boolean checkControl(Flow.Subscriber<? super T> s, int c) {
-            boolean stat = true;
-            if ((c & SUBSCRIBE) != 0) {
-                if (CTL.compareAndSet(this, c, c & ~SUBSCRIBE)) {
-                    try {
-                        if (s != null)
-                            s.onSubscribe(this);
-                    } catch (Throwable ex) {
-                        onError(ex);
-                    }
+        final int takeItems(Subscriber<? super T> s, long d, int h) {
+            Object[] a;
+            int k = 0, cap;
+            if ((a = array) != null && (cap = a.length) > 0) {
+                int m = cap - 1, b = (m >>> 3) + 1; // min(1, cap/8)
+                int n = (d < (long)b) ? (int)d : b;
+                for (; k < n; ++h, ++k) {
+                    Object x = QA.getAndSet(a, h & m, null);
+                    if (waiting != 0)
+                        signalWaiter();
+                    if (x == null)
+                        break;
+                    else if (!consumeNext(s, x))
+                        break;
                 }
             }
-            else if ((c & ERROR) != 0) {
-                Throwable ex = pendingError;
-                ctl = DISABLED;           // no need for CAS
-                if (ex != null) {         // null if errorless cancel
-                    try {
-                        if (s != null)
-                            s.onError(ex);
-                    } catch (Throwable ignore) {
-                    }
-                }
-            }
-            else {
-                detach();
-                stat = false;
-            }
-            return stat;
+            return k;
         }
 
-        /**
-         * Responds to apparent emptiness in consume().
-         */
-        private boolean checkEmpty(Flow.Subscriber<? super T> s, int c) {
-            boolean stat = true;
-            if (head == tail) {
-                if ((c & CONSUME) != 0)
-                    CTL.compareAndSet(this, c, c & ~CONSUME);
-                else if ((c & COMPLETE) != 0) {
-                    if (CTL.compareAndSet(this, c, DISABLED)) {
-                        try {
-                            if (s != null)
-                                s.onComplete();
-                        } catch (Throwable ignore) {
-                        }
-                    }
-                }
-                else if (CTL.compareAndSet(this, c, c & ~ACTIVE))
-                    stat = false;
+        final boolean consumeNext(Subscriber<? super T> s, Object x) {
+            try {
+                @SuppressWarnings("unchecked") T y = (T) x;
+                if (s != null)
+                    s.onNext(y);
+                return true;
+            } catch (Throwable ex) {
+                handleOnNext(s, ex);
+                return false;
             }
-            return stat;
-        }
-
-        /**
-         * Responds to apparent zero demand in consume().
-         */
-        private boolean checkDemand(int c) {
-            boolean stat = true;
-            if (demand == 0L) {
-                if ((c & CONSUME) != 0)
-                    CTL.compareAndSet(this, c, c & ~CONSUME);
-                else if (CTL.compareAndSet(this, c, c & ~ACTIVE))
-                    stat = false;
-            }
-            return stat;
         }
 
         /**
          * Processes exception in Subscriber.onNext.
          */
-        private void handleOnNext(Flow.Subscriber<? super T> s, Throwable ex) {
-            BiConsumer<? super Flow.Subscriber<? super T>, ? super Throwable> h;
-            if ((h = onNextHandler) != null) {
-                try {
+        final void handleOnNext(Subscriber<? super T> s, Throwable ex) {
+            BiConsumer<? super Subscriber<? super T>, ? super Throwable> h;
+            try {
+                if ((h = onNextHandler) != null)
                     h.accept(s, ex);
-                } catch (Throwable ignore) {
+            } catch (Throwable ignore) {
+            }
+            closeOnError(s, ex);
+        }
+
+        /**
+         * Issues subscriber.onSubscribe if this is first signal.
+         */
+        final void subscribeOnOpen(Subscriber<? super T> s) {
+            if ((ctl & OPEN) == 0 && (getAndBitwiseOrCtl(OPEN) & OPEN) == 0)
+                consumeSubscribe(s);
+        }
+
+        final void consumeSubscribe(Subscriber<? super T> s) {
+            try {
+                if (s != null) // ignore if disabled
+                    s.onSubscribe(this);
+            } catch (Throwable ex) {
+                closeOnError(s, ex);
+            }
+        }
+
+        /**
+         * Issues subscriber.onComplete unless already closed.
+         */
+        final void closeOnComplete(Subscriber<? super T> s) {
+            if ((getAndBitwiseOrCtl(CLOSED) & CLOSED) == 0)
+                consumeComplete(s);
+        }
+
+        final void consumeComplete(Subscriber<? super T> s) {
+            try {
+                if (s != null)
+                    s.onComplete();
+            } catch (Throwable ignore) {
+            }
+        }
+
+        /**
+         * Issues subscriber.onError, and unblocks producer if needed.
+         */
+        final void closeOnError(Subscriber<? super T> s, Throwable ex) {
+            if ((getAndBitwiseOrCtl(ERROR | CLOSED) & CLOSED) == 0) {
+                if (ex == null)
+                    ex = pendingError;
+                pendingError = null;  // detach
+                executor = null;      // suppress racing start calls
+                signalWaiter();
+                consumeError(s, ex);
+            }
+        }
+
+        final void consumeError(Subscriber<? super T> s, Throwable ex) {
+            try {
+                if (ex != null && s != null)
+                    s.onError(ex);
+            } catch (Throwable ignore) {
+            }
+        }
+
+        // Blocking support
+
+        /**
+         * Unblocks waiting producer.
+         */
+        final void signalWaiter() {
+            Thread w;
+            waiting = 0;
+            if ((w = waiter) != null)
+                LockSupport.unpark(w);
+        }
+
+        /**
+         * Returns true if closed or space available.
+         * For ManagedBlocker.
+         */
+        public final boolean isReleasable() {
+            Object[] a; int cap;
+            return ((ctl & CLOSED) != 0 ||
+                    ((a = array) != null && (cap = a.length) > 0 &&
+                     QA.getAcquire(a, (cap - 1) & tail) == null));
+        }
+
+        /**
+         * Helps or blocks until timeout, closed, or space available.
+         */
+        final void awaitSpace(long nanos) {
+            if (!isReleasable()) {
+                ForkJoinPool.helpAsyncBlocker(executor, this);
+                if (!isReleasable()) {
+                    timeout = nanos;
+                    try {
+                        ForkJoinPool.managedBlock(this);
+                    } catch (InterruptedException ie) {
+                        timeout = INTERRUPTED;
+                    }
+                    if (timeout == INTERRUPTED)
+                        Thread.currentThread().interrupt();
                 }
             }
-            onError(ex);
+        }
+
+        /**
+         * Blocks until closed, space available or timeout.
+         * For ManagedBlocker.
+         */
+        public final boolean block() {
+            long nanos = timeout;
+            boolean timed = (nanos < Long.MAX_VALUE);
+            long deadline = timed ? System.nanoTime() + nanos : 0L;
+            while (!isReleasable()) {
+                if (Thread.interrupted()) {
+                    timeout = INTERRUPTED;
+                    if (timed)
+                        break;
+                }
+                else if (timed && (nanos = deadline - System.nanoTime()) <= 0L)
+                    break;
+                else if (waiter == null)
+                    waiter = Thread.currentThread();
+                else if (waiting == 0)
+                    waiting = 1;
+                else if (timed)
+                    LockSupport.parkNanos(this, nanos);
+                else
+                    LockSupport.park(this);
+            }
+            waiter = null;
+            waiting = 0;
+            return true;
         }
 
         // VarHandle mechanics
-        private static final VarHandle CTL;
-        private static final VarHandle TAIL;
-        private static final VarHandle HEAD;
-        private static final VarHandle DEMAND;
-        private static final VarHandle QA;
+        static final VarHandle CTL;
+        static final VarHandle DEMAND;
+        static final VarHandle QA;
 
         static {
             try {
                 MethodHandles.Lookup l = MethodHandles.lookup();
                 CTL = l.findVarHandle(BufferedSubscription.class, "ctl",
                                       int.class);
-                TAIL = l.findVarHandle(BufferedSubscription.class, "tail",
-                                       int.class);
-                HEAD = l.findVarHandle(BufferedSubscription.class, "head",
-                                       int.class);
                 DEMAND = l.findVarHandle(BufferedSubscription.class, "demand",
                                          long.class);
                 QA = MethodHandles.arrayElementVarHandle(Object[].class);
--- a/src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java	Thu Nov 30 22:05:19 2017 +0100
+++ b/src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedLongSynchronizer.java	Wed Dec 06 11:39:23 2017 +0000
@@ -422,8 +422,8 @@
      * @return {@code true} if interrupted while waiting
      */
     final boolean acquireQueued(final Node node, long arg) {
+        boolean interrupted = false;
         try {
-            boolean interrupted = false;
             for (;;) {
                 final Node p = node.predecessor();
                 if (p == head && tryAcquire(arg)) {
@@ -431,12 +431,13 @@
                     p.next = null; // help GC
                     return interrupted;
                 }
-                if (shouldParkAfterFailedAcquire(p, node) &&
-                    parkAndCheckInterrupt())
-                    interrupted = true;
+                if (shouldParkAfterFailedAcquire(p, node))
+                    interrupted |= parkAndCheckInterrupt();
             }
         } catch (Throwable t) {
             cancelAcquire(node);
+            if (interrupted)
+                selfInterrupt();
             throw t;
         }
     }
@@ -510,8 +511,8 @@
      */
     private void doAcquireShared(long arg) {
         final Node node = addWaiter(Node.SHARED);
+        boolean interrupted = false;
         try {
-            boolean interrupted = false;
             for (;;) {
                 final Node p = node.predecessor();
                 if (p == head) {
@@ -519,18 +520,18 @@
                     if (r >= 0) {
                         setHeadAndPropagate(node, r);
                         p.next = null; // help GC
-                        if (interrupted)
-                            selfInterrupt();
                         return;
                     }
                 }
-                if (shouldParkAfterFailedAcquire(p, node) &&
-                    parkAndCheckInterrupt())
-                    interrupted = true;
+                if (shouldParkAfterFailedAcquire(p, node))
+                    interrupted |= parkAndCheckInterrupt();
             }
         } catch (Throwable t) {
             cancelAcquire(node);
             throw t;
+        } finally {
+            if (interrupted)
+                selfInterrupt();
         }
     }
 
--- a/src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedSynchronizer.java	Thu Nov 30 22:05:19 2017 +0100
+++ b/src/java.base/share/classes/java/util/concurrent/locks/AbstractQueuedSynchronizer.java	Wed Dec 06 11:39:23 2017 +0000
@@ -505,7 +505,7 @@
          *
          * @return the predecessor of this node
          */
-        final Node predecessor() throws NullPointerException {
+        final Node predecessor() {
             Node p = prev;
             if (p == null)
                 throw new NullPointerException();
@@ -902,8 +902,8 @@
      * @return {@code true} if interrupted while waiting
      */
     final boolean acquireQueued(final Node node, int arg) {
+        boolean interrupted = false;
         try {
-            boolean interrupted = false;
             for (;;) {
                 final Node p = node.predecessor();
                 if (p == head && tryAcquire(arg)) {
@@ -911,12 +911,13 @@
                     p.next = null; // help GC
                     return interrupted;
                 }
-                if (shouldParkAfterFailedAcquire(p, node) &&
-                    parkAndCheckInterrupt())
-                    interrupted = true;
+                if (shouldParkAfterFailedAcquire(p, node))
+                    interrupted |= parkAndCheckInterrupt();
             }
         } catch (Throwable t) {
             cancelAcquire(node);
+            if (interrupted)
+                selfInterrupt();
             throw t;
         }
     }
@@ -990,8 +991,8 @@
      */
     private void doAcquireShared(int arg) {
         final Node node = addWaiter(Node.SHARED);
+        boolean interrupted = false;
         try {
-            boolean interrupted = false;
             for (;;) {
                 final Node p = node.predecessor();
                 if (p == head) {
@@ -999,18 +1000,18 @@
                     if (r >= 0) {
                         setHeadAndPropagate(node, r);
                         p.next = null; // help GC
-                        if (interrupted)
-                            selfInterrupt();
                         return;
                     }
                 }
-                if (shouldParkAfterFailedAcquire(p, node) &&
-                    parkAndCheckInterrupt())
-                    interrupted = true;
+                if (shouldParkAfterFailedAcquire(p, node))
+                    interrupted |= parkAndCheckInterrupt();
             }
         } catch (Throwable t) {
             cancelAcquire(node);
             throw t;
+        } finally {
+            if (interrupted)
+                selfInterrupt();
         }
     }
 
--- a/src/java.base/share/classes/java/util/jar/JarFile.java	Thu Nov 30 22:05:19 2017 +0100
+++ b/src/java.base/share/classes/java/util/jar/JarFile.java	Wed Dec 06 11:39:23 2017 +0000
@@ -43,17 +43,12 @@
 import java.security.cert.Certificate;
 import java.util.ArrayList;
 import java.util.Enumeration;
-import java.util.Iterator;
 import java.util.List;
 import java.util.Locale;
-import java.util.Map;
 import java.util.NoSuchElementException;
 import java.util.Objects;
-import java.util.Spliterator;
-import java.util.Spliterators;
-import java.util.stream.Collector;
+import java.util.function.Function;
 import java.util.stream.Stream;
-import java.util.stream.StreamSupport;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipException;
 import java.util.zip.ZipFile;
@@ -566,7 +561,14 @@
      * given entry name or {@code null} if not found.
      */
     private JarFileEntry getEntry0(String name) {
-        return (JarFileEntry)JUZFA.getEntry(this, name, JarFileEntry::new);
+        // Not using a lambda/method reference here to optimize startup time
+        Function<String, JarEntry> newJarFileEntryFn = new Function<>() {
+            @Override
+            public JarEntry apply(String name) {
+                return new JarFileEntry(name);
+            }
+        };
+        return (JarFileEntry)JUZFA.getEntry(this, name, newJarFileEntryFn);
     }
 
     private String getBasename(String name) {
--- a/src/java.base/share/classes/java/util/stream/Collectors.java	Thu Nov 30 22:05:19 2017 +0100
+++ b/src/java.base/share/classes/java/util/stream/Collectors.java	Wed Dec 06 11:39:23 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -116,6 +116,8 @@
             = Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.UNORDERED,
                                                      Collector.Characteristics.IDENTITY_FINISH));
     static final Set<Collector.Characteristics> CH_NOID = Collections.emptySet();
+    static final Set<Collector.Characteristics> CH_UNORDERED_NOID
+            = Collections.unmodifiableSet(EnumSet.of(Collector.Characteristics.UNORDERED));
 
     private Collectors() { }
 
@@ -279,6 +281,26 @@
     }
 
     /**
+     * Returns a {@code Collector} that accumulates the input elements into an
+     * <a href="../List.html#unmodifiable">unmodifiable List</a> in encounter
+     * order. The returned Collector disallows null values and will throw
+     * {@code NullPointerException} if it is presented with a null value.
+     *
+     * @param <T> the type of the input elements
+     * @return a {@code Collector} that accumulates the input elements into an
+     * <a href="../List.html#unmodifiable">unmodifiable List</a> in encounter order
+     * @since 10
+     */
+    @SuppressWarnings("unchecked")
+    public static <T>
+    Collector<T, ?, List<T>> toUnmodifiableList() {
+        return new CollectorImpl<>((Supplier<List<T>>) ArrayList::new, List::add,
+                                   (left, right) -> { left.addAll(right); return left; },
+                                   list -> (List<T>)List.of(list.toArray()),
+                                   CH_NOID);
+    }
+
+    /**
      * Returns a {@code Collector} that accumulates the input elements into a
      * new {@code Set}. There are no guarantees on the type, mutability,
      * serializability, or thread-safety of the {@code Set} returned; if more
@@ -306,6 +328,36 @@
     }
 
     /**
+     * Returns a {@code Collector} that accumulates the input elements into an
+     * <a href="../Set.html#unmodifiable">unmodifiable Set</a>. The returned
+     * Collector disallows null values and will throw {@code NullPointerException}
+     * if it is presented with a null value. If the input contains duplicate elements,
+     * an arbitrary element of the duplicates is preserved.
+     *
+     * <p>This is an {@link Collector.Characteristics#UNORDERED unordered}
+     * Collector.
+     *
+     * @param <T> the type of the input elements
+     * @return a {@code Collector} that accumulates the input elements into an
+     * <a href="../Set.html#unmodifiable">unmodifiable Set</a>
+     * @since 10
+     */
+    @SuppressWarnings("unchecked")
+    public static <T>
+    Collector<T, ?, Set<T>> toUnmodifiableSet() {
+        return new CollectorImpl<>((Supplier<Set<T>>) HashSet::new, Set::add,
+                                   (left, right) -> {
+                                       if (left.size() < right.size()) {
+                                           right.addAll(left); return right;
+                                       } else {
+                                           left.addAll(right); return left;
+                                       }
+                                   },
+                                   set -> (Set<T>)Set.of(set.toArray()),
+                                   CH_UNORDERED_NOID);
+    }
+
+    /**
      * Returns a {@code Collector} that concatenates the input elements into a
      * {@code String}, in encounter order.
      *
@@ -1353,7 +1405,7 @@
      * <p>If the mapped keys contain duplicates (according to
      * {@link Object#equals(Object)}), an {@code IllegalStateException} is
      * thrown when the collection operation is performed.  If the mapped keys
-     * may have duplicates, use {@link #toMap(Function, Function, BinaryOperator)}
+     * might have duplicates, use {@link #toMap(Function, Function, BinaryOperator)}
      * instead.
      *
      * <p>There are no guarantees on the type, mutability, serializability,
@@ -1411,6 +1463,45 @@
     }
 
     /**
+     * Returns a {@code Collector} that accumulates the input elements into an
+     * <a href="../Map.html#unmodifiable">unmodifiable Map</a>,
+     * whose keys and values are the result of applying the provided
+     * mapping functions to the input elements.
+     *
+     * <p>If the mapped keys contain duplicates (according to
+     * {@link Object#equals(Object)}), an {@code IllegalStateException} is
+     * thrown when the collection operation is performed.  If the mapped keys
+     * might have duplicates, use {@link #toUnmodifiableMap(Function, Function, BinaryOperator)}
+     * to handle merging of the values.
+     *
+     * <p>The returned Collector disallows null keys and values. If either mapping function
+     * returns null, {@code NullPointerException} will be thrown.
+     *
+     * @param <T> the type of the input elements
+     * @param <K> the output type of the key mapping function
+     * @param <U> the output type of the value mapping function
+     * @param keyMapper a mapping function to produce keys, must be non-null
+     * @param valueMapper a mapping function to produce values, must be non-null
+     * @return a {@code Collector} that accumulates the input elements into an
+     * <a href="../Map.html#unmodifiable">unmodifiable Map</a>, whose keys and values
+     * are the result of applying the provided mapping functions to the input elements
+     * @throws NullPointerException if either keyMapper or valueMapper is null
+     *
+     * @see #toUnmodifiableMap(Function, Function, BinaryOperator)
+     * @since 10
+     */
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    public static <T, K, U>
+    Collector<T, ?, Map<K,U>> toUnmodifiableMap(Function<? super T, ? extends K> keyMapper,
+                                                Function<? super T, ? extends U> valueMapper) {
+        Objects.requireNonNull(keyMapper, "keyMapper");
+        Objects.requireNonNull(valueMapper, "valueMapper");
+        return collectingAndThen(
+                toMap(keyMapper, valueMapper),
+                map -> (Map<K,U>)Map.ofEntries(map.entrySet().toArray(new Map.Entry[0])));
+    }
+
+    /**
      * Returns a {@code Collector} that accumulates elements into a
      * {@code Map} whose keys and values are the result of applying the provided
      * mapping functions to the input elements.
@@ -1473,6 +1564,51 @@
         return toMap(keyMapper, valueMapper, mergeFunction, HashMap::new);
     }
 
+
+    /**
+     * Returns a {@code Collector} that accumulates the input elements into an
+     * <a href="../Map.html#unmodifiable">unmodifiable Map</a>,
+     * whose keys and values are the result of applying the provided
+     * mapping functions to the input elements.
+     *
+     * <p>If the mapped
+     * keys contain duplicates (according to {@link Object#equals(Object)}),
+     * the value mapping function is applied to each equal element, and the
+     * results are merged using the provided merging function.
+     *
+     * <p>The returned Collector disallows null keys and values. If either mapping function
+     * returns null, {@code NullPointerException} will be thrown.
+     *
+     * @param <T> the type of the input elements
+     * @param <K> the output type of the key mapping function
+     * @param <U> the output type of the value mapping function
+     * @param keyMapper a mapping function to produce keys, must be non-null
+     * @param valueMapper a mapping function to produce values, must be non-null
+     * @param mergeFunction a merge function, used to resolve collisions between
+     *                      values associated with the same key, as supplied
+     *                      to {@link Map#merge(Object, Object, BiFunction)},
+     *                      must be non-null
+     * @return a {@code Collector} that accumulates the input elements into an
+     * <a href="../Map.html#unmodifiable">unmodifiable Map</a>, whose keys and values
+     * are the result of applying the provided mapping functions to the input elements
+     * @throws NullPointerException if the keyMapper, valueMapper, or mergeFunction is null
+     *
+     * @see #toUnmodifiableMap(Function, Function)
+     * @since 10
+     */
+    @SuppressWarnings({"rawtypes", "unchecked"})
+    public static <T, K, U>
+    Collector<T, ?, Map<K,U>> toUnmodifiableMap(Function<? super T, ? extends K> keyMapper,
+                                                Function<? super T, ? extends U> valueMapper,
+                                                BinaryOperator<U> mergeFunction) {
+        Objects.requireNonNull(keyMapper, "keyMapper");
+        Objects.requireNonNull(valueMapper, "valueMapper");
+        Objects.requireNonNull(mergeFunction, "mergeFunction");
+        return collectingAndThen(
+                toMap(keyMapper, valueMapper, mergeFunction, HashMap::new),
+                map -> (Map<K,U>)Map.ofEntries(map.entrySet().toArray(new Map.Entry[0])));
+    }
+
     /**
      * Returns a {@code Collector} that accumulates elements into a
      * {@code Map} whose keys and values are the result of applying the provided
--- a/src/java.base/share/classes/jdk/internal/jrtfs/JrtPath.java	Thu Nov 30 22:05:19 2017 +0100
+++ b/src/java.base/share/classes/jdk/internal/jrtfs/JrtPath.java	Wed Dec 06 11:39:23 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -33,7 +33,7 @@
 import java.nio.channels.FileChannel;
 import java.nio.channels.SeekableByteChannel;
 import java.nio.file.*;
-import java.nio.file.DirectoryStream.Filter;;
+import java.nio.file.DirectoryStream.Filter;
 import java.nio.file.attribute.BasicFileAttributes;
 import java.nio.file.attribute.BasicFileAttributeView;
 import java.nio.file.attribute.FileAttribute;
@@ -274,7 +274,7 @@
         if (o.path.length() == 0) {
             return this;
         }
-        StringBuilder sb = new StringBuilder(path.length() + o.path.length());
+        StringBuilder sb = new StringBuilder(path.length() + o.path.length() + 1);
         sb.append(path);
         if (path.charAt(path.length() - 1) != '/')
             sb.append('/');
@@ -478,12 +478,15 @@
 
     // Remove DotSlash(./) and resolve DotDot (..) components
     private String getResolved() {
-        if (path.length() == 0) {
+        int length = path.length();
+        if (length == 0 || (path.indexOf("./") == -1 && path.charAt(length - 1) != '.')) {
             return path;
+        } else {
+            return resolvePath();
         }
-        if (path.indexOf('.') == -1) {
-            return path;
-        }
+    }
+
+    private String resolvePath() {
         int length = path.length();
         char[] to = new char[length];
         int nc = getNameCount();
--- a/src/java.base/share/classes/jdk/internal/misc/JavaLangAccess.java	Thu Nov 30 22:05:19 2017 +0100
+++ b/src/java.base/share/classes/jdk/internal/misc/JavaLangAccess.java	Wed Dec 06 11:39:23 2017 +0000
@@ -124,16 +124,6 @@
     void registerShutdownHook(int slot, boolean registerShutdownInProgress, Runnable hook);
 
     /**
-     * Returns a new string backed by the provided character array. The
-     * character array is not copied and must never be modified after the
-     * String is created, in order to fulfill String's contract.
-     *
-     * @param chars the character array to back the string
-     * @return a newly created string whose content is the character array
-     */
-    String newStringUnsafe(char[] chars);
-
-    /**
      * Returns a new Thread with the given Runnable and an
      * inherited AccessControlContext.
      */
--- a/src/java.base/share/classes/jdk/internal/util/jar/VersionedStream.java	Thu Nov 30 22:05:19 2017 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,85 +0,0 @@
-/*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package jdk.internal.util.jar;
-
-import java.util.Objects;
-import java.util.jar.JarEntry;
-import java.util.jar.JarFile;
-import java.util.stream.Stream;
-
-public class VersionedStream {
-    private static final String META_INF_VERSIONS = "META-INF/versions/";
-
-    /**
-     * Returns a stream of versioned entries, derived from the base names of
-     * all entries in a multi-release {@code JarFile} that are present either in
-     * the base directory or in any versioned directory with a version number
-     * less than or equal to the {@code Runtime.Version::major} that the
-     * {@code JarFile} was opened with.  These versioned entries are aliases
-     * for the real entries -- i.e. the names are base names and the content
-     * may come from a versioned directory entry.  If the {@code jarFile} is not
-     * a multi-release jar, a stream of all entries is returned.
-     *
-     * @param jf the input JarFile
-     * @return stream of entries
-     * @since 9
-     */
-    public static Stream<JarEntry> stream(JarFile jf) {
-        if (jf.isMultiRelease()) {
-            int version = jf.getVersion().major();
-            return jf.stream()
-                    .map(je -> getBaseSuffix(je, version))
-                    .filter(Objects::nonNull)
-                    .distinct()
-                    .map(jf::getJarEntry);
-        }
-        return jf.stream();
-    }
-
-    private static String getBaseSuffix(JarEntry je, int version) {
-        String name = je.getName();
-        if (name.startsWith(META_INF_VERSIONS)) {
-            int len = META_INF_VERSIONS.length();
-            int index = name.indexOf('/', len);
-            if (index == -1 || index == (name.length() - 1)) {
-                // filter out META-INF/versions/* and META-INF/versions/*/
-                return null;
-            }
-            try {
-                if (Integer.parseInt(name, len, index, 10) > version) {
-                    // not an integer
-                    return null;
-                }
-            } catch (NumberFormatException x) {
-                // silently remove malformed entries
-                return null;
-            }
-            // We know name looks like META-INF/versions/*/*
-            return name.substring(index + 1);
-        }
-        return name;
-    }
-}
--- a/src/java.base/share/classes/sun/security/tools/keytool/Main.java	Thu Nov 30 22:05:19 2017 +0100
+++ b/src/java.base/share/classes/sun/security/tools/keytool/Main.java	Wed Dec 06 11:39:23 2017 +0000
@@ -2746,12 +2746,12 @@
                     if (rfc) {
                         dumpCert(cert, out);
                     } else {
-                        out.println("Certificate #" + i++);
+                        out.println("Certificate #" + i);
                         out.println("====================================");
                         printX509Cert((X509Certificate)cert, out);
                         out.println();
                     }
-                    checkWeak(oneInMany(rb.getString("the.certificate"), i, chain.size()), cert);
+                    checkWeak(oneInMany(rb.getString("the.certificate"), i++, chain.size()), cert);
                 } catch (Exception e) {
                     if (debug) {
                         e.printStackTrace();
--- a/src/java.base/share/native/libzip/Deflater.c	Thu Nov 30 22:05:19 2017 +0100
+++ b/src/java.base/share/native/libzip/Deflater.c	Wed Dec 06 11:39:23 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -164,17 +164,14 @@
         res = deflateParams(strm, level, strategy);
         (*env)->ReleasePrimitiveArrayCritical(env, b, out_buf, 0);
         (*env)->ReleasePrimitiveArrayCritical(env, this_buf, in_buf, 0);
-
         switch (res) {
         case Z_OK:
             (*env)->SetBooleanField(env, this, setParamsID, JNI_FALSE);
+        case Z_BUF_ERROR:
             this_off += this_len - strm->avail_in;
             (*env)->SetIntField(env, this, offID, this_off);
             (*env)->SetIntField(env, this, lenID, strm->avail_in);
             return (jint) (len - strm->avail_out);
-        case Z_BUF_ERROR:
-            (*env)->SetBooleanField(env, this, setParamsID, JNI_FALSE);
-            return 0;
         default:
             JNU_ThrowInternalError(env, strm->msg);
             return 0;
@@ -203,19 +200,17 @@
         res = deflate(strm, finish ? Z_FINISH : flush);
         (*env)->ReleasePrimitiveArrayCritical(env, b, out_buf, 0);
         (*env)->ReleasePrimitiveArrayCritical(env, this_buf, in_buf, 0);
-
         switch (res) {
         case Z_STREAM_END:
             (*env)->SetBooleanField(env, this, finishedID, JNI_TRUE);
             /* fall through */
         case Z_OK:
+        case Z_BUF_ERROR:
             this_off += this_len - strm->avail_in;
             (*env)->SetIntField(env, this, offID, this_off);
             (*env)->SetIntField(env, this, lenID, strm->avail_in);
             return len - strm->avail_out;
-        case Z_BUF_ERROR:
-            return 0;
-            default:
+        default:
             JNU_ThrowInternalError(env, strm->msg);
             return 0;
         }
--- a/src/java.base/share/native/libzip/zlib/deflate.c	Thu Nov 30 22:05:19 2017 +0100
+++ b/src/java.base/share/native/libzip/zlib/deflate.c	Wed Dec 06 11:39:23 2017 +0000
@@ -505,8 +505,6 @@
     s->pending = 0;
     s->pending_out = s->pending_buf;
 
-    s->high_water = 0;      /* reset to its inital value 0 */
-
     if (s->wrap < 0) {
         s->wrap = -s->wrap; /* was made negative by deflate(..., Z_FINISH); */
     }
@@ -520,7 +518,7 @@
         s->wrap == 2 ? crc32(0L, Z_NULL, 0) :
 #endif
         adler32(0L, Z_NULL, 0);
-    s->last_flush = Z_NO_FLUSH;
+    s->last_flush = -2;
 
     _tr_init(s);
 
@@ -613,7 +611,7 @@
     func = configuration_table[s->level].func;
 
     if ((strategy != s->strategy || func != configuration_table[level].func) &&
-        s->high_water) {
+        s->last_flush != -2) {
         /* Flush the last buffer: */
         int err = deflate(strm, Z_BLOCK);
         if (err == Z_STREAM_ERROR)
--- a/src/java.base/share/native/libzip/zlib/patches/ChangeLog_java	Thu Nov 30 22:05:19 2017 +0100
+++ b/src/java.base/share/native/libzip/zlib/patches/ChangeLog_java	Wed Dec 06 11:39:23 2017 +0000
@@ -93,4 +93,6 @@
       s->status =
   #ifdef GZIP
 
+(7) deflate.c undo (6), replaced withe the official zlib repo fix see#305/#f969409
+
   
--- a/src/java.base/unix/classes/java/net/PlainDatagramSocketImpl.java	Thu Nov 30 22:05:19 2017 +0100
+++ b/src/java.base/unix/classes/java/net/PlainDatagramSocketImpl.java	Wed Dec 06 11:39:23 2017 +0000
@@ -45,41 +45,33 @@
             ExtendedSocketOptions.getInstance();
 
     protected <T> void setOption(SocketOption<T> name, T value) throws IOException {
-        if (!extendedOptions.isOptionSupported(name)) {
-            if (!name.equals(StandardSocketOptions.SO_REUSEPORT)) {
+        if (isClosed()) {
+            throw new SocketException("Socket closed");
+        }
+        if (supportedOptions().contains(name)) {
+            if (extendedOptions.isOptionSupported(name)) {
+                extendedOptions.setOption(fd, name, value);
+            } else {
                 super.setOption(name, value);
-            } else {
-               if (supportedOptions().contains(name)) {
-                   super.setOption(name, value);
-               } else {
-                   throw new UnsupportedOperationException("unsupported option");
-               }
             }
         } else {
-            if (isClosed()) {
-                throw new SocketException("Socket closed");
-            }
-            extendedOptions.setOption(fd, name, value);
+            throw new UnsupportedOperationException("unsupported option");
         }
     }
 
     @SuppressWarnings("unchecked")
     protected <T> T getOption(SocketOption<T> name) throws IOException {
-        if (!extendedOptions.isOptionSupported(name)) {
-            if (!name.equals(StandardSocketOptions.SO_REUSEPORT)) {
+        if (isClosed()) {
+            throw new SocketException("Socket closed");
+        }
+        if (supportedOptions().contains(name)) {
+            if (extendedOptions.isOptionSupported(name)) {
+                return (T) extendedOptions.getOption(fd, name);
+            } else {
                 return super.getOption(name);
-            } else {
-                if (supportedOptions().contains(name)) {
-                    return super.getOption(name);
-                } else {
-                    throw new UnsupportedOperationException("unsupported option");
-                }
             }
         } else {
-            if (isClosed()) {
-                throw new SocketException("Socket closed");
-            }
-            return (T) extendedOptions.getOption(fd, name);
+            throw new UnsupportedOperationException("unsupported option");
         }
     }
 
--- a/src/java.base/unix/classes/java/net/PlainSocketImpl.java	Thu Nov 30 22:05:19 2017 +0100
+++ b/src/java.base/unix/classes/java/net/PlainSocketImpl.java	Wed Dec 06 11:39:23 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -58,58 +58,57 @@
             ExtendedSocketOptions.getInstance();
 
     protected <T> void setOption(SocketOption<T> name, T value) throws IOException {
-        if (!extendedOptions.isOptionSupported(name)) {
-            if (!name.equals(StandardSocketOptions.SO_REUSEPORT)) {
+        if (isClosedOrPending()) {
+            throw new SocketException("Socket closed");
+        }
+        if (supportedOptions().contains(name)) {
+            if (extendedOptions.isOptionSupported(name)) {
+                extendedOptions.setOption(fd, name, value);
+            } else {
                 super.setOption(name, value);
-            } else {
-                if (supportedOptions().contains(name)) {
-                    super.setOption(name, value);
-                } else {
-                    throw new UnsupportedOperationException("unsupported option");
-                }
             }
         } else {
-            if (getSocket() == null) {
-                throw new UnsupportedOperationException("unsupported option");
-            }
-            if (isClosedOrPending()) {
-                throw new SocketException("Socket closed");
-            }
-            extendedOptions.setOption(fd, name, value);
+            throw new UnsupportedOperationException("unsupported option");
         }
     }
 
     @SuppressWarnings("unchecked")
     protected <T> T getOption(SocketOption<T> name) throws IOException {
-        if (!extendedOptions.isOptionSupported(name)) {
-            if (!name.equals(StandardSocketOptions.SO_REUSEPORT)) {
+        if (isClosedOrPending()) {
+            throw new SocketException("Socket closed");
+        }
+        if (supportedOptions().contains(name)) {
+            if (extendedOptions.isOptionSupported(name)) {
+                return (T) extendedOptions.getOption(fd, name);
+            } else {
                 return super.getOption(name);
-            } else {
-                if (supportedOptions().contains(name)) {
-                    return super.getOption(name);
-                } else {
-                    throw new UnsupportedOperationException("unsupported option");
-                }
             }
         } else {
-            if (getSocket() == null) {
-                throw new UnsupportedOperationException("unsupported option");
-            }
-            if (isClosedOrPending()) {
-                throw new SocketException("Socket closed");
-            }
-            return (T) extendedOptions.getOption(fd, name);
+            throw new UnsupportedOperationException("unsupported option");
         }
     }
 
     protected Set<SocketOption<?>> supportedOptions() {
         HashSet<SocketOption<?>> options = new HashSet<>(super.supportedOptions());
-        if (getSocket() != null) {
-            options.addAll(extendedOptions.options());
-        }
+        addExtSocketOptions(extendedOptions.options(), options);
         return options;
     }
 
+    private void addExtSocketOptions(Set<SocketOption<?>> extOptions,
+            Set<SocketOption<?>> options) {
+        extOptions.forEach((option) -> {
+            if (option.name().equals("SO_FLOW_SLA")) {
+                // SO_FLOW_SLA is Solaris specific option which is not applicable
+                // for ServerSockets.
+                // getSocket() will always return null for server socket
+                if (getSocket() != null) {
+                    options.add(option);
+                }
+            } else {
+                options.add(option);
+            }
+        });
+    }
     protected void socketSetOption(int opt, boolean b, Object val) throws SocketException {
         if (opt == SocketOptions.SO_REUSEPORT &&
             !supportedOptions().contains(StandardSocketOptions.SO_REUSEPORT)) {
--- a/src/java.desktop/share/classes/sun/awt/FontDescriptor.java	Thu Nov 30 22:05:19 2017 +0100
+++ b/src/java.desktop/share/classes/sun/awt/FontDescriptor.java	Wed Dec 06 11:39:23 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -26,7 +26,7 @@
 
 import java.io.ByteArrayOutputStream;
 import java.io.OutputStreamWriter;
-import java.io.IOException;;
+import java.io.IOException;
 import java.nio.charset.Charset;
 import java.nio.charset.CharsetEncoder;
 import java.nio.charset.StandardCharsets;
--- a/src/java.security.jgss/share/native/libj2gss/GSSLibStub.c	Thu Nov 30 22:05:19 2017 +0100
+++ b/src/java.security.jgss/share/native/libj2gss/GSSLibStub.c	Wed Dec 06 11:39:23 2017 +0000
@@ -1410,7 +1410,6 @@
     checkStatus(env, jobj, GSS_S_CONTEXT_EXPIRED, 0, "[GSSLibStub_getMic]");
     return NULL;
   }
-  contextHdl = (gss_ctx_id_t) jlong_to_ptr(pContext);
   qop = (gss_qop_t) jqop;
   initGSSBuffer(env, jmsg, &msg);
   if ((*env)->ExceptionCheck(env)) {
--- a/src/java.sql/share/classes/java/sql/Date.java	Thu Nov 30 22:05:19 2017 +0100
+++ b/src/java.sql/share/classes/java/sql/Date.java	Wed Dec 06 11:39:23 2017 +0000
@@ -27,8 +27,6 @@
 
 import java.time.Instant;
 import java.time.LocalDate;
-import jdk.internal.misc.SharedSecrets;
-import jdk.internal.misc.JavaLangAccess;
 
 /**
  * <P>A thin wrapper around a millisecond value that allows
@@ -46,8 +44,6 @@
  */
 public class Date extends java.util.Date {
 
-    private static final JavaLangAccess jla = SharedSecrets.getJavaLangAccess();
-
     /**
      * Constructs a <code>Date</code> object initialized with the given
      * year, month, and day.
@@ -168,7 +164,7 @@
         buf[7] = '-';
         Date.formatDecimalInt(day, buf, 8, 2);
 
-        return jla.newStringUnsafe(buf);
+        return new String(buf);
     }
 
     /**
--- a/src/java.sql/share/classes/java/sql/Time.java	Thu Nov 30 22:05:19 2017 +0100
+++ b/src/java.sql/share/classes/java/sql/Time.java	Wed Dec 06 11:39:23 2017 +0000
@@ -27,8 +27,6 @@
 
 import java.time.Instant;
 import java.time.LocalTime;
-import jdk.internal.misc.SharedSecrets;
-import jdk.internal.misc.JavaLangAccess;
 
 /**
  * <P>A thin wrapper around the <code>java.util.Date</code> class that allows the JDBC
@@ -43,8 +41,6 @@
  */
 public class Time extends java.util.Date {
 
-    private static final JavaLangAccess jla = SharedSecrets.getJavaLangAccess();
-
     /**
      * Constructs a <code>Time</code> object initialized with the
      * given values for the hour, minute, and second.
@@ -134,7 +130,7 @@
         buf[5] = ':';
         Date.formatDecimalInt(second, buf, 6, 2);
 
-        return jla.newStringUnsafe(buf);
+        return new String(buf);
     }
 
     // Override all the date operations inherited from java.util.Date;
--- a/src/java.sql/share/classes/java/sql/Timestamp.java	Thu Nov 30 22:05:19 2017 +0100
+++ b/src/java.sql/share/classes/java/sql/Timestamp.java	Wed Dec 06 11:39:23 2017 +0000
@@ -27,8 +27,6 @@
 
 import java.time.Instant;
 import java.time.LocalDateTime;
-import jdk.internal.misc.SharedSecrets;
-import jdk.internal.misc.JavaLangAccess;
 
 /**
  * <P>A thin wrapper around {@code java.util.Date} that allows
@@ -74,8 +72,6 @@
  */
 public class Timestamp extends java.util.Date {
 
-    private static final JavaLangAccess jla = SharedSecrets.getJavaLangAccess();
-
     /**
      * Constructs a {@code Timestamp} object initialized
      * with the given values.
@@ -313,7 +309,7 @@
         buf[yearSize + 15] = '.';
         Date.formatDecimalInt(tmpNanos, buf, yearSize + 16, 9 - trailingZeros);
 
-        return jla.newStringUnsafe(buf);
+        return new String(buf);
     }
 
     /**
--- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ConstantDouble.java	Thu Nov 30 22:05:19 2017 +0100
+++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ConstantDouble.java	Wed Dec 06 11:39:23 2017 +0000
@@ -32,6 +32,7 @@
  *
  * @version $Id: ConstantDouble.java 1747278 2016-06-07 17:28:43Z britter $
  * @see     Constant
+ * @LastModified: Nov 2017
  */
 public final class ConstantDouble extends Constant implements ConstantObject {
 
@@ -121,6 +122,6 @@
      */
     @Override
     public Object getConstantValue( final ConstantPool cp ) {
-        return new Double(bytes);
+        return bytes;
     }
 }
--- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ConstantFloat.java	Thu Nov 30 22:05:19 2017 +0100
+++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/classfile/ConstantFloat.java	Wed Dec 06 11:39:23 2017 +0000
@@ -32,6 +32,7 @@
  *
  * @version $Id: ConstantFloat.java 1747278 2016-06-07 17:28:43Z britter $
  * @see     Constant
+ * @LastModified: Nov 2017
  */
 public final class ConstantFloat extends Constant implements ConstantObject {
 
@@ -122,6 +123,6 @@
      */
     @Override
     public Object getConstantValue( final ConstantPool cp ) {
-        return new Float(bytes);
+        return bytes;
     }
 }
--- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/DCONST.java	Thu Nov 30 22:05:19 2017 +0100
+++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/DCONST.java	Wed Dec 06 11:39:23 2017 +0000
@@ -26,6 +26,7 @@
  * <PRE>Stack: ... -&gt; ..., </PRE>
  *
  * @version $Id: DCONST.java 1747278 2016-06-07 17:28:43Z britter $
+ * @LastModified: Nov 2017
  */
 public class DCONST extends Instruction implements ConstantPushInstruction {
 
@@ -55,7 +56,7 @@
 
     @Override
     public Number getValue() {
-        return new Double(value);
+        return value;
     }
 
 
--- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/FCONST.java	Thu Nov 30 22:05:19 2017 +0100
+++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/FCONST.java	Wed Dec 06 11:39:23 2017 +0000
@@ -26,6 +26,7 @@
  * <PRE>Stack: ... -&gt; ..., </PRE>
  *
  * @version $Id: FCONST.java 1747278 2016-06-07 17:28:43Z britter $
+ * @LastModified: Nov 2017
  */
 public class FCONST extends Instruction implements ConstantPushInstruction {
 
@@ -57,7 +58,7 @@
 
     @Override
     public Number getValue() {
-        return new Float(value);
+        return value;
     }
 
 
--- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/INVOKEDYNAMIC.java	Thu Nov 30 22:05:19 2017 +0100
+++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/INVOKEDYNAMIC.java	Wed Dec 06 11:39:23 2017 +0000
@@ -1,6 +1,5 @@
 /*
- * reserved comment block
- * DO NOT REMOVE OR ALTER!
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
  */
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
@@ -41,6 +40,7 @@
  * <a href="http://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html#jvms-6.5.invokedynamic">
  * The invokedynamic instruction in The Java Virtual Machine Specification</a>
  * @since 6.0
+ * @LastModified: Nov 2017
  */
 public class INVOKEDYNAMIC extends InvokeInstruction {
 
@@ -124,8 +124,14 @@
 
     /**
      * Override the parent method because our classname is held elsewhere.
+     *
+     * @param cpg the ConstantPool generator
+     * @deprecated in FieldOrMethod
+     *
+     * @return name of the referenced class/interface
      */
     @Override
+    @Deprecated
     public String getClassName( final ConstantPoolGen cpg ) {
         final ConstantPool cp = cpg.getConstantPool();
         final ConstantInvokeDynamic cid = (ConstantInvokeDynamic) cp.getConstant(super.getIndex(), Const.CONSTANT_InvokeDynamic);
--- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/InstructionFactory.java	Thu Nov 30 22:05:19 2017 +0100
+++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/InstructionFactory.java	Wed Dec 06 11:39:23 2017 +0000
@@ -32,6 +32,7 @@
  * @version $Id: InstructionFactory.java 1749603 2016-06-21 20:50:19Z ggregory $
  * @see Const
  * @see InstructionConst
+ * @LastModified: Nov 2017
  */
 public class InstructionFactory {
 
@@ -573,7 +574,7 @@
                     + short_names[dest - Const.T_CHAR];
             Instruction i = null;
             try {
-                i = (Instruction) java.lang.Class.forName(name).newInstance();
+                i = (Instruction) java.lang.Class.forName(name).getDeclaredConstructor().newInstance();
             } catch (final Exception e) {
                 throw new RuntimeException("Could not find instruction: " + name, e);
             }
--- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/LDC.java	Thu Nov 30 22:05:19 2017 +0100
+++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/LDC.java	Wed Dec 06 11:39:23 2017 +0000
@@ -32,6 +32,7 @@
  * <PRE>Stack: ... -&gt; ..., item</PRE>
  *
  * @version $Id: LDC.java 1749603 2016-06-21 20:50:19Z ggregory $
+ * @LastModified: Nov 2017
  */
 public class LDC extends CPInstruction implements PushInstruction, ExceptionThrower {
 
@@ -104,9 +105,9 @@
                 c = cpg.getConstantPool().getConstant(i);
                 return ((com.sun.org.apache.bcel.internal.classfile.ConstantUtf8) c).getBytes();
             case com.sun.org.apache.bcel.internal.Const.CONSTANT_Float:
-                return new Float(((com.sun.org.apache.bcel.internal.classfile.ConstantFloat) c).getBytes());
+                return ((com.sun.org.apache.bcel.internal.classfile.ConstantFloat) c).getBytes();
             case com.sun.org.apache.bcel.internal.Const.CONSTANT_Integer:
-                return Integer.valueOf(((com.sun.org.apache.bcel.internal.classfile.ConstantInteger) c).getBytes());
+                return ((com.sun.org.apache.bcel.internal.classfile.ConstantInteger) c).getBytes();
             case com.sun.org.apache.bcel.internal.Const.CONSTANT_Class:
                 final int nameIndex = ((com.sun.org.apache.bcel.internal.classfile.ConstantClass) c).getNameIndex();
                 c = cpg.getConstantPool().getConstant(nameIndex);
--- a/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/LDC2_W.java	Thu Nov 30 22:05:19 2017 +0100
+++ b/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/LDC2_W.java	Wed Dec 06 11:39:23 2017 +0000
@@ -26,6 +26,7 @@
  * <PRE>Stack: ... -&gt; ..., item.word1, item.word2</PRE>
  *
  * @version $Id: LDC2_W.java 1749603 2016-06-21 20:50:19Z ggregory $
+ * @LastModified: Nov 2017
  */
 public class LDC2_W extends CPInstruction implements PushInstruction {
 
@@ -59,9 +60,9 @@
         final com.sun.org.apache.bcel.internal.classfile.Constant c = cpg.getConstantPool().getConstant(super.getIndex());
         switch (c.getTag()) {
             case com.sun.org.apache.bcel.internal.Const.CONSTANT_Long:
-                return Long.valueOf(((com.sun.org.apache.bcel.internal.classfile.ConstantLong) c).getBytes());
+                return ((com.sun.org.apache.bcel.internal.classfile.ConstantLong) c).getBytes();
             case com.sun.org.apache.bcel.internal.Const.CONSTANT_Double:
-                return new Double(((com.sun.org.apache.bcel.internal.classfile.ConstantDouble) c).getBytes());
+                return ((com.sun.org.apache.bcel.internal.classfile.ConstantDouble) c).getBytes();
             default: // Never reached
                 throw new RuntimeException("Unknown or invalid constant type at " + super.getIndex());
         }
--- a/src/jdk.compiler/share/classes/com/sun/source/doctree/DocTreeVisitor.java	Thu Nov 30 22:05:19 2017 +0100
+++ b/src/jdk.compiler/share/classes/com/sun/source/doctree/DocTreeVisitor.java	Wed Dec 06 11:39:23 2017 +0000
@@ -145,11 +145,19 @@
 
     /**
      * Visits a HiddenTree node.
+     *
+     * @implSpec Visits a {@code HiddenTree} node
+     * by calling {@code visitOther(node, p)}.
+     *
      * @param node the node being visited
      * @param p a parameter value
      * @return a result value
+     *
+     * @since 9
      */
-    R visitHidden(HiddenTree node, P p);
+    default R visitHidden(HiddenTree node, P p)  {
+        return visitOther(node, p);
+    }
 
     /**
      * Visits an IdentifierTree node.
@@ -161,11 +169,19 @@
 
     /**
      * Visits an IndexTree node.
+     *
+     * @implSpec Visits an {@code IndexTree} node
+     * by calling {@code visitOther(node, p)}.
+     *
      * @param node the node being visited
      * @param p a parameter value
      * @return a result value
+     *
+     * @since 9
      */
-    R visitIndex(IndexTree node, P p);
+    default R visitIndex(IndexTree node, P p) {
+        return visitOther(node, p);
+    }
 
     /**
      * Visits an InheritDocTree node.
@@ -201,11 +217,19 @@
 
     /**
      * Visits a ProvidesTree node.
+     *
+     * @implSpec Visits a {@code ProvidesTree} node
+     * by calling {@code visitOther(node, p)}.
+     *
      * @param node the node being visited
      * @param p a parameter value
      * @return a result value
+     *
+     * @since 9
      */
-    R visitProvides(ProvidesTree node, P p);
+    default R visitProvides(ProvidesTree node, P p) {
+        return visitOther(node, p);
+    }
 
     /**
      * Visits a ReferenceTree node.
@@ -320,11 +344,19 @@
 
     /**
      * Visits a UsesTree node.
+     *
+     * @implSpec Visits a {@code UsesTree} node
+     * by calling {@code visitOther(node, p)}.
+     *
      * @param node the node being visited
      * @param p a parameter value
      * @return a result value
+     *
+     * @since 9
      */
-    R visitUses(UsesTree node, P p);
+    default R visitUses(UsesTree node, P p) {
+        return visitOther(node, p);
+    }
 
     /**
      * Visits a ValueTree node.
--- a/src/jdk.compiler/share/classes/com/sun/source/util/SimpleDocTreeVisitor.java	Thu Nov 30 22:05:19 2017 +0100
+++ b/src/jdk.compiler/share/classes/com/sun/source/util/SimpleDocTreeVisitor.java	Wed Dec 06 11:39:23 2017 +0000
@@ -220,6 +220,8 @@
      * @param node {@inheritDoc}
      * @param p {@inheritDoc}
      * @return the result of {@code defaultAction}
+     *
+     * @since 9
      */
     @Override
     public R visitHidden(HiddenTree node, P p) {
@@ -244,6 +246,8 @@
      * @param node {@inheritDoc}
      * @param p {@inheritDoc}
      * @return  the result of {@code defaultAction}
+     *
+     * @since 9
      */
     @Override
     public R visitIndex(IndexTree node, P p) {
@@ -304,6 +308,8 @@
      * @param node {@inheritDoc}
      * @param p {@inheritDoc}
      * @return  the result of {@code defaultAction}
+     *
+     * @since 9
      */
     @Override
     public R visitProvides(ProvidesTree node, P p) {
@@ -473,6 +479,8 @@
      * @param node {@inheritDoc}
      * @param p {@inheritDoc}
      * @return  the result of {@code defaultAction}
+     *
+     * @since 9
      */
     @Override
     public R visitUses(UsesTree node, P p) {
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Lint.java	Thu Nov 30 22:05:19 2017 +0100
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Lint.java	Wed Dec 06 11:39:23 2017 +0000
@@ -115,7 +115,7 @@
             values = EnumSet.noneOf(LintCategory.class);
 
             Source source = Source.instance(context);
-            if (source.compareTo(Source.JDK1_9) >= 0) {
+            if (source.compareTo(Source.JDK9) >= 0) {
                 values.add(LintCategory.DEP_ANN);
             }
             values.add(LintCategory.REQUIRES_TRANSITIVE_AUTOMATIC);
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Source.java	Thu Nov 30 22:05:19 2017 +0100
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Source.java	Wed Dec 06 11:39:23 2017 +0000
@@ -31,7 +31,12 @@
 import static javax.lang.model.SourceVersion.*;
 
 import com.sun.tools.javac.jvm.Target;
+import com.sun.tools.javac.resources.CompilerProperties.Errors;
+import com.sun.tools.javac.resources.CompilerProperties.Fragments;
 import com.sun.tools.javac.util.*;
+import com.sun.tools.javac.util.JCDiagnostic.Error;
+import com.sun.tools.javac.util.JCDiagnostic.Fragment;
+
 import static com.sun.tools.javac.main.Option.*;
 
 /** The source language version accepted.
@@ -59,22 +64,22 @@
 
     /** 1.5 introduced generics, attributes, foreach, boxing, static import,
      *  covariant return, enums, varargs, et al. */
-    JDK1_5("1.5"),
+    JDK5("5"),
 
     /** 1.6 reports encoding problems as errors instead of warnings. */
-    JDK1_6("1.6"),
+    JDK6("6"),
 
     /** 1.7 introduced try-with-resources, multi-catch, string switch, etc. */
-    JDK1_7("1.7"),
+    JDK7("7"),
 
     /** 1.8 lambda expressions and default methods. */
-    JDK1_8("1.8"),
+    JDK8("8"),
 
     /** 1.9 modularity. */
-    JDK1_9("1.9"),
+    JDK9("9"),
 
     /** 1.10 covers the to be determined language features that will be added in JDK 10. */
-    JDK1_10("1.10");
+    JDK10("10");
 
     private static final Context.Key<Source> sourceKey = new Context.Key<>();
 
@@ -97,19 +102,19 @@
         for (Source s : values()) {
             tab.put(s.name, s);
         }
-        tab.put("5", JDK1_5); // Make 5 an alias for 1.5
-        tab.put("6", JDK1_6); // Make 6 an alias for 1.6
-        tab.put("7", JDK1_7); // Make 7 an alias for 1.7
-        tab.put("8", JDK1_8); // Make 8 an alias for 1.8
-        tab.put("9", JDK1_9); // Make 9 an alias for 1.9
-        tab.put("10", JDK1_10); // Make 10 an alias for 1.10
+        tab.put("1.5", JDK5); // Make 5 an alias for 1.5
+        tab.put("1.6", JDK6); // Make 6 an alias for 1.6
+        tab.put("1.7", JDK7); // Make 7 an alias for 1.7
+        tab.put("1.8", JDK8); // Make 8 an alias for 1.8
+        tab.put("1.9", JDK9); // Make 9 an alias for 1.9
+        tab.put("1.10", JDK10); // Make 10 an alias for 1.10
     }
 
     private Source(String name) {
         this.name = name;
     }
 
-    public static final Source MIN = Source.JDK1_6;
+    public static final Source MIN = Source.JDK6;
 
     private static final Source MAX = values()[values().length - 1];
 
@@ -120,120 +125,110 @@
     }
 
     public Target requiredTarget() {
-        if (this.compareTo(JDK1_10) >= 0) return Target.JDK1_10;
-        if (this.compareTo(JDK1_9) >= 0) return Target.JDK1_9;
-        if (this.compareTo(JDK1_8) >= 0) return Target.JDK1_8;
-        if (this.compareTo(JDK1_7) >= 0) return Target.JDK1_7;
-        if (this.compareTo(JDK1_6) >= 0) return Target.JDK1_6;
-        if (this.compareTo(JDK1_5) >= 0) return Target.JDK1_5;
+        if (this.compareTo(JDK10) >= 0) return Target.JDK1_10;
+        if (this.compareTo(JDK9) >= 0) return Target.JDK1_9;
+        if (this.compareTo(JDK8) >= 0) return Target.JDK1_8;
+        if (this.compareTo(JDK7) >= 0) return Target.JDK1_7;
+        if (this.compareTo(JDK6) >= 0) return Target.JDK1_6;
+        if (this.compareTo(JDK5) >= 0) return Target.JDK1_5;
         if (this.compareTo(JDK1_4) >= 0) return Target.JDK1_4;
         return Target.JDK1_1;
     }
 
-    public boolean allowDiamond() {
-        return compareTo(JDK1_7) >= 0;
+    /**
+     * Models a feature of the Java programming language. Each feature can be associated with a
+     * minimum source level, a maximum source level and a diagnostic fragment describing the feature,
+     * which is used to generate error messages of the kind {@code feature XYZ not supported in source N}.
+     */
+    public enum Feature {
+
+        DIAMOND(JDK7, Fragments.FeatureDiamond, DiagKind.NORMAL),
+        MULTICATCH(JDK7, Fragments.FeatureMulticatch, DiagKind.PLURAL),
+        IMPROVED_RETHROW_ANALYSIS(JDK7),
+        IMPROVED_CATCH_ANALYSIS(JDK7),
+        MODULES(JDK9, Fragments.FeatureModules, DiagKind.PLURAL),
+        TRY_WITH_RESOURCES(JDK7, Fragments.FeatureTryWithResources, DiagKind.NORMAL),
+        EFFECTIVELY_FINAL_VARIABLES_IN_TRY_WITH_RESOURCES(JDK9, Fragments.FeatureVarInTryWithResources, DiagKind.PLURAL),
+        BINARY_LITERALS(JDK7, Fragments.FeatureBinaryLit, DiagKind.PLURAL),
+        UNDERSCORES_IN_LITERALS(JDK7, Fragments.FeatureUnderscoreLit, DiagKind.PLURAL),
+        STRINGS_IN_SWITCH(JDK7, Fragments.FeatureStringSwitch, DiagKind.PLURAL),
+        DEPRECATION_ON_IMPORT(MIN, JDK9),
+        SIMPLIFIED_VARARGS(JDK7),
+        OBJECT_TO_PRIMITIVE_CAST(JDK7),
+        ENFORCE_THIS_DOT_INIT(JDK7),
+        POLY(JDK8),
+        LAMBDA(JDK8, Fragments.FeatureLambda, DiagKind.PLURAL),
+        METHOD_REFERENCES(JDK8, Fragments.FeatureMethodReferences, DiagKind.PLURAL),
+        DEFAULT_METHODS(JDK8, Fragments.FeatureDefaultMethods, DiagKind.PLURAL),
+        STATIC_INTERFACE_METHODS(JDK8, Fragments.FeatureStaticIntfMethods, DiagKind.PLURAL),
+        STATIC_INTERFACE_METHODS_INVOKE(JDK8, Fragments.FeatureStaticIntfMethodInvoke, DiagKind.PLURAL),
+        STRICT_METHOD_CLASH_CHECK(JDK8),
+        EFFECTIVELY_FINAL_IN_INNER_CLASSES(JDK8),
+        TYPE_ANNOTATIONS(JDK8, Fragments.FeatureTypeAnnotations, DiagKind.PLURAL),
+        ANNOTATIONS_AFTER_TYPE_PARAMS(JDK8, Fragments.FeatureAnnotationsAfterTypeParams, DiagKind.PLURAL),
+        REPEATED_ANNOTATIONS(JDK8, Fragments.FeatureRepeatableAnnotations, DiagKind.PLURAL),
+        INTERSECTION_TYPES_IN_CAST(JDK8, Fragments.FeatureIntersectionTypesInCast, DiagKind.PLURAL),
+        GRAPH_INFERENCE(JDK8),
+        FUNCTIONAL_INTERFACE_MOST_SPECIFIC(JDK8),
+        POST_APPLICABILITY_VARARGS_ACCESS_CHECK(JDK8),
+        MAP_CAPTURES_TO_BOUNDS(MIN, JDK7),
+        PRIVATE_SAFE_VARARGS(JDK9),
+        DIAMOND_WITH_ANONYMOUS_CLASS_CREATION(JDK9, Fragments.FeatureDiamondAndAnonClass, DiagKind.NORMAL),
+        UNDERSCORE_IDENTIFIER(MIN, JDK8),
+        PRIVATE_INTERFACE_METHODS(JDK9, Fragments.FeaturePrivateIntfMethods, DiagKind.PLURAL),
+        LOCAL_VARIABLE_TYPE_INFERENCE(JDK10),
+        LAMBDA_PARAMETER_SHADOWING(JDK10),
+        UNDERSCORE_AS_PARAM_NAME(JDK10);
+
+        enum DiagKind {
+            NORMAL,
+            PLURAL;
+        }
+
+        private final Source minLevel;
+        private final Source maxLevel;
+        private final Fragment optFragment;
+        private final DiagKind optKind;
+
+        Feature(Source minLevel) {
+            this(minLevel, null, null);
+        }
+
+        Feature(Source minLevel, Fragment optFragment, DiagKind optKind) {
+            this(minLevel, MAX, optFragment, optKind);
+        }
+
+        Feature(Source minLevel, Source maxLevel) {
+            this(minLevel, maxLevel, null, null);
+        }
+
+        Feature(Source minLevel, Source maxLevel, Fragment optFragment, DiagKind optKind) {
+            this.minLevel = minLevel;
+            this.maxLevel = maxLevel;
+            this.optFragment = optFragment;
+            this.optKind = optKind;
+        }
+
+        public boolean allowedInSource(Source source) {
+            return source.compareTo(minLevel) >= 0 &&
+                    source.compareTo(maxLevel) <= 0;
+        }
+
+        public Fragment fragment(String sourceName) {
+            Assert.checkNonNull(optFragment);
+            return optKind == DiagKind.NORMAL ?
+                    Fragments.FeatureNotSupportedInSource(optFragment, sourceName, minLevel.name) :
+                    Fragments.FeatureNotSupportedInSourcePlural(optFragment, sourceName, minLevel.name);
+        }
+
+        public Error error(String sourceName) {
+            Assert.checkNonNull(optFragment);
+            return optKind == DiagKind.NORMAL ?
+                    Errors.FeatureNotSupportedInSource(optFragment, sourceName, minLevel.name) :
+                    Errors.FeatureNotSupportedInSourcePlural(optFragment, sourceName, minLevel.name);
+        }
     }
-    public boolean allowMulticatch() {
-        return compareTo(JDK1_7) >= 0;
-    }
-    public boolean allowImprovedRethrowAnalysis() {
-        return compareTo(JDK1_7) >= 0;
-    }
-    public boolean allowImprovedCatchAnalysis() {
-        return compareTo(JDK1_7) >= 0;
-    }
-    public boolean allowModules() {
-        return compareTo(JDK1_9) >= 0;
-    }
-    public boolean allowTryWithResources() {
-        return compareTo(JDK1_7) >= 0;
-    }
-    public boolean allowEffectivelyFinalVariablesInTryWithResources() {
-        return compareTo(JDK1_9) >= 0;
-    }
-    public boolean allowBinaryLiterals() {
-        return compareTo(JDK1_7) >= 0;
-    }
-    public boolean allowUnderscoresInLiterals() {
-        return compareTo(JDK1_7) >= 0;
-    }
-    public boolean allowStringsInSwitch() {
-        return compareTo(JDK1_7) >= 0;
-    }
-    public boolean allowDeprecationOnImport() {
-        return compareTo(JDK1_9) < 0;
-    }
-    public boolean allowSimplifiedVarargs() {
-        return compareTo(JDK1_7) >= 0;
-    }
-    public boolean allowObjectToPrimitiveCast() {
-        return compareTo(JDK1_7) >= 0;
-    }
-    public boolean enforceThisDotInit() {
-        return compareTo(JDK1_7) >= 0;
-    }
-    public boolean allowPoly() {
-        return compareTo(JDK1_8) >= 0;
-    }
-    public boolean allowLambda() {
-        return compareTo(JDK1_8) >= 0;
-    }
-    public boolean allowMethodReferences() {
-        return compareTo(JDK1_8) >= 0;
-    }
-    public boolean allowDefaultMethods() {
-        return compareTo(JDK1_8) >= 0;
-    }
-    public boolean allowStaticInterfaceMethods() {
-        return compareTo(JDK1_8) >= 0;
-    }
-    public boolean allowStrictMethodClashCheck() {
-        return compareTo(JDK1_8) >= 0;
-    }
-    public boolean allowEffectivelyFinalInInnerClasses() {
-        return compareTo(JDK1_8) >= 0;
-    }
-    public boolean allowTypeAnnotations() {
-        return compareTo(JDK1_8) >= 0;
-    }
-    public boolean allowAnnotationsAfterTypeParams() {
-        return compareTo(JDK1_8) >= 0;
-    }
-    public boolean allowRepeatedAnnotations() {
-        return compareTo(JDK1_8) >= 0;
-    }
-    public boolean allowIntersectionTypesInCast() {
-        return compareTo(JDK1_8) >= 0;
-    }
-    public boolean allowGraphInference() {
-        return compareTo(JDK1_8) >= 0;
-    }
-    public boolean allowFunctionalInterfaceMostSpecific() {
-        return compareTo(JDK1_8) >= 0;
-    }
-    public boolean allowPostApplicabilityVarargsAccessCheck() {
-        return compareTo(JDK1_8) >= 0;
-    }
-    public boolean mapCapturesToBounds() {
-        return compareTo(JDK1_8) < 0;
-    }
-    public boolean allowPrivateSafeVarargs() {
-        return compareTo(JDK1_9) >= 0;
-    }
-    public boolean allowDiamondWithAnonymousClassCreation() {
-        return compareTo(JDK1_9) >= 0;
-    }
-    public boolean allowUnderscoreIdentifier() {
-        return compareTo(JDK1_8) <= 0;
-    }
-    public boolean allowUnderscoreAsFormal() {
-        return compareTo(JDK1_10) >= 0;
-    }
-    public boolean allowShadowingOfLambdaParameters() {
-        return compareTo(JDK1_10) >= 0;
-    }
-    public boolean allowPrivateInterfaceMethods() { return compareTo(JDK1_9) >= 0; }
-    public boolean allowLocalVariableTypeInference() { return compareTo(JDK1_10) >= 0; }
+
     public static SourceVersion toSourceVersion(Source source) {
         switch(source) {
         case JDK1_2:
@@ -242,17 +237,17 @@
             return RELEASE_3;
         case JDK1_4:
             return RELEASE_4;
-        case JDK1_5:
+        case JDK5:
             return RELEASE_5;
-        case JDK1_6:
+        case JDK6:
             return RELEASE_6;
-        case JDK1_7:
+        case JDK7:
             return RELEASE_7;
-        case JDK1_8:
+        case JDK8:
             return RELEASE_8;
-        case JDK1_9:
+        case JDK9:
             return RELEASE_9;
-        case JDK1_10:
+        case JDK10:
             return RELEASE_10;
         default:
             return null;
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symtab.java	Thu Nov 30 22:05:19 2017 +0100
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symtab.java	Wed Dec 06 11:39:23 2017 +0000
@@ -35,6 +35,7 @@
 import javax.lang.model.element.ElementVisitor;
 
 import com.sun.tools.javac.code.Scope.WriteableScope;
+import com.sun.tools.javac.code.Source.Feature;
 import com.sun.tools.javac.code.Symbol.ClassSymbol;
 import com.sun.tools.javac.code.Symbol.Completer;
 import com.sun.tools.javac.code.Symbol.CompletionFailure;
@@ -479,7 +480,7 @@
         scope.enter(errSymbol);
 
         Source source = Source.instance(context);
-        if (source.allowModules()) {
+        if (Feature.MODULES.allowedInSource(source)) {
             java_base = enterModule(names.java_base);
             //avoid completing java.base during the Symtab initialization
             java_base.completer = Completer.NULL_COMPLETER;
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java	Thu Nov 30 22:05:19 2017 +0100
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java	Wed Dec 06 11:39:23 2017 +0000
@@ -41,6 +41,7 @@
 
 import com.sun.tools.javac.code.Attribute.RetentionPolicy;
 import com.sun.tools.javac.code.Lint.LintCategory;
+import com.sun.tools.javac.code.Source.Feature;
 import com.sun.tools.javac.code.Type.UndetVar.InferenceBound;
 import com.sun.tools.javac.code.TypeMetadata.Entry.Kind;
 import com.sun.tools.javac.comp.AttrContext;
@@ -113,9 +114,9 @@
         syms = Symtab.instance(context);
         names = Names.instance(context);
         Source source = Source.instance(context);
-        allowObjectToPrimitiveCast = source.allowObjectToPrimitiveCast();
-        allowDefaultMethods = source.allowDefaultMethods();
-        mapCapturesToBounds = source.mapCapturesToBounds();
+        allowObjectToPrimitiveCast = Feature.OBJECT_TO_PRIMITIVE_CAST.allowedInSource(source);
+        allowDefaultMethods = Feature.DEFAULT_METHODS.allowedInSource(source);
+        mapCapturesToBounds = Feature.MAP_CAPTURES_TO_BOUNDS.allowedInSource(source);
         chk = Check.instance(context);
         enter = Enter.instance(context);
         capturedName = names.fromString("<captured wildcard>");
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Analyzer.java	Thu Nov 30 22:05:19 2017 +0100
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Analyzer.java	Wed Dec 06 11:39:23 2017 +0000
@@ -29,6 +29,7 @@
 
 import com.sun.source.tree.LambdaExpressionTree;
 import com.sun.tools.javac.code.Source;
+import com.sun.tools.javac.code.Source.Feature;
 import com.sun.tools.javac.code.Type;
 import com.sun.tools.javac.code.Types;
 import com.sun.tools.javac.comp.ArgumentAttr.LocalCacheContext;
@@ -128,7 +129,7 @@
         String findOpt = options.get("find");
         //parse modes
         Source source = Source.instance(context);
-        allowDiamondWithAnonymousClassCreation = source.allowDiamondWithAnonymousClassCreation();
+        allowDiamondWithAnonymousClassCreation = Feature.DIAMOND_WITH_ANONYMOUS_CLASS_CREATION.allowedInSource(source);
         analyzerModes = AnalyzerMode.getAnalyzerModes(findOpt, source);
     }
 
@@ -137,17 +138,17 @@
      * the {@code -XDfind} option.
      */
     enum AnalyzerMode {
-        DIAMOND("diamond", Source::allowDiamond),
-        LAMBDA("lambda", Source::allowLambda),
-        METHOD("method", Source::allowGraphInference),
-        LOCAL("local", Source::allowLocalVariableTypeInference);
+        DIAMOND("diamond", Feature.DIAMOND),
+        LAMBDA("lambda", Feature.LAMBDA),
+        METHOD("method", Feature.GRAPH_INFERENCE),
+        LOCAL("local", Feature.LOCAL_VARIABLE_TYPE_INFERENCE);
 
         final String opt;
-        final Predicate<Source> sourceFilter;
+        final Feature feature;
 
-        AnalyzerMode(String opt, Predicate<Source> sourceFilter) {
+        AnalyzerMode(String opt, Feature feature) {
             this.opt = opt;
-            this.sourceFilter = sourceFilter;
+            this.feature = feature;
         }
 
         /**
@@ -168,7 +169,7 @@
             for (AnalyzerMode mode : values()) {
                 if (modes.contains(mode.opt)) {
                     res.add(mode);
-                } else if (modes.contains("-" + mode.opt) || !mode.sourceFilter.test(source)) {
+                } else if (modes.contains("-" + mode.opt) || !mode.feature.allowedInSource(source)) {
                     res.remove(mode);
                 }
             }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Annotate.java	Thu Nov 30 22:05:19 2017 +0100
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Annotate.java	Wed Dec 06 11:39:23 2017 +0000
@@ -30,10 +30,12 @@
 import com.sun.tools.javac.code.Attribute.TypeCompound;
 import com.sun.tools.javac.code.Kinds.KindSelector;
 import com.sun.tools.javac.code.Scope.WriteableScope;
+import com.sun.tools.javac.code.Source.Feature;
 import com.sun.tools.javac.code.Symbol.*;
 import com.sun.tools.javac.code.TypeMetadata.Entry.Kind;
 import com.sun.tools.javac.comp.Check.CheckContext;
 import com.sun.tools.javac.resources.CompilerProperties.Errors;
+import com.sun.tools.javac.resources.CompilerProperties.Fragments;
 import com.sun.tools.javac.tree.JCTree;
 import com.sun.tools.javac.tree.JCTree.*;
 import com.sun.tools.javac.tree.TreeInfo;
@@ -121,7 +123,7 @@
         theUnfinishedDefaultValue =  new Attribute.Error(syms.errType);
 
         Source source = Source.instance(context);
-        allowRepeatedAnnos = source.allowRepeatedAnnotations();
+        allowRepeatedAnnos = Feature.REPEATED_ANNOTATIONS.allowedInSource(source);
         sourceName = source.name;
 
         blockCount = 1;
@@ -344,7 +346,7 @@
 
             if (annotated.containsKey(a.type.tsym)) {
                 if (!allowRepeatedAnnos) {
-                    log.error(DiagnosticFlag.SOURCE_LEVEL, a.pos(), Errors.RepeatableAnnotationsNotSupportedInSource(sourceName));
+                    log.error(DiagnosticFlag.SOURCE_LEVEL, a.pos(), Feature.REPEATED_ANNOTATIONS.error(sourceName));
                 }
                 ListBuffer<T> l = annotated.get(a.type.tsym);
                 l = l.append(c);
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java	Thu Nov 30 22:05:19 2017 +0100
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java	Wed Dec 06 11:39:23 2017 +0000
@@ -38,6 +38,7 @@
 import com.sun.tools.javac.code.*;
 import com.sun.tools.javac.code.Lint.LintCategory;
 import com.sun.tools.javac.code.Scope.WriteableScope;
+import com.sun.tools.javac.code.Source.Feature;
 import com.sun.tools.javac.code.Symbol.*;
 import com.sun.tools.javac.code.Type.*;
 import com.sun.tools.javac.code.TypeMetadata.Annotations;
@@ -150,13 +151,13 @@
         Options options = Options.instance(context);
 
         Source source = Source.instance(context);
-        allowStringsInSwitch = source.allowStringsInSwitch();
-        allowPoly = source.allowPoly();
-        allowTypeAnnos = source.allowTypeAnnotations();
-        allowLambda = source.allowLambda();
-        allowDefaultMethods = source.allowDefaultMethods();
-        allowStaticInterfaceMethods = source.allowStaticInterfaceMethods();
-        allowShadowingOfLambdaParameters = source.allowShadowingOfLambdaParameters();
+        allowStringsInSwitch = Feature.STRINGS_IN_SWITCH.allowedInSource(source);
+        allowPoly = Feature.POLY.allowedInSource(source);
+        allowTypeAnnos = Feature.TYPE_ANNOTATIONS.allowedInSource(source);
+        allowLambda = Feature.LAMBDA.allowedInSource(source);
+        allowDefaultMethods = Feature.DEFAULT_METHODS.allowedInSource(source);
+        allowStaticInterfaceMethods = Feature.STATIC_INTERFACE_METHODS.allowedInSource(source);
+        allowShadowingOfLambdaParameters = Feature.LAMBDA_PARAMETER_SHADOWING.allowedInSource(source);
         sourceName = source.name;
         useBeforeDeclarationWarning = options.isSet("useBeforeDeclarationWarning");
 
@@ -1404,7 +1405,7 @@
             boolean enumSwitch = (seltype.tsym.flags() & Flags.ENUM) != 0;
             boolean stringSwitch = types.isSameType(seltype, syms.stringType);
             if (stringSwitch && !allowStringsInSwitch) {
-                log.error(DiagnosticFlag.SOURCE_LEVEL, tree.selector.pos(), Errors.StringSwitchNotSupportedInSource(sourceName));
+                log.error(DiagnosticFlag.SOURCE_LEVEL, tree.selector.pos(), Feature.STRINGS_IN_SWITCH.error(sourceName));
             }
             if (!enumSwitch && !stringSwitch)
                 seltype = chk.checkType(tree.selector.pos(), seltype, syms.intType);
@@ -3690,7 +3691,7 @@
             }
             if (!allowStaticInterfaceMethods && sitesym.isInterface() &&
                     sym.isStatic() && sym.kind == MTH) {
-                log.error(DiagnosticFlag.SOURCE_LEVEL, tree.pos(), Errors.StaticIntfMethodInvokeNotSupportedInSource(sourceName));
+                log.error(DiagnosticFlag.SOURCE_LEVEL, tree.pos(), Feature.STATIC_INTERFACE_METHODS_INVOKE.error(sourceName));
             }
         } else if (sym.kind != ERR &&
                    (sym.flags() & STATIC) != 0 &&
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java	Thu Nov 30 22:05:19 2017 +0100
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java	Wed Dec 06 11:39:23 2017 +0000
@@ -33,6 +33,7 @@
 import com.sun.tools.javac.code.Attribute.Compound;
 import com.sun.tools.javac.code.Directive.ExportsDirective;
 import com.sun.tools.javac.code.Directive.RequiresDirective;
+import com.sun.tools.javac.code.Source.Feature;
 import com.sun.tools.javac.comp.Annotate.AnnotationTypeMetadata;
 import com.sun.tools.javac.jvm.*;
 import com.sun.tools.javac.resources.CompilerProperties.Errors;
@@ -127,11 +128,6 @@
         fileManager = context.get(JavaFileManager.class);
 
         source = Source.instance(context);
-        allowSimplifiedVarargs = source.allowSimplifiedVarargs();
-        allowDefaultMethods = source.allowDefaultMethods();
-        allowStrictMethodClashCheck = source.allowStrictMethodClashCheck();
-        allowPrivateSafeVarargs = source.allowPrivateSafeVarargs();
-        allowDiamondWithAnonymousClassCreation = source.allowDiamondWithAnonymousClassCreation();
         warnOnAnyAccessToMembers = options.isSet("warnOnAccessToMembers");
 
         Target target = Target.instance(context);
@@ -156,26 +152,6 @@
         deferredLintHandler = DeferredLintHandler.instance(context);
     }
 
-    /** Switch: simplified varargs enabled?
-     */
-    boolean allowSimplifiedVarargs;
-
-    /** Switch: default methods enabled?
-     */
-    boolean allowDefaultMethods;
-
-    /** Switch: should unrelated return types trigger a method clash?
-     */
-    boolean allowStrictMethodClashCheck;
-
-    /** Switch: can the @SafeVarargs annotation be applied to private methods?
-     */
-    boolean allowPrivateSafeVarargs;
-
-    /** Switch: can diamond inference be used in anonymous instance creation ?
-     */
-    boolean allowDiamondWithAnonymousClassCreation;
-
     /** Character for synthetic names
      */
     char syntheticNameChar;
@@ -256,7 +232,7 @@
      *  @param pos        Position to be used for error reporting.
      */
     void warnUnsafeVararg(DiagnosticPosition pos, String key, Object... args) {
-        if (lint.isEnabled(LintCategory.VARARGS) && allowSimplifiedVarargs)
+        if (lint.isEnabled(LintCategory.VARARGS) && Feature.SIMPLIFIED_VARARGS.allowedInSource(source))
             log.warning(LintCategory.VARARGS, pos, key, args);
     }
 
@@ -814,9 +790,9 @@
                 t.isErroneous()) {
             return checkClassType(tree.clazz.pos(), t, true);
         } else {
-            if (tree.def != null && !allowDiamondWithAnonymousClassCreation) {
+            if (tree.def != null && !Feature.DIAMOND_WITH_ANONYMOUS_CLASS_CREATION.allowedInSource(source)) {
                 log.error(DiagnosticFlag.SOURCE_LEVEL, tree.clazz.pos(),
-                        Errors.CantApplyDiamond1(t, Fragments.DiamondAndAnonClassNotSupportedInSource(source.name)));
+                        Errors.CantApplyDiamond1(t, Feature.DIAMOND_WITH_ANONYMOUS_CLASS_CREATION.fragment(source.name)));
             }
             if (t.tsym.type.getTypeArguments().isEmpty()) {
                 log.error(tree.clazz.pos(),
@@ -906,7 +882,7 @@
 
     void checkVarargsMethodDecl(Env<AttrContext> env, JCMethodDecl tree) {
         MethodSymbol m = tree.sym;
-        if (!allowSimplifiedVarargs) return;
+        if (!Feature.SIMPLIFIED_VARARGS.allowedInSource(source)) return;
         boolean hasTrustMeAnno = m.attribute(syms.trustMeType.tsym) != null;
         Type varargElemType = null;
         if (m.isVarArgs()) {
@@ -914,7 +890,7 @@
         }
         if (hasTrustMeAnno && !isTrustMeAllowedOnMethod(m)) {
             if (varargElemType != null) {
-                JCDiagnostic msg = allowPrivateSafeVarargs ?
+                JCDiagnostic msg = Feature.PRIVATE_SAFE_VARARGS.allowedInSource(source) ?
                         diags.fragment(Fragments.VarargsTrustmeOnVirtualVarargs(m)) :
                         diags.fragment(Fragments.VarargsTrustmeOnVirtualVarargsFinalOnly(m));
                 log.error(tree,
@@ -942,7 +918,7 @@
             return (s.flags() & VARARGS) != 0 &&
                 (s.isConstructor() ||
                     (s.flags() & (STATIC | FINAL |
-                                  (allowPrivateSafeVarargs ? PRIVATE : 0) )) != 0);
+                                  (Feature.PRIVATE_SAFE_VARARGS.allowedInSource(source) ? PRIVATE : 0) )) != 0);
         }
 
     Type checkLocalVarType(DiagnosticPosition pos, Type t, Name name) {
@@ -1019,7 +995,7 @@
         if (useVarargs) {
             Type argtype = owntype.getParameterTypes().last();
             if (!types.isReifiable(argtype) &&
-                (!allowSimplifiedVarargs ||
+                (!Feature.SIMPLIFIED_VARARGS.allowedInSource(source) ||
                  sym.baseSymbol().attribute(syms.trustMeType.tsym) == null ||
                  !isTrustMeAllowedOnMethod(sym))) {
                 warnUnchecked(env.tree.pos(),
@@ -2489,7 +2465,7 @@
                 if (m2 == m1) continue;
                 //if (i) the signature of 'sym' is not a subsignature of m1 (seen as
                 //a member of 'site') and (ii) m1 has the same erasure as m2, issue an error
-                if (!types.isSubSignature(sym.type, types.memberType(site, m2), allowStrictMethodClashCheck) &&
+                if (!types.isSubSignature(sym.type, types.memberType(site, m2), Feature.STRICT_METHOD_CLASH_CHECK.allowedInSource(source)) &&
                         types.hasSameArgs(m2.erasure(types), m1.erasure(types))) {
                     sym.flags_field |= CLASH;
                     if (m1 == sym) {
@@ -2534,7 +2510,7 @@
         for (Symbol s : types.membersClosure(site, true).getSymbolsByName(sym.name, cf)) {
             //if (i) the signature of 'sym' is not a subsignature of m1 (seen as
             //a member of 'site') and (ii) 'sym' has the same erasure as m1, issue an error
-            if (!types.isSubSignature(sym.type, types.memberType(site, s), allowStrictMethodClashCheck)) {
+            if (!types.isSubSignature(sym.type, types.memberType(site, s), Feature.STRICT_METHOD_CLASH_CHECK.allowedInSource(source))) {
                 if (types.hasSameArgs(s.erasure(types), sym.erasure(types))) {
                     log.error(pos,
                               Errors.NameClashSameErasureNoHide(sym, sym.location(), s, s.location()));
@@ -2634,7 +2610,7 @@
     void checkPotentiallyAmbiguousOverloads(DiagnosticPosition pos, Type site,
             MethodSymbol msym1, MethodSymbol msym2) {
         if (msym1 != msym2 &&
-                allowDefaultMethods &&
+                Feature.DEFAULT_METHODS.allowedInSource(source) &&
                 lint.isEnabled(LintCategory.OVERLOADS) &&
                 (msym1.flags() & POTENTIALLY_AMBIGUOUS) == 0 &&
                 (msym2.flags() & POTENTIALLY_AMBIGUOUS) == 0) {
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java	Thu Nov 30 22:05:19 2017 +0100
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java	Wed Dec 06 11:39:23 2017 +0000
@@ -32,6 +32,7 @@
 import com.sun.source.tree.LambdaExpressionTree.BodyKind;
 import com.sun.tools.javac.code.*;
 import com.sun.tools.javac.code.Scope.WriteableScope;
+import com.sun.tools.javac.code.Source.Feature;
 import com.sun.tools.javac.resources.CompilerProperties.Errors;
 import com.sun.tools.javac.resources.CompilerProperties.Warnings;
 import com.sun.tools.javac.tree.*;
@@ -291,10 +292,10 @@
         rs = Resolve.instance(context);
         diags = JCDiagnostic.Factory.instance(context);
         Source source = Source.instance(context);
-        allowImprovedRethrowAnalysis = source.allowImprovedRethrowAnalysis();
-        allowImprovedCatchAnalysis = source.allowImprovedCatchAnalysis();
-        allowEffectivelyFinalInInnerClasses = source.allowEffectivelyFinalInInnerClasses();
-        enforceThisDotInit = source.enforceThisDotInit();
+        allowImprovedRethrowAnalysis = Feature.IMPROVED_RETHROW_ANALYSIS.allowedInSource(source);
+        allowImprovedCatchAnalysis = Feature.IMPROVED_CATCH_ANALYSIS.allowedInSource(source);
+        allowEffectivelyFinalInInnerClasses = Feature.EFFECTIVELY_FINAL_IN_INNER_CLASSES.allowedInSource(source);
+        enforceThisDotInit = Feature.ENFORCE_THIS_DOT_INIT.allowedInSource(source);
     }
 
     /**
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Infer.java	Thu Nov 30 22:05:19 2017 +0100
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Infer.java	Wed Dec 06 11:39:23 2017 +0000
@@ -25,6 +25,7 @@
 
 package com.sun.tools.javac.comp;
 
+import com.sun.tools.javac.code.Source.Feature;
 import com.sun.tools.javac.code.Type.UndetVar.UndetVarListener;
 import com.sun.tools.javac.code.Types.TypeMapping;
 import com.sun.tools.javac.comp.Attr.CheckMode;
@@ -116,7 +117,8 @@
         log = Log.instance(context);
         inferenceException = new InferenceException(diags);
         Options options = Options.instance(context);
-        allowGraphInference = Source.instance(context).allowGraphInference()
+        Source source = Source.instance(context);
+        allowGraphInference = Feature.GRAPH_INFERENCE.allowedInSource(source)
                 && options.isUnset("useLegacyInference");
         dependenciesFolder = options.get("debug.dumpInferenceGraphsTo");
         pendingGraphs = List.nil();
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Modules.java	Thu Nov 30 22:05:19 2017 +0100
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Modules.java	Wed Dec 06 11:39:23 2017 +0000
@@ -66,6 +66,7 @@
 import com.sun.tools.javac.code.Lint.LintCategory;
 import com.sun.tools.javac.code.ModuleFinder;
 import com.sun.tools.javac.code.Source;
+import com.sun.tools.javac.code.Source.Feature;
 import com.sun.tools.javac.code.Symbol;
 import com.sun.tools.javac.code.Symbol.ClassSymbol;
 import com.sun.tools.javac.code.Symbol.Completer;
@@ -185,7 +186,7 @@
         types = Types.instance(context);
         fileManager = context.get(JavaFileManager.class);
         source = Source.instance(context);
-        allowModules = source.allowModules();
+        allowModules = Feature.MODULES.allowedInSource(source);
         Options options = Options.instance(context);
 
         allowAccessIntoSystem = options.isUnset(Option.RELEASE);
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java	Thu Nov 30 22:05:19 2017 +0100
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java	Wed Dec 06 11:39:23 2017 +0000
@@ -28,6 +28,7 @@
 import com.sun.tools.javac.api.Formattable.LocalizedString;
 import com.sun.tools.javac.code.*;
 import com.sun.tools.javac.code.Scope.WriteableScope;
+import com.sun.tools.javac.code.Source.Feature;
 import com.sun.tools.javac.code.Symbol.*;
 import com.sun.tools.javac.code.Type.*;
 import com.sun.tools.javac.comp.Attr.ResultInfo;
@@ -137,15 +138,15 @@
         verboseResolutionMode = VerboseResolutionMode.getVerboseResolutionMode(options);
         Target target = Target.instance(context);
         allowMethodHandles = target.hasMethodHandles();
-        allowFunctionalInterfaceMostSpecific = source.allowFunctionalInterfaceMostSpecific();
-        allowLocalVariableTypeInference = source.allowLocalVariableTypeInference();
+        allowFunctionalInterfaceMostSpecific = Feature.FUNCTIONAL_INTERFACE_MOST_SPECIFIC.allowedInSource(source);
+        allowLocalVariableTypeInference = Feature.LOCAL_VARIABLE_TYPE_INFERENCE.allowedInSource(source);
         checkVarargsAccessAfterResolution =
-                source.allowPostApplicabilityVarargsAccessCheck();
+                Feature.POST_APPLICABILITY_VARARGS_ACCESS_CHECK.allowedInSource(source);
         polymorphicSignatureScope = WriteableScope.create(syms.noSymbol);
 
         inapplicableMethodException = new InapplicableMethodException(diags);
 
-        allowModules = source.allowModules();
+        allowModules = Feature.MODULES.allowedInSource(source);
     }
 
     /** error symbols, which are returned when resolution fails
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransTypes.java	Thu Nov 30 22:05:19 2017 +0100
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransTypes.java	Wed Dec 06 11:39:23 2017 +0000
@@ -29,6 +29,7 @@
 
 import com.sun.tools.javac.code.*;
 import com.sun.tools.javac.code.Attribute.TypeCompound;
+import com.sun.tools.javac.code.Source.Feature;
 import com.sun.tools.javac.code.Symbol.*;
 import com.sun.tools.javac.resources.CompilerProperties.Errors;
 import com.sun.tools.javac.tree.*;
@@ -94,8 +95,8 @@
         make = TreeMaker.instance(context);
         resolve = Resolve.instance(context);
         Source source = Source.instance(context);
-        allowInterfaceBridges = source.allowDefaultMethods();
-        allowGraphInference = source.allowGraphInference();
+        allowInterfaceBridges = Feature.DEFAULT_METHODS.allowedInSource(source);
+        allowGraphInference = Feature.GRAPH_INFERENCE.allowedInSource(source);
         annotate = Annotate.instance(context);
         attr = Attr.instance(context);
     }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TypeEnter.java	Thu Nov 30 22:05:19 2017 +0100
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TypeEnter.java	Wed Dec 06 11:39:23 2017 +0000
@@ -37,6 +37,7 @@
 import com.sun.tools.javac.code.Scope.NamedImportScope;
 import com.sun.tools.javac.code.Scope.StarImportScope;
 import com.sun.tools.javac.code.Scope.WriteableScope;
+import com.sun.tools.javac.code.Source.Feature;
 import com.sun.tools.javac.comp.Annotate.AnnotationTypeMetadata;
 import com.sun.tools.javac.tree.*;
 import com.sun.tools.javac.util.*;
@@ -137,8 +138,8 @@
         typeEnvs = TypeEnvs.instance(context);
         dependencies = Dependencies.instance(context);
         Source source = Source.instance(context);
-        allowTypeAnnos = source.allowTypeAnnotations();
-        allowDeprecationOnImport = source.allowDeprecationOnImport();
+        allowTypeAnnos = Feature.TYPE_ANNOTATIONS.allowedInSource(source);
+        allowDeprecationOnImport = Feature.DEPRECATION_ON_IMPORT.allowedInSource(source);
     }
 
     /** Switch: support type annotations.
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java	Thu Nov 30 22:05:19 2017 +0100
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java	Wed Dec 06 11:39:23 2017 +0000
@@ -42,6 +42,7 @@
 import javax.tools.JavaFileManager;
 import javax.tools.JavaFileObject;
 
+import com.sun.tools.javac.code.Source.Feature;
 import com.sun.tools.javac.comp.Annotate;
 import com.sun.tools.javac.comp.Annotate.AnnotationTypeCompleter;
 import com.sun.tools.javac.code.*;
@@ -246,8 +247,8 @@
         verbose         = options.isSet(Option.VERBOSE);
 
         Source source = Source.instance(context);
-        allowSimplifiedVarargs = source.allowSimplifiedVarargs();
-        allowModules     = source.allowModules();
+        allowSimplifiedVarargs = Feature.SIMPLIFIED_VARARGS.allowedInSource(source);
+        allowModules     = Feature.MODULES.allowedInSource(source);
 
         saveParameterNames = options.isSet(PARAMETERS);
 
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Arguments.java	Thu Nov 30 22:05:19 2017 +0100
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/main/Arguments.java	Wed Dec 06 11:39:23 2017 +0000
@@ -54,6 +54,7 @@
 import com.sun.tools.doclint.DocLint;
 import com.sun.tools.javac.code.Lint.LintCategory;
 import com.sun.tools.javac.code.Source;
+import com.sun.tools.javac.code.Source.Feature;
 import com.sun.tools.javac.file.BaseFileManager;
 import com.sun.tools.javac.file.JavacFileManager;
 import com.sun.tools.javac.jvm.Profile;
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java	Thu Nov 30 22:05:19 2017 +0100
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java	Wed Dec 06 11:39:23 2017 +0000
@@ -52,6 +52,7 @@
 import com.sun.tools.javac.api.MultiTaskListener;
 import com.sun.tools.javac.code.*;
 import com.sun.tools.javac.code.Lint.LintCategory;
+import com.sun.tools.javac.code.Source.Feature;
 import com.sun.tools.javac.code.Symbol.ClassSymbol;
 import com.sun.tools.javac.code.Symbol.CompletionFailure;
 import com.sun.tools.javac.code.Symbol.PackageSymbol;
@@ -684,7 +685,7 @@
         if (sep == -1) {
             msym = modules.getDefaultModule();
             typeName = name;
-        } else if (source.allowModules()) {
+        } else if (Feature.MODULES.allowedInSource(source)) {
             Name modName = names.fromString(name.substring(0, sep));
 
             msym = moduleFinder.findModule(modName);
@@ -1544,7 +1545,7 @@
             env.tree = transTypes.translateTopLevelClass(env.tree, localMake);
             compileStates.put(env, CompileState.TRANSTYPES);
 
-            if (source.allowLambda() && scanner.hasLambdas) {
+            if (Feature.LAMBDA.allowedInSource(source) && scanner.hasLambdas) {
                 if (shouldStop(CompileState.UNLAMBDA))
                     return;
 
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/model/JavacElements.java	Thu Nov 30 22:05:19 2017 +0100
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/model/JavacElements.java	Wed Dec 06 11:39:23 2017 +0000
@@ -51,6 +51,7 @@
 import com.sun.tools.javac.code.Directive.RequiresDirective;
 import com.sun.tools.javac.code.Directive.RequiresFlag;
 import com.sun.tools.javac.code.Scope.WriteableScope;
+import com.sun.tools.javac.code.Source.Feature;
 import com.sun.tools.javac.code.Symbol.*;
 import com.sun.tools.javac.comp.AttrContext;
 import com.sun.tools.javac.comp.Enter;
@@ -114,7 +115,7 @@
         javacTaskImpl = t instanceof JavacTaskImpl ? (JavacTaskImpl) t : null;
         log = Log.instance(context);
         Source source = Source.instance(context);
-        allowModules = source.allowModules();
+        allowModules = Feature.MODULES.allowedInSource(source);
     }
 
     @Override @DefinedBy(Api.LANGUAGE_MODEL)
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavaTokenizer.java	Thu Nov 30 22:05:19 2017 +0100
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavaTokenizer.java	Wed Dec 06 11:39:23 2017 +0000
@@ -26,8 +26,11 @@
 package com.sun.tools.javac.parser;
 
 import com.sun.tools.javac.code.Source;
+import com.sun.tools.javac.code.Source.Feature;
 import com.sun.tools.javac.parser.Tokens.Comment.CommentStyle;
+import com.sun.tools.javac.resources.CompilerProperties.Errors;
 import com.sun.tools.javac.util.*;
+import com.sun.tools.javac.util.JCDiagnostic.DiagnosticFlag;
 
 import java.nio.CharBuffer;
 
@@ -46,14 +49,6 @@
 
     private static final boolean scannerDebug = false;
 
-    /** Allow binary literals.
-     */
-    private boolean allowBinaryLiterals;
-
-    /** Allow underscores in literals.
-     */
-    private boolean allowUnderscoresInLiterals;
-
     /** The source language setting.
      */
     private Source source;
@@ -121,14 +116,24 @@
         this.tokens = fac.tokens;
         this.source = fac.source;
         this.reader = reader;
-        this.allowBinaryLiterals = source.allowBinaryLiterals();
-        this.allowUnderscoresInLiterals = source.allowUnderscoresInLiterals();
+    }
+
+    private void checkSourceLevel(int pos, Feature feature) {
+        if (!feature.allowedInSource(source)) {
+            lexError(DiagnosticFlag.SOURCE_LEVEL, pos, feature.error(source.name));
+        }
     }
 
     /** Report an error at the given position using the provided arguments.
      */
-    protected void lexError(int pos, String key, Object... args) {
-        log.error(pos, key, args);
+    protected void lexError(int pos, JCDiagnostic.Error key) {
+        log.error(pos, key);
+        tk = TokenKind.ERROR;
+        errPos = pos;
+    }
+
+    protected void lexError(DiagnosticFlag flags, int pos, JCDiagnostic.Error key) {
+        log.error(flags, pos, key);
         tk = TokenKind.ERROR;
         errPos = pos;
     }
@@ -175,7 +180,7 @@
                 case '\\':
                     reader.putChar('\\', true); break;
                 default:
-                    lexError(reader.bp, "illegal.esc.char");
+                    lexError(reader.bp, Errors.IllegalEscChar);
                 }
             }
         } else if (reader.bp != reader.buflen) {
@@ -190,17 +195,14 @@
             if (reader.ch != '_') {
                 reader.putChar(false);
             } else {
-                if (!allowUnderscoresInLiterals) {
-                    lexError(pos, "unsupported.underscore.lit", source.name);
-                    allowUnderscoresInLiterals = true;
-                }
+                checkSourceLevel(pos, Feature.UNDERSCORES_IN_LITERALS);
             }
             saveCh = reader.ch;
             savePos = reader.bp;
             reader.scanChar();
         } while (reader.digit(pos, digitRadix) >= 0 || reader.ch == '_');
         if (saveCh == '_')
-            lexError(savePos, "illegal.underscore");
+            lexError(savePos, Errors.IllegalUnderscore);
     }
 
     /** Read fractional part of hexadecimal floating point number.
@@ -216,11 +218,11 @@
             if (reader.digit(pos, 10) >= 0) {
                 scanDigits(pos, 10);
                 if (!hexFloatsWork)
-                    lexError(pos, "unsupported.cross.fp.lit");
+                    lexError(pos, Errors.UnsupportedCrossFpLit);
             } else
-                lexError(pos, "malformed.fp.lit");
+                lexError(pos, Errors.MalformedFpLit);
         } else {
-            lexError(pos, "malformed.fp.lit");
+            lexError(pos, Errors.MalformedFpLit);
         }
         if (reader.ch == 'f' || reader.ch == 'F') {
             reader.putChar(true);
@@ -254,7 +256,7 @@
                 scanDigits(pos, 10);
                 return;
             }
-            lexError(pos, "malformed.fp.lit");
+            lexError(pos, Errors.MalformedFpLit);
             reader.sp = sp1;
         }
     }
@@ -287,14 +289,14 @@
             scanDigits(pos, 16);
         }
         if (!seendigit)
-            lexError(pos, "invalid.hex.number");
+            lexError(pos, Errors.InvalidHexNumber);
         else
             scanHexExponentAndSuffix(pos);
     }
 
     private void skipIllegalUnderscores() {
         if (reader.ch == '_') {
-            lexError(reader.bp, "illegal.underscore");
+            lexError(reader.bp, Errors.IllegalUnderscore);
             while (reader.ch == '_')
                 reader.scanChar();
         }
@@ -329,10 +331,10 @@
             if (!seenValidDigit) {
                 switch (radix) {
                 case 2:
-                    lexError(pos, "invalid.binary.number");
+                    lexError(pos, Errors.InvalidBinaryNumber);
                     break;
                 case 16:
-                    lexError(pos, "invalid.hex.number");
+                    lexError(pos, Errors.InvalidHexNumber);
                     break;
                 }
             }
@@ -504,10 +506,7 @@
                         skipIllegalUnderscores();
                         scanNumber(pos, 16);
                     } else if (reader.ch == 'b' || reader.ch == 'B') {
-                        if (!allowBinaryLiterals) {
-                            lexError(pos, "unsupported.binary.lit", source.name);
-                            allowBinaryLiterals = true;
-                        }
+                        checkSourceLevel(pos, Feature.BINARY_LITERALS);
                         reader.scanChar();
                         skipIllegalUnderscores();
                         scanNumber(pos, 2);
@@ -519,7 +518,7 @@
                                 reader.scanChar();
                             } while (reader.ch == '_');
                             if (reader.digit(pos, 10) < 0) {
-                                lexError(savePos, "illegal.underscore");
+                                lexError(savePos, Errors.IllegalUnderscore);
                             }
                         }
                         scanNumber(pos, 8);
@@ -542,7 +541,7 @@
                             reader.putChar('.');
                             tk = TokenKind.ELLIPSIS;
                         } else {
-                            lexError(savePos, "illegal.dot");
+                            lexError(savePos, Errors.IllegalDot);
                         }
                     } else {
                         tk = TokenKind.DOT;
@@ -600,7 +599,7 @@
                             comments = addComment(comments, processComment(pos, reader.bp, style));
                             break;
                         } else {
-                            lexError(pos, "unclosed.comment");
+                            lexError(pos, Errors.UnclosedComment);
                             break loop;
                         }
                     } else if (reader.ch == '=') {
@@ -613,17 +612,17 @@
                 case '\'':
                     reader.scanChar();
                     if (reader.ch == '\'') {
-                        lexError(pos, "empty.char.lit");
+                        lexError(pos, Errors.EmptyCharLit);
                         reader.scanChar();
                     } else {
                         if (reader.ch == CR || reader.ch == LF)
-                            lexError(pos, "illegal.line.end.in.char.lit");
+                            lexError(pos, Errors.IllegalLineEndInCharLit);
                         scanLitChar(pos);
                         if (reader.ch == '\'') {
                             reader.scanChar();
                             tk = TokenKind.CHARLITERAL;
                         } else {
-                            lexError(pos, "unclosed.char.lit");
+                            lexError(pos, Errors.UnclosedCharLit);
                         }
                     }
                     break loop;
@@ -635,7 +634,7 @@
                         tk = TokenKind.STRINGLITERAL;
                         reader.scanChar();
                     } else {
-                        lexError(pos, "unclosed.str.lit");
+                        lexError(pos, Errors.UnclosedStrLit);
                     }
                     break loop;
                 default:
@@ -676,7 +675,7 @@
                                                 String.format("%s", reader.ch) :
                                                 String.format("\\u%04x", (int)reader.ch);
                             }
-                            lexError(pos, "illegal.char", arg);
+                            lexError(pos, Errors.IllegalChar(arg));
                             reader.scanChar();
                         }
                     }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java	Thu Nov 30 22:05:19 2017 +0100
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java	Wed Dec 06 11:39:23 2017 +0000
@@ -26,12 +26,15 @@
 package com.sun.tools.javac.parser;
 
 import java.util.*;
+import java.util.function.Function;
+import java.util.function.Predicate;
 import java.util.stream.Collectors;
 
 import com.sun.source.tree.MemberReferenceTree.ReferenceMode;
 import com.sun.source.tree.ModuleTree.ModuleKind;
 
 import com.sun.tools.javac.code.*;
+import com.sun.tools.javac.code.Source.Feature;
 import com.sun.tools.javac.parser.Tokens.*;
 import com.sun.tools.javac.parser.Tokens.Comment.CommentStyle;
 import com.sun.tools.javac.resources.CompilerProperties;
@@ -41,6 +44,7 @@
 import com.sun.tools.javac.util.*;
 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticFlag;
 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
+import com.sun.tools.javac.util.JCDiagnostic.Error;
 import com.sun.tools.javac.util.List;
 
 import static com.sun.tools.javac.parser.Tokens.TokenKind.*;
@@ -163,24 +167,7 @@
         this.log = fac.log;
         this.names = fac.names;
         this.source = fac.source;
-        this.allowTWR = source.allowTryWithResources();
-        this.allowEffectivelyFinalVariablesInTWR =
-                source.allowEffectivelyFinalVariablesInTryWithResources();
-        this.allowDiamond = source.allowDiamond();
-        this.allowMulticatch = source.allowMulticatch();
         this.allowStringFolding = fac.options.getBoolean("allowStringFolding", true);
-        this.allowLambda = source.allowLambda();
-        this.allowMethodReferences = source.allowMethodReferences();
-        this.allowDefaultMethods = source.allowDefaultMethods();
-        this.allowStaticInterfaceMethods = source.allowStaticInterfaceMethods();
-        this.allowIntersectionTypesInCast = source.allowIntersectionTypesInCast();
-        this.allowTypeAnnotations = source.allowTypeAnnotations();
-        this.allowModules = source.allowModules();
-        this.allowAnnotationsAfterTypeParams = source.allowAnnotationsAfterTypeParams();
-        this.allowUnderscoreIdentifier = source.allowUnderscoreIdentifier();
-        this.allowUnderscoreAsFormal = source.allowUnderscoreAsFormal();
-        this.allowPrivateInterfaceMethods = source.allowPrivateInterfaceMethods();
-        this.allowLocalVariableTypeInference = source.allowLocalVariableTypeInference();
         this.keepDocComments = keepDocComments;
         this.parseModuleInfo = parseModuleInfo;
         docComments = newDocCommentTable(keepDocComments, fac);
@@ -199,54 +186,10 @@
         return keepDocComments ? new LazyDocCommentTable(fac) : null;
     }
 
-    /** Switch: Should diamond operator be recognized?
-     */
-    boolean allowDiamond;
-
-    /** Switch: Should multicatch clause be accepted?
-     */
-    boolean allowMulticatch;
-
-    /** Switch: should we recognize try-with-resources?
-     */
-    boolean allowTWR;
-
-    /** Switch: should we allow (effectively) final variables as resources in try-with-resources?
-     */
-    boolean allowEffectivelyFinalVariablesInTWR;
-
     /** Switch: should we fold strings?
      */
     boolean allowStringFolding;
 
-    /** Switch: should we recognize lambda expressions?
-     */
-    boolean allowLambda;
-
-    /** Switch: should we allow method/constructor references?
-     */
-    boolean allowMethodReferences;
-
-    /** Switch: should we recognize modules?
-     */
-    boolean allowModules;
-
-    /** Switch: should we allow default methods in interfaces?
-     */
-    boolean allowDefaultMethods;
-
-    /** Switch: should we allow static methods in interfaces?
-     */
-    boolean allowStaticInterfaceMethods;
-
-    /** Switch: should we allow private (instance) methods in interfaces?
-     */
-    boolean allowPrivateInterfaceMethods;
-
-    /** Switch: should we allow intersection types in cast?
-     */
-    boolean allowIntersectionTypesInCast;
-
     /** Switch: should we keep docComments?
      */
     boolean keepDocComments;
@@ -255,31 +198,11 @@
      */
     boolean keepLineMap;
 
-    /** Switch: should we recognize type annotations?
-     */
-    boolean allowTypeAnnotations;
-
-    /** Switch: should we allow annotations after the method type parameters?
-     */
-    boolean allowAnnotationsAfterTypeParams;
-
-    /** Switch: should we allow '_' as an identifier?
-     */
-    boolean allowUnderscoreIdentifier;
-
-    /** Switch: should we allow '_' as an unused argument for lambdas, catch etc?
-     */
-    boolean allowUnderscoreAsFormal;
-
     /** Switch: is "this" allowed as an identifier?
      * This is needed to parse receiver types.
      */
     boolean allowThisIdent;
 
-    /** Switch: is local variable inference allowed?
-     */
-    boolean allowLocalVariableTypeInference;
-
     /** The type of the method receiver, as specified by a first "this" parameter.
      */
     JCVariableDecl receiverParam;
@@ -637,7 +560,7 @@
         } else if (token.kind == THIS) {
             if (allowThisIdent) {
                 // Make sure we're using a supported source version.
-                checkTypeAnnotations();
+                checkSourceLevel(Feature.TYPE_ANNOTATIONS);
                 Name name = token.name();
                 nextToken();
                 return name;
@@ -648,10 +571,10 @@
             }
         } else if (token.kind == UNDERSCORE) {
             if (!underscoreAllowed) {
-                if (allowUnderscoreAsFormal) {
+                if (Feature.UNDERSCORE_AS_PARAM_NAME.allowedInSource(source)) {
                     error(token.pos, "underscore.not.allowed");
                 } else {
-                    if (allowUnderscoreIdentifier) {
+                    if (Feature.UNDERSCORE_IDENTIFIER.allowedInSource(source)) {
                         warning(token.pos, "underscore.as.identifier");
                     } else {
                         error(token.pos, "underscore.as.identifier");
@@ -1189,7 +1112,7 @@
                        int pos1 = pos;
                        List<JCExpression> targets = List.of(t = parseType());
                        while (token.kind == AMP) {
-                           checkIntersectionTypesInCast();
+                           checkSourceLevel(Feature.INTERSECTION_TYPES_IN_CAST);
                            accept(AMP);
                            targets = targets.prepend(parseType());
                        }
@@ -1790,7 +1713,7 @@
     }
 
     JCExpression lambdaExpressionOrStatementRest(List<JCVariableDecl> args, int pos) {
-        checkLambda();
+        checkSourceLevel(Feature.LAMBDA);
         accept(ARROW);
 
         return token.kind == LBRACE ?
@@ -1909,7 +1832,7 @@
         if (token.kind == LT) {
             nextToken();
             if (token.kind == GT && diamondAllowed) {
-                checkDiamond();
+                checkSourceLevel(Feature.DIAMOND);
                 mode |= DIAMOND;
                 nextToken();
                 return List.nil();
@@ -2084,7 +2007,7 @@
     }
 
     JCExpression memberReferenceSuffix(int pos1, JCExpression t) {
-        checkMethodReferences();
+        checkSourceLevel(Feature.METHOD_REFERENCES);
         mode = EXPR;
         List<JCExpression> typeArgs = null;
         if (token.kind == LT) {
@@ -2587,7 +2510,7 @@
             nextToken();
             List<JCTree> resources = List.nil();
             if (token.kind == LPAREN) {
-                checkTryWithResources();
+                checkSourceLevel(Feature.TRY_WITH_RESOURCES);
                 nextToken();
                 resources = resources();
                 accept(RPAREN);
@@ -2603,7 +2526,7 @@
                 }
             } else {
                 if (resources.isEmpty()) {
-                    if (allowTWR) {
+                    if (Feature.TRY_WITH_RESOURCES.allowedInSource(source)) {
                         error(pos, "try.without.catch.finally.or.resource.decls");
                     } else {
                         error(pos, "try.without.catch.or.finally");
@@ -2720,7 +2643,7 @@
         ListBuffer<JCExpression> catchTypes = new ListBuffer<>();
         catchTypes.add(parseType());
         while (token.kind == BAR) {
-            checkMulticatch();
+            checkSourceLevel(Feature.MULTICATCH);
             nextToken();
             // Instead of qualident this is now parseType.
             // But would that allow too much, e.g. arrays or generics?
@@ -2889,7 +2812,7 @@
             case SYNCHRONIZED: flag = Flags.SYNCHRONIZED; break;
             case STRICTFP    : flag = Flags.STRICTFP; break;
             case MONKEYS_AT  : flag = Flags.ANNOTATION; break;
-            case DEFAULT     : checkDefaultMethods(); flag = Flags.DEFAULT; break;
+            case DEFAULT     : checkSourceLevel(Feature.DEFAULT_METHODS); flag = Flags.DEFAULT; break;
             case ERROR       : flag = 0; nextToken(); break;
             default: break loop;
             }
@@ -2933,7 +2856,7 @@
     JCAnnotation annotation(int pos, Tag kind) {
         // accept(AT); // AT consumed by caller
         if (kind == Tag.TYPE_ANNOTATION) {
-            checkTypeAnnotations();
+            checkSourceLevel(Feature.TYPE_ANNOTATIONS);
         }
         JCTree ident = qualident(false);
         List<JCExpression> fieldValues = annotationFieldValuesOpt();
@@ -3047,7 +2970,7 @@
                                                                      boolean localDecl)
     {
         JCVariableDecl head = variableDeclaratorRest(pos, mods, type, name, reqInit, dc, localDecl);
-        boolean implicit = allowLocalVariableTypeInference && head.vartype == null;
+        boolean implicit = Feature.LOCAL_VARIABLE_TYPE_INFERENCE.allowedInSource(source) && head.vartype == null;
         vdefs.append(head);
         while (token.kind == COMMA) {
             if (implicit) {
@@ -3085,7 +3008,7 @@
         else if (reqInit) syntaxError(token.pos, "expected", EQ);
         JCTree elemType = TreeInfo.innermostType(type, true);
         int startPos = Position.NOPOS;
-        if (allowLocalVariableTypeInference && elemType.hasTag(IDENT)) {
+        if (Feature.LOCAL_VARIABLE_TYPE_INFERENCE.allowedInSource(source) && elemType.hasTag(IDENT)) {
             Name typeName = ((JCIdent)elemType).name;
             if (isRestrictedLocalVarTypeName(typeName)) {
                 if (type.hasTag(TYPEARRAY)) {
@@ -3119,10 +3042,10 @@
     }
 
     boolean isRestrictedLocalVarTypeName(Name name) {
-        return allowLocalVariableTypeInference && name == names.var;
+        return Feature.LOCAL_VARIABLE_TYPE_INFERENCE.allowedInSource(source) && name == names.var;
     }
 
-     /** The kind of a formal parameter
+    /** The kind of a formal parameter
      */
     enum FormalParameterKind {
         /* a formal lambda parameter
@@ -3154,6 +3077,7 @@
     JCVariableDecl variableDeclaratorId(JCModifiers mods, JCExpression type, FormalParameterKind parameterKind) {
         int pos = token.pos;
         Name name;
+        boolean allowUnderscoreAsFormal = Feature.UNDERSCORE_AS_PARAM_NAME.allowedInSource(source);
         boolean isUnderscore = token.kind == UNDERSCORE;
         if (parameterKind.isLambdaParameter() && isUnderscore && !allowUnderscoreAsFormal) {
             log.error(pos, Errors.UnderscoreAsIdentifierInLambda);
@@ -3227,7 +3151,7 @@
             JCModifiers mods = toP(F.at(startPos).Modifiers(Flags.FINAL));
             return variableDeclaratorRest(token.pos, mods, t, ident(), true, null, true);
         } else {
-            checkVariableInTryWithResources(startPos);
+            checkSourceLevel(Feature.EFFECTIVELY_FINAL_VARIABLES_IN_TRY_WITH_RESOURCES);
             if (!t.hasTag(IDENT) && !t.hasTag(SELECT)) {
                 log.error(t.pos(), Errors.TryWithResourcesExprNeedsVar);
             }
@@ -3329,10 +3253,7 @@
 
     JCModuleDecl moduleDecl(JCModifiers mods, ModuleKind kind, Comment dc) {
         int pos = token.pos;
-        if (!allowModules) {
-            log.error(pos, Errors.ModulesNotSupportedInSource(source.name));
-            allowModules = true;
-        }
+        checkSourceLevel(Feature.MODULES);
 
         nextToken();
         JCExpression name = qualident(false);
@@ -3751,7 +3672,7 @@
                 List<JCAnnotation> annosAfterParams = annotationsOpt(Tag.ANNOTATION);
 
                 if (annosAfterParams.nonEmpty()) {
-                    checkAnnotationsAfterTypeParams(annosAfterParams.head.pos);
+                    checkSourceLevel(annosAfterParams.head.pos, Feature.ANNOTATIONS_AFTER_TYPE_PARAMS);
                     mods.annotations = mods.annotations.appendList(annosAfterParams);
                     if (mods.pos == Position.NOPOS)
                         mods.pos = mods.annotations.head.pos;
@@ -3819,10 +3740,10 @@
                               Comment dc) {
         if (isInterface) {
             if ((mods.flags & Flags.STATIC) != 0) {
-                checkStaticInterfaceMethods();
+                checkSourceLevel(Feature.STATIC_INTERFACE_METHODS);
             }
             if ((mods.flags & Flags.PRIVATE) != 0) {
-                checkPrivateInterfaceMethods();
+                checkSourceLevel(Feature.PRIVATE_INTERFACE_METHODS);
             }
         }
         JCVariableDecl prevReceiverParam = this.receiverParam;
@@ -4271,64 +4192,13 @@
         }
     }
 
-    void checkDiamond() {
-        if (!allowDiamond) {
-            log.error(DiagnosticFlag.SOURCE_LEVEL, token.pos, Errors.DiamondNotSupportedInSource(source.name));
-        }
+    void checkSourceLevel(Feature feature) {
+        checkSourceLevel(token.pos, feature);
     }
-    void checkMulticatch() {
-        if (!allowMulticatch) {
-            log.error(DiagnosticFlag.SOURCE_LEVEL, token.pos, Errors.MulticatchNotSupportedInSource(source.name));
-        }
-    }
-    void checkTryWithResources() {
-        if (!allowTWR) {
-            log.error(DiagnosticFlag.SOURCE_LEVEL, token.pos, Errors.TryWithResourcesNotSupportedInSource(source.name));
-        }
-    }
-    void checkVariableInTryWithResources(int startPos) {
-        if (!allowEffectivelyFinalVariablesInTWR) {
-            log.error(DiagnosticFlag.SOURCE_LEVEL, startPos, Errors.VarInTryWithResourcesNotSupportedInSource(source.name));
-        }
-    }
-    void checkLambda() {
-        if (!allowLambda) {
-            log.error(DiagnosticFlag.SOURCE_LEVEL, token.pos, Errors.LambdaNotSupportedInSource(source.name));
-        }
-    }
-    void checkMethodReferences() {
-        if (!allowMethodReferences) {
-            log.error(DiagnosticFlag.SOURCE_LEVEL, token.pos, Errors.MethodReferencesNotSupportedInSource(source.name));
-        }
-    }
-    void checkDefaultMethods() {
-        if (!allowDefaultMethods) {
-            log.error(DiagnosticFlag.SOURCE_LEVEL, token.pos, Errors.DefaultMethodsNotSupportedInSource(source.name));
-        }
-    }
-    void checkIntersectionTypesInCast() {
-        if (!allowIntersectionTypesInCast) {
-            log.error(DiagnosticFlag.SOURCE_LEVEL, token.pos, Errors.IntersectionTypesInCastNotSupportedInSource(source.name));
-        }
-    }
-    void checkStaticInterfaceMethods() {
-        if (!allowStaticInterfaceMethods) {
-            log.error(DiagnosticFlag.SOURCE_LEVEL, token.pos, Errors.StaticIntfMethodsNotSupportedInSource(source.name));
-        }
-    }
-    void checkTypeAnnotations() {
-        if (!allowTypeAnnotations) {
-            log.error(DiagnosticFlag.SOURCE_LEVEL, token.pos, Errors.TypeAnnotationsNotSupportedInSource(source.name));
-        }
-    }
-    void checkPrivateInterfaceMethods() {
-        if (!allowPrivateInterfaceMethods) {
-            log.error(DiagnosticFlag.SOURCE_LEVEL, token.pos, CompilerProperties.Errors.PrivateIntfMethodsNotSupportedInSource(source.name));
-        }
-    }
-    protected void checkAnnotationsAfterTypeParams(int pos) {
-        if (!allowAnnotationsAfterTypeParams) {
-            log.error(DiagnosticFlag.SOURCE_LEVEL, pos, Errors.AnnotationsAfterTypeParamsNotSupportedInSource(source.name));
+
+    protected void checkSourceLevel(int pos, Feature feature) {
+        if (!feature.allowedInSource(source)) {
+            log.error(DiagnosticFlag.SOURCE_LEVEL, pos, feature.error(source.name));
         }
     }
 
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java	Thu Nov 30 22:05:19 2017 +0100
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java	Wed Dec 06 11:39:23 2017 +0000
@@ -53,6 +53,7 @@
 import com.sun.tools.javac.api.MultiTaskListener;
 import com.sun.tools.javac.code.*;
 import com.sun.tools.javac.code.Scope.WriteableScope;
+import com.sun.tools.javac.code.Source.Feature;
 import com.sun.tools.javac.code.Symbol.*;
 import com.sun.tools.javac.code.Type.ClassType;
 import com.sun.tools.javac.code.Types;
@@ -116,7 +117,6 @@
     private final boolean fatalErrors;
     private final boolean werror;
     private final boolean showResolveErrors;
-    private final boolean allowModules;
 
     private final JavacFiler filer;
     private final JavacMessager messager;
@@ -233,8 +233,6 @@
         initialCompleter = ClassFinder.instance(context).getCompleter();
         chk = Check.instance(context);
         initProcessorLoader();
-
-        allowModules = source.allowModules();
     }
 
     public void setProcessors(Iterable<? extends Processor> processors) {
@@ -770,7 +768,7 @@
 
                 if (psi.processorIterator.hasNext()) {
                     ProcessorState ps = new ProcessorState(psi.processorIterator.next(),
-                                                           log, source, allowModules,
+                                                           log, source, Feature.MODULES.allowedInSource(source),
                                                            JavacProcessingEnvironment.this);
                     psi.procStateList.add(ps);
                     return ps;
@@ -837,7 +835,7 @@
 
         for(TypeElement a  : annotationsPresent) {
             ModuleElement mod = elementUtils.getModuleOf(a);
-            String moduleSpec = allowModules && mod != null ? mod.getQualifiedName() + "/" : "";
+            String moduleSpec = Feature.MODULES.allowedInSource(source) && mod != null ? mod.getQualifiedName() + "/" : "";
             unmatchedAnnotations.put(moduleSpec + a.getQualifiedName().toString(),
                                      a);
         }
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties	Thu Nov 30 22:05:19 2017 +0100
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties	Wed Dec 06 11:39:23 2017 +0000
@@ -2601,38 +2601,87 @@
     ({3})
 
 ########################################
-# Diagnostics for language feature changes
+# Diagnostics for language feature changes.
+# Such diagnostics have a common template which can be customized by using a feature
+# diagnostic fragment (one of those given below).
 ########################################
 
-# 0: string
-compiler.err.modules.not.supported.in.source=\
-   modules are not supported in -source {0}\n\
-    (use -source 9 or higher to enable modules)
-
-# 0: string
-compiler.misc.diamond.and.anon.class.not.supported.in.source=\
-    cannot use ''<>'' with anonymous inner classes in -source {0}\n\
-    (use -source 9 or higher to enable ''<>'' with anonymous inner classes)
-
-# 0: string
-compiler.err.unsupported.binary.lit=\
-    binary literals are not supported in -source {0}\n\
-    (use -source 7 or higher to enable binary literals)
-
-# 0: string
-compiler.err.unsupported.underscore.lit=\
-    underscores in literals are not supported in -source {0}\n\
-    (use -source 7 or higher to enable underscores in literals)
-
-# 0: string
-compiler.err.try.with.resources.not.supported.in.source=\
-    try-with-resources is not supported in -source {0}\n\
-    (use -source 7 or higher to enable try-with-resources)
-
-# 0: string
-compiler.err.var.in.try.with.resources.not.supported.in.source=\
-    variables in try-with-resources not supported in -source {0}\n\
-    (use -source 9 or higher to enable variables in try-with-resources)
+# 0: message segment (feature), 1: string (found version), 2: string (expected version)
+compiler.err.feature.not.supported.in.source=\
+   {0} is not supported in -source {1}\n\
+    (use -source {2} or higher to enable {0})
+
+# 0: message segment (feature), 1: string (found version), 2: string (expected version)
+compiler.err.feature.not.supported.in.source.plural=\
+   {0} are not supported in -source {1}\n\
+    (use -source {2} or higher to enable {0})
+
+# 0: message segment (feature), 1: string (found version), 2: string (expected version)
+compiler.misc.feature.not.supported.in.source=\
+   {0} is not supported in -source {1}\n\
+    (use -source {2} or higher to enable {0})
+
+# 0: message segment (feature), 1: string (found version), 2: string (expected version)
+compiler.misc.feature.not.supported.in.source.plural=\
+   {0} are not supported in -source {1}\n\
+    (use -source {2} or higher to enable {0})
+
+compiler.misc.feature.modules=\
+    modules
+
+compiler.misc.feature.diamond.and.anon.class=\
+    ''<>'' with anonymous inner classes
+
+compiler.misc.feature.binary.lit=\
+    binary literals
+
+compiler.misc.feature.underscore.lit=\
+    underscores in literals
+
+compiler.misc.feature.try.with.resources=\
+    try-with-resources
+
+compiler.misc.feature.var.in.try.with.resources=\
+    variables in try-with-resources
+
+compiler.misc.feature.type.annotations=\
+    type annotations
+
+compiler.misc.feature.annotations.after.type.params=\
+    annotations after method type parameters
+
+compiler.misc.feature.repeatable.annotations=\
+    repeated annotations
+
+compiler.misc.feature.diamond=\
+    diamond operator
+
+compiler.misc.feature.multicatch=\
+    multi-catch statements
+
+compiler.misc.feature.string.switch=\
+    strings in switch
+
+compiler.misc.feature.lambda=\
+    lambda expressions
+
+compiler.misc.feature.method.references=\
+    method references
+
+compiler.misc.feature.default.methods=\
+    default methods
+
+compiler.misc.feature.intersection.types.in.cast=\
+    intersection types
+
+compiler.misc.feature.static.intf.methods=\
+    static interface methods
+
+compiler.misc.feature.static.intf.method.invoke=\
+    static interface method invocations
+
+compiler.misc.feature.private.intf.methods=\
+    private interface methods
 
 compiler.warn.underscore.as.identifier=\
     as of release 9, ''_'' is a keyword, and may not be used as an identifier
@@ -2704,71 +2753,6 @@
 compiler.err.no.annotations.on.dot.class=\
     no annotations are allowed in the type of a class literal
 
-# 0: string
-compiler.err.type.annotations.not.supported.in.source=\
-    type annotations are not supported in -source {0}\n\
-(use -source 8 or higher to enable type annotations)
-
-# 0: string
-compiler.err.annotations.after.type.params.not.supported.in.source=\
-    annotations after method type parameters are not supported in -source {0}\n\
-(use -source 8 or higher to enable annotations after method type parameters)
-
-# 0: string
-compiler.err.repeatable.annotations.not.supported.in.source=\
-    repeated annotations are not supported in -source {0}\n\
-(use -source 8 or higher to enable repeated annotations)
-
-# 0: string
-compiler.err.diamond.not.supported.in.source=\
-    diamond operator is not supported in -source {0}\n\
-    (use -source 7 or higher to enable diamond operator)
-
-# 0: string
-compiler.err.multicatch.not.supported.in.source=\
-    multi-catch statement is not supported in -source {0}\n\
-    (use -source 7 or higher to enable multi-catch statement)
-
-# 0: string
-compiler.err.string.switch.not.supported.in.source=\
-    strings in switch are not supported in -source {0}\n\
-    (use -source 7 or higher to enable strings in switch)
-
-# 0: string
-compiler.err.lambda.not.supported.in.source=\
-    lambda expressions are not supported in -source {0}\n\
-    (use -source 8 or higher to enable lambda expressions)
-
-# 0: string
-compiler.err.method.references.not.supported.in.source=\
-    method references are not supported in -source {0}\n\
-    (use -source 8 or higher to enable method references)
-
-# 0: string
-compiler.err.default.methods.not.supported.in.source=\
-    default methods are not supported in -source {0}\n\
-    (use -source 8 or higher to enable default methods)
-
-# 0: string
-compiler.err.intersection.types.in.cast.not.supported.in.source=\
-    intersection types in cast are not supported in -source {0}\n\
-    (use -source 8 or higher to enable intersection types in cast)
-
-# 0: string
-compiler.err.static.intf.methods.not.supported.in.source=\
-    static interface methods are not supported in -source {0}\n\
-    (use -source 8 or higher to enable static interface methods)
-
-# 0: string
-compiler.err.static.intf.method.invoke.not.supported.in.source=\
-    static interface method invocations are not supported in -source {0}\n\
-    (use -source 8 or higher to enable static interface method invocations)
-
-# 0: string
-compiler.err.private.intf.methods.not.supported.in.source=\
-    private interface methods are not supported in -source {0}\n\
-    (use -source 9 or higher to enable private interface methods)
-
 ########################################
 # Diagnostics for verbose resolution
 # used by Resolve (debug only)
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Log.java	Thu Nov 30 22:05:19 2017 +0100
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Log.java	Wed Dec 06 11:39:23 2017 +0000
@@ -426,7 +426,7 @@
     /** A set of "not-supported-in-source-X" errors produced so far. This is used to only generate
      *  one such error per file.
      */
-    protected Set<Pair<JavaFileObject, String>>  recordedSourceLevelErrors = new HashSet<>();
+    protected Set<Pair<JavaFileObject, List<String>>>  recordedSourceLevelErrors = new HashSet<>();
 
     public boolean hasDiagnosticListener() {
         return diagListener != null;
@@ -521,13 +521,29 @@
         if (!d.isFlagSet(DiagnosticFlag.SOURCE_LEVEL))
             return true;
 
-        Pair<JavaFileObject, String> coords = new Pair<>(file, d.getCode());
+        Pair<JavaFileObject, List<String>> coords = new Pair<>(file, getCode(d));
         boolean shouldReport = !recordedSourceLevelErrors.contains(coords);
         if (shouldReport)
             recordedSourceLevelErrors.add(coords);
         return shouldReport;
     }
 
+    //where
+        private List<String> getCode(JCDiagnostic d) {
+            ListBuffer<String> buf = new ListBuffer<>();
+            getCodeRecursive(buf, d);
+            return buf.toList();
+        }
+
+        private void getCodeRecursive(ListBuffer<String> buf, JCDiagnostic d) {
+            buf.add(d.getCode());
+            for (Object o : d.getArgs()) {
+                if (o instanceof JCDiagnostic) {
+                    getCodeRecursive(buf, (JCDiagnostic)o);
+                }
+            }
+        }
+
     /** Prompt user after an error.
      */
     public void prompt() {
--- a/src/jdk.javadoc/share/classes/com/sun/tools/javadoc/main/RootDocImpl.java	Thu Nov 30 22:05:19 2017 +0100
+++ b/src/jdk.javadoc/share/classes/com/sun/tools/javadoc/main/RootDocImpl.java	Wed Dec 06 11:39:23 2017 +0000
@@ -34,6 +34,7 @@
 import javax.tools.StandardJavaFileManager;
 
 import com.sun.javadoc.*;
+import com.sun.tools.javac.code.Source.Feature;
 import com.sun.tools.javac.tree.JCTree.JCClassDecl;
 import com.sun.tools.javac.util.List;
 import com.sun.tools.javac.util.ListBuffer;
@@ -388,7 +389,7 @@
     }
 
     public boolean isFunctionalInterface(AnnotationDesc annotationDesc) {
-        return env.source.allowLambda()
+        return Feature.LAMBDA.allowedInSource(env.source)
             && annotationDesc.annotationType().qualifiedName().equals(
                 env.syms.functionalInterfaceType.toString());
     }
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/WorkArounds.java	Thu Nov 30 22:05:19 2017 +0100
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/WorkArounds.java	Wed Dec 06 11:39:23 2017 +0000
@@ -55,6 +55,7 @@
 import com.sun.tools.javac.code.Attribute;
 import com.sun.tools.javac.code.Flags;
 import com.sun.tools.javac.code.Scope;
+import com.sun.tools.javac.code.Source.Feature;
 import com.sun.tools.javac.code.Symbol;
 import com.sun.tools.javac.code.Symbol.ClassSymbol;
 import com.sun.tools.javac.code.Symbol.MethodSymbol;
@@ -187,7 +188,7 @@
     // TODO: we need ElementUtils.getPackage to cope with input strings
     // to return the proper unnamedPackage for all supported releases.
     PackageElement getUnnamedPackage() {
-        return (toolEnv.source.allowModules())
+        return (Feature.MODULES.allowedInSource(toolEnv.source))
                 ? toolEnv.syms.unnamedModule.unnamedPackage
                 : toolEnv.syms.noModule.unnamedPackage;
     }
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/ElementsTable.java	Thu Nov 30 22:05:19 2017 +0100
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/ElementsTable.java	Wed Dec 06 11:39:23 2017 +0000
@@ -55,6 +55,7 @@
 
 import com.sun.tools.javac.code.Kinds.Kind;
 import com.sun.tools.javac.code.Source;
+import com.sun.tools.javac.code.Source.Feature;
 import com.sun.tools.javac.code.Symbol;
 import com.sun.tools.javac.code.Symbol.ClassSymbol;
 import com.sun.tools.javac.code.Symbol.CompletionFailure;
@@ -222,7 +223,7 @@
             else
                 locs.add(StandardLocation.CLASS_PATH);
         }
-        if (source.allowModules() && toolEnv.fileManager.hasLocation(StandardLocation.PATCH_MODULE_PATH))
+        if (Feature.MODULES.allowedInSource(source) && toolEnv.fileManager.hasLocation(StandardLocation.PATCH_MODULE_PATH))
             locs.add(StandardLocation.PATCH_MODULE_PATH);
         this.locations = Collections.unmodifiableList(locs);
 
--- a/src/jdk.jshell/share/classes/jdk/jshell/CompletenessAnalyzer.java	Thu Nov 30 22:05:19 2017 +0100
+++ b/src/jdk.jshell/share/classes/jdk/jshell/CompletenessAnalyzer.java	Wed Dec 06 11:39:23 2017 +0000
@@ -34,6 +34,7 @@
 import com.sun.tools.javac.util.JCDiagnostic;
 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticFlag;
 import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
+import com.sun.tools.javac.util.JCDiagnostic.Error;
 import com.sun.tools.javac.util.Log;
 import java.io.PrintWriter;
 import java.io.StringWriter;
@@ -78,7 +79,7 @@
         Context context = new Context();
         Log log = CaLog.createLog(context);
         context.put(Log.class, log);
-        context.put(Source.class, Source.JDK1_9);
+        context.put(Source.class, Source.JDK9);
         scannerFactory = ScannerFactory.instance(context);
     }
 
@@ -138,6 +139,11 @@
         }
 
         @Override
+        public void error(int pos, Error errorKey) {
+            die();
+        }
+
+        @Override
         public void error(int pos, String key, Object... args) {
             die();
         }
--- a/src/jdk.jshell/share/classes/jdk/jshell/ReplParser.java	Thu Nov 30 22:05:19 2017 +0100
+++ b/src/jdk.jshell/share/classes/jdk/jshell/ReplParser.java	Wed Dec 06 11:39:23 2017 +0000
@@ -25,6 +25,7 @@
 
 package jdk.jshell;
 
+import com.sun.tools.javac.code.Source.Feature;
 import com.sun.tools.javac.code.TypeTag;
 import com.sun.tools.javac.parser.JavacParser;
 import com.sun.tools.javac.parser.ParserFactory;
@@ -191,7 +192,7 @@
                     List<JCAnnotation> annosAfterParams = annotationsOpt(Tag.ANNOTATION);
 
                     if (annosAfterParams.nonEmpty()) {
-                        checkAnnotationsAfterTypeParams(annosAfterParams.head.pos);
+                        checkSourceLevel(annosAfterParams.head.pos, Feature.ANNOTATIONS_AFTER_TYPE_PARAMS);
                         mods.annotations = mods.annotations.appendList(annosAfterParams);
                         if (mods.pos == Position.NOPOS) {
                             mods.pos = mods.annotations.head.pos;
--- a/test/jdk/ProblemList.txt	Thu Nov 30 22:05:19 2017 +0100
+++ b/test/jdk/ProblemList.txt	Wed Dec 06 11:39:23 2017 +0000
@@ -124,8 +124,6 @@
 
 java/lang/StringCoding/CheckEncodings.sh                        7008363 generic-all
 
-jdk/internal/misc/JavaLangAccess/NewUnsafeString.java           8176188 generic-all
-
 java/lang/String/nativeEncoding/StringPlatformChars.java        8182569 windows-all,solaris-all
 
 ############################################################################
--- a/test/jdk/java/awt/Component/GetScreenLocTest/ComponentGetLocationOnScreenNPETest.java	Thu Nov 30 22:05:19 2017 +0100
+++ b/test/jdk/java/awt/Component/GetScreenLocTest/ComponentGetLocationOnScreenNPETest.java	Wed Dec 06 11:39:23 2017 +0000
@@ -25,6 +25,7 @@
  * @test
  * @bug 8189204
  * @summary Possible NPE in Component::getLocationOnScreen()
+ * @key headful
  * @run main ComponentGetLocationOnScreenNPETest
  */
 
--- a/test/jdk/java/awt/Dialog/SiblingChildOrder/SiblingChildOrderTest.java	Thu Nov 30 22:05:19 2017 +0100
+++ b/test/jdk/java/awt/Dialog/SiblingChildOrder/SiblingChildOrderTest.java	Wed Dec 06 11:39:23 2017 +0000
@@ -21,9 +21,11 @@
  * questions.
  */
 
-/* @test
+/**
+ * @test
  * @bug 8190230
  * @summary [macosx] Order of overlapping of modal dialogs is wrong
+ * @key headful
  * @run main SiblingChildOrderTest
  */
 
--- a/test/jdk/java/awt/Focus/FocusTransitionTest/FocusTransitionTest.java	Thu Nov 30 22:05:19 2017 +0100
+++ b/test/jdk/java/awt/Focus/FocusTransitionTest/FocusTransitionTest.java	Wed Dec 06 11:39:23 2017 +0000
@@ -21,10 +21,12 @@
  * questions.
  */
 
-/* @test
+/**
+ * @test
  * @bug 8155197
  * @summary Tests whether the value of mostRecentFocusOwner for a window is correct, if
  *          another window is displayed during focus transition
+ * @key headful
  * @library ../../regtesthelpers
  * @build Util
  * @run main FocusTransitionTest
--- a/test/jdk/java/io/Serializable/maskSyntheticModifier/MaskSyntheticModifierTest.java	Thu Nov 30 22:05:19 2017 +0100
+++ b/test/jdk/java/io/Serializable/maskSyntheticModifier/MaskSyntheticModifierTest.java	Wed Dec 06 11:39:23 2017 +0000
@@ -30,6 +30,7 @@
  *          serialVersionUID calculation.
  */
 
+import java.io.File;
 import java.io.ObjectStreamClass;
 import java.nio.file.Files;
 import java.nio.file.Paths;
@@ -46,7 +47,10 @@
     }
 
     private static void setup() throws Exception {
+        // Copy the class file to the first component of the class path
+        String cp = System.getProperty("java.class.path");
+        String cp1 = cp.substring(0, cp.indexOf(File.pathSeparatorChar));
         Files.copy(Paths.get(System.getProperty("test.src"), "Foo.class"),
-                Paths.get("Foo.class"), StandardCopyOption.REPLACE_EXISTING);
+                Paths.get(cp1, "Foo.class"), StandardCopyOption.REPLACE_EXISTING);
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/lang/ClassLoader/RecursiveSystemLoader.java	Wed Dec 06 11:39:23 2017 +0000
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8187222
+ * @run main/othervm -Djava.system.class.loader=RecursiveSystemLoader RecursiveSystemLoader
+ * @summary Test for IllegalStateException if a custom system loader recursively calls getSystemClassLoader()
+ */
+public class RecursiveSystemLoader extends ClassLoader {
+    public static void main(String[] args) {
+        ClassLoader sys = ClassLoader.getSystemClassLoader();
+        if (!(sys instanceof RecursiveSystemLoader)) {
+            throw new RuntimeException("Unexpected system classloader: " + sys);
+        }
+    }
+    public RecursiveSystemLoader(ClassLoader classLoader) {
+        super("RecursiveSystemLoader", classLoader);
+
+        // Calling ClassLoader.getSystemClassLoader() before the VM is booted
+        // should throw an IllegalStateException.
+        try {
+            ClassLoader.getSystemClassLoader();
+        } catch(IllegalStateException ise) {
+            System.err.println("Caught expected exception:");
+            ise.printStackTrace();
+            return;
+        }
+        throw new RuntimeException("Expected IllegalStateException was not thrown.");
+    }
+
+    @Override
+    public Class<?> loadClass(String name) throws ClassNotFoundException {
+        return super.loadClass(name);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/lang/reflect/StaticFieldsOnInterface.java	Wed Dec 06 11:39:23 2017 +0000
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8186961
+ * @run main/othervm StaticFieldsOnInterface C
+ * @run main/othervm StaticFieldsOnInterface D
+ * @run main/othervm StaticFieldsOnInterface Y
+ */
+
+public class StaticFieldsOnInterface {
+    /*
+            A
+           / \
+          B  C
+          \  /
+           D
+
+        Interface A has a public field
+        Ensure B, C, D only report exactly one public field
+
+          A
+         /
+        X A
+        |/
+        Y
+
+        Ensure class Y, extending class X, reports exactly one public field
+     */
+
+    public interface A {
+        public static final int CONSTANT = 42;
+    }
+
+    public interface B extends A {
+    }
+
+    public interface C extends A {
+    }
+
+    public interface D extends B, C {
+    }
+
+    static class X implements A {}
+    static class Y extends X implements A {}
+
+    public static void main(String[] args) throws Exception {
+        char first = 'C';
+        if (args.length > 0) {
+            first = args[0].charAt(0);
+        }
+
+        assertOneField(A.class);
+        // D first
+        if (first == 'D') {
+            assertOneField(D.class);
+            assertOneField(C.class);
+        }
+        // C first
+        else if (first == 'C') {
+            assertOneField(C.class);
+            assertOneField(D.class);
+        }
+        else {
+            assertOneField(Y.class);
+        }
+    }
+
+    static void assertOneField(Class<?> c) {
+        int nfs = c.getFields().length;
+        if (nfs != 1) {
+            throw new AssertionError(String.format(
+                    "Class %s does not have exactly one field: %d", c.getName(), nfs));
+        }
+    }
+}
--- a/test/jdk/java/net/SocketOption/UnsupportedOptionsTest.java	Thu Nov 30 22:05:19 2017 +0100
+++ b/test/jdk/java/net/SocketOption/UnsupportedOptionsTest.java	Wed Dec 06 11:39:23 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -57,6 +57,8 @@
             Class<?> c = Class.forName("jdk.net.ExtendedSocketOptions");
             Field field = c.getField("SO_FLOW_SLA");
             socketOptions.add((SocketOption<?>)field.get(null));
+            field = c.getField("TCP_QUICKACK");
+            socketOptions.add((SocketOption<?>)field.get(null));
         } catch (ClassNotFoundException e) {
             // ignore, jdk.net module not present
         } catch (ReflectiveOperationException e) {
--- a/test/jdk/java/util/Collection/MOAT.java	Thu Nov 30 22:05:19 2017 +0100
+++ b/test/jdk/java/util/Collection/MOAT.java	Wed Dec 06 11:39:23 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -57,6 +57,8 @@
 import java.util.concurrent.*;
 import static java.util.Collections.*;
 import java.lang.reflect.*;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 public class MOAT {
     // Collections under test must not be initialized to contain this value,
@@ -230,6 +232,17 @@
             testListMutatorsAlwaysThrow(list);
         }
 
+        List<Integer> listCopy = List.copyOf(Arrays.asList(1, 2, 3));
+        testCollection(listCopy);
+        testImmutableList(listCopy);
+        testListMutatorsAlwaysThrow(listCopy);
+
+        List<Integer> listCollected = Stream.of(1, 2, 3).collect(Collectors.toUnmodifiableList());
+        equal(listCollected, List.of(1, 2, 3));
+        testCollection(listCollected);
+        testImmutableList(listCollected);
+        testListMutatorsAlwaysThrow(listCollected);
+
         // Immutable Set
         testEmptySet(Set.of());
         testCollMutatorsAlwaysThrow(Set.of());
@@ -252,6 +265,18 @@
             testCollMutatorsAlwaysThrow(set);
         }
 
+        Set<Integer> setCopy = Set.copyOf(Arrays.asList(1, 2, 3));
+        testCollection(setCopy);
+        testImmutableSet(setCopy);
+        testCollMutatorsAlwaysThrow(setCopy);
+
+        Set<Integer> setCollected = Stream.of(1, 1, 2, 3, 2, 3)
+                                          .collect(Collectors.toUnmodifiableSet());
+        equal(setCollected, Set.of(1, 2, 3));
+        testCollection(setCollected);
+        testImmutableSet(setCollected);
+        testCollMutatorsAlwaysThrow(setCollected);
+
         // Immutable Map
 
         @SuppressWarnings("unchecked")
@@ -280,6 +305,35 @@
             testImmutableMap(map);
             testMapMutatorsAlwaysThrow(map);
         }
+
+        Map<Integer,Integer> mapCopy = Map.copyOf(new HashMap<>(Map.of(1, 101, 2, 202, 3, 303)));
+        testMap(mapCopy);
+        testImmutableMap(mapCopy);
+        testMapMutatorsAlwaysThrow(mapCopy);
+
+        Map<Integer,Integer> mapCollected1 =
+            Stream.of(1, 2, 3)
+                  .collect(Collectors.toUnmodifiableMap(i -> i, i -> 101 * i));
+        equal(mapCollected1, Map.of(1, 101, 2, 202, 3, 303));
+        testMap(mapCollected1);
+        testImmutableMap(mapCollected1);
+        testMapMutatorsAlwaysThrow(mapCollected1);
+
+        try {
+            Stream.of(1, 1, 2, 3, 2, 3)
+                  .collect(Collectors.toUnmodifiableMap(i -> i, i -> 101 * i));
+            fail("duplicates should have thrown an exception");
+        } catch (IllegalStateException ise) {
+            pass();
+        }
+
+        Map<Integer,Integer> mapCollected2 =
+            Stream.of(1, 1, 2, 3, 2, 3)
+                  .collect(Collectors.toUnmodifiableMap(i -> i, i -> 101 * i, Integer::sum));
+        equal(mapCollected2, Map.of(1, 202, 2, 404, 3, 606));
+        testMap(mapCollected2);
+        testImmutableMap(mapCollected2);
+        testMapMutatorsAlwaysThrow(mapCollected2);
     }
 
     private static void checkContainsSelf(Collection<Integer> c) {
--- a/test/jdk/java/util/Collection/SetFactories.java	Thu Nov 30 22:05:19 2017 +0100
+++ b/test/jdk/java/util/Collection/SetFactories.java	Wed Dec 06 11:39:23 2017 +0000
@@ -40,6 +40,9 @@
 import org.testng.annotations.Test;
 
 import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotEquals;
+import static org.testng.Assert.assertNotSame;
+import static org.testng.Assert.assertSame;
 import static org.testng.Assert.assertTrue;
 import static org.testng.Assert.fail;
 
@@ -275,9 +278,9 @@
     static <T> T serialClone(T obj) {
         try {
             ByteArrayOutputStream baos = new ByteArrayOutputStream();
-            ObjectOutputStream oos = new ObjectOutputStream(baos);
-            oos.writeObject(obj);
-            oos.close();
+            try (ObjectOutputStream oos = new ObjectOutputStream(baos)) {
+                oos.writeObject(obj);
+            }
             ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
             ObjectInputStream ois = new ObjectInputStream(bais);
             return (T) ois.readObject();
@@ -285,4 +288,53 @@
             throw new AssertionError(e);
         }
     }
+
+    Set<Integer> genSet() {
+        return new HashSet<>(Arrays.asList(1, 2, 3));
+    }
+
+    @Test
+    public void copyOfResultsEqual() {
+        Set<Integer> orig = genSet();
+        Set<Integer> copy = Set.copyOf(orig);
+
+        assertEquals(orig, copy);
+        assertEquals(copy, orig);
+    }
+
+    @Test
+    public void copyOfModifiedUnequal() {
+        Set<Integer> orig = genSet();
+        Set<Integer> copy = Set.copyOf(orig);
+        orig.add(4);
+
+        assertNotEquals(orig, copy);
+        assertNotEquals(copy, orig);
+    }
+
+    @Test
+    public void copyOfIdentity() {
+        Set<Integer> orig = genSet();
+        Set<Integer> copy1 = Set.copyOf(orig);
+        Set<Integer> copy2 = Set.copyOf(copy1);
+
+        assertNotSame(orig, copy1);
+        assertSame(copy1, copy2);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class)
+    public void copyOfRejectsNullCollection() {
+        Set<Integer> set = Set.copyOf(null);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class)
+    public void copyOfRejectsNullElements() {
+        Set<Integer> set = Set.copyOf(Arrays.asList(1, null, 3));
+    }
+
+    @Test
+    public void copyOfAcceptsDuplicates() {
+        Set<Integer> set = Set.copyOf(Arrays.asList(1, 1, 2, 3, 3, 3));
+        assertEquals(set, Set.of(1, 2, 3));
+    }
 }
--- a/test/jdk/java/util/List/ListFactories.java	Thu Nov 30 22:05:19 2017 +0100
+++ b/test/jdk/java/util/List/ListFactories.java	Wed Dec 06 11:39:23 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -39,6 +39,9 @@
 
 import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotEquals;
+import static org.testng.Assert.assertNotSame;
+import static org.testng.Assert.assertSame;
 import static org.testng.Assert.assertTrue;
 import static org.testng.Assert.fail;
 
@@ -221,9 +224,9 @@
     static <T> T serialClone(T obj) {
         try {
             ByteArrayOutputStream baos = new ByteArrayOutputStream();
-            ObjectOutputStream oos = new ObjectOutputStream(baos);
-            oos.writeObject(obj);
-            oos.close();
+            try (ObjectOutputStream oos = new ObjectOutputStream(baos)) {
+                oos.writeObject(obj);
+            }
             ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
             ObjectInputStream ois = new ObjectInputStream(bais);
             return (T) ois.readObject();
@@ -231,4 +234,47 @@
             throw new AssertionError(e);
         }
     }
+
+    List<Integer> genList() {
+        return new ArrayList<>(Arrays.asList(1, 2, 3));
+    }
+
+    @Test
+    public void copyOfResultsEqual() {
+        List<Integer> orig = genList();
+        List<Integer> copy = List.copyOf(orig);
+
+        assertEquals(orig, copy);
+        assertEquals(copy, orig);
+    }
+
+    @Test
+    public void copyOfModifiedUnequal() {
+        List<Integer> orig = genList();
+        List<Integer> copy = List.copyOf(orig);
+        orig.add(4);
+
+        assertNotEquals(orig, copy);
+        assertNotEquals(copy, orig);
+    }
+
+    @Test
+    public void copyOfIdentity() {
+        List<Integer> orig = genList();
+        List<Integer> copy1 = List.copyOf(orig);
+        List<Integer> copy2 = List.copyOf(copy1);
+
+        assertNotSame(orig, copy1);
+        assertSame(copy1, copy2);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class)
+    public void copyOfRejectsNullCollection() {
+        List<Integer> list = List.copyOf(null);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class)
+    public void copyOfRejectsNullElements() {
+        List<Integer> list = List.copyOf(Arrays.asList(1, null, 3));
+    }
 }
--- a/test/jdk/java/util/Map/MapFactories.java	Thu Nov 30 22:05:19 2017 +0100
+++ b/test/jdk/java/util/Map/MapFactories.java	Wed Dec 06 11:39:23 2017 +0000
@@ -42,6 +42,9 @@
 
 import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertNotEquals;
+import static org.testng.Assert.assertNotSame;
+import static org.testng.Assert.assertSame;
 import static org.testng.Assert.assertTrue;
 import static org.testng.Assert.fail;
 
@@ -70,6 +73,12 @@
     }
 
     // for varargs Map.Entry methods
+
+    @SuppressWarnings("unchecked")
+    Map.Entry<Integer,String>[] genEmptyEntryArray1() {
+        return (Map.Entry<Integer,String>[])new Map.Entry<?,?>[1];
+    }
+
     @SuppressWarnings("unchecked")
     Map.Entry<Integer,String>[] genEntries(int n) {
         return IntStream.range(0, n)
@@ -322,21 +331,41 @@
     }
 
     @Test(expectedExceptions=NullPointerException.class)
-    public void nullKeyDisallowedN() {
-        Map.Entry<Integer,String>[] entries = genEntries(MAX_ENTRIES);
-        entries[0] = new AbstractMap.SimpleImmutableEntry(null, "a");
+    public void nullKeyDisallowedVar1() {
+        Map.Entry<Integer,String>[] entries = genEmptyEntryArray1();
+        entries[0] = new AbstractMap.SimpleImmutableEntry<>(null, "a");
         Map<Integer, String> map = Map.ofEntries(entries);
     }
 
     @Test(expectedExceptions=NullPointerException.class)
-    public void nullValueDisallowedN() {
-        Map.Entry<Integer,String>[] entries = genEntries(MAX_ENTRIES);
-        entries[0] = new AbstractMap.SimpleImmutableEntry(0, null);
+    public void nullValueDisallowedVar1() {
+        Map.Entry<Integer,String>[] entries = genEmptyEntryArray1();
+        entries[0] = new AbstractMap.SimpleImmutableEntry<>(0, null);
         Map<Integer, String> map = Map.ofEntries(entries);
     }
 
     @Test(expectedExceptions=NullPointerException.class)
-    public void nullEntryDisallowedN() {
+    public void nullEntryDisallowedVar1() {
+        Map.Entry<Integer,String>[] entries = genEmptyEntryArray1();
+        Map<Integer, String> map = Map.ofEntries(entries);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class)
+    public void nullKeyDisallowedVarN() {
+        Map.Entry<Integer,String>[] entries = genEntries(MAX_ENTRIES);
+        entries[0] = new AbstractMap.SimpleImmutableEntry<>(null, "a");
+        Map<Integer, String> map = Map.ofEntries(entries);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class)
+    public void nullValueDisallowedVarN() {
+        Map.Entry<Integer,String>[] entries = genEntries(MAX_ENTRIES);
+        entries[0] = new AbstractMap.SimpleImmutableEntry<>(0, null);
+        Map<Integer, String> map = Map.ofEntries(entries);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class)
+    public void nullEntryDisallowedVarN() {
         Map.Entry<Integer,String>[] entries = genEntries(MAX_ENTRIES);
         entries[5] = null;
         Map<Integer, String> map = Map.ofEntries(entries);
@@ -344,7 +373,7 @@
 
     @Test(expectedExceptions=NullPointerException.class)
     public void nullArrayDisallowed() {
-        Map.ofEntries(null);
+        Map.ofEntries((Map.Entry<?,?>[])null);
     }
 
     @Test(dataProvider="all")
@@ -359,9 +388,9 @@
     static <T> T serialClone(T obj) {
         try {
             ByteArrayOutputStream baos = new ByteArrayOutputStream();
-            ObjectOutputStream oos = new ObjectOutputStream(baos);
-            oos.writeObject(obj);
-            oos.close();
+            try (ObjectOutputStream oos = new ObjectOutputStream(baos)) {
+                oos.writeObject(obj);
+            }
             ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
             ObjectInputStream ois = new ObjectInputStream(bais);
             return (T) ois.readObject();
@@ -370,6 +399,62 @@
         }
     }
 
+    Map<Integer, String> genMap() {
+        Map<Integer, String> map = new HashMap<>();
+        map.put(1, "a");
+        map.put(2, "b");
+        map.put(3, "c");
+        return map;
+    }
+
+    @Test
+    public void copyOfResultsEqual() {
+        Map<Integer, String> orig = genMap();
+        Map<Integer, String> copy = Map.copyOf(orig);
+
+        assertEquals(orig, copy);
+        assertEquals(copy, orig);
+    }
+
+    @Test
+    public void copyOfModifiedUnequal() {
+        Map<Integer, String> orig = genMap();
+        Map<Integer, String> copy = Map.copyOf(orig);
+        orig.put(4, "d");
+
+        assertNotEquals(orig, copy);
+        assertNotEquals(copy, orig);
+    }
+
+    @Test
+    public void copyOfIdentity() {
+        Map<Integer, String> orig = genMap();
+        Map<Integer, String> copy1 = Map.copyOf(orig);
+        Map<Integer, String> copy2 = Map.copyOf(copy1);
+
+        assertNotSame(orig, copy1);
+        assertSame(copy1, copy2);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class)
+    public void copyOfRejectsNullMap() {
+        Map<Integer, String> map = Map.copyOf(null);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class)
+    public void copyOfRejectsNullKey() {
+        Map<Integer, String> map = genMap();
+        map.put(null, "x");
+        Map<Integer, String> copy = Map.copyOf(map);
+    }
+
+    @Test(expectedExceptions=NullPointerException.class)
+    public void copyOfRejectsNullValue() {
+        Map<Integer, String> map = genMap();
+        map.put(-1, null);
+        Map<Integer, String> copy = Map.copyOf(map);
+    }
+
     // Map.entry() tests
 
     @Test(expectedExceptions=NullPointerException.class)
@@ -386,7 +471,7 @@
     public void entryBasicTests() {
         Map.Entry<String,String> kvh1 = Map.entry("xyzzy", "plugh");
         Map.Entry<String,String> kvh2 = Map.entry("foobar", "blurfl");
-        Map.Entry<String,String> sie = new AbstractMap.SimpleImmutableEntry("xyzzy", "plugh");
+        Map.Entry<String,String> sie = new AbstractMap.SimpleImmutableEntry<>("xyzzy", "plugh");
 
         assertTrue(kvh1.equals(sie));
         assertTrue(sie.equals(kvh1));
@@ -404,5 +489,4 @@
         Map<Number,Number> map = Map.ofEntries(e1, e2);
         assertEquals(map.size(), 2);
     }
-
 }
--- a/test/jdk/java/util/concurrent/tck/AbstractQueuedLongSynchronizerTest.java	Thu Nov 30 22:05:19 2017 +0100
+++ b/test/jdk/java/util/concurrent/tck/AbstractQueuedLongSynchronizerTest.java	Wed Dec 06 11:39:23 2017 +0000
@@ -39,6 +39,7 @@
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.HashSet;
+import java.util.concurrent.ThreadLocalRandom;
 import java.util.concurrent.locks.AbstractQueuedLongSynchronizer;
 import java.util.concurrent.locks.AbstractQueuedLongSynchronizer.ConditionObject;
 
@@ -1283,4 +1284,57 @@
         sync.release();
     }
 
+    /**
+     * Tests scenario for
+     * JDK-8191937: Lost interrupt in AbstractQueuedSynchronizer when tryAcquire methods throw
+     */
+    public void testInterruptedFailingAcquire() throws InterruptedException {
+        final RuntimeException ex = new RuntimeException();
+
+        // A synchronizer only offering a choice of failure modes
+        class Sync extends AbstractQueuedLongSynchronizer {
+            boolean pleaseThrow;
+            @Override protected boolean tryAcquire(long ignored) {
+                if (pleaseThrow) throw ex;
+                return false;
+            }
+            @Override protected long tryAcquireShared(long ignored) {
+                if (pleaseThrow) throw ex;
+                return -1;
+            }
+            @Override protected boolean tryRelease(long ignored) {
+                return true;
+            }
+            @Override protected boolean tryReleaseShared(long ignored) {
+                return true;
+            }
+        }
+
+        final Sync s = new Sync();
+
+        final Thread thread = newStartedThread(new CheckedRunnable() {
+            public void realRun() {
+                try {
+                    if (ThreadLocalRandom.current().nextBoolean())
+                        s.acquire(1);
+                    else
+                        s.acquireShared(1);
+                    shouldThrow();
+                } catch (Throwable t) {
+                    assertSame(ex, t);
+                    assertTrue(Thread.interrupted());
+                }
+            }});
+        waitForThreadToEnterWaitState(thread);
+        assertSame(thread, s.getFirstQueuedThread());
+        assertTrue(s.hasQueuedPredecessors());
+        assertTrue(s.hasQueuedThreads());
+        assertEquals(1, s.getQueueLength());
+
+        s.pleaseThrow = true;
+        thread.interrupt();
+        s.release(1);
+        awaitTermination(thread);
+    }
+
 }
--- a/test/jdk/java/util/concurrent/tck/AbstractQueuedSynchronizerTest.java	Thu Nov 30 22:05:19 2017 +0100
+++ b/test/jdk/java/util/concurrent/tck/AbstractQueuedSynchronizerTest.java	Wed Dec 06 11:39:23 2017 +0000
@@ -36,9 +36,11 @@
 import static java.util.concurrent.TimeUnit.MILLISECONDS;
 import static java.util.concurrent.TimeUnit.NANOSECONDS;
 
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.HashSet;
+import java.util.concurrent.ThreadLocalRandom;
 import java.util.concurrent.locks.AbstractQueuedSynchronizer;
 import java.util.concurrent.locks.AbstractQueuedSynchronizer.ConditionObject;
 
@@ -1286,4 +1288,105 @@
         sync.release();
     }
 
+    /**
+     * Disabled demo test for (unfixed as of 2017-11)
+     * JDK-8191483: AbstractQueuedSynchronizer cancel/cancel race
+     * ant -Djsr166.tckTestClass=AbstractQueuedSynchronizerTest -Djsr166.methodFilter=testCancelCancelRace -Djsr166.runsPerTest=100 tck
+     */
+    public void DISABLED_testCancelCancelRace() throws InterruptedException {
+        class Sync extends AbstractQueuedSynchronizer {
+            protected boolean tryAcquire(int acquires) {
+                return !hasQueuedPredecessors() && compareAndSetState(0, 1);
+            }
+            protected boolean tryRelease(int releases) {
+                return compareAndSetState(1, 0);
+            }
+        }
+
+        Sync s = new Sync();
+        s.acquire(1);           // acquire to force other threads to enqueue
+
+        // try to trigger double cancel race with two background threads
+        ArrayList<Thread> threads = new ArrayList<>();
+        Runnable failedAcquire = () -> {
+            try {
+                s.acquireInterruptibly(1);
+                shouldThrow();
+            } catch (InterruptedException expected) {}
+        };
+        for (int i = 0; i < 2; i++) {
+            Thread thread = new Thread(failedAcquire);
+            thread.start();
+            threads.add(thread);
+        }
+        Thread.sleep(100);
+        for (Thread thread : threads) thread.interrupt();
+        for (Thread thread : threads) awaitTermination(thread);
+
+        s.release(1);
+
+        // no one holds lock now, we should be able to acquire
+        if (!s.tryAcquire(1))
+            throw new RuntimeException(
+                String.format(
+                    "Broken: hasQueuedPredecessors=%s hasQueuedThreads=%s queueLength=%d firstQueuedThread=%s",
+                    s.hasQueuedPredecessors(),
+                    s.hasQueuedThreads(),
+                    s.getQueueLength(),
+                    s.getFirstQueuedThread()));
+    }
+
+    /**
+     * Tests scenario for
+     * JDK-8191937: Lost interrupt in AbstractQueuedSynchronizer when tryAcquire methods throw
+     */
+    public void testInterruptedFailingAcquire() throws InterruptedException {
+        final RuntimeException ex = new RuntimeException();
+
+        // A synchronizer only offering a choice of failure modes
+        class Sync extends AbstractQueuedSynchronizer {
+            boolean pleaseThrow;
+            @Override protected boolean tryAcquire(int ignored) {
+                if (pleaseThrow) throw ex;
+                return false;
+            }
+            @Override protected int tryAcquireShared(int ignored) {
+                if (pleaseThrow) throw ex;
+                return -1;
+            }
+            @Override protected boolean tryRelease(int ignored) {
+                return true;
+            }
+            @Override protected boolean tryReleaseShared(int ignored) {
+                return true;
+            }
+        }
+
+        final Sync s = new Sync();
+
+        final Thread thread = newStartedThread(new CheckedRunnable() {
+            public void realRun() {
+                try {
+                    if (ThreadLocalRandom.current().nextBoolean())
+                        s.acquire(1);
+                    else
+                        s.acquireShared(1);
+                    shouldThrow();
+                } catch (Throwable t) {
+                    assertSame(ex, t);
+                    assertTrue(Thread.interrupted());
+                }
+            }});
+        waitForThreadToEnterWaitState(thread);
+        assertSame(thread, s.getFirstQueuedThread());
+        assertTrue(s.hasQueuedPredecessors());
+        assertTrue(s.hasQueuedThreads());
+        assertEquals(1, s.getQueueLength());
+
+        s.pleaseThrow = true;
+        thread.interrupt();
+        s.release(1);
+        awaitTermination(thread);
+    }
+
 }
--- a/test/jdk/java/util/concurrent/tck/StampedLockTest.java	Thu Nov 30 22:05:19 2017 +0100
+++ b/test/jdk/java/util/concurrent/tck/StampedLockTest.java	Wed Dec 06 11:39:23 2017 +0000
@@ -614,7 +614,7 @@
         long s = lock.readLock();
         Thread t = newStartedThread(new CheckedRunnable() {
             public void realRun() {
-                threadAssertEquals(0L, lock.tryWriteLock());
+                assertEquals(0L, lock.tryWriteLock());
             }});
 
         awaitTermination(t);
--- a/test/jdk/java/util/concurrent/tck/SubmissionPublisherTest.java	Thu Nov 30 22:05:19 2017 +0100
+++ b/test/jdk/java/util/concurrent/tck/SubmissionPublisherTest.java	Wed Dec 06 11:39:23 2017 +0000
@@ -33,6 +33,7 @@
  */
 
 import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.Executor;
 import java.util.concurrent.Executors;
 import java.util.concurrent.Flow;
@@ -429,7 +430,8 @@
      * Cancelling a subscription eventually causes no more onNexts to be issued
      */
     public void testCancel() {
-        SubmissionPublisher<Integer> p = basicPublisher();
+        SubmissionPublisher<Integer> p =
+            new SubmissionPublisher<Integer>(basicExecutor, 4); // must be < 20
         TestSubscriber s1 = new TestSubscriber();
         TestSubscriber s2 = new TestSubscriber();
         p.subscribe(s1);
@@ -666,7 +668,6 @@
         p.subscribe(s1);
         p.subscribe(s2);
         for (int i = 1; i <= 20; ++i) {
-            assertTrue(p.estimateMinimumDemand() <= 1);
             assertTrue(p.submit(i) >= 0);
         }
         p.close();
@@ -1005,4 +1006,31 @@
         assertTrue(count.get() < n);
     }
 
+    /**
+     * Tests scenario for
+     * JDK-8187947: A race condition in SubmissionPublisher
+     * cvs update -D '2017-11-25' src/main/java/util/concurrent/SubmissionPublisher.java && ant -Djsr166.expensiveTests=true -Djsr166.tckTestClass=SubmissionPublisherTest -Djsr166.methodFilter=testMissedSignal tck; cvs update -A src/main/java/util/concurrent/SubmissionPublisher.java
+     */
+    public void testMissedSignal_8187947() throws Exception {
+        final int N = expensiveTests ? (1 << 20) : (1 << 10);
+        final CountDownLatch finished = new CountDownLatch(1);
+        final SubmissionPublisher<Boolean> pub = new SubmissionPublisher<>();
+        class Sub implements Subscriber<Boolean> {
+            int received;
+            public void onSubscribe(Subscription s) {
+                s.request(N);
+            }
+            public void onNext(Boolean item) {
+                if (++received == N)
+                    finished.countDown();
+                else
+                    CompletableFuture.runAsync(() -> pub.submit(Boolean.TRUE));
+            }
+            public void onError(Throwable t) { throw new AssertionError(t); }
+            public void onComplete() {}
+        }
+        pub.subscribe(new Sub());
+        CompletableFuture.runAsync(() -> pub.submit(Boolean.TRUE));
+        await(finished);
+    }
 }
--- a/test/jdk/java/util/zip/InflateIn_DeflateOut.java	Thu Nov 30 22:05:19 2017 +0100
+++ b/test/jdk/java/util/zip/InflateIn_DeflateOut.java	Wed Dec 06 11:39:23 2017 +0000
@@ -23,8 +23,9 @@
 
 /**
  * @test
- * @bug 4206909 4813885
- * @summary Test basic functionality of DeflaterOutputStream/InflaterInputStream and GZIPOutputStream/GZIPInputStream, including flush
+ * @bug 4206909 4813885 8191918
+ * @summary Test basic functionality of DeflaterOutputStream/InflaterInputStream
+ *          and GZIPOutputStream/GZIPInputStream, including flush
  * @key randomness
  */
 
@@ -147,6 +148,36 @@
         check(Arrays.equals(data, buf));
     }
 
+    private static void TestFlushableGZIPOutputStream() throws Throwable {
+        var random = new Random(new Date().getTime());
+
+        var byteOutStream = new ByteArrayOutputStream();
+        var output = new FlushableGZIPOutputStream(byteOutStream);
+
+        var data = new byte[random.nextInt(1024 * 1024)];
+        var buf = new byte[data.length];
+        random.nextBytes(data);
+
+        output.write(data);
+        for (int i=0; i<data.length; i++) {
+            output.write(data[i]);
+        }
+        output.flush();
+        for (int i=0; i<data.length; i++) {
+            output.write(data[i]);
+        }
+        output.write(data);
+        output.close();
+
+        var baos = new ByteArrayOutputStream();
+        try (var gzis = new GZIPInputStream(new
+                ByteArrayInputStream(byteOutStream.toByteArray()))) {
+            gzis.transferTo(baos);
+        }
+        var decompressedBytes = baos.toByteArray();
+        check(decompressedBytes.length == data.length * 4);
+    }
+
     private static void check(InputStream is, OutputStream os)
         throws Throwable
     {
@@ -268,6 +299,7 @@
         LineOrientedProtocol();
         GZWriteFlushRead();
         GZLineOrientedProtocol();
+        TestFlushableGZIPOutputStream();
     }
 
     //--------------------- Infrastructure ---------------------------
@@ -285,3 +317,80 @@
         System.out.println("\nPassed = " + passed + " failed = " + failed);
         if (failed > 0) throw new AssertionError("Some tests failed");}
 }
+
+class FlushableGZIPOutputStream extends GZIPOutputStream {
+    public FlushableGZIPOutputStream(OutputStream os) throws IOException {
+        super(os);
+    }
+
+    private static final byte[] EMPTYBYTEARRAY = new byte[0];
+    private boolean hasData = false;
+
+    /**
+     * Here we make sure we have received data, so that the header has been for
+     * sure written to the output stream already.
+     */
+    @Override
+    public synchronized void write(byte[] bytes, int i, int i1)
+            throws IOException {
+        super.write(bytes, i, i1);
+        hasData = true;
+    }
+
+    @Override
+    public synchronized void write(int i) throws IOException {
+        super.write(i);
+        hasData = true;
+    }
+
+    @Override
+    public synchronized void write(byte[] bytes) throws IOException {
+        super.write(bytes);
+        hasData = true;
+    }
+
+    @Override
+    public synchronized void flush() throws IOException {
+        if (!hasData) {
+            return; // do not allow the gzip header to be flushed on its own
+        }
+
+        // trick the deflater to flush
+        /**
+         * Now this is tricky: We force the Deflater to flush its data by
+         * switching compression level. As yet, a perplexingly simple workaround
+         * for
+         * http://developer.java.sun.com/developer/bugParade/bugs/4255743.html
+         */
+        if (!def.finished()) {
+            def.setInput(EMPTYBYTEARRAY, 0, 0);
+
+            def.setLevel(Deflater.NO_COMPRESSION);
+            deflate();
+
+            def.setLevel(Deflater.DEFAULT_COMPRESSION);
+            deflate();
+
+            out.flush();
+        }
+
+        hasData = false; // no more data to flush
+    }
+
+    /*
+     * Keep on calling deflate until it runs dry. The default implementation
+     * only does it once and can therefore hold onto data when they need to be
+     * flushed out.
+     */
+    @Override
+    protected void deflate() throws IOException {
+        int len;
+        do {
+            len = def.deflate(buf, 0, buf.length);
+            if (len > 0) {
+                out.write(buf, 0, len);
+            }
+        } while (len != 0);
+    }
+
+}
--- a/test/jdk/javax/swing/DefaultButtonModel/DefaultButtonModelCrashTest.java	Thu Nov 30 22:05:19 2017 +0100
+++ b/test/jdk/javax/swing/DefaultButtonModel/DefaultButtonModelCrashTest.java	Wed Dec 06 11:39:23 2017 +0000
@@ -20,12 +20,15 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
-/*
+
+/**
  * @test
  * @bug 8182577
  * @summary  Verifies if moving focus via custom ButtonModel causes crash
+ * @key headful
  * @run main DefaultButtonModelCrashTest
  */
+
 import java.awt.BorderLayout;
 import java.awt.Container;
 import java.awt.Point;
@@ -61,7 +64,7 @@
             robot.keyPress(KeyEvent.VK_TAB);
             robot.keyRelease(KeyEvent.VK_TAB);
         } finally {
-            SwingUtilities.invokeAndWait(()->frame  .dispose());
+            if (frame != null) { SwingUtilities.invokeAndWait(()->frame.dispose()); }
         }
     }
 
--- a/test/jdk/javax/swing/GraphicsConfigNotifier/TestMultiScreenGConfigNotify.java	Thu Nov 30 22:05:19 2017 +0100
+++ b/test/jdk/javax/swing/GraphicsConfigNotifier/TestMultiScreenGConfigNotify.java	Wed Dec 06 11:39:23 2017 +0000
@@ -20,12 +20,14 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
-/*
+
+/**
  * @test
  * @bug 8178025
  * @summary  Verifies if graphicsConfiguration property notification is sent
  *           when frame is moved from one screen to another in multiscreen
  *           environment.
+ * @key headful
  * @run main TestMultiScreenGConfigNotify
  */
 
--- a/test/jdk/javax/swing/JButton/TestGlyphBreak.java	Thu Nov 30 22:05:19 2017 +0100
+++ b/test/jdk/javax/swing/JButton/TestGlyphBreak.java	Wed Dec 06 11:39:23 2017 +0000
@@ -20,10 +20,12 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
-/*
+
+/**
  * @test
  * @bug 8191428
  * @summary  Verifies if text view is not borken into multiple lines
+ * @key headful
  * @run main/othervm -Dsun.java2d.uiScale=1.2 TestGlyphBreak
  */
 
--- a/test/jdk/javax/swing/JComboBox/8182031/ComboPopupTest.java	Thu Nov 30 22:05:19 2017 +0100
+++ b/test/jdk/javax/swing/JComboBox/8182031/ComboPopupTest.java	Wed Dec 06 11:39:23 2017 +0000
@@ -20,12 +20,15 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
-/*
+
+/**
  * @test
  * @bug 8182031
  * @summary  Verifies if ComboBox Popup opens and closes immediately
+ * @key headful
  * @run main ComboPopupTest
  */
+
 import java.awt.Container;
 import java.awt.Dimension;
 import java.awt.FlowLayout;
@@ -80,7 +83,7 @@
                 throw new RuntimeException("combobox popup is not visible");
             }
         } finally {
-            SwingUtilities.invokeAndWait(()->frame.dispose());
+            if (frame != null) { SwingUtilities.invokeAndWait(()->frame.dispose()); }
         }
     }
 
--- a/test/jdk/javax/swing/JMenu/8178430/LabelDotTest.java	Thu Nov 30 22:05:19 2017 +0100
+++ b/test/jdk/javax/swing/JMenu/8178430/LabelDotTest.java	Wed Dec 06 11:39:23 2017 +0000
@@ -20,13 +20,16 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
-/*
+
+/**
  * @test
  * @bug 8178430
  * @summary JMenu in GridBagLayout flickers when label text shows "..." and
  * is updated
+ * @key headful
  * @run main LabelDotTest
  */
+
 import java.awt.Dimension;
 import java.awt.GridBagConstraints;
 import java.awt.GridBagLayout;
@@ -112,7 +115,9 @@
             SwingUtilities.invokeAndWait(() -> createUI());
             runTest(50);
         } finally {
-            SwingUtilities.invokeAndWait(() -> frame.dispose());
+            if (frame != null) {
+                SwingUtilities.invokeAndWait(() -> frame.dispose());
+            }
             if (isException)
                 throw new RuntimeException("Size of Menu bar is not correct.");
         }
--- a/test/jdk/javax/swing/JTextArea/TestTabSize.java	Thu Nov 30 22:05:19 2017 +0100
+++ b/test/jdk/javax/swing/JTextArea/TestTabSize.java	Wed Dec 06 11:39:23 2017 +0000
@@ -20,10 +20,12 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
-/*
+
+/**
  * @test
  * @bug 8187957
  * @summary  Verifies Tab Size works correctly in JTextArea
+ * @key headful
  * @run main TestTabSize
  */
 
@@ -96,7 +98,9 @@
             } catch (BadLocationException ex) {
                 excpnthrown = true;
             } finally {
-                f.dispose();
+                if (f != null) {
+                    f.dispose();
+                }
             }
         });
         if (excpnthrown) {
--- a/test/jdk/javax/swing/dnd/8139050/NativeErrorsInTableDnD.java	Thu Nov 30 22:05:19 2017 +0100
+++ b/test/jdk/javax/swing/dnd/8139050/NativeErrorsInTableDnD.java	Wed Dec 06 11:39:23 2017 +0000
@@ -40,10 +40,12 @@
 /**
  * @test
  * @bug 8139050 8153871
+ * @key headful
  * @library ../../../../lib/testlibrary
  * @build ExtendedRobot
  * @run main/othervm/timeout=360 -Xcheck:jni NativeErrorsInTableDnD
  */
+
 public final class NativeErrorsInTableDnD {
 
     private static JFrame frame;
--- a/test/jdk/javax/swing/plaf/nimbus/TestNimbusOverride.java	Thu Nov 30 22:05:19 2017 +0100
+++ b/test/jdk/javax/swing/plaf/nimbus/TestNimbusOverride.java	Wed Dec 06 11:39:23 2017 +0000
@@ -20,13 +20,16 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
-/*
+
+/**
  * @test
  * @bug 8043315
  * @summary  Verifies if setting Nimbus.Overrides property affects
  *           keymap installation
+ * @key headful
  * @run main TestNimbusOverride
  */
+
 import java.awt.BorderLayout;
 import java.awt.Component;
 import java.awt.Dimension;
--- a/test/jdk/javax/swing/text/DefaultCaret/HidingSelection/HidingSelectionTest.java	Thu Nov 30 22:05:19 2017 +0100
+++ b/test/jdk/javax/swing/text/DefaultCaret/HidingSelection/HidingSelectionTest.java	Wed Dec 06 11:39:23 2017 +0000
@@ -30,6 +30,7 @@
  * @test
  * @bug 8188081
  * @summary  Text selection does not clear after focus is lost
+ * @key headful
  * @run main HidingSelectionTest
  */
 
--- a/test/jdk/jdk/internal/misc/JavaLangAccess/NewUnsafeString.java	Thu Nov 30 22:05:19 2017 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,88 +0,0 @@
-/*
- * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-import java.util.Objects;
-import java.util.Comparator;
-import jdk.internal.misc.JavaLangAccess;
-import jdk.internal.misc.SharedSecrets;
-
-/*
- * @test
- * @bug 8013528
- * @summary Test JavaLangAccess.newUnsafeString
- * @modules java.base/jdk.internal.misc
- * @compile -XDignore.symbol.file NewUnsafeString.java
- * @run main NewUnsafeString
- */
-public class NewUnsafeString {
-
-    static final JavaLangAccess jla = SharedSecrets.getJavaLangAccess();
-
-    public static void testNewUnsafeString() {
-        String benchmark = "exemplar";
-        String constructorCopy = new String(benchmark);
-        char[] jlaChars = benchmark.toCharArray();
-        String jlaCopy = jla.newStringUnsafe(jlaChars);
-
-        if (benchmark == constructorCopy) {
-            throw new Error("should be different instances");
-        }
-        if (!benchmark.equals(constructorCopy)) {
-            throw new Error("Copy not equal");
-        }
-        if (0 != Objects.compare(benchmark, constructorCopy, Comparator.naturalOrder())) {
-            throw new Error("Copy not equal");
-        }
-
-        if (benchmark == jlaCopy) {
-            throw new Error("should be different instances");
-        }
-        if (!benchmark.equals(jlaCopy)) {
-            throw new Error("Copy not equal");
-        }
-        if (0 != Objects.compare(benchmark, jlaCopy, Comparator.naturalOrder())) {
-            throw new Error("Copy not equal");
-        }
-
-        if (constructorCopy == jlaCopy) {
-            throw new Error("should be different instances");
-        }
-        if (!constructorCopy.equals(jlaCopy)) {
-            throw new Error("Copy not equal");
-        }
-        if (0 != Objects.compare(constructorCopy, jlaCopy, Comparator.naturalOrder())) {
-            throw new Error("Copy not equal");
-        }
-
-        // The following is extremely "evil". Never ever do this in non-test code.
-        jlaChars[0] = 'X';
-        if (!"Xxemplar".equals(jlaCopy)) {
-            throw new Error("jla.newStringUnsafe did not use provided string");
-        }
-
-    }
-
-    public static void main(String[] args) {
-        testNewUnsafeString();
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/jdk/net/Sockets/ExtOptionTest.java	Wed Dec 06 11:39:23 2017 +0000
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+ /*
+ * @test
+ * @bug 8190843
+ * @summary can not set/get extendedOptions to ServerSocket
+ * @modules jdk.net
+ * @run main ExtOptionTest
+ */
+import java.io.IOException;
+import java.net.ServerSocket;
+
+import static jdk.net.ExtendedSocketOptions.TCP_QUICKACK;
+import static jdk.net.ExtendedSocketOptions.SO_FLOW_SLA;
+
+public class ExtOptionTest {
+
+    private static final String OS = "Linux";
+
+    public static void main(String args[]) throws IOException {
+        var operSys = System.getProperty("os.name");
+        try (ServerSocket ss = new ServerSocket(0)) {
+            // currently TCP_QUICKACK is available only on Linux.
+            if (operSys.equals(OS)) {
+                ss.setOption(TCP_QUICKACK, true);
+                if (!ss.getOption(TCP_QUICKACK)) {
+                    throw new RuntimeException("Test failed, TCP_QUICKACK should"
+                            + " have been set");
+                }
+            } else if (operSys.equals("SunOS")) {
+                if (ss.supportedOptions().contains(SO_FLOW_SLA)) {
+                    throw new RuntimeException("Test failed, SO_FLOW_SLA is not "
+                            + "applicable for ServerSocket");
+                }
+            } else {
+                if (ss.supportedOptions().contains(TCP_QUICKACK)) {
+                    ss.setOption(TCP_QUICKACK, true);
+                    if (!ss.getOption(TCP_QUICKACK)) {
+                        throw new RuntimeException("Test failed, TCP_QUICKACK should"
+                                + " have been set");
+                    }
+                }
+            }
+        }
+    }
+}
--- a/test/jdk/sun/security/tools/jarsigner/TimestampCheck.java	Thu Nov 30 22:05:19 2017 +0100
+++ b/test/jdk/sun/security/tools/jarsigner/TimestampCheck.java	Wed Dec 06 11:39:23 2017 +0000
@@ -694,11 +694,15 @@
         gencert("ts", "-ext eku:critical=ts");
 
 
-        // Issue another cert for "ts" with a different EKU.
-        // Length should be the same. Try several times.
-        keytool("-gencert -alias ca -infile ts.req -outfile ts2.cert " +
-                "-ext eku:critical=1.3.6.1.5.5.7.3.9");
         for (int i = 0; i < 5; i++) {
+            // Issue another cert for "ts" with a different EKU.
+            // Length might be different because serial number is
+            // random. Try several times until a cert with the same
+            // length is generated so we can substitute ts.cert
+            // embedded in the PKCS7 block with ts2.cert.
+            // If cannot create one, related test will be ignored.
+            keytool("-gencert -alias ca -infile ts.req -outfile ts2.cert " +
+                    "-ext eku:critical=1.3.6.1.5.5.7.3.9");
             if (Files.size(Paths.get("ts.cert")) != Files.size(Paths.get("ts2.cert"))) {
                 Files.delete(Paths.get("ts2.cert"));
                 System.out.println("Warning: cannot create same length");
--- a/test/langtools/jdk/jshell/CompilerOptionsTest.java	Thu Nov 30 22:05:19 2017 +0100
+++ b/test/langtools/jdk/jshell/CompilerOptionsTest.java	Wed Dec 06 11:39:23 2017 +0000
@@ -51,6 +51,6 @@
     public void testSourceVersion() {
         assertEval("import java.util.function.*;", added(VALID));
         assertDeclareFail("Function<Integer,Integer> f = x -> x*2;",
-                new ExpectedDiagnostic("compiler.err.lambda.not.supported.in.source", 32, 32, 32, -1, -1, Diagnostic.Kind.ERROR));
+                new ExpectedDiagnostic("compiler.err.feature.not.supported.in.source.plural", 32, 32, 32, -1, -1, Diagnostic.Kind.ERROR));
     }
 }
--- a/test/langtools/tools/javac/6302184/HiddenOptionsShouldUseGivenEncodingTest.java	Thu Nov 30 22:05:19 2017 +0100
+++ b/test/langtools/tools/javac/6302184/HiddenOptionsShouldUseGivenEncodingTest.java	Wed Dec 06 11:39:23 2017 +0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -29,28 +29,62 @@
  * @library /tools/lib
  * @modules jdk.compiler/com.sun.tools.javac.api
  *          jdk.compiler/com.sun.tools.javac.main
- * @build toolbox.ToolBox
- * @run compile -encoding iso-8859-1 -XD-printsource T6302184.java
+ * @build toolbox.ToolBox toolbox.JavacTask
  * @run main HiddenOptionsShouldUseGivenEncodingTest
  */
 
+import java.nio.charset.Charset;
+import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
+import java.util.Arrays;
 import java.util.List;
 
+import toolbox.JavacTask;
 import toolbox.ToolBox;
 
 // Original test: test/tools/javac/6302184/T6302184.sh
 public class HiddenOptionsShouldUseGivenEncodingTest {
 
     public static void main(String[] args) throws Exception {
+        String encoding = "iso-8859-1";
+        Path src = Paths.get("src");
+        Files.createDirectories(src);
+        Files.write(src.resolve("T6302184.java"), source, Charset.forName(encoding));
+        Files.write(src.resolve("T6302184.out"), expect, Charset.forName(encoding));
+
+        Path out = Paths.get("out");
+        Files.createDirectories(out);
+
         ToolBox tb = new ToolBox();
-        String encoding = "iso-8859-1";
-        Path path1 = Paths.get(ToolBox.testClasses, "T6302184.java");
+        new JavacTask(tb)
+                .outdir("out")
+                .options("-encoding", encoding, "-XD-printsource")
+                .files(src.resolve("T6302184.java"))
+                .run();
+
+        Path path1 = Paths.get("out").resolve("T6302184.java");
         List<String> file1 = tb.readAllLines(path1, encoding);
-        Path path2 = Paths.get(ToolBox.testSrc, "T6302184.out");
+        Path path2 = src.resolve("T6302184.out");
         List<String> file2 = tb.readAllLines(path2, encoding);
         tb.checkEqual(file1, file2);
     }
 
+    static List<String> source = Arrays.asList(
+        "class T6302184 {",
+        "    int \u00c0\u00c1\u00c2\u00c3\u00c4\u00c5 = 1;",
+        "}"
+    );
+
+    static List<String> expect = A