--- old/./.hgtags 2019-05-21 01:00:54.065195697 +0200 +++ new/./.hgtags 2019-05-21 01:00:53.901195990 +0200 @@ -553,4 +553,3 @@ 83cace4142c8563b6a921787db02388e1bc48d01 jdk-13+13 46cf212cdccaf4fb064d913b12004007d3322b67 jdk-13+14 f855ec13aa2501ae184c8b3e0626a8cec9966116 jdk-13+15 -9d0ae9508d5337b0dc7cc4684be42888c4023755 jdk-13+16 --- old/doc/testing.html 2019-05-21 01:00:54.261195345 +0200 +++ new/doc/testing.html 2019-05-21 01:00:54.109195618 +0200 @@ -1,24 +1,19 @@ - + - - - + + + Testing the JDK - - + + -
+

Testing the JDK

Using "make test" (the run-test framework)

@@ -188,11 +180,5 @@

Additional VM arguments to provide to forked off VMs. Same as -jvmArgs <args>

OPTIONS

Additional arguments to send to JMH.

-

Notes for Specific Tests

-

Docker Tests

-

Docker tests with default parameters may fail on systems with glibc versions not compatible with the one used in the default docker image (e.g., Oracle Linux 7.6 for x86). For example, they pass on Ubuntu 16.04 but fail on Ubuntu 18.04 if run like this on x86:

-
$ make test TEST="jtreg:test/hotspot/jtreg/containers/docker"
-

To run these tests correctly, additional parameters for the correct docker image are required on Ubuntu 18.04 by using JAVA_OPTIONS.

-
$ make test TEST="jtreg:test/hotspot/jtreg/containers/docker" JTREG="JAVA_OPTIONS=-Djdk.test.docker.image.name=ubuntu -Djdk.test.docker.image.version=latest"
--- old/doc/testing.md 2019-05-21 01:00:54.449195006 +0200 +++ new/doc/testing.md 2019-05-21 01:00:54.305195266 +0200 @@ -373,21 +373,6 @@ #### OPTIONS Additional arguments to send to JMH. -## Notes for Specific Tests - -### Docker Tests - -Docker tests with default parameters may fail on systems with glibc versions not -compatible with the one used in the default docker image (e.g., Oracle Linux 7.6 for x86). -For example, they pass on Ubuntu 16.04 but fail on Ubuntu 18.04 if run like this on x86: - - $ make test TEST="jtreg:test/hotspot/jtreg/containers/docker" - -To run these tests correctly, additional parameters for the correct docker image are -required on Ubuntu 18.04 by using `JAVA_OPTIONS`. - - $ make test TEST="jtreg:test/hotspot/jtreg/containers/docker" JTREG="JAVA_OPTIONS=-Djdk.test.docker.image.name=ubuntu -Djdk.test.docker.image.version=latest" - --- # Override some definitions in the global css file that are not optimal for # this document. --- old/make/CompileJavaModules.gmk 2019-05-21 01:00:54.629194685 +0200 +++ new/make/CompileJavaModules.gmk 2019-05-21 01:00:54.489194935 +0200 @@ -38,7 +38,7 @@ ################################################################################ # Module specific build settings -java.base_ADD_JAVAC_FLAGS += -Xdoclint:all/protected,-reference,-accessibility '-Xdoclint/package:java.*,javax.*' -XDstringConcat=inline +java.base_ADD_JAVAC_FLAGS += -Xdoclint:all/protected,-reference,-accessibility '-Xdoclint/package:java.*,javax.*' -XDstringConcat=inline -XDfolding=false -XDforNonCapturingLambda=generateIndy java.base_COPY += .icu .dat .spp content-types.properties hijrah-config-islamic-umalqura.properties java.base_CLEAN += intrinsic.properties @@ -256,7 +256,7 @@ ################################################################################ -java.rmi_ADD_JAVAC_FLAGS += -Xdoclint:all/protected '-Xdoclint/package:java.*,javax.*' +java.rmi_ADD_JAVAC_FLAGS += -Xdoclint:all/protected '-Xdoclint/package:java.*,javax.*' -XDforNonCapturingLambda=generateIndy java.rmi_CLEAN_FILES += $(wildcard \ $(TOPDIR)/src/java.rmi/share/classes/sun/rmi/registry/resources/*.properties \ $(TOPDIR)/src/java.rmi/share/classes/sun/rmi/server/resources/*.properties) --- old/make/Coverage.gmk 2019-05-21 01:00:54.817194348 +0200 +++ new/make/Coverage.gmk 2019-05-21 01:00:54.669194613 +0200 @@ -49,7 +49,6 @@ -exclude 'java.lang.Object' \ -exclude 'jdk.internal.org.objectweb.**' \ -exclude jdk.test.Main -exclude '**\$Proxy*' \ - $(JCOV_FILTERS) \ $(JCOV_TEMP)/$(JCOV_IMAGE_SUBDIR) $(MV) $(JCOV_TEMP)/$(JCOV_IMAGE_SUBDIR) $(JCOV_IMAGE_DIR) $(RMDIR) $(JCOV_TEMP) --- old/make/Init.gmk 2019-05-21 01:00:55.001194017 +0200 +++ new/make/Init.gmk 2019-05-21 01:00:54.857194275 +0200 @@ -279,7 +279,7 @@ else $(ECHO) "Re-running configure using default settings" endif - ( cd $(CONFIGURE_START_DIR) && PATH="$(ORIGINAL_PATH)" AUTOCONF="$(AUTOCONF)" \ + ( cd $(OUTPUTDIR) && PATH="$(ORIGINAL_PATH)" AUTOCONF="$(AUTOCONF)" \ CUSTOM_ROOT="$(CUSTOM_ROOT)" \ CUSTOM_CONFIG_DIR="$(CUSTOM_CONFIG_DIR)" \ $(BASH) $(TOPDIR)/configure $(CONFIGURE_COMMAND_LINE) ) --- old/make/Main.gmk 2019-05-21 01:00:55.189193681 +0200 +++ new/make/Main.gmk 2019-05-21 01:00:55.037193954 +0200 @@ -335,7 +335,6 @@ bootcycle-images: ifneq ($(COMPILE_TYPE), cross) $(call LogWarn, Boot cycle build step 2: Building a new JDK image using previously built image) - $(call MakeDir, $(OUTPUTDIR)/bootcycle-build) +$(MAKE) $(MAKE_ARGS) -f $(TOPDIR)/make/Init.gmk PARALLEL_TARGETS=$(BOOTCYCLE_TARGET) \ JOBS= SPEC=$(dir $(SPEC))bootcycle-spec.gmk main else --- old/make/RunTests.gmk 2019-05-21 01:00:55.401193301 +0200 +++ new/make/RunTests.gmk 2019-05-21 01:00:55.241193587 +0200 @@ -1194,18 +1194,10 @@ $(call LogWarn, Stopping JCov Grabber...) $(JAVA) -jar $(JCOV_HOME)/lib/jcov.jar GrabberManager -stop -stoptimeout 3600 - JCOV_REPORT_TITLE := JDK code coverage report
- ifneq ($(JCOV_FILTERS), ) - JCOV_REPORT_TITLE += Code filters: $(JCOV_FILTERS)
- endif - JCOV_REPORT_TITLE += Tests: $(TEST) - jcov-gen-report: jcov-stop-grabber $(call LogWarn, Generating JCov report ...) $(JAVA) -Xmx4g -jar $(JCOV_HOME)/lib/jcov.jar RepGen -sourcepath \ `$(ECHO) $(TOPDIR)/src/*/share/classes/ | $(TR) ' ' ':'` -fmt html \ - $(JCOV_FILTERS) \ - -mainReportTitle "$(JCOV_REPORT_TITLE)" \ -o $(JCOV_REPORT) $(JCOV_RESULT_FILE) TARGETS += jcov-do-start-grabber jcov-start-grabber jcov-stop-grabber \ --- old/make/autoconf/basics.m4 2019-05-21 01:00:55.597192949 +0200 +++ new/make/autoconf/basics.m4 2019-05-21 01:00:55.449193215 +0200 @@ -627,7 +627,7 @@ AC_DEFUN_ONCE([BASIC_SETUP_PATHS], [ # Save the current directory this script was started from - CONFIGURE_START_DIR="$PWD" + CURDIR="$PWD" # We might need to rewrite ORIGINAL_PATH, if it includes "#", to quote them # for make. We couldn't do this when we retrieved ORIGINAL_PATH, since SED @@ -653,10 +653,9 @@ AC_MSG_CHECKING([for top-level directory]) AC_MSG_RESULT([$TOPDIR]) AC_SUBST(TOPDIR) - AC_SUBST(CONFIGURE_START_DIR) # We can only call BASIC_FIXUP_PATH after BASIC_CHECK_PATHS_WINDOWS. - BASIC_FIXUP_PATH(CONFIGURE_START_DIR) + BASIC_FIXUP_PATH(CURDIR) BASIC_FIXUP_PATH(TOPDIR) # Locate the directory of this script. @@ -869,10 +868,9 @@ # Test from where we are running configure, in or outside of src root. AC_MSG_CHECKING([where to store configuration]) - if test "x$CONFIGURE_START_DIR" = "x$TOPDIR" \ - || test "x$CONFIGURE_START_DIR" = "x$CUSTOM_ROOT" \ - || test "x$CONFIGURE_START_DIR" = "x$TOPDIR/make/autoconf" \ - || test "x$CONFIGURE_START_DIR" = "x$TOPDIR/make" ; then + if test "x$CURDIR" = "x$TOPDIR" || test "x$CURDIR" = "x$CUSTOM_ROOT" \ + || test "x$CURDIR" = "x$TOPDIR/make/autoconf" \ + || test "x$CURDIR" = "x$TOPDIR/make" ; then # We are running configure from the src root. # Create a default ./build/target-variant-debuglevel output root. if test "x${CONF_NAME}" = x; then @@ -883,11 +881,10 @@ fi if test "x$CUSTOM_ROOT" != x; then - WORKSPACE_ROOT="${CUSTOM_ROOT}" + OUTPUTDIR="${CUSTOM_ROOT}/build/${CONF_NAME}" else - WORKSPACE_ROOT="${TOPDIR}" + OUTPUTDIR="${TOPDIR}/build/${CONF_NAME}" fi - OUTPUTDIR="${WORKSPACE_ROOT}/build/${CONF_NAME}" $MKDIR -p "$OUTPUTDIR" if test ! -d "$OUTPUTDIR"; then AC_MSG_ERROR([Could not create build directory $OUTPUTDIR]) @@ -898,9 +895,9 @@ # If configuration is situated in normal build directory, just use the build # directory name as configuration name, otherwise use the complete path. if test "x${CONF_NAME}" = x; then - CONF_NAME=`$ECHO $CONFIGURE_START_DIR | $SED -e "s!^${TOPDIR}/build/!!"` + CONF_NAME=`$ECHO $CURDIR | $SED -e "s!^${TOPDIR}/build/!!"` fi - OUTPUTDIR="$CONFIGURE_START_DIR" + OUTPUTDIR="$CURDIR" AC_MSG_RESULT([in current directory]) # WARNING: This might be a bad thing to do. You need to be sure you want to @@ -920,14 +917,14 @@ -e 's/ //g' \ | $TR -d '\n'` if test "x$filtered_files" != x; then - AC_MSG_NOTICE([Current directory is $CONFIGURE_START_DIR.]) + AC_MSG_NOTICE([Current directory is $CURDIR.]) AC_MSG_NOTICE([Since this is not the source root, configure will output the configuration here]) AC_MSG_NOTICE([(as opposed to creating a configuration in /build/).]) AC_MSG_NOTICE([However, this directory is not empty. This is not allowed, since it could]) AC_MSG_NOTICE([seriously mess up just about everything.]) AC_MSG_NOTICE([Try 'cd $TOPDIR' and restart configure]) AC_MSG_NOTICE([(or create a new empty directory and cd to it).]) - AC_MSG_ERROR([Will not continue creating configuration in $CONFIGURE_START_DIR]) + AC_MSG_ERROR([Will not continue creating configuration in $CURDIR]) fi fi fi @@ -943,7 +940,6 @@ AC_SUBST(SPEC) AC_SUBST(CONF_NAME) AC_SUBST(OUTPUTDIR) - AC_SUBST(WORKSPACE_ROOT) AC_SUBST(CONFIGURESUPPORT_OUTPUTDIR) # The spec.gmk file contains all variables for the make system. --- old/make/autoconf/basics_windows.m4 2019-05-21 01:00:55.789192605 +0200 +++ new/make/autoconf/basics_windows.m4 2019-05-21 01:00:55.645192863 +0200 @@ -551,7 +551,7 @@ $MKDIR -p $FIXPATH_DIR $CONFIGURESUPPORT_OUTPUTDIR/bin cd $FIXPATH_DIR $CC $FIXPATH_SRC_W -Fe$FIXPATH_BIN_W > $FIXPATH_DIR/fixpath1.log 2>&1 - cd $CONFIGURE_START_DIR + cd $CURDIR if test ! -x $FIXPATH_BIN; then AC_MSG_RESULT([no]) @@ -574,7 +574,7 @@ cd $FIXPATH_DIR $FIXPATH $CC $FIXPATH_SRC -Fe$FIXPATH_DIR/fixpath2.exe \ > $FIXPATH_DIR/fixpath2.log 2>&1 - cd $CONFIGURE_START_DIR + cd $CURDIR if test ! -x $FIXPATH_DIR/fixpath2.exe; then AC_MSG_RESULT([no]) cat $FIXPATH_DIR/fixpath2.log --- old/make/autoconf/flags-cflags.m4 2019-05-21 01:00:55.977192269 +0200 +++ new/make/autoconf/flags-cflags.m4 2019-05-21 01:00:55.833192526 +0200 @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -799,29 +799,15 @@ $1_WARNING_CFLAGS_JVM="-Wno-format-zero-length -Wtype-limits -Wuninitialized" fi - if test "x$TOOLCHAIN_TYPE" = xgcc || test "x$TOOLCHAIN_TYPE" = xclang; then - # Check if compiler supports -fmacro-prefix-map. If so, use that to make - # the __FILE__ macro resolve to paths relative to the workspace root. - workspace_root_trailing_slash="${WORKSPACE_ROOT%/}/" - FILE_MACRO_CFLAGS="-fmacro-prefix-map=${workspace_root_trailing_slash}=" - FLAGS_COMPILER_CHECK_ARGUMENTS(ARGUMENT: [${FILE_MACRO_CFLAGS}], - PREFIX: $3, - IF_FALSE: [ - FILE_MACRO_CFLAGS= - ] - ) - fi - # EXPORT to API CFLAGS_JVM_COMMON="$ALWAYS_CFLAGS_JVM $ALWAYS_DEFINES_JVM \ $TOOLCHAIN_CFLAGS_JVM ${$1_TOOLCHAIN_CFLAGS_JVM} \ $OS_CFLAGS $OS_CFLAGS_JVM $CFLAGS_OS_DEF_JVM $DEBUG_CFLAGS_JVM \ - $WARNING_CFLAGS $WARNING_CFLAGS_JVM $JVM_PICFLAG $FILE_MACRO_CFLAGS" + $WARNING_CFLAGS $WARNING_CFLAGS_JVM $JVM_PICFLAG" CFLAGS_JDK_COMMON="$ALWAYS_CFLAGS_JDK $ALWAYS_DEFINES_JDK $TOOLCHAIN_CFLAGS_JDK \ $OS_CFLAGS $CFLAGS_OS_DEF_JDK $DEBUG_CFLAGS_JDK $DEBUG_OPTIONS_FLAGS_JDK \ - $WARNING_CFLAGS $WARNING_CFLAGS_JDK $DEBUG_SYMBOLS_CFLAGS_JDK \ - $FILE_MACRO_CFLAGS" + $WARNING_CFLAGS $WARNING_CFLAGS_JDK $DEBUG_SYMBOLS_CFLAGS_JDK" # Use ${$2EXTRA_CFLAGS} to block EXTRA_CFLAGS to be added to build flags. # (Currently we don't have any OPENJDK_BUILD_EXTRA_CFLAGS, but that might --- old/make/autoconf/flags-other.m4 2019-05-21 01:00:56.173191917 +0200 +++ new/make/autoconf/flags-other.m4 2019-05-21 01:00:56.021192190 +0200 @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -81,21 +81,21 @@ RC_FLAGS="$RC_FLAGS \ -D\"JDK_VERSION_STRING=\$(VERSION_STRING)\" \ -D\"JDK_COMPANY=\$(COMPANY_NAME)\" \ - -D\"JDK_FILEDESC=\$(JDK_RC_NAME) binary\" \ + -D\"JDK_COMPONENT=\$(PRODUCT_NAME) \$(JDK_RC_PLATFORM_NAME) binary\" \ -D\"JDK_VER=\$(VERSION_NUMBER)\" \ -D\"JDK_COPYRIGHT=Copyright \xA9 $COPYRIGHT_YEAR\" \ - -D\"JDK_NAME=\$(JDK_RC_NAME) \$(VERSION_FEATURE)\" \ + -D\"JDK_NAME=\$(PRODUCT_NAME) \$(JDK_RC_PLATFORM_NAME) \$(VERSION_FEATURE)\" \ -D\"JDK_FVER=\$(subst .,\$(COMMA),\$(VERSION_NUMBER_FOUR_POSITIONS))\"" JVM_RCFLAGS="$JVM_RCFLAGS \ - -D\"HS_VERSION_STRING=\$(VERSION_STRING)\" \ + -D\"HS_BUILD_ID=\$(VERSION_STRING)\" \ -D\"HS_COMPANY=\$(COMPANY_NAME)\" \ - -D\"HS_VER=\$(VERSION_NUMBER_FOUR_POSITIONS)\" \ - -D\"HS_INTERNAL_NAME=jvm\" \ + -D\"JDK_DOTVER=\$(VERSION_NUMBER_FOUR_POSITIONS)\" \ -D\"HS_COPYRIGHT=Copyright $COPYRIGHT_YEAR\" \ - -D\"HS_FNAME=jvm.dll\" \ -D\"HS_NAME=\$(PRODUCT_NAME) \$(VERSION_SHORT)\" \ - -D\"HS_FVER=\$(subst .,\$(COMMA),\$(VERSION_NUMBER_FOUR_POSITIONS))\"" + -D\"JDK_VER=\$(subst .,\$(COMMA),\$(VERSION_NUMBER_FOUR_POSITIONS))\" \ + -D\"HS_FNAME=jvm.dll\" \ + -D\"HS_INTERNAL_NAME=jvm\"" fi AC_SUBST(RC_FLAGS) AC_SUBST(JVM_RCFLAGS) --- old/make/autoconf/jdk-options.m4 2019-05-21 01:00:56.361191579 +0200 +++ new/make/autoconf/jdk-options.m4 2019-05-21 01:00:56.213191846 +0200 @@ -404,12 +404,9 @@ [jcov library location])]) AC_ARG_WITH(jcov-input-jdk, [AS_HELP_STRING([--with-jcov-input-jdk], [jdk image to instrument])]) - AC_ARG_WITH(jcov-filters, [AS_HELP_STRING([--with-jcov-filters], - [filters to limit code for jcov instrumentation and report generation])]) JCOV_HOME= JCOV_INPUT_JDK= JCOV_ENABLED= - JCOV_FILTERS= if test "x$with_jcov" = "x" ; then JCOV_ENABLED="false" else @@ -428,14 +425,10 @@ fi BASIC_FIXUP_PATH(JCOV_INPUT_JDK) fi - if test "x$with_jcov_filters" != "x" ; then - JCOV_FILTERS="$with_jcov_filters" - fi fi AC_SUBST(JCOV_ENABLED) AC_SUBST(JCOV_HOME) AC_SUBST(JCOV_INPUT_JDK) - AC_SUBST(JCOV_FILTERS) ]) ############################################################################### --- old/make/autoconf/jdk-version.m4 2019-05-21 01:00:56.549191242 +0200 +++ new/make/autoconf/jdk-version.m4 2019-05-21 01:00:56.405191500 +0200 @@ -1,5 +1,5 @@ # -# Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -66,52 +66,9 @@ AC_SUBST(PRODUCT_SUFFIX) AC_SUBST(JDK_RC_PLATFORM_NAME) AC_SUBST(HOTSPOT_VM_DISTRO) - - # Set the MACOSX Bundle Name base - AC_ARG_WITH(macosx-bundle-name-base, [AS_HELP_STRING([--with-macosx-bundle-name-base], - [Set the MacOSX Bundle Name base. This is the base name for calculating MacOSX Bundle Names. - @<:@not specified@:>@])]) - if test "x$with_macosx_bundle_name_base" = xyes; then - AC_MSG_ERROR([--with-macosx-bundle-name-base must have a value]) - elif [ ! [[ $with_macosx_bundle_name_base =~ ^[[:print:]]*$ ]] ]; then - AC_MSG_ERROR([--with-macosx-bundle-name-base contains non-printing characters: $with_macosx_bundle_name_base]) - elif test "x$with_macosx_bundle_name_base" != x; then - # Set MACOSX_BUNDLE_NAME_BASE to the configured value. - MACOSX_BUNDLE_NAME_BASE="$with_macosx_bundle_name_base" - fi AC_SUBST(MACOSX_BUNDLE_NAME_BASE) - - # Set the MACOSX Bundle ID base - AC_ARG_WITH(macosx-bundle-id-base, [AS_HELP_STRING([--with-macosx-bundle-id-base], - [Set the MacOSX Bundle ID base. This is the base ID for calculating MacOSX Bundle IDs. - @<:@not specified@:>@])]) - if test "x$with_macosx_bundle_id_base" = xyes; then - AC_MSG_ERROR([--with-macosx-bundle-id-base must have a value]) - elif [ ! [[ $with_macosx_bundle_id_base =~ ^[[:print:]]*$ ]] ]; then - AC_MSG_ERROR([--with-macosx-bundle-id-base contains non-printing characters: $with_macosx_bundle_id_base]) - elif test "x$with_macosx_bundle_id_base" != x; then - # Set MACOSX_BUNDLE_ID_BASE to the configured value. - MACOSX_BUNDLE_ID_BASE="$with_macosx_bundle_id_base" - fi AC_SUBST(MACOSX_BUNDLE_ID_BASE) - # Set the JDK RC name - AC_ARG_WITH(jdk-rc-name, [AS_HELP_STRING([--with-jdk-rc-name], - [Set JDK RC name. This is used for FileDescription and ProductName properties - of MS Windows binaries. @<:@not specified@:>@])]) - if test "x$with_jdk_rc_name" = xyes; then - AC_MSG_ERROR([--with-jdk-rc-name must have a value]) - elif [ ! [[ $with_jdk_rc_name =~ ^[[:print:]]*$ ]] ]; then - AC_MSG_ERROR([--with-jdk-rc-name contains non-printing characters: $with_jdk_rc_name]) - elif test "x$with_jdk_rc_name" != x; then - # Set JDK_RC_NAME to a custom value if '--with-jdk-rc-name' was used and is not empty. - JDK_RC_NAME="$with_jdk_rc_name" - else - # Otherwise calculate from "version-numbers" included above. - JDK_RC_NAME="$PRODUCT_NAME $JDK_RC_PLATFORM_NAME" - fi - AC_SUBST(JDK_RC_NAME) - # The vendor name, if any AC_ARG_WITH(vendor-name, [AS_HELP_STRING([--with-vendor-name], [Set vendor name. Among others, used to set the 'java.vendor' --- old/make/autoconf/spec.gmk.in 2019-05-21 01:00:56.741190898 +0200 +++ new/make/autoconf/spec.gmk.in 2019-05-21 01:00:56.593191163 +0200 @@ -32,8 +32,6 @@ # The command line given to configure. CONFIGURE_COMMAND_LINE:=@CONFIGURE_COMMAND_LINE@ -# The current directory when configure was run -CONFIGURE_START_DIR:=@CONFIGURE_START_DIR@ # A self-referential reference to this file. SPEC:=@SPEC@ @@ -140,9 +138,8 @@ # The top-level directory of the source repository TOPDIR:=@TOPDIR@ -# Usually the top level directory, but could be something else if a custom -# root is defined. -WORKSPACE_ROOT:=@WORKSPACE_ROOT@ + + IMPORT_MODULES_CLASSES:=@IMPORT_MODULES_CLASSES@ IMPORT_MODULES_CMDS:=@IMPORT_MODULES_CMDS@ IMPORT_MODULES_LIBS:=@IMPORT_MODULES_LIBS@ @@ -159,7 +156,6 @@ PRODUCT_NAME:=@PRODUCT_NAME@ PRODUCT_SUFFIX:=@PRODUCT_SUFFIX@ JDK_RC_PLATFORM_NAME:=@JDK_RC_PLATFORM_NAME@ -JDK_RC_NAME:=@JDK_RC_NAME@ COMPANY_NAME:=@COMPANY_NAME@ HOTSPOT_VM_DISTRO:=@HOTSPOT_VM_DISTRO@ MACOSX_BUNDLE_NAME_BASE=@MACOSX_BUNDLE_NAME_BASE@ @@ -389,7 +385,6 @@ JCOV_ENABLED=@JCOV_ENABLED@ JCOV_HOME=@JCOV_HOME@ JCOV_INPUT_JDK=@JCOV_INPUT_JDK@ -JCOV_FILTERS=@JCOV_FILTERS@ # AddressSanitizer export ASAN_ENABLED:=@ASAN_ENABLED@ --- old/make/autoconf/toolchain_windows.m4 2019-05-21 01:00:56.933190554 +0200 +++ new/make/autoconf/toolchain_windows.m4 2019-05-21 01:00:56.789190812 +0200 @@ -472,7 +472,7 @@ # Change directory so we don't need to mess with Windows paths in redirects. cd $VS_ENV_TMP_DIR $CMD /c extract-vs-env.bat | $CAT - cd $CONFIGURE_START_DIR + cd $CURDIR if test ! -s $VS_ENV_TMP_DIR/set-vs-env.sh; then AC_MSG_NOTICE([Could not succesfully extract the environment variables needed for the VS setup.]) --- old/make/common/JavaCompilation.gmk 2019-05-21 01:00:57.117190225 +0200 +++ new/make/common/JavaCompilation.gmk 2019-05-21 01:00:56.977190475 +0200 @@ -197,6 +197,7 @@ ifneq ($$($1_DEBUG_SYMBOLS), false) $1_FLAGS := -g endif + # remove this option once ASM knows how to deal with condy $1_FLAGS += $$($$($1_SETUP)_FLAGS) $$($1_ADD_JAVAC_FLAGS) $(JAVAC_FLAGS) ifneq ($$($1_CLASSPATH), ) $1_FLAGS += -cp $$(call PathList, $$($1_CLASSPATH)) --- old/make/common/NativeCompilation.gmk 2019-05-21 01:00:57.305189886 +0200 +++ new/make/common/NativeCompilation.gmk 2019-05-21 01:00:57.161190146 +0200 @@ -236,10 +236,8 @@ # This is the definite source file to use for $1_FILENAME. $1_SRC_FILE := $$($1_FILE) - ifneq ($$($1_DEFINE_THIS_FILE), false) - ifneq ($$($$($1_BASE)_DEFINE_THIS_FILE), false) - $1_THIS_FILE = -DTHIS_FILE='"$$($1_FILENAME)"' - endif + ifneq ($$($1_DISABLE_THIS_FILE_DEFINE), true) + $1_THIS_FILE = -DTHIS_FILE='"$$($1_FILENAME)"' endif ifeq ($$($1_OPTIMIZATION), ) @@ -372,7 +370,6 @@ $(ECHO) $$@: \\ > $$($1_DEPS_FILE) ; \ $(SED) $(WINDOWS_SHOWINCLUDE_SED_PATTERN) $$($1_OBJ).log \ | $(SORT) -u >> $$($1_DEPS_FILE) ; \ - $(ECHO) >> $$($1_DEPS_FILE) ; \ $(SED) $(DEPENDENCY_TARGET_SED_PATTERN) $$($1_DEPS_FILE) > $$($1_DEPS_TARGETS_FILE) endif endif @@ -429,7 +426,6 @@ # STRIPFLAGS Optionally change the flags given to the strip command # PRECOMPILED_HEADER Header file to use as precompiled header # PRECOMPILED_HEADER_EXCLUDE List of source files that should not use PCH -# DEFINE_THIS_FILE Set to false to not set the THIS_FILE preprocessor macro # # After being called, some variables are exported from this macro, all prefixed # with parameter 1 followed by a '_': @@ -707,7 +703,7 @@ FILE := $$($1_GENERATED_PCH_SRC), \ BASE := $1, \ EXTRA_CXXFLAGS := -Fp$$($1_PCH_FILE) -Yc$$(notdir $$($1_PRECOMPILED_HEADER)), \ - DEFINE_THIS_FILE := false, \ + DISABLE_THIS_FILE_DEFINE := true, \ )) $1_USE_PCH_FLAGS := \ @@ -844,7 +840,6 @@ $(ECHO) $$($1_RES): \\ > $$($1_RES_DEPS_FILE) ; \ $(SED) $(WINDOWS_SHOWINCLUDE_SED_PATTERN) $$($1_RES_DEPS_FILE).obj.log \ >> $$($1_RES_DEPS_FILE) ; \ - $(ECHO) >> $$($1_RES_DEPS_FILE) ;\ $(SED) $(DEPENDENCY_TARGET_SED_PATTERN) $$($1_RES_DEPS_FILE) \ > $$($1_RES_DEPS_TARGETS_FILE) endif --- old/make/hotspot/gensrc/GensrcAdlc.gmk 2019-05-21 01:00:57.501189535 +0200 +++ new/make/hotspot/gensrc/GensrcAdlc.gmk 2019-05-21 01:00:57.361189787 +0200 @@ -76,7 +76,6 @@ DEBUG_SYMBOLS := false, \ DISABLED_WARNINGS_clang := tautological-compare, \ DISABLED_WARNINGS_solstudio := notemsource, \ - DEFINE_THIS_FILE := false, \ )) ADLC_TOOL := $(BUILD_ADLC_TARGET) --- old/make/hotspot/gensrc/GensrcDtrace.gmk 2019-05-21 01:00:57.685189206 +0200 +++ new/make/hotspot/gensrc/GensrcDtrace.gmk 2019-05-21 01:00:57.537189471 +0200 @@ -80,7 +80,6 @@ EXTRA_DEPS := $(JVMTI_H) $(JFR_FILES), \ OBJECT_DIR := $(JVM_VARIANT_OUTPUTDIR)/tools/dtrace-gen-offsets/objs, \ OUTPUT_DIR := $(JVM_VARIANT_OUTPUTDIR)/tools/dtrace-gen-offsets, \ - DEFINE_THIS_FILE := false, \ )) DTRACE_GEN_OFFSETS_TOOL := $(BUILD_DTRACE_GEN_OFFSETS_TARGET) --- old/make/hotspot/lib/CompileDtraceLibraries.gmk 2019-05-21 01:00:57.865188882 +0200 +++ new/make/hotspot/lib/CompileDtraceLibraries.gmk 2019-05-21 01:00:57.721189142 +0200 @@ -42,7 +42,6 @@ LDFLAGS := -m64 -mt -xnolib $(SHARED_LIBRARY_FLAGS), \ LIBS := $(LIBDL) -lthread -ldoor, \ OBJECT_DIR := $(LIBJVM_DTRACE_OUTPUTDIR)/objs, \ - DEFINE_THIS_FILE := false, \ )) # Note that libjvm_db.c has tests for COMPILER2, but this was never set by @@ -55,7 +54,6 @@ CFLAGS := -I$(DTRACE_GENSRC_DIR) $(JNI_INCLUDE_FLAGS) -m64 -G -mt -KPIC -xldscope=hidden, \ LDFLAGS := -m64 -mt -xnolib $(SHARED_LIBRARY_FLAGS), \ OBJECT_DIR := $(LIBJVM_DB_OUTPUTDIR)/objs, \ - DEFINE_THIS_FILE := false, \ )) TARGETS += $(BUILD_LIBJVM_DTRACE) $(BUILD_LIBJVM_DB) --- old/make/hotspot/lib/CompileGtest.gmk 2019-05-21 01:00:58.041188569 +0200 +++ new/make/hotspot/lib/CompileGtest.gmk 2019-05-21 01:00:57.901188819 +0200 @@ -92,7 +92,6 @@ STRIP_SYMBOLS := false, \ PRECOMPILED_HEADER := $(JVM_PRECOMPILED_HEADER), \ PRECOMPILED_HEADER_EXCLUDE := gtest-all.cc gtestMain.cpp, \ - DEFINE_THIS_FILE := false, \ )) TARGETS += $(BUILD_GTEST_LIBJVM) @@ -116,7 +115,6 @@ LIBS_windows := $(JVM_OUTPUTDIR)/gtest/objs/jvm.lib, \ COPY_DEBUG_SYMBOLS := $(GTEST_COPY_DEBUG_SYMBOLS), \ ZIP_EXTERNAL_DEBUG_SYMBOLS := false, \ - DEFINE_THIS_FILE := false, \ )) $(BUILD_GTEST_LAUNCHER): $(BUILD_GTEST_LIBJVM) --- old/make/hotspot/lib/CompileJvm.gmk 2019-05-21 01:00:58.221188245 +0200 +++ new/make/hotspot/lib/CompileJvm.gmk 2019-05-21 01:00:58.077188503 +0200 @@ -202,7 +202,6 @@ VERSIONINFO_RESOURCE := $(TOPDIR)/src/hotspot/os/windows/version.rc, \ PRECOMPILED_HEADER := $(JVM_PRECOMPILED_HEADER), \ PRECOMPILED_HEADER_EXCLUDE := $(JVM_PRECOMPILED_HEADER_EXCLUDE), \ - DEFINE_THIS_FILE := false, \ )) # Always recompile vm_version.cpp if libjvm needs to be relinked. This ensures --- old/make/jdk/src/classes/build/tools/classlist/HelloClasslist.java 2019-05-21 01:00:58.413187901 +0200 +++ new/make/jdk/src/classes/build/tools/classlist/HelloClasslist.java 2019-05-21 01:00:58.265188166 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -59,32 +59,24 @@ List strings = Arrays.asList("Hello", "World!", "From: ", InetAddress.getLoopbackAddress().toString()); - String helloWorld = strings.parallelStream() + String helloWorld = ""; + /* + strings.parallelStream() .map(s -> s.toLowerCase(Locale.ROOT)) .collect(joining(",")); + */ Stream.of(helloWorld.split(",")) .forEach(System.out::println); // Common concatenation patterns - String SS = String.valueOf(args.length) + String.valueOf(args.length); - String CS = "string" + String.valueOf(args.length); - String SC = String.valueOf(args.length) + "string"; - String SCS = String.valueOf(args.length) + "string" + String.valueOf(args.length); - String CSS = "string" + String.valueOf(args.length) + String.valueOf(args.length); - String CSCS = "string" + String.valueOf(args.length) + "string" + String.valueOf(args.length); - String SCSC = String.valueOf(args.length) + "string" + String.valueOf(args.length) + "string"; - String CSCSC = "string" + String.valueOf(args.length) + "string" + String.valueOf(args.length) + "string"; - String SCSCS = String.valueOf(args.length) + "string" + String.valueOf(args.length) + "string" + String.valueOf(args.length); - String CI = "string" + args.length; - String IC = args.length + "string"; - String CIC = "string" + args.length + "string"; - String CICI = "string" + args.length + "string" + args.length; - String CJ = "string" + System.currentTimeMillis(); - String JC = System.currentTimeMillis() + "string"; - String CJC = "string" + System.currentTimeMillis() + "string"; - String CJCJ = "string" + System.currentTimeMillis() + "string" + System.currentTimeMillis(); - String CJCJC = "string" + System.currentTimeMillis() + "string" + System.currentTimeMillis() + "string"; + String const_I = "string" + args.length; + String const_S = "string" + String.valueOf(args.length); + String S_const = String.valueOf(args.length) + "string"; + String S_S = String.valueOf(args.length) + String.valueOf(args.length); + String const_J = "string" + System.currentTimeMillis(); + String I_const = args.length + "string"; + String J_const = System.currentTimeMillis() + "string"; String newDate = DateTimeFormatter.ISO_LOCAL_DATE_TIME.format( LocalDateTime.now(ZoneId.of("GMT"))); --- old/make/launcher/Launcher-java.base.gmk 2019-05-21 01:00:58.597187570 +0200 +++ new/make/launcher/Launcher-java.base.gmk 2019-05-21 01:00:58.449187837 +0200 @@ -39,6 +39,7 @@ # overwritten. $(eval $(call SetupBuildLauncher, java, \ CFLAGS := -DEXPAND_CLASSPATH_WILDCARDS -DENABLE_ARG_FILES, \ + LDFLAGS_solaris := -R$(OPENWIN_HOME)/lib$(OPENJDK_TARGET_CPU_ISADIR), \ EXTRA_RC_FLAGS := $(JAVA_RC_FLAGS), \ VERSION_INFO_RESOURCE := $(JAVA_VERSION_INFO_RESOURCE), \ OUTPUT_DIR := $(SUPPORT_OUTPUTDIR)/native/$(MODULE)/java_objs, \ --- old/make/launcher/Launcher-jdk.accessibility.gmk 2019-05-21 01:00:58.789187226 +0200 +++ new/make/launcher/Launcher-jdk.accessibility.gmk 2019-05-21 01:00:58.637187499 +0200 @@ -1,5 +1,5 @@ # -# Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -43,7 +43,7 @@ DISABLED_WARNINGS_microsoft := 4267 4996, \ LDFLAGS := $(LDFLAGS_JDKEXE), \ LIBS := advapi32.lib version.lib user32.lib, \ - VERSIONINFO_RESOURCE := $(ACCESSBRIDGE_SRC)/AccessBridgeStatusWindow.rc, \ + VERSIONINFO_RESOURCE := $(ACCESSBRIDGE_SRC)/AccessBridgeStatusWindow.RC, \ MANIFEST := $(JABSWITCH_SRC)/jabswitch.manifest, \ MANIFEST_VERSION := $(VERSION_NUMBER_FOUR_POSITIONS), \ )) --- old/make/launcher/LauncherCommon.gmk 2019-05-21 01:00:58.981186882 +0200 +++ new/make/launcher/LauncherCommon.gmk 2019-05-21 01:00:58.825187162 +0200 @@ -73,7 +73,8 @@ # compile time defines exceeding Visual Studio 2013 limitations. # CFLAGS Additional CFLAGS # CFLAGS_windows Additional CFLAGS_windows -# EXTRA_RC_FLAGS Additional EXTRA_RC_FLAGS +# LDFLAGS_solaris Additional LDFLAGS_solaris +# RC_FLAGS Additional RC_FLAGS # MACOSX_SIGNED On macosx, sign this binary # OPTIMIZATION Override default optimization level (LOW) # OUTPUT_DIR Override default output directory @@ -138,7 +139,7 @@ NAME := $1, \ EXTRA_FILES := $(LAUNCHER_SRC)/main.c, \ OPTIMIZATION := $$($1_OPTIMIZATION), \ - CFLAGS := $$(CFLAGS_JDKEXE) \ + CFLAGS := $$(CFLAGS_JDKEXE) $$($1_CFLAGS) \ $(LAUNCHER_CFLAGS) \ $(VERSION_CFLAGS) \ -DLAUNCHER_NAME='"$(LAUNCHER_NAME)"' \ --- old/make/test/JtregNativeJdk.gmk 2019-05-21 01:00:59.173186538 +0200 +++ new/make/test/JtregNativeJdk.gmk 2019-05-21 01:00:59.025186803 +0200 @@ -1,5 +1,5 @@ # -# Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -61,7 +61,6 @@ BUILD_JDK_JTREG_LIBRARIES_LIBS_libstringPlatformChars := $(WIN_LIB_JAVA) WIN_LIB_JLI := $(SUPPORT_OUTPUTDIR)/native/java.base/libjli/jli.lib BUILD_JDK_JTREG_EXECUTABLES_LIBS_exeJliLaunchTest := $(WIN_LIB_JLI) - BUILD_JDK_JTREG_EXECUTABLES_LIBS_exeCallerAccessTest := jvm.lib else BUILD_JDK_JTREG_LIBRARIES_LIBS_libstringPlatformChars := -ljava BUILD_JDK_JTREG_LIBRARIES_LIBS_libDirectIO := -ljava @@ -71,7 +70,6 @@ BUILD_JDK_JTREG_LIBRARIES_LIBS_libInheritedChannel := -ljava -lsocket -lnsl endif BUILD_JDK_JTREG_EXECUTABLES_LIBS_exeJliLaunchTest := -ljli - BUILD_JDK_JTREG_EXECUTABLES_LIBS_exeCallerAccessTest := -ljvm endif ifeq ($(call isTargetOs, macosx), true) --- old/src/hotspot/cpu/aarch64/aarch64.ad 2019-05-21 01:00:59.373186181 +0200 +++ new/src/hotspot/cpu/aarch64/aarch64.ad 2019-05-21 01:00:59.221186453 +0200 @@ -3932,8 +3932,7 @@ operand immL_bitmask() %{ - predicate((n->get_long() != 0) - && ((n->get_long() & 0xc000000000000000l) == 0) + predicate(((n->get_long() & 0xc000000000000000l) == 0) && is_power_of_2(n->get_long() + 1)); match(ConL); @@ -3944,8 +3943,7 @@ operand immI_bitmask() %{ - predicate((n->get_int() != 0) - && ((n->get_int() & 0xc0000000) == 0) + predicate(((n->get_int() & 0xc0000000) == 0) && is_power_of_2(n->get_int() + 1)); match(ConI); @@ -11434,13 +11432,11 @@ instruct ubfxwI(iRegINoSp dst, iRegIorL2I src, immI rshift, immI_bitmask mask) %{ match(Set dst (AndI (URShiftI src rshift) mask)); - // Make sure we are not going to exceed what ubfxw can do. - predicate((exact_log2(n->in(2)->get_int() + 1) + (n->in(1)->in(2)->get_int() & 31)) <= (31 + 1)); ins_cost(INSN_COST); format %{ "ubfxw $dst, $src, $rshift, $mask" %} ins_encode %{ - int rshift = $rshift$$constant & 31; + int rshift = $rshift$$constant; long mask = $mask$$constant; int width = exact_log2(mask+1); __ ubfxw(as_Register($dst$$reg), @@ -11451,15 +11447,13 @@ instruct ubfxL(iRegLNoSp dst, iRegL src, immI rshift, immL_bitmask mask) %{ match(Set dst (AndL (URShiftL src rshift) mask)); - // Make sure we are not going to exceed what ubfx can do. - predicate((exact_log2_long(n->in(2)->get_long() + 1) + (n->in(1)->in(2)->get_int() & 63)) <= (63 + 1)); ins_cost(INSN_COST); format %{ "ubfx $dst, $src, $rshift, $mask" %} ins_encode %{ - int rshift = $rshift$$constant & 63; + int rshift = $rshift$$constant; long mask = $mask$$constant; - int width = exact_log2_long(mask+1); + int width = exact_log2(mask+1); __ ubfx(as_Register($dst$$reg), as_Register($src$$reg), rshift, width); %} @@ -11471,13 +11465,11 @@ instruct ubfxIConvI2L(iRegLNoSp dst, iRegIorL2I src, immI rshift, immI_bitmask mask) %{ match(Set dst (ConvI2L (AndI (URShiftI src rshift) mask))); - // Make sure we are not going to exceed what ubfxw can do. - predicate((exact_log2(n->in(1)->in(2)->get_int() + 1) + (n->in(1)->in(1)->in(2)->get_int() & 31)) <= (31 + 1)); ins_cost(INSN_COST * 2); format %{ "ubfx $dst, $src, $rshift, $mask" %} ins_encode %{ - int rshift = $rshift$$constant & 31; + int rshift = $rshift$$constant; long mask = $mask$$constant; int width = exact_log2(mask+1); __ ubfx(as_Register($dst$$reg), @@ -11518,7 +11510,7 @@ ins_encode %{ int lshift = $lshift$$constant; long mask = $mask$$constant; - int width = exact_log2_long(mask+1); + int width = exact_log2(mask+1); __ ubfiz(as_Register($dst$$reg), as_Register($src$$reg), lshift, width); %} --- old/src/hotspot/cpu/aarch64/aarch64_ad.m4 2019-05-21 01:00:59.669185649 +0200 +++ new/src/hotspot/cpu/aarch64/aarch64_ad.m4 2019-05-21 01:00:59.521185914 +0200 @@ -181,35 +181,31 @@ `instruct $3$1(iReg$1NoSp dst, iReg$1`'ORL2I($1) src, immI rshift, imm$1_bitmask mask) %{ match(Set dst (And$1 ($2$1 src rshift) mask)); - // Make sure we are not going to exceed what $3 can do. - predicate((exact_log2$6(n->in(2)->get_$5() + 1) + (n->in(1)->in(2)->get_int() & $4)) <= ($4 + 1)); ins_cost(INSN_COST); format %{ "$3 $dst, $src, $rshift, $mask" %} ins_encode %{ - int rshift = $rshift$$constant & $4; + int rshift = $rshift$$constant; long mask = $mask$$constant; - int width = exact_log2$6(mask+1); + int width = exact_log2(mask+1); __ $3(as_Register($dst$$reg), as_Register($src$$reg), rshift, width); %} ins_pipe(ialu_reg_shift); %}') -BFX_INSN(I, URShift, ubfxw, 31, int) -BFX_INSN(L, URShift, ubfx, 63, long, _long) +BFX_INSN(I,URShift,ubfxw) +BFX_INSN(L,URShift,ubfx) // We can use ubfx when extending an And with a mask when we know mask // is positive. We know that because immI_bitmask guarantees it. instruct ubfxIConvI2L(iRegLNoSp dst, iRegIorL2I src, immI rshift, immI_bitmask mask) %{ match(Set dst (ConvI2L (AndI (URShiftI src rshift) mask))); - // Make sure we are not going to exceed what ubfxw can do. - predicate((exact_log2(n->in(1)->in(2)->get_int() + 1) + (n->in(1)->in(1)->in(2)->get_int() & 31)) <= (31 + 1)); ins_cost(INSN_COST * 2); format %{ "ubfx $dst, $src, $rshift, $mask" %} ins_encode %{ - int rshift = $rshift$$constant & 31; + int rshift = $rshift$$constant; long mask = $mask$$constant; int width = exact_log2(mask+1); __ ubfx(as_Register($dst$$reg), @@ -232,7 +228,7 @@ ins_encode %{ int lshift = $lshift$$constant; long mask = $mask$$constant; - int width = exact_log2$5(mask+1); + int width = exact_log2(mask+1); __ $2(as_Register($dst$$reg), as_Register($src$$reg), lshift, width); %} --- old/src/hotspot/cpu/aarch64/assembler_aarch64.hpp 2019-05-21 01:00:59.857185312 +0200 +++ new/src/hotspot/cpu/aarch64/assembler_aarch64.hpp 2019-05-21 01:00:59.709185577 +0200 @@ -1211,8 +1211,8 @@ /* The size bit is in bit 30, not 31 */ sz = (operand_size)(sz == word ? 0b00:0b01); } - f(sz, 31, 30), f(0b001000, 29, 24), f(not_pair ? 1 : 0, 23), f(a, 22), f(1, 21); - zrf(Rs, 16), f(r, 15), f(0b11111, 14, 10), srf(Rn, 5), zrf(Rt, 0); + f(sz, 31, 30), f(0b001000, 29, 24), f(1, 23), f(a, 22), f(1, 21); + rf(Rs, 16), f(r, 15), f(0b11111, 14, 10), rf(Rn, 5), rf(Rt, 0); } // CAS --- old/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp 2019-05-21 01:01:00.065184940 +0200 +++ new/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp 2019-05-21 01:00:59.917185205 +0200 @@ -34,7 +34,6 @@ #include "c1/c1_ValueStack.hpp" #include "ci/ciArrayKlass.hpp" #include "ci/ciInstance.hpp" -#include "code/compiledIC.hpp" #include "gc/shared/barrierSet.hpp" #include "gc/shared/cardTableBarrierSet.hpp" #include "gc/shared/collectedHeap.hpp" @@ -2064,10 +2063,11 @@ int start = __ offset(); __ relocate(static_stub_Relocation::spec(call_pc)); - __ emit_static_call_stub(); + __ mov_metadata(rmethod, (Metadata*)NULL); + __ movptr(rscratch1, 0); + __ br(rscratch1); - assert(__ offset() - start + CompiledStaticCall::to_trampoline_stub_size() - <= call_stub_size(), "stub too big"); + assert(__ offset() - start <= call_stub_size(), "stub too big"); __ end_a_stub(); } --- old/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.hpp 2019-05-21 01:01:00.289184538 +0200 +++ new/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.hpp 2019-05-21 01:01:00.137184810 +0200 @@ -69,9 +69,7 @@ void deoptimize_trap(CodeEmitInfo *info); enum { - // call stub: CompiledStaticCall::to_interp_stub_size() + - // CompiledStaticCall::to_trampoline_stub_size() - _call_stub_size = 13 * NativeInstruction::instruction_size, + _call_stub_size = 12 * NativeInstruction::instruction_size, _call_aot_stub_size = 0, _exception_handler_size = DEBUG_ONLY(1*K) NOT_DEBUG(175), _deopt_handler_size = 7 * NativeInstruction::instruction_size --- old/src/hotspot/cpu/aarch64/compiledIC_aarch64.cpp 2019-05-21 01:01:00.513184137 +0200 +++ new/src/hotspot/cpu/aarch64/compiledIC_aarch64.cpp 2019-05-21 01:01:00.353184423 +0200 @@ -61,14 +61,14 @@ // Don't create a Metadata reloc if we're generating immutable PIC. if (cbuf.immutable_PIC()) { __ movptr(rmethod, 0); - __ movptr(rscratch1, 0); - __ br(rscratch1); - - } else -#endif - { - __ emit_static_call_stub(); + } else { + __ mov_metadata(rmethod, (Metadata*)NULL); } +#else + __ mov_metadata(rmethod, (Metadata*)NULL); +#endif + __ movptr(rscratch1, 0); + __ br(rscratch1); assert((__ offset() - offset) <= (int)to_interp_stub_size(), "stub too big"); __ end_a_stub(); @@ -77,8 +77,7 @@ #undef __ int CompiledStaticCall::to_interp_stub_size() { - // isb; movk; movz; movz; movk; movz; movz; br - return 8 * NativeInstruction::instruction_size; + return 7 * NativeInstruction::instruction_size; } int CompiledStaticCall::to_trampoline_stub_size() { @@ -160,8 +159,7 @@ } // Creation also verifies the object. - NativeMovConstReg* method_holder - = nativeMovConstReg_at(stub + NativeInstruction::instruction_size); + NativeMovConstReg* method_holder = nativeMovConstReg_at(stub); #ifndef PRODUCT NativeGeneralJump* jump = nativeGeneralJump_at(method_holder->next_instruction_address()); @@ -186,8 +184,7 @@ assert(stub != NULL, "stub not found"); assert(CompiledICLocker::is_safe(stub), "mt unsafe call"); // Creation also verifies the object. - NativeMovConstReg* method_holder - = nativeMovConstReg_at(stub + NativeInstruction::instruction_size); + NativeMovConstReg* method_holder = nativeMovConstReg_at(stub); method_holder->set_data(0); } @@ -204,9 +201,8 @@ address stub = find_stub(false /* is_aot */); assert(stub != NULL, "no stub found for static call"); // Creation also verifies the object. - NativeMovConstReg* method_holder - = nativeMovConstReg_at(stub + NativeInstruction::instruction_size); - NativeJump* jump = nativeJump_at(method_holder->next_instruction_address()); + NativeMovConstReg* method_holder = nativeMovConstReg_at(stub); + NativeJump* jump = nativeJump_at(method_holder->next_instruction_address()); // Verify state. assert(is_clean() || is_call_to_compiled() || is_call_to_interpreted(), "sanity check"); --- old/src/hotspot/cpu/aarch64/frame_aarch64.cpp 2019-05-21 01:01:00.705183793 +0200 +++ new/src/hotspot/cpu/aarch64/frame_aarch64.cpp 2019-05-21 01:01:00.553184066 +0200 @@ -559,7 +559,7 @@ // validate constantPoolCache* ConstantPoolCache* cp = *interpreter_frame_cache_addr(); - if (MetaspaceObj::is_valid(cp) == false) return false; + if (cp == NULL || !cp->is_metaspace_object()) return false; // validate locals --- old/src/hotspot/cpu/aarch64/interpreterRT_aarch64.cpp 2019-05-21 01:01:00.893183454 +0200 +++ new/src/hotspot/cpu/aarch64/interpreterRT_aarch64.cpp 2019-05-21 01:01:00.749183714 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -418,7 +418,7 @@ }; -JRT_ENTRY(address, +IRT_ENTRY(address, InterpreterRuntime::slow_signature_handler(JavaThread* thread, Method* method, intptr_t* from, @@ -435,4 +435,4 @@ // return result handler return Interpreter::result_handler(m->result_type()); -JRT_END +IRT_END --- old/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp 2019-05-21 01:01:01.085183110 +0200 +++ new/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp 2019-05-21 01:01:00.937183375 +0200 @@ -812,18 +812,6 @@ return stub_start_addr; } -void MacroAssembler::emit_static_call_stub() { - // CompiledDirectStaticCall::set_to_interpreted knows the - // exact layout of this stub. - - isb(); - mov_metadata(rmethod, (Metadata*)NULL); - - // Jump to the entry point of the i2c stub. - movptr(rscratch1, 0); - br(rscratch1); -} - void MacroAssembler::c2bool(Register x) { // implements x == 0 ? 0 : 1 // note: must only look at least-significant byte of x --- old/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp 2019-05-21 01:01:01.305182715 +0200 +++ new/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp 2019-05-21 01:01:01.153182988 +0200 @@ -607,7 +607,6 @@ static int patch_narrow_klass(address insn_addr, narrowKlass n); address emit_trampoline_stub(int insts_call_instruction_offset, address target); - void emit_static_call_stub(); // The following 4 methods return the offset of the appropriate move instruction --- old/src/hotspot/cpu/aarch64/nativeInst_aarch64.cpp 2019-05-21 01:01:01.509182351 +0200 +++ new/src/hotspot/cpu/aarch64/nativeInst_aarch64.cpp 2019-05-21 01:01:01.357182623 +0200 @@ -232,11 +232,7 @@ //------------------------------------------------------------------- void NativeMovConstReg::verify() { - if (! (nativeInstruction_at(instruction_address())->is_movz() || - is_adrp_at(instruction_address()) || - is_ldr_literal_at(instruction_address())) ) { - fatal("should be MOVZ or ADRP or LDR (literal)"); - } + // make sure code pattern is actually mov reg64, imm64 instructions } --- old/src/hotspot/cpu/arm/frame_arm.cpp 2019-05-21 01:01:01.701182007 +0200 +++ new/src/hotspot/cpu/arm/frame_arm.cpp 2019-05-21 01:01:01.549182279 +0200 @@ -494,7 +494,7 @@ // validate ConstantPoolCache* ConstantPoolCache* cp = *interpreter_frame_cache_addr(); - if (MetaspaceObj::is_valid(cp) == false) return false; + if (cp == NULL || !cp->is_metaspace_object()) return false; // validate locals --- old/src/hotspot/cpu/arm/interpreterRT_arm.cpp 2019-05-21 01:01:01.897181655 +0200 +++ new/src/hotspot/cpu/arm/interpreterRT_arm.cpp 2019-05-21 01:01:01.745181928 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -369,9 +369,9 @@ } }; -JRT_ENTRY(address, InterpreterRuntime::slow_signature_handler(JavaThread* thread, Method* method, intptr_t* from, intptr_t* to)) +IRT_ENTRY(address, InterpreterRuntime::slow_signature_handler(JavaThread* thread, Method* method, intptr_t* from, intptr_t* to)) methodHandle m(thread, (Method*)method); assert(m->is_native(), "sanity check"); SlowSignatureHandler(m, (address)from, to).iterate(UCONST64(-1)); return Interpreter::result_handler(m->result_type()); -JRT_END +IRT_END --- old/src/hotspot/cpu/ppc/interpreterRT_ppc.cpp 2019-05-21 01:01:02.113181268 +0200 +++ new/src/hotspot/cpu/ppc/interpreterRT_ppc.cpp 2019-05-21 01:01:01.937181584 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012, 2013 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -148,15 +148,15 @@ // Access function to get the signature. -JRT_ENTRY(address, InterpreterRuntime::get_signature(JavaThread* thread, Method* method)) +IRT_ENTRY(address, InterpreterRuntime::get_signature(JavaThread* thread, Method* method)) methodHandle m(thread, method); assert(m->is_native(), "sanity check"); Symbol *s = m->signature(); return (address) s->base(); -JRT_END +IRT_END -JRT_ENTRY(address, InterpreterRuntime::get_result_handler(JavaThread* thread, Method* method)) +IRT_ENTRY(address, InterpreterRuntime::get_result_handler(JavaThread* thread, Method* method)) methodHandle m(thread, method); assert(m->is_native(), "sanity check"); return AbstractInterpreter::result_handler(m->result_type()); -JRT_END +IRT_END --- old/src/hotspot/cpu/ppc/vm_version_ppc.cpp 2019-05-21 01:01:02.333180873 +0200 +++ new/src/hotspot/cpu/ppc/vm_version_ppc.cpp 2019-05-21 01:01:02.169181168 +0200 @@ -381,27 +381,6 @@ } } -void VM_Version::print_platform_virtualization_info(outputStream* st) { - const char* info_file = "/proc/ppc64/lparcfg"; - const char* kw[] = { "system_type=", // qemu indicates PowerKVM - "partition_entitled_capacity=", // entitled processor capacity percentage - "partition_max_entitled_capacity=", - "capacity_weight=", // partition CPU weight - "partition_active_processors=", - "partition_potential_processors=", - "entitled_proc_capacity_available=", - "capped=", // 0 - uncapped, 1 - vcpus capped at entitled processor capacity percentage - "shared_processor_mode=", // (non)dedicated partition - "system_potential_processors=", - "pool=", // CPU-pool number - "pool_capacity=", - "NumLpars=", // on non-KVM machines, NumLpars is not found for full partition mode machines - NULL }; - if (!print_matching_lines_from_file(info_file, st, kw)) { - st->print_cr(" <%s Not Available>", info_file); - } -} - bool VM_Version::use_biased_locking() { #if INCLUDE_RTM_OPT // RTM locking is most useful when there is high lock contention and --- old/src/hotspot/cpu/ppc/vm_version_ppc.hpp 2019-05-21 01:01:02.541180501 +0200 +++ new/src/hotspot/cpu/ppc/vm_version_ppc.hpp 2019-05-21 01:01:02.377180794 +0200 @@ -89,9 +89,6 @@ static void initialize(); // Override Abstract_VM_Version implementation - static void print_platform_virtualization_info(outputStream*); - - // Override Abstract_VM_Version implementation static bool use_biased_locking(); static bool is_determine_features_test_running() { return _is_determine_features_test_running; } --- old/src/hotspot/cpu/s390/interpreterRT_s390.cpp 2019-05-21 01:01:02.733180157 +0200 +++ new/src/hotspot/cpu/s390/interpreterRT_s390.cpp 2019-05-21 01:01:02.581180429 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2016 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -151,15 +151,15 @@ void SignatureHandlerLibrary::pd_set_handler(address handler) {} -JRT_ENTRY(address, InterpreterRuntime::get_signature(JavaThread* thread, Method* method)) +IRT_ENTRY(address, InterpreterRuntime::get_signature(JavaThread* thread, Method* method)) methodHandle m(thread, method); assert(m->is_native(), "sanity check"); Symbol *s = m->signature(); return (address) s->base(); -JRT_END +IRT_END -JRT_ENTRY(address, InterpreterRuntime::get_result_handler(JavaThread* thread, Method* method)) +IRT_ENTRY(address, InterpreterRuntime::get_result_handler(JavaThread* thread, Method* method)) methodHandle m(thread, method); assert(m->is_native(), "sanity check"); return AbstractInterpreter::result_handler(m->result_type()); -JRT_END +IRT_END --- old/src/hotspot/cpu/s390/macroAssembler_s390.cpp 2019-05-21 01:01:02.933179798 +0200 +++ new/src/hotspot/cpu/s390/macroAssembler_s390.cpp 2019-05-21 01:01:02.785180062 +0200 @@ -4355,9 +4355,12 @@ // Emitter does not KILL cnt and base arguments, since they need to be copied to // work registers anyway. // Actually, only r0, r1, and r5 are killed. -unsigned int MacroAssembler::Clear_Array(Register cnt_arg, Register base_pointer_arg, Register odd_tmp_reg) { +unsigned int MacroAssembler::Clear_Array(Register cnt_arg, Register base_pointer_arg, Register src_addr, Register src_len) { + // Src_addr is evenReg. + // Src_len is odd_Reg. int block_start = offset(); + Register tmp_reg = src_len; // Holds target instr addr for EX. Register dst_len = Z_R1; // Holds dst len for MVCLE. Register dst_addr = Z_R0; // Holds dst addr for MVCLE. @@ -4366,7 +4369,7 @@ BLOCK_COMMENT("Clear_Array {"); // Check for zero len and convert to long. - z_ltgfr(odd_tmp_reg, cnt_arg); + z_ltgfr(src_len, cnt_arg); // Remember casted value for doSTG case. z_bre(done); // Nothing to do if len == 0. // Prefetch data to be cleared. @@ -4375,17 +4378,16 @@ z_pfd(0x02, 256, Z_R0, base_pointer_arg); } - z_sllg(dst_len, odd_tmp_reg, 3); // #bytes to clear. - z_cghi(odd_tmp_reg, 32); // Check for len <= 256 bytes (<=32 DW). - z_brnh(doXC); // If so, use executed XC to clear. + z_sllg(dst_len, src_len, 3); // #bytes to clear. + z_cghi(src_len, 32); // Check for len <= 256 bytes (<=32 DW). + z_brnh(doXC); // If so, use executed XC to clear. // MVCLE: initialize long arrays (general case). bind(doMVCLE); z_lgr(dst_addr, base_pointer_arg); - // Pass 0 as source length to MVCLE: destination will be filled with padding byte 0. - // The even register of the register pair is not killed. - clear_reg(odd_tmp_reg, true, false); - MacroAssembler::move_long_ext(dst_addr, as_Register(odd_tmp_reg->encoding()-1), 0); + clear_reg(src_len, true, false); // Src len of MVCLE is zero. + + MacroAssembler::move_long_ext(dst_addr, src_addr, 0); z_bru(done); // XC: initialize short arrays. @@ -4394,12 +4396,12 @@ z_xc(0,0,base_pointer_arg,0,base_pointer_arg); bind(doXC); - add2reg(dst_len, -1); // Get #bytes-1 for EXECUTE. + add2reg(dst_len, -1); // Get #bytes-1 for EXECUTE. if (VM_Version::has_ExecuteExtensions()) { - z_exrl(dst_len, XC_template); // Execute XC with var. len. + z_exrl(dst_len, XC_template); // Execute XC with var. len. } else { - z_larl(odd_tmp_reg, XC_template); - z_ex(dst_len,0,Z_R0,odd_tmp_reg); // Execute XC with var. len. + z_larl(tmp_reg, XC_template); + z_ex(dst_len,0,Z_R0,tmp_reg); // Execute XC with var. len. } // z_bru(done); // fallthru @@ -4461,7 +4463,7 @@ // Compiler ensures base is doubleword aligned and cnt is #doublewords. // Emitter does not KILL cnt and base arguments, since they need to be copied to // work registers anyway. -// Actually, only r0, r1, (which are work registers) and odd_tmp_reg are killed. +// Actually, only r0, r1, r4, and r5 (which are work registers) are killed. // // For very large arrays, exploit MVCLE H/W support. // MVCLE instruction automatically exploits H/W-optimized page mover. @@ -4469,7 +4471,9 @@ // - All full pages are cleared with the page mover H/W assist. // - Remaining bytes are again cleared by a series of XC to self. // -unsigned int MacroAssembler::Clear_Array_Const_Big(long cnt, Register base_pointer_arg, Register odd_tmp_reg) { +unsigned int MacroAssembler::Clear_Array_Const_Big(long cnt, Register base_pointer_arg, Register src_addr, Register src_len) { + // Src_addr is evenReg. + // Src_len is odd_Reg. int block_start = offset(); Register dst_len = Z_R1; // Holds dst len for MVCLE. @@ -4482,10 +4486,11 @@ // Prepare other args to MVCLE. z_lgr(dst_addr, base_pointer_arg); - // Pass 0 as source length to MVCLE: destination will be filled with padding byte 0. - // The even register of the register pair is not killed. - (void) clear_reg(odd_tmp_reg, true, false); // Src len of MVCLE is zero. - MacroAssembler::move_long_ext(dst_addr, as_Register(odd_tmp_reg->encoding() - 1), 0); + // Indicate unused result. + (void) clear_reg(src_len, true, false); // Src len of MVCLE is zero. + + // Clear. + MacroAssembler::move_long_ext(dst_addr, src_addr, 0); BLOCK_COMMENT("} Clear_Array_Const_Big"); int block_end = offset(); --- old/src/hotspot/cpu/s390/macroAssembler_s390.hpp 2019-05-21 01:01:03.165179382 +0200 +++ new/src/hotspot/cpu/s390/macroAssembler_s390.hpp 2019-05-21 01:01:03.017179647 +0200 @@ -828,9 +828,9 @@ //-------------------------- //--- Operations on arrays. //-------------------------- - unsigned int Clear_Array(Register cnt_arg, Register base_pointer_arg, Register odd_tmp_reg); + unsigned int Clear_Array(Register cnt_arg, Register base_pointer_arg, Register src_addr, Register src_len); unsigned int Clear_Array_Const(long cnt, Register base); - unsigned int Clear_Array_Const_Big(long cnt, Register base_pointer_arg, Register odd_tmp_reg); + unsigned int Clear_Array_Const_Big(long cnt, Register base_pointer_arg, Register src_addr, Register src_len); unsigned int CopyRawMemory_AlignedDisjoint(Register src_reg, Register dst_reg, Register cnt_reg, Register tmp1_reg, Register tmp2_reg); --- old/src/hotspot/cpu/s390/s390.ad 2019-05-21 01:01:03.357179038 +0200 +++ new/src/hotspot/cpu/s390/s390.ad 2019-05-21 01:01:03.209179303 +0200 @@ -474,19 +474,6 @@ /*Z_R15_H,Z_R15*/ // SP ); -// z_long_reg without even registers -reg_class z_long_odd_reg( -/*Z_R0_H,Z_R0*/ // R0 -/*Z_R1_H,Z_R1*/ - Z_R3_H,Z_R3, - Z_R5_H,Z_R5, - Z_R7_H,Z_R7, - Z_R9_H,Z_R9, - Z_R11_H,Z_R11, - Z_R13_H,Z_R13 -/*Z_R14_H,Z_R14,*/ // return_pc -/*Z_R15_H,Z_R15*/ // SP -); // Special Class for Condition Code Flags Register @@ -3391,7 +3378,6 @@ match(RegL); match(revenRegL); match(roddRegL); - match(allRoddRegL); match(rarg1RegL); match(rarg5RegL); format %{ %} @@ -3414,14 +3400,6 @@ interface(REG_INTER); %} -// available odd registers for iRegL -operand allRoddRegL() %{ - constraint(ALLOC_IN_RC(z_long_odd_reg)); - match(iRegL); - format %{ %} - interface(REG_INTER); -%} - operand rarg1RegL() %{ constraint(ALLOC_IN_RC(z_rarg1_long_reg)); match(iRegL); @@ -9921,23 +9899,23 @@ ins_pipe(pipe_class_dummy); %} -instruct inlineCallClearArrayConstBig(immL cnt, iRegP_N2P base, Universe dummy, allRoddRegL tmpL, flagsReg cr) %{ +instruct inlineCallClearArrayConstBig(immL cnt, iRegP_N2P base, Universe dummy, revenRegL srcA, roddRegL srcL, flagsReg cr) %{ match(Set dummy (ClearArray cnt base)); - effect(TEMP tmpL, KILL cr); // R0, R1 are killed, too. + effect(TEMP srcA, TEMP srcL, KILL cr); // R0, R1 are killed, too. ins_cost(200); // TODO: s390 port size(VARIABLE_SIZE); // Variable in size due to optimized constant loader. format %{ "ClearArrayConstBig $cnt,$base" %} - ins_encode %{ __ Clear_Array_Const_Big($cnt$$constant, $base$$Register, $tmpL$$Register); %} + ins_encode %{ __ Clear_Array_Const_Big($cnt$$constant, $base$$Register, $srcA$$Register, $srcL$$Register); %} ins_pipe(pipe_class_dummy); %} -instruct inlineCallClearArray(iRegL cnt, iRegP_N2P base, Universe dummy, allRoddRegL tmpL, flagsReg cr) %{ +instruct inlineCallClearArray(iRegL cnt, iRegP_N2P base, Universe dummy, revenRegL srcA, roddRegL srcL, flagsReg cr) %{ match(Set dummy (ClearArray cnt base)); - effect(TEMP tmpL, KILL cr); // R0, R1 are killed, too. + effect(TEMP srcA, TEMP srcL, KILL cr); // R0, R1 are killed, too. ins_cost(300); // TODO: s390 port size(FIXED_SIZE); // z/Architecture: emitted code depends on PreferLAoverADD being on/off. format %{ "ClearArrayVar $cnt,$base" %} - ins_encode %{ __ Clear_Array($cnt$$Register, $base$$Register, $tmpL$$Register); %} + ins_encode %{ __ Clear_Array($cnt$$Register, $base$$Register, $srcA$$Register, $srcL$$Register); %} ins_pipe(pipe_class_dummy); %} --- old/src/hotspot/cpu/s390/vm_version_s390.cpp 2019-05-21 01:01:03.621178564 +0200 +++ new/src/hotspot/cpu/s390/vm_version_s390.cpp 2019-05-21 01:01:03.469178837 +0200 @@ -516,19 +516,6 @@ } } -void VM_Version::print_platform_virtualization_info(outputStream* st) { - // /proc/sysinfo contains interesting information about - // - LPAR - // - whole "Box" (CPUs ) - // - z/VM / KVM (VM); this is not available in an LPAR-only setup - const char* kw[] = { "LPAR", "CPUs", "VM", NULL }; - const char* info_file = "/proc/sysinfo"; - - if (!print_matching_lines_from_file(info_file, st, kw)) { - st->print_cr(" <%s Not Available>", info_file); - } -} - void VM_Version::print_features() { print_features_internal("Version:"); } --- old/src/hotspot/cpu/s390/vm_version_s390.hpp 2019-05-21 01:01:03.817178212 +0200 +++ new/src/hotspot/cpu/s390/vm_version_s390.hpp 2019-05-21 01:01:03.665178485 +0200 @@ -346,9 +346,6 @@ static void print_features(); static bool is_determine_features_test_running() { return _is_determine_features_test_running; } - // Override Abstract_VM_Version implementation - static void print_platform_virtualization_info(outputStream*); - // CPU feature query functions static const char* get_model_string() { return _model_string; } static bool has_StoreFacilityListExtended() { return (_features[0] & StoreFacilityListExtendedMask) == StoreFacilityListExtendedMask; } --- old/src/hotspot/cpu/sparc/frame_sparc.cpp 2019-05-21 01:01:04.005177876 +0200 +++ new/src/hotspot/cpu/sparc/frame_sparc.cpp 2019-05-21 01:01:03.861178133 +0200 @@ -665,7 +665,7 @@ // validate ConstantPoolCache* ConstantPoolCache* cp = *interpreter_frame_cache_addr(); - if (MetaspaceObj::is_valid(cp) == false) return false; + if (cp == NULL || !cp->is_metaspace_object()) return false; // validate locals --- old/src/hotspot/cpu/sparc/interpreterRT_sparc.cpp 2019-05-21 01:01:04.197177532 +0200 +++ new/src/hotspot/cpu/sparc/interpreterRT_sparc.cpp 2019-05-21 01:01:04.049177797 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -191,7 +191,7 @@ }; -JRT_ENTRY(address, InterpreterRuntime::slow_signature_handler( +IRT_ENTRY(address, InterpreterRuntime::slow_signature_handler( JavaThread* thread, Method* method, intptr_t* from, @@ -204,4 +204,4 @@ SlowSignatureHandler(m, (address)from, m->is_static() ? to+2 : to+1, to).iterate((uint64_t)CONST64(-1)); // return result handler return Interpreter::result_handler(m->result_type()); -JRT_END +IRT_END --- old/src/hotspot/cpu/x86/assembler_x86.cpp 2019-05-21 01:01:04.385177195 +0200 +++ new/src/hotspot/cpu/x86/assembler_x86.cpp 2019-05-21 01:01:04.237177460 +0200 @@ -3099,7 +3099,7 @@ } return; } - if (UseAddressNop && VM_Version::is_amd_family()) { + if (UseAddressNop && VM_Version::is_amd()) { // // Using multi-bytes nops "0x0F 0x1F [address]" for AMD. // 1: 0x90 --- old/src/hotspot/cpu/x86/frame_x86.cpp 2019-05-21 01:01:04.621176772 +0200 +++ new/src/hotspot/cpu/x86/frame_x86.cpp 2019-05-21 01:01:04.477177030 +0200 @@ -546,7 +546,7 @@ // validate ConstantPoolCache* ConstantPoolCache* cp = *interpreter_frame_cache_addr(); - if (MetaspaceObj::is_valid(cp) == false) return false; + if (cp == NULL || !cp->is_metaspace_object()) return false; // validate locals --- old/src/hotspot/cpu/x86/interpreterRT_x86_32.cpp 2019-05-21 01:01:04.813176428 +0200 +++ new/src/hotspot/cpu/x86/interpreterRT_x86_32.cpp 2019-05-21 01:01:04.665176693 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -147,11 +147,11 @@ } }; -JRT_ENTRY(address, InterpreterRuntime::slow_signature_handler(JavaThread* thread, Method* method, intptr_t* from, intptr_t* to)) +IRT_ENTRY(address, InterpreterRuntime::slow_signature_handler(JavaThread* thread, Method* method, intptr_t* from, intptr_t* to)) methodHandle m(thread, (Method*)method); assert(m->is_native(), "sanity check"); // handle arguments SlowSignatureHandler(m, (address)from, to + 1).iterate((uint64_t)CONST64(-1)); // return result handler return Interpreter::result_handler(m->result_type()); -JRT_END +IRT_END --- old/src/hotspot/cpu/x86/interpreterRT_x86_64.cpp 2019-05-21 01:01:05.001176090 +0200 +++ new/src/hotspot/cpu/x86/interpreterRT_x86_64.cpp 2019-05-21 01:01:04.853176357 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -496,7 +496,7 @@ #endif -JRT_ENTRY(address, +IRT_ENTRY(address, InterpreterRuntime::slow_signature_handler(JavaThread* thread, Method* method, intptr_t* from, @@ -509,4 +509,4 @@ // return result handler return Interpreter::result_handler(m->result_type()); -JRT_END +IRT_END --- old/src/hotspot/cpu/x86/stubGenerator_x86_32.cpp 2019-05-21 01:01:05.193175746 +0200 +++ new/src/hotspot/cpu/x86/stubGenerator_x86_32.cpp 2019-05-21 01:01:05.041176018 +0200 @@ -2968,8 +2968,9 @@ __ enter(); __ subptr(rsp, 8 * wordSize); - handleSOERegisters(true /*saving*/); - + if (multi_block) { + __ push(limit); + } __ movptr(buf, buf_param); __ movptr(state, state_param); if (multi_block) { @@ -2980,7 +2981,9 @@ __ fast_sha1(abcd, e0, e1, msg0, msg1, msg2, msg3, shuf_mask, buf, state, ofs, limit, rsp, multi_block); - handleSOERegisters(false /*restoring*/); + if (multi_block) { + __ pop(limit); + } __ addptr(rsp, 8 * wordSize); __ leave(); __ ret(0); --- old/src/hotspot/cpu/x86/vm_version_ext_x86.cpp 2019-05-21 01:01:05.405175366 +0200 +++ new/src/hotspot/cpu/x86/vm_version_ext_x86.cpp 2019-05-21 01:01:05.257175631 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -43,10 +43,10 @@ CPU_FAMILY_PENTIUM_4 = 0xF } FamilyFlag; -typedef enum { - RDTSCP_FLAG = 0x08000000, // bit 27 - INTEL64_FLAG = 0x20000000 // bit 29 -} _featureExtendedEdxFlag; + typedef enum { + RDTSCP_FLAG = 0x08000000, // bit 27 + INTEL64_FLAG = 0x20000000 // bit 29 + } _featureExtendedEdxFlag; #define CPUID_STANDARD_FN 0x0 #define CPUID_STANDARD_FN_1 0x1 @@ -340,10 +340,6 @@ return !is_amd_Barcelona(); } - if (is_hygon()) { - return true; - } - return false; } @@ -403,20 +399,13 @@ const char* VM_Version_Ext::cpu_family_description(void) { int cpu_family_id = extended_cpu_family(); if (is_amd()) { - if (cpu_family_id < ExtendedFamilyIdLength_AMD) { - return _family_id_amd[cpu_family_id]; - } + return _family_id_amd[cpu_family_id]; } if (is_intel()) { if (cpu_family_id == CPU_FAMILY_PENTIUMPRO) { return cpu_model_description(); } - if (cpu_family_id < ExtendedFamilyIdLength_INTEL) { - return _family_id_intel[cpu_family_id]; - } - } - if (is_hygon()) { - return "Dhyana"; + return _family_id_intel[cpu_family_id]; } return "Unknown x86"; } @@ -434,9 +423,6 @@ } else if (is_amd()) { cpu_type = "AMD"; x64 = cpu_is_em64t() ? " AMD64" : ""; - } else if (is_hygon()) { - cpu_type = "Hygon"; - x64 = cpu_is_em64t() ? " AMD64" : ""; } else { cpu_type = "Unknown x86"; x64 = cpu_is_em64t() ? " x86_64" : ""; @@ -708,7 +694,7 @@ return _max_qualified_cpu_frequency; } -const char* const VM_Version_Ext::_family_id_intel[ExtendedFamilyIdLength_INTEL] = { +const char* const VM_Version_Ext::_family_id_intel[] = { "8086/8088", "", "286", @@ -727,7 +713,7 @@ "Pentium 4" }; -const char* const VM_Version_Ext::_family_id_amd[ExtendedFamilyIdLength_AMD] = { +const char* const VM_Version_Ext::_family_id_amd[] = { "", "", "", @@ -745,13 +731,6 @@ "", "Opteron/Athlon64", "Opteron QC/Phenom" // Barcelona et.al. - "", - "", - "", - "", - "", - "", - "Zen" }; // Partially from Intel 64 and IA-32 Architecture Software Developer's Manual, // September 2013, Vol 3C Table 35-1 --- old/src/hotspot/cpu/x86/vm_version_ext_x86.hpp 2019-05-21 01:01:05.629174965 +0200 +++ new/src/hotspot/cpu/x86/vm_version_ext_x86.hpp 2019-05-21 01:01:05.473175244 +0200 @@ -29,20 +29,14 @@ #include "vm_version_x86.hpp" class VM_Version_Ext : public VM_Version { - - enum { - ExtendedFamilyIdLength_INTEL = 16, - ExtendedFamilyIdLength_AMD = 24 - }; - private: static const size_t VENDOR_LENGTH; static const size_t CPU_EBS_MAX_LENGTH; static const size_t CPU_TYPE_DESC_BUF_SIZE; static const size_t CPU_DETAILED_DESC_BUF_SIZE; - static const char* const _family_id_intel[ExtendedFamilyIdLength_INTEL]; - static const char* const _family_id_amd[ExtendedFamilyIdLength_AMD]; + static const char* const _family_id_intel[]; + static const char* const _family_id_amd[]; static const char* const _brand_id[]; static const char* const _model_id_pentium_pro[]; --- old/src/hotspot/cpu/x86/vm_version_x86.cpp 2019-05-21 01:01:05.817174627 +0200 +++ new/src/hotspot/cpu/x86/vm_version_x86.cpp 2019-05-21 01:01:05.669174894 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -680,7 +680,7 @@ _features &= ~CPU_HT; } - if (is_intel()) { // Intel cpus specific settings + if( is_intel() ) { // Intel cpus specific settings if (is_knights_family()) { _features &= ~CPU_VZEROUPPER; } @@ -781,7 +781,7 @@ FLAG_SET_DEFAULT(UseAESCTRIntrinsics, false); } } else { - if (supports_sse4_1()) { + if(supports_sse4_1()) { if (FLAG_IS_DEFAULT(UseAESCTRIntrinsics)) { FLAG_SET_DEFAULT(UseAESCTRIntrinsics, true); } @@ -1001,7 +1001,7 @@ } else if (UseAVX == 1 || UseAVX == 2) { // 32 bytes vectors (in YMM) are only supported with AVX+ max_vector_size = 32; - } else if (UseAVX > 2) { + } else if (UseAVX > 2 ) { // 64 bytes vectors (in ZMM) are only supported with AVX 3 max_vector_size = 64; } @@ -1165,38 +1165,38 @@ } } - if (is_amd_family()) { // AMD cpus specific settings - if (supports_sse2() && FLAG_IS_DEFAULT(UseAddressNop)) { + if( is_amd() ) { // AMD cpus specific settings + if( supports_sse2() && FLAG_IS_DEFAULT(UseAddressNop) ) { // Use it on new AMD cpus starting from Opteron. UseAddressNop = true; } - if (supports_sse2() && FLAG_IS_DEFAULT(UseNewLongLShift)) { + if( supports_sse2() && FLAG_IS_DEFAULT(UseNewLongLShift) ) { // Use it on new AMD cpus starting from Opteron. UseNewLongLShift = true; } - if (FLAG_IS_DEFAULT(UseXmmLoadAndClearUpper)) { + if( FLAG_IS_DEFAULT(UseXmmLoadAndClearUpper) ) { if (supports_sse4a()) { UseXmmLoadAndClearUpper = true; // use movsd only on '10h' Opteron } else { UseXmmLoadAndClearUpper = false; } } - if (FLAG_IS_DEFAULT(UseXmmRegToRegMoveAll)) { - if (supports_sse4a()) { + if( FLAG_IS_DEFAULT(UseXmmRegToRegMoveAll) ) { + if( supports_sse4a() ) { UseXmmRegToRegMoveAll = true; // use movaps, movapd only on '10h' } else { UseXmmRegToRegMoveAll = false; } } - if (FLAG_IS_DEFAULT(UseXmmI2F)) { - if (supports_sse4a()) { + if( FLAG_IS_DEFAULT(UseXmmI2F) ) { + if( supports_sse4a() ) { UseXmmI2F = true; } else { UseXmmI2F = false; } } - if (FLAG_IS_DEFAULT(UseXmmI2D)) { - if (supports_sse4a()) { + if( FLAG_IS_DEFAULT(UseXmmI2D) ) { + if( supports_sse4a() ) { UseXmmI2D = true; } else { UseXmmI2D = false; @@ -1214,7 +1214,7 @@ } // some defaults for AMD family 15h - if (cpu_family() == 0x15) { + if ( cpu_family() == 0x15 ) { // On family 15h processors default is no sw prefetch if (FLAG_IS_DEFAULT(AllocatePrefetchStyle)) { FLAG_SET_DEFAULT(AllocatePrefetchStyle, 0); @@ -1239,8 +1239,8 @@ } #endif // COMPILER2 - // Some defaults for AMD family 17h || Hygon family 18h - if (cpu_family() == 0x17 || cpu_family() == 0x18) { + // Some defaults for AMD family 17h + if ( cpu_family() == 0x17 ) { // On family 17h processors use XMM and UnalignedLoadStores for Array Copy if (supports_sse2() && FLAG_IS_DEFAULT(UseXMMForArrayCopy)) { FLAG_SET_DEFAULT(UseXMMForArrayCopy, true); @@ -1256,29 +1256,29 @@ } } - if (is_intel()) { // Intel cpus specific settings - if (FLAG_IS_DEFAULT(UseStoreImmI16)) { + if( is_intel() ) { // Intel cpus specific settings + if( FLAG_IS_DEFAULT(UseStoreImmI16) ) { UseStoreImmI16 = false; // don't use it on Intel cpus } - if (cpu_family() == 6 || cpu_family() == 15) { - if (FLAG_IS_DEFAULT(UseAddressNop)) { + if( cpu_family() == 6 || cpu_family() == 15 ) { + if( FLAG_IS_DEFAULT(UseAddressNop) ) { // Use it on all Intel cpus starting from PentiumPro UseAddressNop = true; } } - if (FLAG_IS_DEFAULT(UseXmmLoadAndClearUpper)) { + if( FLAG_IS_DEFAULT(UseXmmLoadAndClearUpper) ) { UseXmmLoadAndClearUpper = true; // use movsd on all Intel cpus } - if (FLAG_IS_DEFAULT(UseXmmRegToRegMoveAll)) { - if (supports_sse3()) { + if( FLAG_IS_DEFAULT(UseXmmRegToRegMoveAll) ) { + if( supports_sse3() ) { UseXmmRegToRegMoveAll = true; // use movaps, movapd on new Intel cpus } else { UseXmmRegToRegMoveAll = false; } } - if (cpu_family() == 6 && supports_sse3()) { // New Intel cpus + if( cpu_family() == 6 && supports_sse3() ) { // New Intel cpus #ifdef COMPILER2 - if (FLAG_IS_DEFAULT(MaxLoopPad)) { + if( FLAG_IS_DEFAULT(MaxLoopPad) ) { // For new Intel cpus do the next optimization: // don't align the beginning of a loop if there are enough instructions // left (NumberOfLoopInstrToAlign defined in c2_globals.hpp) @@ -1324,7 +1324,7 @@ FLAG_SET_DEFAULT(UseIncDec, false); } } - if (FLAG_IS_DEFAULT(AllocatePrefetchInstr) && supports_3dnow_prefetch()) { + if(FLAG_IS_DEFAULT(AllocatePrefetchInstr) && supports_3dnow_prefetch()) { FLAG_SET_DEFAULT(AllocatePrefetchInstr, 3); } } @@ -1573,65 +1573,6 @@ #endif // !PRODUCT } -void VM_Version::print_platform_virtualization_info(outputStream* st) { - VirtualizationType vrt = VM_Version::get_detected_virtualization(); - if (vrt == XenHVM) { - st->print_cr("Xen hardware-assisted virtualization detected"); - } else if (vrt == KVM) { - st->print_cr("KVM virtualization detected"); - } else if (vrt == VMWare) { - st->print_cr("VMWare virtualization detected"); - } else if (vrt == HyperV) { - st->print_cr("HyperV virtualization detected"); - } -} - -void VM_Version::check_virt_cpuid(uint32_t idx, uint32_t *regs) { -// TODO support 32 bit -#if defined(_LP64) -#if defined(_MSC_VER) - // Allocate space for the code - const int code_size = 100; - ResourceMark rm; - CodeBuffer cb("detect_virt", code_size, 0); - MacroAssembler* a = new MacroAssembler(&cb); - address code = a->pc(); - void (*test)(uint32_t idx, uint32_t *regs) = (void(*)(uint32_t idx, uint32_t *regs))code; - - a->movq(r9, rbx); // save nonvolatile register - - // next line would not work on 32-bit - a->movq(rax, c_rarg0 /* rcx */); - a->movq(r8, c_rarg1 /* rdx */); - a->cpuid(); - a->movl(Address(r8, 0), rax); - a->movl(Address(r8, 4), rbx); - a->movl(Address(r8, 8), rcx); - a->movl(Address(r8, 12), rdx); - - a->movq(rbx, r9); // restore nonvolatile register - a->ret(0); - - uint32_t *code_end = (uint32_t *)a->pc(); - a->flush(); - - // execute code - (*test)(idx, regs); -#elif defined(__GNUC__) - __asm__ volatile ( - " cpuid;" - " mov %%eax,(%1);" - " mov %%ebx,4(%1);" - " mov %%ecx,8(%1);" - " mov %%edx,12(%1);" - : "+a" (idx) - : "S" (regs) - : "ebx", "ecx", "edx", "memory" ); -#endif -#endif -} - - bool VM_Version::use_biased_locking() { #if INCLUDE_RTM_OPT // RTM locking is most useful when there is high lock contention and @@ -1653,54 +1594,6 @@ return UseBiasedLocking; } -// On Xen, the cpuid instruction returns -// eax / registers[0]: Version of Xen -// ebx / registers[1]: chars 'XenV' -// ecx / registers[2]: chars 'MMXe' -// edx / registers[3]: chars 'nVMM' -// -// On KVM / VMWare / MS Hyper-V, the cpuid instruction returns -// ebx / registers[1]: chars 'KVMK' / 'VMwa' / 'Micr' -// ecx / registers[2]: chars 'VMKV' / 'reVM' / 'osof' -// edx / registers[3]: chars 'M' / 'ware' / 't Hv' -// -// more information : -// https://kb.vmware.com/s/article/1009458 -// -void VM_Version::check_virtualizations() { -#if defined(_LP64) - uint32_t registers[4]; - char signature[13]; - uint32_t base; - signature[12] = '\0'; - memset((void*)registers, 0, 4*sizeof(uint32_t)); - - for (base = 0x40000000; base < 0x40010000; base += 0x100) { - check_virt_cpuid(base, registers); - - *(uint32_t *)(signature + 0) = registers[1]; - *(uint32_t *)(signature + 4) = registers[2]; - *(uint32_t *)(signature + 8) = registers[3]; - - if (strncmp("VMwareVMware", signature, 12) == 0) { - Abstract_VM_Version::_detected_virtualization = VMWare; - } - - if (strncmp("Microsoft Hv", signature, 12) == 0) { - Abstract_VM_Version::_detected_virtualization = HyperV; - } - - if (strncmp("KVMKVMKVM", signature, 9) == 0) { - Abstract_VM_Version::_detected_virtualization = KVM; - } - - if (strncmp("XenVMMXenVMM", signature, 12) == 0) { - Abstract_VM_Version::_detected_virtualization = XenHVM; - } - } -#endif -} - void VM_Version::initialize() { ResourceMark rm; // Making this stub must be FIRST use of assembler @@ -1715,7 +1608,4 @@ g.generate_get_cpu_info()); get_processor_features(); - if (cpu_family() > 4) { // it supports CPUID - check_virtualizations(); - } } --- old/src/hotspot/cpu/x86/vm_version_x86.hpp 2019-05-21 01:01:06.021174262 +0200 +++ new/src/hotspot/cpu/x86/vm_version_x86.hpp 2019-05-21 01:01:05.873174527 +0200 @@ -495,13 +495,13 @@ result |= CPU_CX8; if (_cpuid_info.std_cpuid1_edx.bits.cmov != 0) result |= CPU_CMOV; - if (_cpuid_info.std_cpuid1_edx.bits.fxsr != 0 || (is_amd_family() && + if (_cpuid_info.std_cpuid1_edx.bits.fxsr != 0 || (is_amd() && _cpuid_info.ext_cpuid1_edx.bits.fxsr != 0)) result |= CPU_FXSR; // HT flag is set for multi-core processors also. if (threads_per_core() > 1) result |= CPU_HT; - if (_cpuid_info.std_cpuid1_edx.bits.mmx != 0 || (is_amd_family() && + if (_cpuid_info.std_cpuid1_edx.bits.mmx != 0 || (is_amd() && _cpuid_info.ext_cpuid1_edx.bits.mmx != 0)) result |= CPU_MMX; if (_cpuid_info.std_cpuid1_edx.bits.sse != 0) @@ -553,7 +553,7 @@ result |= CPU_VNNI; } } - if (_cpuid_info.sef_cpuid7_ebx.bits.bmi1 != 0) + if(_cpuid_info.sef_cpuid7_ebx.bits.bmi1 != 0) result |= CPU_BMI1; if (_cpuid_info.std_cpuid1_edx.bits.tsc != 0) result |= CPU_TSC; @@ -567,17 +567,17 @@ result |= CPU_CLMUL; if (_cpuid_info.sef_cpuid7_ebx.bits.rtm != 0) result |= CPU_RTM; - if (_cpuid_info.sef_cpuid7_ebx.bits.adx != 0) + if(_cpuid_info.sef_cpuid7_ebx.bits.adx != 0) result |= CPU_ADX; - if (_cpuid_info.sef_cpuid7_ebx.bits.bmi2 != 0) + if(_cpuid_info.sef_cpuid7_ebx.bits.bmi2 != 0) result |= CPU_BMI2; if (_cpuid_info.sef_cpuid7_ebx.bits.sha != 0) result |= CPU_SHA; if (_cpuid_info.std_cpuid1_ecx.bits.fma != 0) result |= CPU_FMA; - // AMD|Hygon features. - if (is_amd_family()) { + // AMD features. + if (is_amd()) { if ((_cpuid_info.ext_cpuid1_edx.bits.tdnow != 0) || (_cpuid_info.ext_cpuid1_ecx.bits.prefetchw != 0)) result |= CPU_3DNOW_PREFETCH; @@ -587,8 +587,8 @@ result |= CPU_SSE4A; } // Intel features. - if (is_intel()) { - if (_cpuid_info.ext_cpuid1_ecx.bits.lzcnt_intel != 0) + if(is_intel()) { + if(_cpuid_info.ext_cpuid1_ecx.bits.lzcnt_intel != 0) result |= CPU_LZCNT; // for Intel, ecx.bits.misalignsse bit (bit 8) indicates support for prefetchw if (_cpuid_info.ext_cpuid1_ecx.bits.misalignsse != 0) { @@ -686,9 +686,6 @@ static void initialize(); // Override Abstract_VM_Version implementation - static void print_platform_virtualization_info(outputStream*); - - // Override Abstract_VM_Version implementation static bool use_biased_locking(); // Asserts @@ -714,8 +711,6 @@ static int cpu_family() { return _cpu;} static bool is_P6() { return cpu_family() >= 6; } static bool is_amd() { assert_is_initialized(); return _cpuid_info.std_vendor_name_0 == 0x68747541; } // 'htuA' - static bool is_hygon() { assert_is_initialized(); return _cpuid_info.std_vendor_name_0 == 0x6F677948; } // 'ogyH' - static bool is_amd_family() { return is_amd() || is_hygon(); } static bool is_intel() { assert_is_initialized(); return _cpuid_info.std_vendor_name_0 == 0x756e6547; } // 'uneG' static bool is_zx() { assert_is_initialized(); return (_cpuid_info.std_vendor_name_0 == 0x746e6543) || (_cpuid_info.std_vendor_name_0 == 0x68532020); } // 'tneC'||'hS ' static bool is_atom_family() { return ((cpu_family() == 0x06) && ((extended_cpu_model() == 0x36) || (extended_cpu_model() == 0x37) || (extended_cpu_model() == 0x4D))); } //Silvermont and Centerton @@ -739,7 +734,7 @@ if (!supports_topology || result == 0) { result = (_cpuid_info.dcp_cpuid4_eax.bits.cores_per_cpu + 1); } - } else if (is_amd_family()) { + } else if (is_amd()) { result = (_cpuid_info.ext_cpuid8_ecx.bits.cores_per_cpu + 1); } else if (is_zx()) { bool supports_topology = supports_processor_topology(); @@ -775,7 +770,7 @@ intx result = 0; if (is_intel()) { result = (_cpuid_info.dcp_cpuid4_ebx.bits.L1_line_size + 1); - } else if (is_amd_family()) { + } else if (is_amd()) { result = _cpuid_info.ext_cpuid5_ecx.bits.L1_line_size; } else if (is_zx()) { result = (_cpuid_info.dcp_cpuid4_ebx.bits.L1_line_size + 1); @@ -862,7 +857,7 @@ // AMD features static bool supports_3dnow_prefetch() { return (_features & CPU_3DNOW_PREFETCH) != 0; } - static bool supports_mmx_ext() { return is_amd_family() && _cpuid_info.ext_cpuid1_edx.bits.mmx_amd != 0; } + static bool supports_mmx_ext() { return is_amd() && _cpuid_info.ext_cpuid1_edx.bits.mmx_amd != 0; } static bool supports_lzcnt() { return (_features & CPU_LZCNT) != 0; } static bool supports_sse4a() { return (_features & CPU_SSE4A) != 0; } @@ -875,8 +870,8 @@ } static bool supports_tscinv() { return supports_tscinv_bit() && - ((is_amd_family() && !is_amd_Barcelona()) || - is_intel_tsc_synched_at_init()); + ( (is_amd() && !is_amd_Barcelona()) || + is_intel_tsc_synched_at_init() ); } // Intel Core and newer cpus have fast IDIV instruction (excluding Atom). @@ -901,7 +896,7 @@ // Core - 256 / prefetchnta // It will be used only when AllocatePrefetchStyle > 0 - if (is_amd_family()) { // AMD | Hygon + if (is_amd()) { // AMD if (supports_sse2()) { return 256; // Opteron } else { @@ -935,11 +930,6 @@ // that can be used for efficient implementation of // the intrinsic for java.lang.Thread.onSpinWait() static bool supports_on_spin_wait() { return supports_sse2(); } - - // support functions for virtualization detection - private: - static void check_virt_cpuid(uint32_t idx, uint32_t *regs); - static void check_virtualizations(); }; #endif // CPU_X86_VM_VERSION_X86_HPP --- old/src/hotspot/cpu/x86/x86_32.ad 2019-05-21 01:01:06.221173903 +0200 +++ new/src/hotspot/cpu/x86/x86_32.ad 2019-05-21 01:01:06.069174176 +0200 @@ -1309,7 +1309,7 @@ } uint MachSpillCopyNode::size(PhaseRegAlloc *ra_) const { - return MachNode::size(ra_); + return implementation( NULL, ra_, true, NULL ); } --- old/src/hotspot/cpu/zero/cppInterpreter_zero.cpp 2019-05-21 01:01:06.493173416 +0200 +++ new/src/hotspot/cpu/zero/cppInterpreter_zero.cpp 2019-05-21 01:01:06.345173681 +0200 @@ -371,12 +371,14 @@ intptr_t result[4 - LogBytesPerWord]; ffi_call(handler->cif(), (void (*)()) function, result, arguments); - // Change the thread state back to _thread_in_Java and ensure it - // is seen by the GC thread. + // Change the thread state back to _thread_in_Java. // ThreadStateTransition::transition_from_native() cannot be used // here because it does not check for asynchronous exceptions. // We have to manage the transition ourself. - thread->set_thread_state_fence(_thread_in_native_trans); + thread->set_thread_state(_thread_in_native_trans); + + // Make sure new state is visible in the GC thread + InterfaceSupport::serialize_thread_state(thread); // Handle safepoint operations, pending suspend requests, // and pending asynchronous exceptions. @@ -699,11 +701,11 @@ return stack->sp() + argument_slots; } -JRT_ENTRY(void, CppInterpreter::throw_exception(JavaThread* thread, +IRT_ENTRY(void, CppInterpreter::throw_exception(JavaThread* thread, Symbol* name, char* message)) THROW_MSG(name, message); -JRT_END +IRT_END InterpreterFrame *InterpreterFrame::build(Method* const method, TRAPS) { JavaThread *thread = (JavaThread *) THREAD; --- old/src/hotspot/cpu/zero/interpreterRT_zero.cpp 2019-05-21 01:01:06.685173072 +0200 +++ new/src/hotspot/cpu/zero/interpreterRT_zero.cpp 2019-05-21 01:01:06.537173337 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. * Copyright 2007, 2008, 2010 Red Hat, Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -141,7 +141,7 @@ assert(status == FFI_OK, "should be"); } -JRT_ENTRY(address, +IRT_ENTRY(address, InterpreterRuntime::slow_signature_handler(JavaThread* thread, Method* method, intptr_t* unused1, @@ -162,7 +162,7 @@ handler->finalize(); return (address) handler; -JRT_END +IRT_END void SignatureHandlerLibrary::pd_set_handler(address handlerAddr) { InterpreterRuntime::SignatureHandler *handler = --- old/src/hotspot/os/aix/os_perf_aix.cpp 2019-05-21 01:01:06.873172735 +0200 +++ new/src/hotspot/os/aix/os_perf_aix.cpp 2019-05-21 01:01:06.725173001 +0200 @@ -273,12 +273,110 @@ return n; } +static FILE* open_statfile(void) { + FILE *f; + + if ((f = fopen("/proc/stat", "r")) == NULL) { + static int haveWarned = 0; + if (!haveWarned) { + haveWarned = 1; + } + } + return f; +} + +static void +next_line(FILE *f) { + int c; + do { + c = fgetc(f); + } while (c != '\n' && c != EOF); +} + /** - * on Linux we got the ticks related information from /proc/stat - * this does not work on AIX, libperfstat might be an alternative + * Return the total number of ticks since the system was booted. + * If the usedTicks parameter is not NULL, it will be filled with + * the number of ticks spent on actual processes (user, system or + * nice processes) since system boot. Note that this is the total number + * of "executed" ticks on _all_ CPU:s, that is on a n-way system it is + * n times the number of ticks that has passed in clock time. + * + * Returns a negative value if the reading of the ticks failed. */ static OSReturn get_total_ticks(int which_logical_cpu, CPUPerfTicks* pticks) { - return OS_ERR; + FILE* fh; + uint64_t userTicks, niceTicks, systemTicks, idleTicks; + uint64_t iowTicks = 0, irqTicks = 0, sirqTicks= 0; + int logical_cpu = -1; + const int expected_assign_count = (-1 == which_logical_cpu) ? 4 : 5; + int n; + + if ((fh = open_statfile()) == NULL) { + return OS_ERR; + } + if (-1 == which_logical_cpu) { + n = fscanf(fh, "cpu " UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT " " + UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT, + &userTicks, &niceTicks, &systemTicks, &idleTicks, + &iowTicks, &irqTicks, &sirqTicks); + } else { + // Move to next line + next_line(fh); + + // find the line for requested cpu faster to just iterate linefeeds? + for (int i = 0; i < which_logical_cpu; i++) { + next_line(fh); + } + + n = fscanf(fh, "cpu%u " UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT " " + UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT, + &logical_cpu, &userTicks, &niceTicks, + &systemTicks, &idleTicks, &iowTicks, &irqTicks, &sirqTicks); + } + + fclose(fh); + if (n < expected_assign_count || logical_cpu != which_logical_cpu) { +#ifdef DEBUG_LINUX_PROC_STAT + vm_fprintf(stderr, "[stat] read failed"); +#endif + return OS_ERR; + } + +#ifdef DEBUG_LINUX_PROC_STAT + vm_fprintf(stderr, "[stat] read " + UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT " " + UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT " \n", + userTicks, niceTicks, systemTicks, idleTicks, + iowTicks, irqTicks, sirqTicks); +#endif + + pticks->used = userTicks + niceTicks; + pticks->usedKernel = systemTicks + irqTicks + sirqTicks; + pticks->total = userTicks + niceTicks + systemTicks + idleTicks + + iowTicks + irqTicks + sirqTicks; + + return OS_OK; +} + + +static int get_systemtype(void) { + static int procEntriesType = UNDETECTED; + DIR *taskDir; + + if (procEntriesType != UNDETECTED) { + return procEntriesType; + } + + // Check whether we have a task subdirectory + if ((taskDir = opendir("/proc/self/task")) == NULL) { + procEntriesType = UNDETECTABLE; + } else { + // The task subdirectory exists; we're on a Linux >= 2.6 system + closedir(taskDir); + procEntriesType = LINUX26_NPTL; + } + + return procEntriesType; } /** read user and system ticks from a named procfile, assumed to be in 'stat' format then. */ @@ -292,7 +390,26 @@ * to the JVM on any CPU. */ static OSReturn get_jvm_ticks(CPUPerfTicks* pticks) { - return OS_ERR; + uint64_t userTicks; + uint64_t systemTicks; + + if (get_systemtype() != LINUX26_NPTL) { + return OS_ERR; + } + + if (read_ticks("/proc/self/stat", &userTicks, &systemTicks) != 2) { + return OS_ERR; + } + + // get the total + if (get_total_ticks(-1, pticks) != OS_OK) { + return OS_ERR; + } + + pticks->used = userTicks; + pticks->usedKernel = systemTicks; + + return OS_OK; } /** @@ -356,7 +473,29 @@ } static int SCANF_ARGS(1, 2) parse_stat(_SCANFMT_ const char* fmt, ...) { - return OS_ERR; + FILE *f; + va_list args; + + va_start(args, fmt); + + if ((f = open_statfile()) == NULL) { + va_end(args); + return OS_ERR; + } + for (;;) { + char line[80]; + if (fgets(line, sizeof(line), f) != NULL) { + if (vsscanf(line, fmt, args) == 1) { + fclose(f); + va_end(args); + return OS_OK; + } + } else { + fclose(f); + va_end(args); + return OS_ERR; + } + } } static int get_noof_context_switches(uint64_t* switches) { --- old/src/hotspot/os/linux/os_linux.cpp 2019-05-21 01:01:07.069172384 +0200 +++ new/src/hotspot/os/linux/os_linux.cpp 2019-05-21 01:01:06.917172657 +0200 @@ -63,7 +63,6 @@ #include "runtime/threadCritical.hpp" #include "runtime/threadSMR.hpp" #include "runtime/timer.hpp" -#include "runtime/vm_version.hpp" #include "semaphore_posix.hpp" #include "services/attachListener.hpp" #include "services/memTracker.hpp" @@ -228,82 +227,6 @@ return phys_mem; } -static uint64_t initial_total_ticks = 0; -static uint64_t initial_steal_ticks = 0; -static bool has_initial_tick_info = false; - -static void next_line(FILE *f) { - int c; - do { - c = fgetc(f); - } while (c != '\n' && c != EOF); -} - -bool os::Linux::get_tick_information(CPUPerfTicks* pticks, int which_logical_cpu) { - FILE* fh; - uint64_t userTicks, niceTicks, systemTicks, idleTicks; - // since at least kernel 2.6 : iowait: time waiting for I/O to complete - // irq: time servicing interrupts; softirq: time servicing softirqs - uint64_t iowTicks = 0, irqTicks = 0, sirqTicks= 0; - // steal (since kernel 2.6.11): time spent in other OS when running in a virtualized environment - uint64_t stealTicks = 0; - // guest (since kernel 2.6.24): time spent running a virtual CPU for guest OS under the - // control of the Linux kernel - uint64_t guestNiceTicks = 0; - int logical_cpu = -1; - const int required_tickinfo_count = (which_logical_cpu == -1) ? 4 : 5; - int n; - - memset(pticks, 0, sizeof(CPUPerfTicks)); - - if ((fh = fopen("/proc/stat", "r")) == NULL) { - return false; - } - - if (which_logical_cpu == -1) { - n = fscanf(fh, "cpu " UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT " " - UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT " " - UINT64_FORMAT " " UINT64_FORMAT " ", - &userTicks, &niceTicks, &systemTicks, &idleTicks, - &iowTicks, &irqTicks, &sirqTicks, - &stealTicks, &guestNiceTicks); - } else { - // Move to next line - next_line(fh); - - // find the line for requested cpu faster to just iterate linefeeds? - for (int i = 0; i < which_logical_cpu; i++) { - next_line(fh); - } - - n = fscanf(fh, "cpu%u " UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT " " - UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT " " - UINT64_FORMAT " " UINT64_FORMAT " ", - &logical_cpu, &userTicks, &niceTicks, - &systemTicks, &idleTicks, &iowTicks, &irqTicks, &sirqTicks, - &stealTicks, &guestNiceTicks); - } - - fclose(fh); - if (n < required_tickinfo_count || logical_cpu != which_logical_cpu) { - return false; - } - pticks->used = userTicks + niceTicks; - pticks->usedKernel = systemTicks + irqTicks + sirqTicks; - pticks->total = userTicks + niceTicks + systemTicks + idleTicks + - iowTicks + irqTicks + sirqTicks + stealTicks + guestNiceTicks; - - if (n > required_tickinfo_count + 3) { - pticks->steal = stealTicks; - pticks->has_steal_ticks = true; - } else { - pticks->steal = 0; - pticks->has_steal_ticks = false; - } - - return true; -} - // Return true if user is running as root. bool os::have_special_privileges() { @@ -1940,6 +1863,35 @@ return true; } +#if defined(S390) || defined(PPC64) +// keywords_to_match - NULL terminated array of keywords +static bool print_matching_lines_from_file(const char* filename, outputStream* st, const char* keywords_to_match[]) { + char* line = NULL; + size_t length = 0; + FILE* fp = fopen(filename, "r"); + if (fp == NULL) { + return false; + } + + st->print_cr("Virtualization information:"); + while (getline(&line, &length, fp) != -1) { + int i = 0; + while (keywords_to_match[i] != NULL) { + if (strncmp(line, keywords_to_match[i], strlen(keywords_to_match[i])) == 0) { + st->print("%s", line); + break; + } + i++; + } + } + + free(line); + fclose(fp); + + return true; +} +#endif + void os::print_dll_info(outputStream *st) { st->print_cr("Dynamic libraries:"); @@ -2024,9 +1976,7 @@ os::Linux::print_container_info(st); - VM_Version::print_platform_virtualization_info(st); - - os::Linux::print_steal_info(st); + os::Linux::print_virtualization_info(st); } // Try to identify popular distros. @@ -2281,22 +2231,38 @@ st->cr(); } -void os::Linux::print_steal_info(outputStream* st) { - if (has_initial_tick_info) { - CPUPerfTicks pticks; - bool res = os::Linux::get_tick_information(&pticks, -1); - - if (res && pticks.has_steal_ticks) { - uint64_t steal_ticks_difference = pticks.steal - initial_steal_ticks; - uint64_t total_ticks_difference = pticks.total - initial_total_ticks; - double steal_ticks_perc = 0.0; - if (total_ticks_difference != 0) { - steal_ticks_perc = (double) steal_ticks_difference / total_ticks_difference; - } - st->print_cr("Steal ticks since vm start: " UINT64_FORMAT, steal_ticks_difference); - st->print_cr("Steal ticks percentage since vm start:%7.3f", steal_ticks_perc); - } +void os::Linux::print_virtualization_info(outputStream* st) { +#if defined(S390) + // /proc/sysinfo contains interesting information about + // - LPAR + // - whole "Box" (CPUs ) + // - z/VM / KVM (VM); this is not available in an LPAR-only setup + const char* kw[] = { "LPAR", "CPUs", "VM", NULL }; + const char* info_file = "/proc/sysinfo"; + + if (!print_matching_lines_from_file(info_file, st, kw)) { + st->print_cr(" <%s Not Available>", info_file); + } +#elif defined(PPC64) + const char* info_file = "/proc/ppc64/lparcfg"; + const char* kw[] = { "system_type=", // qemu indicates PowerKVM + "partition_entitled_capacity=", // entitled processor capacity percentage + "partition_max_entitled_capacity=", + "capacity_weight=", // partition CPU weight + "partition_active_processors=", + "partition_potential_processors=", + "entitled_proc_capacity_available=", + "capped=", // 0 - uncapped, 1 - vcpus capped at entitled processor capacity percentage + "shared_processor_mode=", // (non)dedicated partition + "system_potential_processors=", + "pool=", // CPU-pool number + "pool_capacity=", + "NumLpars=", // on non-KVM machines, NumLpars is not found for full partition mode machines + NULL }; + if (!print_matching_lines_from_file(info_file, st, kw)) { + st->print_cr(" <%s Not Available>", info_file); } +#endif } void os::print_memory_info(outputStream* st) { @@ -5023,15 +4989,6 @@ Linux::initialize_os_info(); - os::Linux::CPUPerfTicks pticks; - bool res = os::Linux::get_tick_information(&pticks, -1); - - if (res && pticks.has_steal_ticks) { - has_initial_tick_info = true; - initial_total_ticks = pticks.total; - initial_steal_ticks = pticks.steal; - } - // _main_thread points to the thread that created/loaded the JVM. Linux::_main_thread = pthread_self(); --- old/src/hotspot/os/linux/os_linux.hpp 2019-05-21 01:01:07.297171974 +0200 +++ new/src/hotspot/os/linux/os_linux.hpp 2019-05-21 01:01:07.149172239 +0200 @@ -108,23 +108,13 @@ static void print_full_memory_info(outputStream* st); static void print_container_info(outputStream* st); - static void print_steal_info(outputStream* st); + static void print_virtualization_info(outputStream* st); static void print_distro_info(outputStream* st); static void print_libversion_info(outputStream* st); static void print_proc_sys_info(outputStream* st); static void print_ld_preload_file(outputStream* st); public: - struct CPUPerfTicks { - uint64_t used; - uint64_t usedKernel; - uint64_t total; - uint64_t steal; - bool has_steal_ticks; - }; - - // which_logical_cpu=-1 returns accumulated ticks for all cpus. - static bool get_tick_information(CPUPerfTicks* pticks, int which_logical_cpu); static bool _stack_is_executable; static void *dlopen_helper(const char *name, char *ebuf, int ebuflen); static void *dll_load_in_vmthread(const char *name, char *ebuf, int ebuflen); --- old/src/hotspot/os/linux/os_perf_linux.cpp 2019-05-21 01:01:07.489171630 +0200 +++ new/src/hotspot/os/linux/os_perf_linux.cpp 2019-05-21 01:01:07.337171903 +0200 @@ -206,6 +206,13 @@ # define _SCANFMT_ #endif + +struct CPUPerfTicks { + uint64_t used; + uint64_t usedKernel; + uint64_t total; +}; + typedef enum { CPU_LOAD_VM_ONLY, CPU_LOAD_GLOBAL, @@ -220,8 +227,8 @@ struct CPUPerfCounters { int nProcs; - os::Linux::CPUPerfTicks jvmTicks; - os::Linux::CPUPerfTicks* cpus; + CPUPerfTicks jvmTicks; + CPUPerfTicks* cpus; }; static double get_cpu_load(int which_logical_cpu, CPUPerfCounters* counters, double* pkernelLoad, CpuLoadTarget target); @@ -280,6 +287,80 @@ return f; } +static void +next_line(FILE *f) { + int c; + do { + c = fgetc(f); + } while (c != '\n' && c != EOF); +} + +/** + * Return the total number of ticks since the system was booted. + * If the usedTicks parameter is not NULL, it will be filled with + * the number of ticks spent on actual processes (user, system or + * nice processes) since system boot. Note that this is the total number + * of "executed" ticks on _all_ CPU:s, that is on a n-way system it is + * n times the number of ticks that has passed in clock time. + * + * Returns a negative value if the reading of the ticks failed. + */ +static OSReturn get_total_ticks(int which_logical_cpu, CPUPerfTicks* pticks) { + FILE* fh; + uint64_t userTicks, niceTicks, systemTicks, idleTicks; + uint64_t iowTicks = 0, irqTicks = 0, sirqTicks= 0; + int logical_cpu = -1; + const int expected_assign_count = (-1 == which_logical_cpu) ? 4 : 5; + int n; + + if ((fh = open_statfile()) == NULL) { + return OS_ERR; + } + if (-1 == which_logical_cpu) { + n = fscanf(fh, "cpu " UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT " " + UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT, + &userTicks, &niceTicks, &systemTicks, &idleTicks, + &iowTicks, &irqTicks, &sirqTicks); + } else { + // Move to next line + next_line(fh); + + // find the line for requested cpu faster to just iterate linefeeds? + for (int i = 0; i < which_logical_cpu; i++) { + next_line(fh); + } + + n = fscanf(fh, "cpu%u " UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT " " + UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT, + &logical_cpu, &userTicks, &niceTicks, + &systemTicks, &idleTicks, &iowTicks, &irqTicks, &sirqTicks); + } + + fclose(fh); + if (n < expected_assign_count || logical_cpu != which_logical_cpu) { +#ifdef DEBUG_LINUX_PROC_STAT + vm_fprintf(stderr, "[stat] read failed"); +#endif + return OS_ERR; + } + +#ifdef DEBUG_LINUX_PROC_STAT + vm_fprintf(stderr, "[stat] read " + UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT " " + UINT64_FORMAT " " UINT64_FORMAT " " UINT64_FORMAT " \n", + userTicks, niceTicks, systemTicks, idleTicks, + iowTicks, irqTicks, sirqTicks); +#endif + + pticks->used = userTicks + niceTicks; + pticks->usedKernel = systemTicks + irqTicks + sirqTicks; + pticks->total = userTicks + niceTicks + systemTicks + idleTicks + + iowTicks + irqTicks + sirqTicks; + + return OS_OK; +} + + static int get_systemtype(void) { static int procEntriesType = UNDETECTED; DIR *taskDir; @@ -310,7 +391,7 @@ * Return the number of ticks spent in any of the processes belonging * to the JVM on any CPU. */ -static OSReturn get_jvm_ticks(os::Linux::CPUPerfTicks* pticks) { +static OSReturn get_jvm_ticks(CPUPerfTicks* pticks) { uint64_t userTicks; uint64_t systemTicks; @@ -323,7 +404,7 @@ } // get the total - if (! os::Linux::get_tick_information(pticks, -1)) { + if (get_total_ticks(-1, pticks) != OS_OK) { return OS_ERR; } @@ -342,8 +423,8 @@ */ static double get_cpu_load(int which_logical_cpu, CPUPerfCounters* counters, double* pkernelLoad, CpuLoadTarget target) { uint64_t udiff, kdiff, tdiff; - os::Linux::CPUPerfTicks* pticks; - os::Linux::CPUPerfTicks tmp; + CPUPerfTicks* pticks; + CPUPerfTicks tmp; double user_load; *pkernelLoad = 0.0; @@ -362,7 +443,7 @@ if (get_jvm_ticks(pticks) != OS_OK) { return -1.0; } - } else if (! os::Linux::get_tick_information(pticks, which_logical_cpu)) { + } else if (get_total_ticks(which_logical_cpu, pticks) != OS_OK) { return -1.0; } @@ -503,19 +584,19 @@ } bool CPUPerformanceInterface::CPUPerformance::initialize() { - size_t tick_array_size = (_counters.nProcs +1) * sizeof(os::Linux::CPUPerfTicks); - _counters.cpus = (os::Linux::CPUPerfTicks*)NEW_C_HEAP_ARRAY(char, tick_array_size, mtInternal); + size_t tick_array_size = (_counters.nProcs +1) * sizeof(CPUPerfTicks); + _counters.cpus = (CPUPerfTicks*)NEW_C_HEAP_ARRAY(char, tick_array_size, mtInternal); if (NULL == _counters.cpus) { return false; } memset(_counters.cpus, 0, tick_array_size); // For the CPU load total - os::Linux::get_tick_information(&_counters.cpus[_counters.nProcs], -1); + get_total_ticks(-1, &_counters.cpus[_counters.nProcs]); // For each CPU for (int i = 0; i < _counters.nProcs; i++) { - os::Linux::get_tick_information(&_counters.cpus[i], i); + get_total_ticks(i, &_counters.cpus[i]); } // For JVM load get_jvm_ticks(&_counters.jvmTicks); --- old/src/hotspot/os/windows/os_windows.cpp 2019-05-21 01:01:07.685171278 +0200 +++ new/src/hotspot/os/windows/os_windows.cpp 2019-05-21 01:01:07.537171543 +0200 @@ -1601,10 +1601,6 @@ #endif st->print("OS:"); os::win32::print_windows_version(st); - -#ifdef _LP64 - VM_Version::print_platform_virtualization_info(st); -#endif } void os::win32::print_windows_version(outputStream* st) { --- old/src/hotspot/os/windows/version.rc 2019-05-21 01:01:07.909170878 +0200 +++ new/src/hotspot/os/windows/version.rc 2019-05-21 01:01:07.761171143 +0200 @@ -1,5 +1,5 @@ // -// Copyright (c) 2004, 2019, Oracle and/or its affiliates. All rights reserved. +// Copyright (c) 2004, 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 @@ -36,8 +36,8 @@ // VS_VERSION_INFO VERSIONINFO - FILEVERSION HS_FVER - PRODUCTVERSION HS_FVER + FILEVERSION JDK_VER + PRODUCTVERSION JDK_VER FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -54,15 +54,15 @@ BEGIN BLOCK "000004b0" BEGIN - VALUE "CompanyName", XSTR(HS_COMPANY) "\0" - VALUE "FileDescription", XSTR(HS_FILEDESC) "\0" - VALUE "FileVersion", XSTR(HS_VER) "\0" - VALUE "Full Version", XSTR(HS_VERSION_STRING) "\0" - VALUE "InternalName", XSTR(HS_INTERNAL_NAME) "\0" - VALUE "LegalCopyright", XSTR(HS_COPYRIGHT) "\0" - VALUE "OriginalFilename", XSTR(HS_FNAME) "\0" - VALUE "ProductName", XSTR(HS_NAME) "\0" - VALUE "ProductVersion", XSTR(HS_VER) "\0" + VALUE "CompanyName", XSTR(HS_COMPANY) "\0" + VALUE "FileDescription", XSTR(HS_FILEDESC) "\0" + VALUE "FileVersion", XSTR(JDK_DOTVER) "\0" + VALUE "Full Version", XSTR(HS_BUILD_ID) "\0" + VALUE "InternalName", XSTR(HS_INTERNAL_NAME) "\0" + VALUE "LegalCopyright", XSTR(HS_COPYRIGHT) "\0" + VALUE "OriginalFilename", XSTR(HS_FNAME) "\0" + VALUE "ProductName", XSTR(HS_NAME) "\0" + VALUE "ProductVersion", XSTR(JDK_DOTVER) "\0" END END BLOCK "VarFileInfo" --- old/src/hotspot/os_cpu/linux_ppc/thread_linux_ppc.cpp 2019-05-21 01:01:08.101170534 +0200 +++ new/src/hotspot/os_cpu/linux_ppc/thread_linux_ppc.cpp 2019-05-21 01:01:07.949170806 +0200 @@ -66,7 +66,7 @@ if (ret_frame.is_interpreted_frame()) { frame::ijava_state* istate = ret_frame.get_ijava_state(); - if (MetaspaceObj::is_valid((Method*)(istate->method)) == false) { + if (!((Method*)(istate->method))->is_metaspace_object()) { return false; } uint64_t reg_bcp = uc->uc_mcontext.regs->gpr[14/*R14_bcp*/]; --- old/src/hotspot/os_cpu/linux_s390/thread_linux_s390.cpp 2019-05-21 01:01:08.289170195 +0200 +++ new/src/hotspot/os_cpu/linux_s390/thread_linux_s390.cpp 2019-05-21 01:01:08.141170462 +0200 @@ -63,8 +63,7 @@ if (ret_frame.is_interpreted_frame()) { frame::z_ijava_state* istate = ret_frame.ijava_state_unchecked(); - if ((stack_base() >= (address)istate && (address)istate > stack_end()) || - MetaspaceObj::is_valid((Method*)(istate->method)) == false) { + if ((stack_base() >= (address)istate && (address)istate > stack_end()) || !((Method*)(istate->method))->is_metaspace_object()) { return false; } uint64_t reg_bcp = uc->uc_mcontext.gregs[13/*Z_BCP*/]; --- old/src/hotspot/share/adlc/formssel.cpp 2019-05-21 01:01:08.477169859 +0200 +++ new/src/hotspot/share/adlc/formssel.cpp 2019-05-21 01:01:08.329170124 +0200 @@ -774,16 +774,10 @@ !strcmp(_matrule->_rChild->_opType,"CheckCastPP") || !strcmp(_matrule->_rChild->_opType,"GetAndSetP") || !strcmp(_matrule->_rChild->_opType,"GetAndSetN") || -#if INCLUDE_ZGC - !strcmp(_matrule->_rChild->_opType,"LoadBarrierSlowReg") || - !strcmp(_matrule->_rChild->_opType,"LoadBarrierWeakSlowReg") || -#endif -#if INCLUDE_SHENANDOAHGC - !strcmp(_matrule->_rChild->_opType,"ShenandoahCompareAndExchangeP") || - !strcmp(_matrule->_rChild->_opType,"ShenandoahCompareAndExchangeN") || -#endif !strcmp(_matrule->_rChild->_opType,"CompareAndExchangeP") || - !strcmp(_matrule->_rChild->_opType,"CompareAndExchangeN"))) return true; + !strcmp(_matrule->_rChild->_opType,"CompareAndExchangeN") || + !strcmp(_matrule->_rChild->_opType,"ShenandoahCompareAndExchangeP") || + !strcmp(_matrule->_rChild->_opType,"ShenandoahCompareAndExchangeN"))) return true; else if ( is_ideal_load() == Form::idealP ) return true; else if ( is_ideal_store() != Form::none ) return true; --- old/src/hotspot/share/classfile/classFileParser.cpp 2019-05-21 01:01:08.689169479 +0200 +++ new/src/hotspot/share/classfile/classFileParser.cpp 2019-05-21 01:01:08.537169752 +0200 @@ -5975,9 +5975,9 @@ _minor_version = stream->get_u2_fast(); _major_version = stream->get_u2_fast(); - if (DumpSharedSpaces && _major_version < JAVA_6_VERSION) { + if (DumpSharedSpaces && _major_version < JAVA_1_5_VERSION) { ResourceMark rm; - warning("Pre JDK 6 class not supported by CDS: %u.%u %s", + warning("Pre JDK 1.5 class not supported by CDS: %u.%u %s", _major_version, _minor_version, _class_name->as_C_string()); Exceptions::fthrow( THREAD_AND_LOCATION, --- old/src/hotspot/share/classfile/javaClasses.cpp 2019-05-21 01:01:08.917169071 +0200 +++ new/src/hotspot/share/classfile/javaClasses.cpp 2019-05-21 01:01:08.761169349 +0200 @@ -160,7 +160,6 @@ int java_lang_String::value_offset = 0; int java_lang_String::hash_offset = 0; -int java_lang_String::hashIsZero_offset = 0; int java_lang_String::coder_offset = 0; bool java_lang_String::initialized = false; @@ -180,8 +179,7 @@ #define STRING_FIELDS_DO(macro) \ macro(value_offset, k, vmSymbols::value_name(), byte_array_signature, false); \ macro(hash_offset, k, "hash", int_signature, false); \ - macro(hashIsZero_offset, k, "hashIsZero", bool_signature, false); \ - macro(coder_offset, k, "coder", byte_signature, false); + macro(coder_offset, k, "coder", byte_signature, false) void java_lang_String::compute_offsets() { if (initialized) { @@ -220,7 +218,7 @@ void java_lang_String::set_compact_strings(bool value) { CompactStringsFixup fix(value); - SystemDictionary::String_klass()->do_local_static_fields(&fix); + InstanceKlass::cast(SystemDictionary::String_klass())->do_local_static_fields(&fix); } Handle java_lang_String::basic_create(int length, bool is_latin1, TRAPS) { @@ -509,38 +507,18 @@ } unsigned int java_lang_String::hash_code(oop java_string) { - // The hash and hashIsZero fields are subject to a benign data race, - // making it crucial to ensure that any observable result of the - // calculation in this method stays correct under any possible read of - // these fields. Necessary restrictions to allow this to be correct - // without explicit memory fences or similar concurrency primitives is - // that we can ever only write to one of these two fields for a given - // String instance, and that the computation is idempotent and derived - // from immutable state - assert(initialized && (hash_offset > 0) && (hashIsZero_offset > 0), "Must be initialized"); - if (java_lang_String::hash_is_set(java_string)) { - return java_string->int_field(hash_offset); - } - - typeArrayOop value = java_lang_String::value(java_string); - int length = java_lang_String::length(java_string, value); - bool is_latin1 = java_lang_String::is_latin1(java_string); + typeArrayOop value = java_lang_String::value(java_string); + int length = java_lang_String::length(java_string, value); + // Zero length string will hash to zero with String.hashCode() function. + if (length == 0) return 0; - unsigned int hash = 0; - if (length > 0) { - if (is_latin1) { - hash = java_lang_String::hash_code(value->byte_at_addr(0), length); - } else { - hash = java_lang_String::hash_code(value->char_at_addr(0), length); - } - } + bool is_latin1 = java_lang_String::is_latin1(java_string); - if (hash != 0) { - java_string->int_field_put(hash_offset, hash); + if (is_latin1) { + return java_lang_String::hash_code(value->byte_at_addr(0), length); } else { - java_string->bool_field_put(hashIsZero_offset, true); + return java_lang_String::hash_code(value->char_at_addr(0), length); } - return hash; } char* java_lang_String::as_quoted_ascii(oop java_string) { @@ -1714,13 +1692,20 @@ jlong java_lang_Thread::stackSize(oop java_thread) { - return java_thread->long_field(_stackSize_offset); + if (_stackSize_offset > 0) { + return java_thread->long_field(_stackSize_offset); + } else { + return 0; + } } // Write the thread status value to threadStatus field in java.lang.Thread java class. void java_lang_Thread::set_thread_status(oop java_thread, java_lang_Thread::ThreadStatus status) { - java_thread->int_field_put(_thread_status_offset, status); + // The threadStatus is only present starting in 1.5 + if (_thread_status_offset > 0) { + java_thread->int_field_put(_thread_status_offset, status); + } } // Read thread status value from threadStatus field in java.lang.Thread java class. @@ -1730,31 +1715,62 @@ assert(Threads_lock->owned_by_self() || Thread::current()->is_VM_thread() || JavaThread::current()->thread_state() == _thread_in_vm, "Java Thread is not running in vm"); - return (java_lang_Thread::ThreadStatus)java_thread->int_field(_thread_status_offset); + // The threadStatus is only present starting in 1.5 + if (_thread_status_offset > 0) { + return (java_lang_Thread::ThreadStatus)java_thread->int_field(_thread_status_offset); + } else { + // All we can easily figure out is if it is alive, but that is + // enough info for a valid unknown status. + // These aren't restricted to valid set ThreadStatus values, so + // use JVMTI values and cast. + JavaThread* thr = java_lang_Thread::thread(java_thread); + if (thr == NULL) { + // the thread hasn't run yet or is in the process of exiting + return NEW; + } + return (java_lang_Thread::ThreadStatus)JVMTI_THREAD_STATE_ALIVE; + } } jlong java_lang_Thread::thread_id(oop java_thread) { - return java_thread->long_field(_tid_offset); + // The thread ID field is only present starting in 1.5 + if (_tid_offset > 0) { + return java_thread->long_field(_tid_offset); + } else { + return 0; + } } oop java_lang_Thread::park_blocker(oop java_thread) { - assert(JDK_Version::current().supports_thread_park_blocker(), - "Must support parkBlocker field"); + assert(JDK_Version::current().supports_thread_park_blocker() && + _park_blocker_offset != 0, "Must support parkBlocker field"); + + if (_park_blocker_offset > 0) { + return java_thread->obj_field(_park_blocker_offset); + } - return java_thread->obj_field(_park_blocker_offset); + return NULL; } jlong java_lang_Thread::park_event(oop java_thread) { - return java_thread->long_field(_park_event_offset); + if (_park_event_offset > 0) { + return java_thread->long_field(_park_event_offset); + } + return 0; } bool java_lang_Thread::set_park_event(oop java_thread, jlong ptr) { - java_thread->long_field_put(_park_event_offset, ptr); - return true; + if (_park_event_offset > 0) { + java_thread->long_field_put(_park_event_offset, ptr); + return true; + } + return false; } + const char* java_lang_Thread::thread_status_name(oop java_thread) { + assert(_thread_status_offset != 0, "Must have thread status"); ThreadStatus status = (java_lang_Thread::ThreadStatus)java_thread->int_field(_thread_status_offset); switch (status) { case NEW : return "NEW"; @@ -3597,48 +3613,23 @@ resolved_method->address_field_put(_vmtarget_offset, (address)m); } -void java_lang_invoke_ResolvedMethodName::set_vmholder(oop resolved_method, oop holder) { - assert(is_instance(resolved_method), "wrong type"); - resolved_method->obj_field_put(_vmholder_offset, holder); -} - oop java_lang_invoke_ResolvedMethodName::find_resolved_method(const methodHandle& m, TRAPS) { - const Method* method = m(); - // lookup ResolvedMethod oop in the table, or create a new one and intern it - oop resolved_method = ResolvedMethodTable::find_method(method); - if (resolved_method != NULL) { - return resolved_method; - } - - InstanceKlass* k = SystemDictionary::ResolvedMethodName_klass(); - if (!k->is_initialized()) { - k->initialize(CHECK_NULL); + oop resolved_method = ResolvedMethodTable::find_method(m()); + if (resolved_method == NULL) { + InstanceKlass* k = SystemDictionary::ResolvedMethodName_klass(); + if (!k->is_initialized()) { + k->initialize(CHECK_NULL); + } + oop new_resolved_method = k->allocate_instance(CHECK_NULL); + new_resolved_method->address_field_put(_vmtarget_offset, (address)m()); + // Add a reference to the loader (actually mirror because unsafe anonymous classes will not have + // distinct loaders) to ensure the metadata is kept alive. + // This mirror may be different than the one in clazz field. + new_resolved_method->obj_field_put(_vmholder_offset, m->method_holder()->java_mirror()); + resolved_method = ResolvedMethodTable::add_method(m, Handle(THREAD, new_resolved_method)); } - - oop new_resolved_method = k->allocate_instance(CHECK_NULL); - - NoSafepointVerifier nsv; - - if (method->is_old()) { - method = (method->is_deleted()) ? Universe::throw_no_such_method_error() : - method->get_new_method(); - } - - InstanceKlass* holder = method->method_holder(); - - set_vmtarget(new_resolved_method, const_cast(method)); - // Add a reference to the loader (actually mirror because unsafe anonymous classes will not have - // distinct loaders) to ensure the metadata is kept alive. - // This mirror may be different than the one in clazz field. - set_vmholder(new_resolved_method, holder->java_mirror()); - - // Set flag in class to indicate this InstanceKlass has entries in the table - // to avoid walking table during redefinition if none of the redefined classes - // have any membernames in the table. - holder->set_has_resolved_methods(); - - return ResolvedMethodTable::add_method(method, Handle(THREAD, new_resolved_method)); + return resolved_method; } oop java_lang_invoke_LambdaForm::vmentry(oop lform) { @@ -4000,48 +3991,6 @@ int java_lang_System::out_offset_in_bytes() { return static_out_offset; } int java_lang_System::err_offset_in_bytes() { return static_err_offset; } -// Support for jdk_internal_misc_UnsafeConstants -// -class UnsafeConstantsFixup : public FieldClosure { -private: - int _address_size; - int _page_size; - bool _big_endian; - bool _use_unaligned_access; -public: - UnsafeConstantsFixup() { - // round up values for all static final fields - _address_size = sizeof(void*); - _page_size = os::vm_page_size(); - _big_endian = LITTLE_ENDIAN_ONLY(false) BIG_ENDIAN_ONLY(true); - _use_unaligned_access = UseUnalignedAccesses; - } - - void do_field(fieldDescriptor* fd) { - oop mirror = fd->field_holder()->java_mirror(); - assert(mirror != NULL, "UnsafeConstants must have mirror already"); - assert(fd->field_holder() == SystemDictionary::UnsafeConstants_klass(), "Should be UnsafeConstants"); - assert(fd->is_final(), "fields of UnsafeConstants must be final"); - assert(fd->is_static(), "fields of UnsafeConstants must be static"); - if (fd->name() == vmSymbols::address_size_name()) { - mirror->int_field_put(fd->offset(), _address_size); - } else if (fd->name() == vmSymbols::page_size_name()) { - mirror->int_field_put(fd->offset(), _page_size); - } else if (fd->name() == vmSymbols::big_endian_name()) { - mirror->bool_field_put(fd->offset(), _big_endian); - } else if (fd->name() == vmSymbols::use_unaligned_access_name()) { - mirror->bool_field_put(fd->offset(), _use_unaligned_access); - } else { - assert(false, "unexpected UnsafeConstants field"); - } - } -}; - -void jdk_internal_misc_UnsafeConstants::set_unsafe_constants() { - UnsafeConstantsFixup fixup; - SystemDictionary::UnsafeConstants_klass()->do_local_static_fields(&fixup); -} - int java_lang_Class::_klass_offset; int java_lang_Class::_array_klass_offset; int java_lang_Class::_oop_size_offset; --- old/src/hotspot/share/classfile/javaClasses.hpp 2019-05-21 01:01:09.145168661 +0200 +++ new/src/hotspot/share/classfile/javaClasses.hpp 2019-05-21 01:01:08.993168934 +0200 @@ -81,7 +81,6 @@ f(java_lang_StackFrameInfo) \ f(java_lang_LiveStackFrameInfo) \ f(java_util_concurrent_locks_AbstractOwnableSynchronizer) \ - f(jdk_internal_misc_UnsafeConstants) \ //end #define BASIC_JAVA_CLASSES_DO(f) \ @@ -94,7 +93,6 @@ private: static int value_offset; static int hash_offset; - static int hashIsZero_offset; static int coder_offset; static bool initialized; @@ -133,10 +131,6 @@ assert(initialized && (hash_offset > 0), "Must be initialized"); return hash_offset; } - static int hashIsZero_offset_in_bytes() { - assert(initialized && (hashIsZero_offset > 0), "Must be initialized"); - return hashIsZero_offset; - } static int coder_offset_in_bytes() { assert(initialized && (coder_offset > 0), "Must be initialized"); return coder_offset; @@ -144,11 +138,12 @@ static inline void set_value_raw(oop string, typeArrayOop buffer); static inline void set_value(oop string, typeArrayOop buffer); + static inline void set_hash(oop string, unsigned int hash); // Accessors static inline typeArrayOop value(oop java_string); static inline typeArrayOop value_no_keepalive(oop java_string); - static inline bool hash_is_set(oop string); + static inline unsigned int hash(oop java_string); static inline bool is_latin1(oop java_string); static inline int length(oop java_string); static inline int length(oop java_string, typeArrayOop string_value); @@ -1063,8 +1058,6 @@ static Method* vmtarget(oop resolved_method); static void set_vmtarget(oop resolved_method, Method* method); - static void set_vmholder(oop resolved_method, oop holder); - // find or create resolved member name static oop find_resolved_method(const methodHandle& m, TRAPS); @@ -1490,15 +1483,6 @@ static void serialize_offsets(SerializeClosure* f) NOT_CDS_RETURN; }; - // Interface to jdk.internal.misc.UnsafeConsants - -class jdk_internal_misc_UnsafeConstants : AllStatic { - public: - static void set_unsafe_constants(); - static void compute_offsets() { } - static void serialize_offsets(SerializeClosure* f) { } -}; - // Use to declare fields that need to be injected into Java classes // for the JVM to use. The name_index and signature_index are // declared in vmSymbols. The may_be_java flag is used to declare --- old/src/hotspot/share/classfile/javaClasses.inline.hpp 2019-05-21 01:01:09.345168304 +0200 +++ new/src/hotspot/share/classfile/javaClasses.inline.hpp 2019-05-21 01:01:09.189168582 +0200 @@ -45,9 +45,9 @@ string->obj_field_put(value_offset, (oop)buffer); } -bool java_lang_String::hash_is_set(oop java_string) { - assert(initialized && (hash_offset > 0) && (hashIsZero_offset > 0), "Must be initialized"); - return java_string->int_field(hash_offset) != 0 || java_string->bool_field(hashIsZero_offset) != 0; +void java_lang_String::set_hash(oop string, unsigned int hash) { + assert(initialized && (hash_offset > 0), "Must be initialized"); + string->int_field_put(hash_offset, hash); } // Accessors @@ -71,6 +71,12 @@ return (typeArrayOop) java_string->obj_field_access(value_offset); } +unsigned int java_lang_String::hash(oop java_string) { + assert(initialized && (hash_offset > 0), "Must be initialized"); + assert(is_instance(java_string), "must be java_string"); + return java_string->int_field(hash_offset); +} + bool java_lang_String::is_latin1(oop java_string) { assert(initialized && (coder_offset > 0), "Must be initialized"); assert(is_instance(java_string), "must be java_string"); --- old/src/hotspot/share/classfile/stringTable.cpp 2019-05-21 01:01:09.561167917 +0200 +++ new/src/hotspot/share/classfile/stringTable.cpp 2019-05-21 01:01:09.401168202 +0200 @@ -761,6 +761,8 @@ return true; } unsigned int hash = java_lang_String::hash_code(s); + + java_lang_String::set_hash(s, hash); oop new_s = StringTable::create_archived_string(s, Thread::current()); if (new_s == NULL) { return true; --- old/src/hotspot/share/classfile/systemDictionary.cpp 2019-05-21 01:01:09.797167494 +0200 +++ new/src/hotspot/share/classfile/systemDictionary.cpp 2019-05-21 01:01:09.625167802 +0200 @@ -68,6 +68,7 @@ #include "oops/symbol.hpp" #include "oops/typeArrayKlass.hpp" #include "prims/jvmtiExport.hpp" +#include "prims/resolvedMethodTable.hpp" #include "prims/methodHandles.hpp" #include "runtime/arguments.hpp" #include "runtime/biasedLocking.hpp" @@ -1835,6 +1836,8 @@ } GCTraceTime(Debug, gc, phases) t("Trigger cleanups", gc_timer); + // Trigger cleaning the ResolvedMethodTable even if no unloading occurred. + ResolvedMethodTable::trigger_cleanup(); if (unloading_occurred) { SymbolTable::trigger_cleanup(); --- old/src/hotspot/share/classfile/systemDictionary.hpp 2019-05-21 01:01:10.029167076 +0200 +++ new/src/hotspot/share/classfile/systemDictionary.hpp 2019-05-21 01:01:09.873167356 +0200 @@ -177,7 +177,6 @@ do_klass(AssertionStatusDirectives_klass, java_lang_AssertionStatusDirectives ) \ do_klass(StringBuffer_klass, java_lang_StringBuffer ) \ do_klass(StringBuilder_klass, java_lang_StringBuilder ) \ - do_klass(UnsafeConstants_klass, jdk_internal_misc_UnsafeConstants ) \ do_klass(internal_Unsafe_klass, jdk_internal_misc_Unsafe ) \ do_klass(module_Modules_klass, jdk_internal_module_Modules ) \ \ --- old/src/hotspot/share/classfile/verifier.cpp 2019-05-21 01:01:10.233166711 +0200 +++ new/src/hotspot/share/classfile/verifier.cpp 2019-05-21 01:01:10.077166992 +0200 @@ -2060,9 +2060,7 @@ ss.vprint(msg, va); va_end(va); if (!_method.is_null()) { - ss.print(" in method '"); - _method->print_external_name(&ss); - ss.print("'"); + ss.print(" in method %s", _method->name_and_sig_as_C_string()); } _message = ss.as_string(); } --- old/src/hotspot/share/classfile/vmSymbols.hpp 2019-05-21 01:01:10.445166332 +0200 +++ new/src/hotspot/share/classfile/vmSymbols.hpp 2019-05-21 01:01:10.289166610 +0200 @@ -446,10 +446,6 @@ template(module_entry_name, "module_entry") \ template(resolved_references_name, "") \ template(init_lock_name, "") \ - template(address_size_name, "ADDRESS_SIZE0") \ - template(page_size_name, "PAGE_SIZE") \ - template(big_endian_name, "BIG_ENDIAN") \ - template(use_unaligned_access_name, "UNALIGNED_ACCESS") \ \ /* name symbols needed by intrinsics */ \ VM_INTRINSICS_DO(VM_INTRINSIC_IGNORE, VM_SYMBOL_IGNORE, template, VM_SYMBOL_IGNORE, VM_ALIAS_IGNORE) \ @@ -1074,9 +1070,6 @@ do_intrinsic(_updateByteBufferAdler32, java_util_zip_Adler32, updateByteBuffer_A_name, updateByteBuffer_signature, F_SN) \ do_name( updateByteBuffer_A_name, "updateByteBuffer") \ \ - /* support for UnsafeConstants */ \ - do_class(jdk_internal_misc_UnsafeConstants, "jdk/internal/misc/UnsafeConstants") \ - \ /* support for Unsafe */ \ do_class(jdk_internal_misc_Unsafe, "jdk/internal/misc/Unsafe") \ \ --- old/src/hotspot/share/code/codeCache.cpp 2019-05-21 01:01:10.665165937 +0200 +++ new/src/hotspot/share/code/codeCache.cpp 2019-05-21 01:01:10.501166230 +0200 @@ -780,14 +780,13 @@ CodeCache::UnloadingScope::UnloadingScope(BoolObjectClosure* is_alive) : _is_unloading_behaviour(is_alive) { - _saved_behaviour = IsUnloadingBehaviour::current(); IsUnloadingBehaviour::set_current(&_is_unloading_behaviour); increment_unloading_cycle(); DependencyContext::cleaning_start(); } CodeCache::UnloadingScope::~UnloadingScope() { - IsUnloadingBehaviour::set_current(_saved_behaviour); + IsUnloadingBehaviour::set_current(NULL); DependencyContext::cleaning_end(); } --- old/src/hotspot/share/code/codeCache.hpp 2019-05-21 01:01:10.869165570 +0200 +++ new/src/hotspot/share/code/codeCache.hpp 2019-05-21 01:01:10.717165843 +0200 @@ -170,7 +170,6 @@ // "unloading_occurred" controls whether metadata should be cleaned because of class unloading. class UnloadingScope: StackObj { ClosureIsUnloadingBehaviour _is_unloading_behaviour; - IsUnloadingBehaviour* _saved_behaviour; public: UnloadingScope(BoolObjectClosure* is_alive); --- old/src/hotspot/share/compiler/compileBroker.cpp 2019-05-21 01:01:11.061165226 +0200 +++ new/src/hotspot/share/compiler/compileBroker.cpp 2019-05-21 01:01:10.909165499 +0200 @@ -135,6 +135,11 @@ volatile jint CompileBroker::_compilation_id = 0; volatile jint CompileBroker::_osr_compilation_id = 0; +// Debugging information +int CompileBroker::_last_compile_type = no_compile; +int CompileBroker::_last_compile_level = CompLevel_none; +char CompileBroker::_last_method_compiled[CompileBroker::name_buffer_length]; + // Performance counters PerfCounter* CompileBroker::_perf_total_compilation = NULL; PerfCounter* CompileBroker::_perf_osr_compilation = NULL; @@ -572,6 +577,8 @@ // // Initialize the Compilation object void CompileBroker::compilation_init_phase1(TRAPS) { + _last_method_compiled[0] = '\0'; + // No need to initialize compilation system if we do not use it. if (!UseCompiler) { return; @@ -2025,10 +2032,8 @@ // Look up matching directives directive = DirectivesStack::getMatchingDirective(method, comp); - // Update compile information when using perfdata. - if (UsePerfData) { - update_compile_perf_data(thread, method, is_osr); - } + // Save information about this method in case of failure. + set_last_compile(thread, method, is_osr, task_level); DTRACE_METHOD_COMPILE_BEGIN_PROBE(method, compiler_name(task_level)); } @@ -2259,49 +2264,58 @@ } // ------------------------------------------------------------------ -// CompileBroker::update_compile_perf_data +// CompileBroker::set_last_compile // // Record this compilation for debugging purposes. -void CompileBroker::update_compile_perf_data(CompilerThread* thread, const methodHandle& method, bool is_osr) { +void CompileBroker::set_last_compile(CompilerThread* thread, const methodHandle& method, bool is_osr, int comp_level) { ResourceMark rm; char* method_name = method->name()->as_C_string(); + strncpy(_last_method_compiled, method_name, CompileBroker::name_buffer_length); + _last_method_compiled[CompileBroker::name_buffer_length - 1] = '\0'; // ensure null terminated char current_method[CompilerCounters::cmname_buffer_length]; size_t maxLen = CompilerCounters::cmname_buffer_length; - const char* class_name = method->method_holder()->name()->as_C_string(); + if (UsePerfData) { + const char* class_name = method->method_holder()->name()->as_C_string(); - size_t s1len = strlen(class_name); - size_t s2len = strlen(method_name); + size_t s1len = strlen(class_name); + size_t s2len = strlen(method_name); - // check if we need to truncate the string - if (s1len + s2len + 2 > maxLen) { + // check if we need to truncate the string + if (s1len + s2len + 2 > maxLen) { - // the strategy is to lop off the leading characters of the - // class name and the trailing characters of the method name. + // the strategy is to lop off the leading characters of the + // class name and the trailing characters of the method name. - if (s2len + 2 > maxLen) { - // lop of the entire class name string, let snprintf handle - // truncation of the method name. - class_name += s1len; // null string - } - else { - // lop off the extra characters from the front of the class name - class_name += ((s1len + s2len + 2) - maxLen); + if (s2len + 2 > maxLen) { + // lop of the entire class name string, let snprintf handle + // truncation of the method name. + class_name += s1len; // null string + } + else { + // lop off the extra characters from the front of the class name + class_name += ((s1len + s2len + 2) - maxLen); + } } - } - jio_snprintf(current_method, maxLen, "%s %s", class_name, method_name); + jio_snprintf(current_method, maxLen, "%s %s", class_name, method_name); + } - int last_compile_type = normal_compile; if (CICountOSR && is_osr) { - last_compile_type = osr_compile; + _last_compile_type = osr_compile; + } else { + _last_compile_type = normal_compile; } + _last_compile_level = comp_level; - CompilerCounters* counters = thread->counters(); - counters->set_current_method(current_method); - counters->set_compile_type((jlong) last_compile_type); + if (UsePerfData) { + CompilerCounters* counters = thread->counters(); + counters->set_current_method(current_method); + counters->set_compile_type((jlong)_last_compile_type); + } } + // ------------------------------------------------------------------ // CompileBroker::push_jni_handle_block // @@ -2604,6 +2618,21 @@ tty->print_cr(" nmethod total size : %8d bytes", nmethods_size); } +// Debugging output for failure +void CompileBroker::print_last_compile() { + if (_last_compile_level != CompLevel_none && + compiler(_last_compile_level) != NULL && + _last_compile_type != no_compile) { + if (_last_compile_type == osr_compile) { + tty->print_cr("Last parse: [osr]%d+++(%d) %s", + _osr_compilation_id, _last_compile_level, _last_method_compiled); + } else { + tty->print_cr("Last parse: %d+++(%d) %s", + _compilation_id, _last_compile_level, _last_method_compiled); + } + } +} + // Print general/accumulated JIT information. void CompileBroker::print_info(outputStream *out) { if (out == NULL) out = tty; --- old/src/hotspot/share/compiler/compileBroker.hpp 2019-05-21 01:01:11.273164846 +0200 +++ new/src/hotspot/share/compiler/compileBroker.hpp 2019-05-21 01:01:11.121165119 +0200 @@ -173,6 +173,10 @@ static volatile jint _compilation_id; static volatile jint _osr_compilation_id; + static int _last_compile_type; + static int _last_compile_level; + static char _last_method_compiled[name_buffer_length]; + static CompileQueue* _c2_compile_queue; static CompileQueue* _c1_compile_queue; @@ -250,8 +254,7 @@ static void invoke_compiler_on_method(CompileTask* task); static void post_compile(CompilerThread* thread, CompileTask* task, bool success, ciEnv* ci_env, int compilable, const char* failure_reason); - static void update_compile_perf_data(CompilerThread *thread, const methodHandle& method, bool is_osr); - + static void set_last_compile(CompilerThread *thread, const methodHandle& method, bool is_osr, int comp_level); static void push_jni_handle_block(); static void pop_jni_handle_block(); static void collect_statistics(CompilerThread* thread, elapsedTimer time, CompileTask* task); @@ -379,6 +382,9 @@ // Print a detailed accounting of compilation time static void print_times(bool per_compiler = true, bool aggregate = true); + // Debugging output for failure + static void print_last_compile(); + // compiler name for debugging static const char* compiler_name(int comp_level); --- old/src/hotspot/share/gc/g1/g1CollectedHeap.cpp 2019-05-21 01:01:11.469164494 +0200 +++ new/src/hotspot/share/gc/g1/g1CollectedHeap.cpp 2019-05-21 01:01:11.317164767 +0200 @@ -154,11 +154,6 @@ reset_from_card_cache(start_idx, num_regions); } -Tickspan G1CollectedHeap::run_task(AbstractGangTask* task) { - Ticks start = Ticks::now(); - workers()->run_task(task, workers()->active_workers()); - return Ticks::now() - start; -} HeapRegion* G1CollectedHeap::new_heap_region(uint hrs_index, MemRegion mr) { @@ -2247,12 +2242,12 @@ _hrm->par_iterate(cl, hrclaimer, 0); } -void G1CollectedHeap::collection_set_iterate_all(HeapRegionClosure* cl) { +void G1CollectedHeap::collection_set_iterate(HeapRegionClosure* cl) { _collection_set.iterate(cl); } -void G1CollectedHeap::collection_set_iterate_increment_from(HeapRegionClosure *cl, uint worker_id) { - _collection_set.iterate_incremental_part_from(cl, worker_id, workers()->active_workers()); +void G1CollectedHeap::collection_set_iterate_from(HeapRegionClosure *cl, uint worker_id) { + _collection_set.iterate_from(cl, worker_id, workers()->active_workers()); } HeapWord* G1CollectedHeap::block_start(const void* addr) const { @@ -2489,7 +2484,7 @@ void G1CollectedHeap::print_cset_rsets() { PrintRSetsClosure cl("Printing CSet RSets"); - collection_set_iterate_all(&cl); + collection_set_iterate(&cl); } void G1CollectedHeap::print_all_rsets() { @@ -2500,8 +2495,8 @@ G1HeapSummary G1CollectedHeap::create_g1_heap_summary() { - size_t eden_used_bytes = _eden.used_bytes(); - size_t survivor_used_bytes = _survivor.used_bytes(); + size_t eden_used_bytes = heap()->eden_regions_count() * HeapRegion::GrainBytes; + size_t survivor_used_bytes = heap()->survivor_regions_count() * HeapRegion::GrainBytes; size_t heap_used = Heap_lock->owned_by_self() ? used() : used_unlocked(); size_t eden_capacity_bytes = @@ -2885,18 +2880,15 @@ phase_times()->record_start_new_cset_time_ms((os::elapsedTime() - start) * 1000.0); } -void G1CollectedHeap::calculate_collection_set(G1EvacuationInfo& evacuation_info, double target_pause_time_ms) { - - _collection_set.finalize_initial_collection_set(target_pause_time_ms, &_survivor); - evacuation_info.set_collectionset_regions(collection_set()->region_length() + - collection_set()->optional_region_length()); +void G1CollectedHeap::calculate_collection_set(G1EvacuationInfo& evacuation_info, double target_pause_time_ms){ + policy()->finalize_collection_set(target_pause_time_ms, &_survivor); + evacuation_info.set_collectionset_regions(collection_set()->region_length()); _cm->verify_no_collection_set_oops(); if (_hr_printer.is_active()) { G1PrintCollectionSetClosure cl(&_hr_printer); _collection_set.iterate(&cl); - _collection_set.iterate_optional(&cl); } } @@ -3068,10 +3060,9 @@ pre_evacuate_collection_set(evacuation_info); // Actually do the work... - evacuate_initial_collection_set(&per_thread_states); - if (_collection_set.optional_region_length() != 0) { - evacuate_optional_collection_set(&per_thread_states); - } + evacuate_collection_set(&per_thread_states); + evacuate_optional_collection_set(&per_thread_states); + post_evacuate_collection_set(evacuation_info, &per_thread_states); start_new_collection_set(); @@ -3097,8 +3088,7 @@ double sample_end_time_sec = os::elapsedTime(); double pause_time_ms = (sample_end_time_sec - sample_start_time_sec) * MILLIUNITS; - size_t total_cards_scanned = phase_times()->sum_thread_work_items(G1GCPhaseTimes::ScanRS, G1GCPhaseTimes::ScanRSScannedCards) + - phase_times()->sum_thread_work_items(G1GCPhaseTimes::OptScanRS, G1GCPhaseTimes::ScanRSScannedCards); + size_t total_cards_scanned = phase_times()->sum_thread_work_items(G1GCPhaseTimes::ScanRS, G1GCPhaseTimes::ScanRSScannedCards); policy()->record_collection_pause_end(pause_time_ms, total_cards_scanned, heap_used_bytes_before_gc); } @@ -3202,6 +3192,86 @@ } while (!offer_termination()); } +class G1ParTask : public AbstractGangTask { +protected: + G1CollectedHeap* _g1h; + G1ParScanThreadStateSet* _pss; + RefToScanQueueSet* _queues; + G1RootProcessor* _root_processor; + TaskTerminator _terminator; + uint _n_workers; + +public: + G1ParTask(G1CollectedHeap* g1h, G1ParScanThreadStateSet* per_thread_states, RefToScanQueueSet *task_queues, G1RootProcessor* root_processor, uint n_workers) + : AbstractGangTask("G1 collection"), + _g1h(g1h), + _pss(per_thread_states), + _queues(task_queues), + _root_processor(root_processor), + _terminator(n_workers, _queues), + _n_workers(n_workers) + {} + + void work(uint worker_id) { + if (worker_id >= _n_workers) return; // no work needed this round + + double start_sec = os::elapsedTime(); + _g1h->phase_times()->record_time_secs(G1GCPhaseTimes::GCWorkerStart, worker_id, start_sec); + + { + ResourceMark rm; + HandleMark hm; + + ReferenceProcessor* rp = _g1h->ref_processor_stw(); + + G1ParScanThreadState* pss = _pss->state_for_worker(worker_id); + pss->set_ref_discoverer(rp); + + double start_strong_roots_sec = os::elapsedTime(); + + _root_processor->evacuate_roots(pss, worker_id); + + _g1h->rem_set()->oops_into_collection_set_do(pss, worker_id); + + double strong_roots_sec = os::elapsedTime() - start_strong_roots_sec; + + double term_sec = 0.0; + size_t evac_term_attempts = 0; + { + double start = os::elapsedTime(); + G1ParEvacuateFollowersClosure evac(_g1h, pss, _queues, _terminator.terminator(), G1GCPhaseTimes::ObjCopy); + evac.do_void(); + + evac_term_attempts = evac.term_attempts(); + term_sec = evac.term_time(); + double elapsed_sec = os::elapsedTime() - start; + + G1GCPhaseTimes* p = _g1h->phase_times(); + p->add_time_secs(G1GCPhaseTimes::ObjCopy, worker_id, elapsed_sec - term_sec); + + p->record_or_add_thread_work_item(G1GCPhaseTimes::ObjCopy, + worker_id, + pss->lab_waste_words() * HeapWordSize, + G1GCPhaseTimes::ObjCopyLABWaste); + p->record_or_add_thread_work_item(G1GCPhaseTimes::ObjCopy, + worker_id, + pss->lab_undo_waste_words() * HeapWordSize, + G1GCPhaseTimes::ObjCopyLABUndoWaste); + + p->record_time_secs(G1GCPhaseTimes::Termination, worker_id, term_sec); + p->record_thread_work_item(G1GCPhaseTimes::Termination, worker_id, evac_term_attempts); + } + + assert(pss->queue_is_empty(), "should be empty"); + + // Close the inner scope so that the ResourceMark and HandleMark + // destructors are executed here and are included as part of the + // "GC Worker Time". + } + _g1h->phase_times()->record_time_secs(G1GCPhaseTimes::GCWorkerEnd, worker_id, os::elapsedTime()); + } +}; + void G1CollectedHeap::complete_cleaning(BoolObjectClosure* is_alive, bool class_unloading_occurred) { uint num_workers = workers()->active_workers(); @@ -3605,196 +3675,176 @@ double recorded_clear_claimed_marks_time_ms = (os::elapsedTime() - start_clear_claimed_marks) * 1000.0; phase_times()->record_clear_claimed_marks_time_ms(recorded_clear_claimed_marks_time_ms); } +} +void G1CollectedHeap::evacuate_collection_set(G1ParScanThreadStateSet* per_thread_states) { // Should G1EvacuationFailureALot be in effect for this GC? NOT_PRODUCT(set_evacuation_failure_alot_for_current_gc();) assert(dirty_card_queue_set().completed_buffers_num() == 0, "Should be empty"); -} -class G1EvacuateRegionsBaseTask : public AbstractGangTask { -protected: - G1CollectedHeap* _g1h; - G1ParScanThreadStateSet* _per_thread_states; - RefToScanQueueSet* _task_queues; - TaskTerminator _terminator; - uint _num_workers; - - void evacuate_live_objects(G1ParScanThreadState* pss, - uint worker_id, - G1GCPhaseTimes::GCParPhases objcopy_phase, - G1GCPhaseTimes::GCParPhases termination_phase) { - G1GCPhaseTimes* p = _g1h->phase_times(); - - Ticks start = Ticks::now(); - G1ParEvacuateFollowersClosure cl(_g1h, pss, _task_queues, _terminator.terminator(), objcopy_phase); - cl.do_void(); + double start_par_time_sec = os::elapsedTime(); + double end_par_time_sec; - assert(pss->queue_is_empty(), "should be empty"); - - Tickspan evac_time = (Ticks::now() - start); - p->record_or_add_time_secs(objcopy_phase, worker_id, evac_time.seconds() - cl.term_time()); + { + const uint n_workers = workers()->active_workers(); + G1RootProcessor root_processor(this, n_workers); + G1ParTask g1_par_task(this, per_thread_states, _task_queues, &root_processor, n_workers); - p->record_or_add_thread_work_item(objcopy_phase, worker_id, pss->lab_waste_words() * HeapWordSize, G1GCPhaseTimes::ObjCopyLABWaste); - p->record_or_add_thread_work_item(objcopy_phase, worker_id, pss->lab_undo_waste_words() * HeapWordSize, G1GCPhaseTimes::ObjCopyLABUndoWaste); + workers()->run_task(&g1_par_task); + end_par_time_sec = os::elapsedTime(); - if (termination_phase == G1GCPhaseTimes::Termination) { - p->record_time_secs(termination_phase, worker_id, cl.term_time()); - p->record_thread_work_item(termination_phase, worker_id, cl.term_attempts()); - } else { - p->record_or_add_time_secs(termination_phase, worker_id, cl.term_time()); - p->record_or_add_thread_work_item(termination_phase, worker_id, cl.term_attempts()); - } - assert(pss->trim_ticks().seconds() == 0.0, "Unexpected partial trimming during evacuation"); + // Closing the inner scope will execute the destructor + // for the G1RootProcessor object. We record the current + // elapsed time before closing the scope so that time + // taken for the destructor is NOT included in the + // reported parallel time. } - virtual void start_work(uint worker_id) { } - - virtual void end_work(uint worker_id) { } - - virtual void scan_roots(G1ParScanThreadState* pss, uint worker_id) = 0; + double par_time_ms = (end_par_time_sec - start_par_time_sec) * 1000.0; + phase_times()->record_par_time(par_time_ms); - virtual void evacuate_live_objects(G1ParScanThreadState* pss, uint worker_id) = 0; - -public: - G1EvacuateRegionsBaseTask(const char* name, G1ParScanThreadStateSet* per_thread_states, RefToScanQueueSet* task_queues, uint num_workers) : - AbstractGangTask(name), - _g1h(G1CollectedHeap::heap()), - _per_thread_states(per_thread_states), - _task_queues(task_queues), - _terminator(num_workers, _task_queues), - _num_workers(num_workers) - { } + double code_root_fixup_time_ms = + (os::elapsedTime() - end_par_time_sec) * 1000.0; + phase_times()->record_code_root_fixup_time(code_root_fixup_time_ms); +} - void work(uint worker_id) { - start_work(worker_id); +class G1EvacuateOptionalRegionTask : public AbstractGangTask { + G1CollectedHeap* _g1h; + G1ParScanThreadStateSet* _per_thread_states; + G1OptionalCSet* _optional; + RefToScanQueueSet* _queues; + ParallelTaskTerminator _terminator; + + Tickspan trim_ticks(G1ParScanThreadState* pss) { + Tickspan copy_time = pss->trim_ticks(); + pss->reset_trim_ticks(); + return copy_time; + } - { - ResourceMark rm; - HandleMark hm; + void scan_roots(G1ParScanThreadState* pss, uint worker_id) { + G1EvacuationRootClosures* root_cls = pss->closures(); + G1ScanObjsDuringScanRSClosure obj_cl(_g1h, pss); - G1ParScanThreadState* pss = _per_thread_states->state_for_worker(worker_id); - pss->set_ref_discoverer(_g1h->ref_processor_stw()); + size_t scanned = 0; + size_t claimed = 0; + size_t skipped = 0; + size_t used_memory = 0; + + Ticks start = Ticks::now(); + Tickspan copy_time; + + for (uint i = _optional->current_index(); i < _optional->current_limit(); i++) { + HeapRegion* hr = _optional->region_at(i); + G1ScanRSForOptionalClosure scan_opt_cl(&obj_cl); + pss->oops_into_optional_region(hr)->oops_do(&scan_opt_cl, root_cls->raw_strong_oops()); + copy_time += trim_ticks(pss); + + G1ScanRSForRegionClosure scan_rs_cl(_g1h->rem_set()->scan_state(), &obj_cl, pss, G1GCPhaseTimes::OptScanRS, worker_id); + scan_rs_cl.do_heap_region(hr); + copy_time += trim_ticks(pss); + scanned += scan_rs_cl.cards_scanned(); + claimed += scan_rs_cl.cards_claimed(); + skipped += scan_rs_cl.cards_skipped(); - scan_roots(pss, worker_id); - evacuate_live_objects(pss, worker_id); + // Chunk lists for this region is no longer needed. + used_memory += pss->oops_into_optional_region(hr)->used_memory(); } - end_work(worker_id); - } -}; - -class G1EvacuateRegionsTask : public G1EvacuateRegionsBaseTask { - G1RootProcessor* _root_processor; + Tickspan scan_time = (Ticks::now() - start) - copy_time; + G1GCPhaseTimes* p = _g1h->phase_times(); + p->record_or_add_time_secs(G1GCPhaseTimes::OptScanRS, worker_id, scan_time.seconds()); + p->record_or_add_time_secs(G1GCPhaseTimes::OptObjCopy, worker_id, copy_time.seconds()); - void scan_roots(G1ParScanThreadState* pss, uint worker_id) { - _root_processor->evacuate_roots(pss, worker_id); - _g1h->rem_set()->update_rem_set(pss, worker_id); - _g1h->rem_set()->scan_rem_set(pss, worker_id, G1GCPhaseTimes::ScanRS, G1GCPhaseTimes::ObjCopy, G1GCPhaseTimes::CodeRoots); + p->record_or_add_thread_work_item(G1GCPhaseTimes::OptScanRS, worker_id, scanned, G1GCPhaseTimes::OptCSetScannedCards); + p->record_or_add_thread_work_item(G1GCPhaseTimes::OptScanRS, worker_id, claimed, G1GCPhaseTimes::OptCSetClaimedCards); + p->record_or_add_thread_work_item(G1GCPhaseTimes::OptScanRS, worker_id, skipped, G1GCPhaseTimes::OptCSetSkippedCards); + p->record_or_add_thread_work_item(G1GCPhaseTimes::OptScanRS, worker_id, used_memory, G1GCPhaseTimes::OptCSetUsedMemory); } void evacuate_live_objects(G1ParScanThreadState* pss, uint worker_id) { - G1EvacuateRegionsBaseTask::evacuate_live_objects(pss, worker_id, G1GCPhaseTimes::ObjCopy, G1GCPhaseTimes::Termination); - } - - void start_work(uint worker_id) { - _g1h->phase_times()->record_time_secs(G1GCPhaseTimes::GCWorkerStart, worker_id, Ticks::now().seconds()); - } + Ticks start = Ticks::now(); + G1ParEvacuateFollowersClosure cl(_g1h, pss, _queues, &_terminator, G1GCPhaseTimes::OptObjCopy); + cl.do_void(); - void end_work(uint worker_id) { - _g1h->phase_times()->record_time_secs(G1GCPhaseTimes::GCWorkerEnd, worker_id, Ticks::now().seconds()); + Tickspan evac_time = (Ticks::now() - start); + G1GCPhaseTimes* p = _g1h->phase_times(); + p->record_or_add_time_secs(G1GCPhaseTimes::OptObjCopy, worker_id, evac_time.seconds()); + assert(pss->trim_ticks().seconds() == 0.0, "Unexpected partial trimming done during optional evacuation"); } -public: - G1EvacuateRegionsTask(G1CollectedHeap* g1h, - G1ParScanThreadStateSet* per_thread_states, - RefToScanQueueSet* task_queues, - G1RootProcessor* root_processor, - uint num_workers) : - G1EvacuateRegionsBaseTask("G1 Evacuate Regions", per_thread_states, task_queues, num_workers), - _root_processor(root_processor) - { } -}; - -void G1CollectedHeap::evacuate_initial_collection_set(G1ParScanThreadStateSet* per_thread_states) { - Tickspan task_time; - const uint num_workers = workers()->active_workers(); - - Ticks start_processing = Ticks::now(); - { - G1RootProcessor root_processor(this, num_workers); - G1EvacuateRegionsTask g1_par_task(this, per_thread_states, _task_queues, &root_processor, num_workers); - task_time = run_task(&g1_par_task); - // Closing the inner scope will execute the destructor for the G1RootProcessor object. - // To extract its code root fixup time we measure total time of this scope and - // subtract from the time the WorkGang task took. + public: + G1EvacuateOptionalRegionTask(G1CollectedHeap* g1h, + G1ParScanThreadStateSet* per_thread_states, + G1OptionalCSet* cset, + RefToScanQueueSet* queues, + uint n_workers) : + AbstractGangTask("G1 Evacuation Optional Region Task"), + _g1h(g1h), + _per_thread_states(per_thread_states), + _optional(cset), + _queues(queues), + _terminator(n_workers, _queues) { } - Tickspan total_processing = Ticks::now() - start_processing; - G1GCPhaseTimes* p = phase_times(); - p->record_initial_evac_time(task_time.seconds() * 1000.0); - p->record_or_add_code_root_fixup_time((total_processing - task_time).seconds() * 1000.0); -} - -class G1EvacuateOptionalRegionsTask : public G1EvacuateRegionsBaseTask { + void work(uint worker_id) { + ResourceMark rm; + HandleMark hm; - void scan_roots(G1ParScanThreadState* pss, uint worker_id) { - _g1h->rem_set()->scan_rem_set(pss, worker_id, G1GCPhaseTimes::OptScanRS, G1GCPhaseTimes::OptObjCopy, G1GCPhaseTimes::OptCodeRoots); - } + G1ParScanThreadState* pss = _per_thread_states->state_for_worker(worker_id); + pss->set_ref_discoverer(_g1h->ref_processor_stw()); - void evacuate_live_objects(G1ParScanThreadState* pss, uint worker_id) { - G1EvacuateRegionsBaseTask::evacuate_live_objects(pss, worker_id, G1GCPhaseTimes::OptObjCopy, G1GCPhaseTimes::OptTermination); - } - -public: - G1EvacuateOptionalRegionsTask(G1ParScanThreadStateSet* per_thread_states, - RefToScanQueueSet* queues, - uint num_workers) : - G1EvacuateRegionsBaseTask("G1 Evacuate Optional Regions", per_thread_states, queues, num_workers) { + scan_roots(pss, worker_id); + evacuate_live_objects(pss, worker_id); } }; -void G1CollectedHeap::evacuate_next_optional_regions(G1ParScanThreadStateSet* per_thread_states) { - class G1MarkScope : public MarkScope { }; +void G1CollectedHeap::evacuate_optional_regions(G1ParScanThreadStateSet* per_thread_states, G1OptionalCSet* ocset) { + class G1MarkScope : public MarkScope {}; + G1MarkScope code_mark_scope; - Tickspan task_time; + G1EvacuateOptionalRegionTask task(this, per_thread_states, ocset, _task_queues, workers()->active_workers()); + workers()->run_task(&task); +} - Ticks start_processing = Ticks::now(); - { - G1MarkScope code_mark_scope; - G1EvacuateOptionalRegionsTask task(per_thread_states, _task_queues, workers()->active_workers()); - task_time = run_task(&task); - // See comment in evacuate_collection_set() for the reason of the scope. +void G1CollectedHeap::evacuate_optional_collection_set(G1ParScanThreadStateSet* per_thread_states) { + G1OptionalCSet optional_cset(&_collection_set, per_thread_states); + if (optional_cset.is_empty()) { + return; } - Tickspan total_processing = Ticks::now() - start_processing; - G1GCPhaseTimes* p = phase_times(); - p->record_or_add_code_root_fixup_time((total_processing - task_time).seconds() * 1000.0); -} + if (evacuation_failed()) { + return; + } -void G1CollectedHeap::evacuate_optional_collection_set(G1ParScanThreadStateSet* per_thread_states) { const double gc_start_time_ms = phase_times()->cur_collection_start_sec() * 1000.0; - Ticks start = Ticks::now(); - - while (!evacuation_failed() && _collection_set.optional_region_length() > 0) { + double start_time_sec = os::elapsedTime(); + do { double time_used_ms = os::elapsedTime() * 1000.0 - gc_start_time_ms; double time_left_ms = MaxGCPauseMillis - time_used_ms; - if (time_left_ms < 0 || - !_collection_set.finalize_optional_for_evacuation(time_left_ms * policy()->optional_evacuation_fraction())) { - log_trace(gc, ergo, cset)("Skipping evacuation of %u optional regions, no more regions can be evacuated in %.3fms", - _collection_set.optional_region_length(), time_left_ms); + if (time_left_ms < 0) { + log_trace(gc, ergo, cset)("Skipping %u optional regions, pause time exceeded %.3fms", optional_cset.size(), time_used_ms); break; } - evacuate_next_optional_regions(per_thread_states); - } + optional_cset.prepare_evacuation(time_left_ms * _policy->optional_evacuation_fraction()); + if (optional_cset.prepare_failed()) { + log_trace(gc, ergo, cset)("Skipping %u optional regions, no regions can be evacuated in %.3fms", optional_cset.size(), time_left_ms); + break; + } - _collection_set.abandon_optional_collection_set(per_thread_states); + evacuate_optional_regions(per_thread_states, &optional_cset); - phase_times()->record_or_add_optional_evac_time((Ticks::now() - start).seconds() * 1000.0); + optional_cset.complete_evacuation(); + if (optional_cset.evacuation_failed()) { + break; + } + } while (!optional_cset.is_empty()); + + phase_times()->record_optional_evacuation((os::elapsedTime() - start_time_sec) * 1000.0); } void G1CollectedHeap::post_evacuate_collection_set(G1EvacuationInfo& evacuation_info, G1ParScanThreadStateSet* per_thread_states) { @@ -4209,14 +4259,15 @@ double free_cset_start_time = os::elapsedTime(); { - uint const num_regions = _collection_set.region_length(); - uint const num_chunks = MAX2(num_regions / G1FreeCollectionSetTask::chunk_size(), 1U); + uint const num_chunks = MAX2(_collection_set.region_length() / G1FreeCollectionSetTask::chunk_size(), 1U); uint const num_workers = MIN2(workers()->active_workers(), num_chunks); G1FreeCollectionSetTask cl(collection_set, &evacuation_info, surviving_young_words); log_debug(gc, ergo)("Running %s using %u workers for collection set length %u", - cl.name(), num_workers, num_regions); + cl.name(), + num_workers, + _collection_set.region_length()); workers()->run_task(&cl, num_workers); } phase_times()->record_total_free_cset_time_ms((os::elapsedTime() - free_cset_start_time) * 1000.0); @@ -4385,7 +4436,7 @@ void G1CollectedHeap::abandon_collection_set(G1CollectionSet* collection_set) { G1AbandonCollectionSetClosure cl; - collection_set_iterate_all(&cl); + collection_set->iterate(&cl); collection_set->clear(); collection_set->stop_incremental_building(); @@ -4585,9 +4636,7 @@ collection_set()->add_eden_region(alloc_region); increase_used(allocated_bytes); - _eden.add_used_bytes(allocated_bytes); _hr_printer.retire(alloc_region); - // We update the eden sizes here, when the region is retired, // instead of when it's allocated, since this is the point that its // used space has been recorded in _summary_bytes_used. @@ -4644,9 +4693,6 @@ policy()->record_bytes_copied_during_gc(allocated_bytes); if (dest.is_old()) { old_set_add(alloc_region); - } else { - assert(dest.is_young(), "Retiring alloc region should be young(%d)", dest.value()); - _survivor.add_used_bytes(allocated_bytes); } bool const during_im = collector_state()->in_initial_mark_gc(); --- old/src/hotspot/share/gc/g1/g1CollectedHeap.hpp 2019-05-21 01:01:11.717164051 +0200 +++ new/src/hotspot/share/gc/g1/g1CollectedHeap.hpp 2019-05-21 01:01:11.561164331 +0200 @@ -143,8 +143,9 @@ // Closures used in implementation. friend class G1ParScanThreadState; friend class G1ParScanThreadStateSet; - friend class G1EvacuateRegionsTask; + friend class G1ParTask; friend class G1PLABAllocator; + friend class G1PrepareCompactClosure; // Other related classes. friend class HeapRegionClaimer; @@ -205,7 +206,7 @@ // Outside of GC pauses, the number of bytes used in all regions other // than the current allocation region(s). - volatile size_t _summary_bytes_used; + size_t _summary_bytes_used; void increase_used(size_t bytes); void decrease_used(size_t bytes); @@ -518,10 +519,6 @@ WorkGang* workers() const { return _workers; } - // Runs the given AbstractGangTask with the current active workers, returning the - // total time taken. - Tickspan run_task(AbstractGangTask* task); - G1Allocator* allocator() { return _allocator; } @@ -741,14 +738,11 @@ void calculate_collection_set(G1EvacuationInfo& evacuation_info, double target_pause_time_ms); - // Actually do the work of evacuating the parts of the collection set. - void evacuate_initial_collection_set(G1ParScanThreadStateSet* per_thread_states); + // Actually do the work of evacuating the collection set. + void evacuate_collection_set(G1ParScanThreadStateSet* per_thread_states); void evacuate_optional_collection_set(G1ParScanThreadStateSet* per_thread_states); -private: - // Evacuate the next set of optional regions. - void evacuate_next_optional_regions(G1ParScanThreadStateSet* per_thread_states); + void evacuate_optional_regions(G1ParScanThreadStateSet* per_thread_states, G1OptionalCSet* ocset); -public: void pre_evacuate_collection_set(G1EvacuationInfo& evacuation_info); void post_evacuate_collection_set(G1EvacuationInfo& evacuation_info, G1ParScanThreadStateSet* pss); @@ -1171,14 +1165,14 @@ void heap_region_par_iterate_from_start(HeapRegionClosure* cl, HeapRegionClaimer* hrclaimer) const; - // Iterate over all regions currently in the current collection set. - void collection_set_iterate_all(HeapRegionClosure* blk); + // Iterate over the regions (if any) in the current collection set. + void collection_set_iterate(HeapRegionClosure* blk); - // Iterate over the regions in the current increment of the collection set. - // Starts the iteration so that the start regions of a given worker id over the - // set active_workers are evenly spread across the set of collection set regions - // to be iterated. - void collection_set_iterate_increment_from(HeapRegionClosure *blk, uint worker_id); + // Iterate over the regions (if any) in the current collection set. Starts the + // iteration over the entire collection set so that the start regions of a given + // worker id over the set active_workers are evenly spread across the set of + // collection set regions. + void collection_set_iterate_from(HeapRegionClosure *blk, uint worker_id); // Returns the HeapRegion that contains addr. addr must not be NULL. template @@ -1258,8 +1252,6 @@ uint eden_regions_count() const { return _eden.length(); } uint survivor_regions_count() const { return _survivor.length(); } - size_t eden_regions_used_bytes() const { return _eden.used_bytes(); } - size_t survivor_regions_used_bytes() const { return _survivor.used_bytes(); } uint young_regions_count() const { return _eden.length() + _survivor.length(); } uint old_regions_count() const { return _old_set.length(); } uint archive_regions_count() const { return _archive_set.length(); } @@ -1428,7 +1420,7 @@ size_t _term_attempts; void start_term_time() { _term_attempts++; _start_term = os::elapsedTime(); } - void end_term_time() { _term_time += (os::elapsedTime() - _start_term); } + void end_term_time() { _term_time += os::elapsedTime() - _start_term; } protected: G1CollectedHeap* _g1h; G1ParScanThreadState* _par_scan_state; --- old/src/hotspot/share/gc/g1/g1CollectionSet.cpp 2019-05-21 01:01:11.933163664 +0200 +++ new/src/hotspot/share/gc/g1/g1CollectionSet.cpp 2019-05-21 01:01:11.773163949 +0200 @@ -59,11 +59,12 @@ _collection_set_regions(NULL), _collection_set_cur_length(0), _collection_set_max_length(0), - _num_optional_regions(0), + _optional_regions(NULL), + _optional_region_length(0), + _optional_region_max_length(0), _bytes_used_before(0), _recorded_rs_lengths(0), _inc_build_state(Inactive), - _inc_part_start(0), _inc_bytes_used_before(0), _inc_recorded_rs_lengths(0), _inc_recorded_rs_lengths_diffs(0), @@ -89,8 +90,8 @@ assert((size_t) young_region_length() == _collection_set_cur_length, "Young region length %u should match collection set length " SIZE_FORMAT, young_region_length(), _collection_set_cur_length); - _old_region_length = 0; - free_optional_regions(); + _old_region_length = 0; + _optional_region_length = 0; } void G1CollectionSet::initialize(uint max_region_length) { @@ -99,8 +100,21 @@ _collection_set_regions = NEW_C_HEAP_ARRAY(uint, max_region_length, mtGC); } +void G1CollectionSet::initialize_optional(uint max_length) { + assert(_optional_regions == NULL, "Already initialized"); + assert(_optional_region_length == 0, "Already initialized"); + assert(_optional_region_max_length == 0, "Already initialized"); + _optional_region_max_length = max_length; + _optional_regions = NEW_C_HEAP_ARRAY(HeapRegion*, _optional_region_max_length, mtGC); +} + void G1CollectionSet::free_optional_regions() { - _num_optional_regions = 0; + _optional_region_length = 0; + _optional_region_max_length = 0; + if (_optional_regions != NULL) { + FREE_C_HEAP_ARRAY(HeapRegion*, _optional_regions); + _optional_regions = NULL; + } } void G1CollectionSet::clear_candidates() { @@ -116,32 +130,39 @@ void G1CollectionSet::add_old_region(HeapRegion* hr) { assert_at_safepoint_on_vm_thread(); - assert(_inc_build_state == Active, + assert(_inc_build_state == Active || hr->index_in_opt_cset() != G1OptionalCSet::InvalidCSetIndex, "Precondition, actively building cset or adding optional later on"); assert(hr->is_old(), "the region should be old"); - assert(!hr->in_collection_set(), "should not already be in the collection set"); + assert(!hr->in_collection_set(), "should not already be in the CSet"); _g1h->register_old_region_with_cset(hr); _collection_set_regions[_collection_set_cur_length++] = hr->hrm_index(); assert(_collection_set_cur_length <= _collection_set_max_length, "Collection set now larger than maximum size."); _bytes_used_before += hr->used(); - _recorded_rs_lengths += hr->rem_set()->occupied(); - _old_region_length++; + size_t rs_length = hr->rem_set()->occupied(); + _recorded_rs_lengths += rs_length; + _old_region_length += 1; - _g1h->old_set_remove(hr); + log_trace(gc, cset)("Added old region %d to collection set", hr->hrm_index()); } void G1CollectionSet::add_optional_region(HeapRegion* hr) { + assert(!optional_is_full(), "Precondition, must have room left for this region"); assert(hr->is_old(), "the region should be old"); assert(!hr->in_collection_set(), "should not already be in the CSet"); _g1h->register_optional_region_with_cset(hr); - hr->set_index_in_opt_cset(_num_optional_regions++); + _optional_regions[_optional_region_length] = hr; + uint index = _optional_region_length++; + hr->set_index_in_opt_cset(index); + + log_trace(gc, cset)("Added region %d to optional collection set (%u)", hr->hrm_index(), _optional_region_length); } +// Initialize the per-collection-set information void G1CollectionSet::start_incremental_building() { assert(_collection_set_cur_length == 0, "Collection set must be empty before starting a new collection set."); assert(_inc_build_state == Inactive, "Precondition"); @@ -152,8 +173,7 @@ _inc_recorded_rs_lengths_diffs = 0; _inc_predicted_elapsed_time_ms = 0.0; _inc_predicted_elapsed_time_ms_diffs = 0.0; - - update_incremental_marker(); + _inc_build_state = Active; } void G1CollectionSet::finalize_incremental_building() { @@ -191,48 +211,29 @@ void G1CollectionSet::clear() { assert_at_safepoint_on_vm_thread(); _collection_set_cur_length = 0; + _optional_region_length = 0; } void G1CollectionSet::iterate(HeapRegionClosure* cl) const { - size_t len = _collection_set_cur_length; - OrderAccess::loadload(); - - for (uint i = 0; i < len; i++) { - HeapRegion* r = _g1h->region_at(_collection_set_regions[i]); - bool result = cl->do_heap_region(r); - if (result) { - cl->set_incomplete(); - return; - } - } -} - -void G1CollectionSet::iterate_optional(HeapRegionClosure* cl) const { - assert_at_safepoint(); - - for (uint i = 0; i < _num_optional_regions; i++) { - HeapRegion* r = _candidates->at(i); - bool result = cl->do_heap_region(r); - guarantee(!result, "Must not cancel iteration"); - } + iterate_from(cl, 0, 1); } -void G1CollectionSet::iterate_incremental_part_from(HeapRegionClosure* cl, uint worker_id, uint total_workers) const { - assert_at_safepoint(); - - size_t len = _collection_set_cur_length - _inc_part_start; +void G1CollectionSet::iterate_from(HeapRegionClosure* cl, uint worker_id, uint total_workers) const { + size_t len = _collection_set_cur_length; + OrderAccess::loadload(); if (len == 0) { return; } - size_t start_pos = (worker_id * len) / total_workers; size_t cur_pos = start_pos; do { - HeapRegion* r = _g1h->region_at(_collection_set_regions[cur_pos + _inc_part_start]); + HeapRegion* r = _g1h->region_at(_collection_set_regions[cur_pos]); bool result = cl->do_heap_region(r); - guarantee(!result, "Must not cancel iteration"); - + if (result) { + cl->set_incomplete(); + return; + } cur_pos++; if (cur_pos == len) { cur_pos = 0; @@ -439,6 +440,30 @@ return time_remaining_ms; } +void G1CollectionSet::add_as_old(HeapRegion* hr) { + candidates()->pop_front(); // already have region via peek() + _g1h->old_set_remove(hr); + add_old_region(hr); +} + +void G1CollectionSet::add_as_optional(HeapRegion* hr) { + assert(_optional_regions != NULL, "Must not be called before array is allocated"); + candidates()->pop_front(); // already have region via peek() + _g1h->old_set_remove(hr); + add_optional_region(hr); +} + +bool G1CollectionSet::optional_is_full() { + assert(_optional_region_length <= _optional_region_max_length, "Invariant"); + return _optional_region_length == _optional_region_max_length; +} + +void G1CollectionSet::clear_optional_region(const HeapRegion* hr) { + assert(_optional_regions != NULL, "Must not be called before array is allocated"); + uint index = hr->index_in_opt_cset(); + _optional_regions[index] = NULL; +} + static int compare_region_idx(const uint a, const uint b) { if (a > b) { return 1; @@ -451,25 +476,87 @@ void G1CollectionSet::finalize_old_part(double time_remaining_ms) { double non_young_start_time_sec = os::elapsedTime(); + double predicted_old_time_ms = 0.0; + double predicted_optional_time_ms = 0.0; + double optional_threshold_ms = time_remaining_ms * _policy->optional_prediction_fraction(); + uint expensive_region_num = 0; if (collector_state()->in_mixed_phase()) { candidates()->verify(); - - uint num_initial_old_regions; - uint num_optional_old_regions; - - _policy->calculate_old_collection_set_regions(candidates(), - time_remaining_ms, - num_initial_old_regions, - num_optional_old_regions); - - // Prepare initial old regions. - move_candidates_to_collection_set(num_initial_old_regions); - - // Prepare optional old regions for evacuation. - uint candidate_idx = candidates()->cur_idx(); - for (uint i = 0; i < num_optional_old_regions; i++) { - add_optional_region(candidates()->at(candidate_idx + i)); + const uint min_old_cset_length = _policy->calc_min_old_cset_length(); + const uint max_old_cset_length = MAX2(min_old_cset_length, _policy->calc_max_old_cset_length()); + bool check_time_remaining = _policy->adaptive_young_list_length(); + + initialize_optional(max_old_cset_length - min_old_cset_length); + log_debug(gc, ergo, cset)("Start adding old regions for mixed gc. min %u regions, max %u regions, " + "time remaining %1.2fms, optional threshold %1.2fms", + min_old_cset_length, max_old_cset_length, time_remaining_ms, optional_threshold_ms); + + HeapRegion* hr = candidates()->peek_front(); + while (hr != NULL) { + if (old_region_length() + optional_region_length() >= max_old_cset_length) { + // Added maximum number of old regions to the CSet. + log_debug(gc, ergo, cset)("Finish adding old regions to CSet (old CSet region num reached max). " + "old %u regions, optional %u regions", + old_region_length(), optional_region_length()); + break; + } + + // Stop adding regions if the remaining reclaimable space is + // not above G1HeapWastePercent. + size_t reclaimable_bytes = candidates()->remaining_reclaimable_bytes(); + double reclaimable_percent = _policy->reclaimable_bytes_percent(reclaimable_bytes); + double threshold = (double) G1HeapWastePercent; + if (reclaimable_percent <= threshold) { + // We've added enough old regions that the amount of uncollected + // reclaimable space is at or below the waste threshold. Stop + // adding old regions to the CSet. + log_debug(gc, ergo, cset)("Finish adding old regions to CSet (reclaimable percentage not over threshold). " + "reclaimable: " SIZE_FORMAT "%s (%1.2f%%) threshold: " UINTX_FORMAT "%%", + byte_size_in_proper_unit(reclaimable_bytes), proper_unit_for_byte_size(reclaimable_bytes), + reclaimable_percent, G1HeapWastePercent); + break; + } + + double predicted_time_ms = predict_region_elapsed_time_ms(hr); + time_remaining_ms = MAX2(time_remaining_ms - predicted_time_ms, 0.0); + // Add regions to old set until we reach minimum amount + if (old_region_length() < min_old_cset_length) { + predicted_old_time_ms += predicted_time_ms; + add_as_old(hr); + // Record the number of regions added when no time remaining + if (time_remaining_ms == 0.0) { + expensive_region_num++; + } + } else { + // In the non-auto-tuning case, we'll finish adding regions + // to the CSet if we reach the minimum. + if (!check_time_remaining) { + log_debug(gc, ergo, cset)("Finish adding old regions to CSet (old CSet region num reached min)."); + break; + } + // Keep adding regions to old set until we reach optional threshold + if (time_remaining_ms > optional_threshold_ms) { + predicted_old_time_ms += predicted_time_ms; + add_as_old(hr); + } else if (time_remaining_ms > 0) { + // Keep adding optional regions until time is up + if (!optional_is_full()) { + predicted_optional_time_ms += predicted_time_ms; + add_as_optional(hr); + } else { + log_debug(gc, ergo, cset)("Finish adding old regions to CSet (optional set full)."); + break; + } + } else { + log_debug(gc, ergo, cset)("Finish adding old regions to CSet (predicted time is too high)."); + break; + } + } + hr = candidates()->peek_front(); + } + if (hr == NULL) { + log_debug(gc, ergo, cset)("Finish adding old regions to CSet (candidate old regions not available)"); } candidates()->verify(); @@ -477,59 +564,99 @@ stop_incremental_building(); + log_debug(gc, ergo, cset)("Finish choosing CSet regions old: %u, optional: %u, " + "predicted old time: %1.2fms, predicted optional time: %1.2fms, time remaining: %1.2f", + old_region_length(), optional_region_length(), + predicted_old_time_ms, predicted_optional_time_ms, time_remaining_ms); + if (expensive_region_num > 0) { + log_debug(gc, ergo, cset)("CSet contains %u old regions that were added although the predicted time was too high.", + expensive_region_num); + } + double non_young_end_time_sec = os::elapsedTime(); phase_times()->record_non_young_cset_choice_time_ms((non_young_end_time_sec - non_young_start_time_sec) * 1000.0); QuickSort::sort(_collection_set_regions, _collection_set_cur_length, compare_region_idx, true); } -void G1CollectionSet::move_candidates_to_collection_set(uint num_old_candidate_regions) { - if (num_old_candidate_regions == 0) { - return; - } - uint candidate_idx = candidates()->cur_idx(); - for (uint i = 0; i < num_old_candidate_regions; i++) { - HeapRegion* r = candidates()->at(candidate_idx + i); - // This potentially optional candidate region is going to be an actual collection - // set region. Clear cset marker. - _g1h->clear_in_cset(r); - add_old_region(r); +HeapRegion* G1OptionalCSet::region_at(uint index) { + return _cset->optional_region_at(index); +} + +void G1OptionalCSet::prepare_evacuation(double time_limit) { + assert(_current_index == _current_limit, "Before prepare no regions should be ready for evac"); + + uint prepared_regions = 0; + double prediction_ms = 0; + + _prepare_failed = true; + for (uint i = _current_index; i < _cset->optional_region_length(); i++) { + HeapRegion* hr = region_at(i); + prediction_ms += _cset->predict_region_elapsed_time_ms(hr); + if (prediction_ms > time_limit) { + log_debug(gc, cset)("Prepared %u regions for optional evacuation. Predicted time: %.3fms", prepared_regions, prediction_ms); + return; + } + + // This region will be included in the next optional evacuation. + prepare_to_evacuate_optional_region(hr); + prepared_regions++; + _current_limit++; + _prepare_failed = false; } - candidates()->remove(num_old_candidate_regions); - candidates()->verify(); + log_debug(gc, cset)("Prepared all %u regions for optional evacuation. Predicted time: %.3fms", + prepared_regions, prediction_ms); } -void G1CollectionSet::finalize_initial_collection_set(double target_pause_time_ms, G1SurvivorRegions* survivor) { - double time_remaining_ms = finalize_young_part(target_pause_time_ms, survivor); - finalize_old_part(time_remaining_ms); +bool G1OptionalCSet::prepare_failed() { + return _prepare_failed; } -bool G1CollectionSet::finalize_optional_for_evacuation(double remaining_pause_time) { - update_incremental_marker(); +void G1OptionalCSet::complete_evacuation() { + _evacuation_failed = false; + for (uint i = _current_index; i < _current_limit; i++) { + HeapRegion* hr = region_at(i); + _cset->clear_optional_region(hr); + if (hr->evacuation_failed()){ + _evacuation_failed = true; + } + } + _current_index = _current_limit; +} - uint num_selected_regions; - _policy->calculate_optional_collection_set_regions(candidates(), - _num_optional_regions, - remaining_pause_time, - num_selected_regions); +bool G1OptionalCSet::evacuation_failed() { + return _evacuation_failed; +} - move_candidates_to_collection_set(num_selected_regions); +G1OptionalCSet::~G1OptionalCSet() { + G1CollectedHeap* g1h = G1CollectedHeap::heap(); + while (!is_empty()) { + // We want to return regions not evacuated to the collection set candidates + // in reverse order to maintain the old order. + HeapRegion* hr = _cset->remove_last_optional_region(); + assert(hr != NULL, "Should be valid region left"); + _pset->record_unused_optional_region(hr); + g1h->old_set_add(hr); + g1h->clear_in_cset(hr); + hr->set_index_in_opt_cset(InvalidCSetIndex); + _cset->candidates()->push_front(hr); + } + _cset->free_optional_regions(); +} - _num_optional_regions -= num_selected_regions; +uint G1OptionalCSet::size() { + return _cset->optional_region_length() - _current_index; +} - stop_incremental_building(); - return num_selected_regions > 0; +bool G1OptionalCSet::is_empty() { + return size() == 0; } -void G1CollectionSet::abandon_optional_collection_set(G1ParScanThreadStateSet* pss) { - for (uint i = 0; i < _num_optional_regions; i++) { - HeapRegion* r = candidates()->at(candidates()->cur_idx() + i); - pss->record_unused_optional_region(r); - _g1h->clear_in_cset(r); - r->clear_index_in_opt_cset(); - } - free_optional_regions(); +void G1OptionalCSet::prepare_to_evacuate_optional_region(HeapRegion* hr) { + log_trace(gc, cset)("Adding region %u for optional evacuation", hr->hrm_index()); + G1CollectedHeap::heap()->clear_in_cset(hr); + _cset->add_old_region(hr); } #ifdef ASSERT --- old/src/hotspot/share/gc/g1/g1CollectionSet.hpp 2019-05-21 01:01:12.137163297 +0200 +++ new/src/hotspot/share/gc/g1/g1CollectionSet.hpp 2019-05-21 01:01:11.985163569 +0200 @@ -38,101 +38,11 @@ class HeapRegion; class HeapRegionClosure; -// The collection set. -// -// The set of regions that are evacuated during an evacuation pause. -// -// At the end of a collection, before freeing the collection set, this set -// contains all regions that were evacuated during this collection: -// -// - survivor regions from the last collection (if any) -// - eden regions allocated by the mutator -// - old gen regions evacuated during mixed gc -// -// This set is built incrementally at mutator time as regions are retired, and -// if this had been a mixed gc, some additional (during gc) incrementally added -// old regions from the collection set candidates built during the concurrent -// cycle. -// -// A more detailed overview of how the collection set changes over time follows: -// -// 0) at the end of GC the survivor regions are added to this collection set. -// 1) the mutator incrementally adds eden regions as they retire -// -// ----- gc starts -// -// 2) prepare (finalize) young regions of the collection set for collection -// - relabel the survivors as eden -// - finish up the incremental building that happened at mutator time -// -// iff this is a young-only collection: -// -// a3) evacuate the current collection set in one "initial evacuation" phase -// -// iff this is a mixed collection: -// -// b3) calculate the set of old gen regions we may be able to collect in this -// collection from the list of collection set candidates. -// - one part is added to the current collection set -// - the remainder regions are labeled as optional, and NOT yet added to the -// collection set. -// b4) evacuate the current collection set in the "initial evacuation" phase -// b5) evacuate the optional regions in the "optional evacuation" phase. This is -// done in increments (or rounds). -// b5-1) add a few of the optional regions to the current collection set -// b5-2) evacuate only these newly added optional regions. For this mechanism we -// reuse the incremental collection set building infrastructure (used also at -// mutator time). -// b5-3) repeat from b5-1 until the policy determines we are done -// -// all collections -// -// 6) free the collection set (contains all regions now; empties collection set -// afterwards) -// 7) add survivors to this collection set -// -// ----- gc ends -// -// goto 1) -// -// Examples of how the collection set might look over time: -// -// Legend: -// S = survivor, E = eden, O = old. -// |xxxx| = increment (with increment markers), containing four regions -// -// |SSSS| ... after step 0), with four survivor regions -// |SSSSEE| ... at step 1), after retiring two eden regions -// |SSSSEEEE| ... after step 1), after retiring four eden regions -// |EEEEEEEE| ... after step 2) -// -// iff this is a young-only collection -// -// EEEEEEEE|| ... after step a3), after initial evacuation phase -// || ... after step 6) -// |SS| ... after step 7), with two survivor regions -// -// iff this is a mixed collection -// -// |EEEEEEEEOOOO| ... after step b3), added four regions to be -// evacuated in the "initial evacuation" phase -// EEEEEEEEOOOO|| ... after step b4), incremental part is empty -// after evacuation -// EEEEEEEEOOOO|OO| ... after step b5.1), added two regions to be -// evacuated in the first round of the -// "optional evacuation" phase -// EEEEEEEEOOOOOO|O| ... after step b5.1), added one region to be -// evacuated in the second round of the -// "optional evacuation" phase -// EEEEEEEEOOOOOOO|| ... after step b5), the complete collection set. -// || ... after step b6) -// |SSS| ... after step 7), with three survivor regions -// class G1CollectionSet { G1CollectedHeap* _g1h; G1Policy* _policy; - // All old gen collection set candidate regions for the current mixed phase. + // All old gen collection set candidate regions for the current mixed gc phase. G1CollectionSetCandidates* _candidates; uint _eden_region_length; @@ -141,7 +51,7 @@ // The actual collection set as a set of region indices. // All entries in _collection_set_regions below _collection_set_cur_length are - // assumed to be part of the collection set. + // assumed to be valid entries. // We assume that at any time there is at most only one writer and (one or more) // concurrent readers. This means we are good with using storestore and loadload // barriers on the writer and reader respectively only. @@ -149,33 +59,31 @@ volatile size_t _collection_set_cur_length; size_t _collection_set_max_length; - // When doing mixed collections we can add old regions to the collection set, which - // will be collected only if there is enough time. We call these optional regions. - // This member records the current number of regions that are of that type that - // correspond to the first x entries in the collection set candidates. - uint _num_optional_regions; + // When doing mixed collections we can add old regions to the collection, which + // can be collected if there is enough time. We call these optional regions and + // the pointer to these regions are stored in the array below. + HeapRegion** _optional_regions; + uint _optional_region_length; + uint _optional_region_max_length; // The number of bytes in the collection set before the pause. Set from // the incrementally built collection set at the start of an evacuation - // pause, and updated as more regions are added to the collection set. + // pause, and incremented in finalize_old_part() when adding old regions + // (if any) to the collection set. size_t _bytes_used_before; - // The number of cards in the remembered set in the collection set. Set from - // the incrementally built collection set at the start of an evacuation - // pause, and updated as more regions are added to the collection set. size_t _recorded_rs_lengths; + // The associated information that is maintained while the incremental + // collection set is being built with young regions. Used to populate + // the recorded info for the evacuation pause. + enum CSetBuildType { Active, // We are actively building the collection set Inactive // We are not actively building the collection set }; CSetBuildType _inc_build_state; - size_t _inc_part_start; - - // The associated information that is maintained while the incremental - // collection set is being built with *young* regions. Used to populate - // the recorded info for the evacuation pause. // The number of bytes in the incrementally built collection set. // Used to set _collection_set_bytes_used_before at the start of @@ -205,44 +113,22 @@ // See the comment for _inc_recorded_rs_lengths_diffs. double _inc_predicted_elapsed_time_ms_diffs; - void set_recorded_rs_lengths(size_t rs_lengths); - G1CollectorState* collector_state(); G1GCPhaseTimes* phase_times(); void verify_young_cset_indices() const NOT_DEBUG_RETURN; + void add_as_optional(HeapRegion* hr); + void add_as_old(HeapRegion* hr); + bool optional_is_full(); - double predict_region_elapsed_time_ms(HeapRegion* hr); - - // Update the incremental collection set information when adding a region. - void add_young_region_common(HeapRegion* hr); - - // Add old region "hr" to the collection set. - void add_old_region(HeapRegion* hr); - void free_optional_regions(); - - // Add old region "hr" to optional collection set. - void add_optional_region(HeapRegion* hr); - - void move_candidates_to_collection_set(uint num_regions); - - // Finalize the young part of the initial collection set. Relabel survivor regions - // as Eden and calculate a prediction on how long the evacuation of all young regions - // will take. - double finalize_young_part(double target_pause_time_ms, G1SurvivorRegions* survivors); - // Perform any final calculations on the incremental collection set fields before we - // can use them. - void finalize_incremental_building(); - - // Select the old regions of the initial collection set and determine how many optional - // regions we might be able to evacuate in this pause. - void finalize_old_part(double time_remaining_ms); public: G1CollectionSet(G1CollectedHeap* g1h, G1Policy* policy); ~G1CollectionSet(); // Initializes the collection set giving the maximum possible length of the collection set. void initialize(uint max_region_length); + void initialize_optional(uint max_length); + void free_optional_regions(); void clear_candidates(); @@ -255,6 +141,8 @@ void init_region_lengths(uint eden_cset_region_length, uint survivor_cset_region_length); + void set_recorded_rs_lengths(size_t rs_lengths); + uint region_length() const { return young_region_length() + old_region_length(); } uint young_region_length() const { return eden_region_length() + @@ -263,29 +151,32 @@ uint eden_region_length() const { return _eden_region_length; } uint survivor_region_length() const { return _survivor_region_length; } uint old_region_length() const { return _old_region_length; } - uint optional_region_length() const { return _num_optional_regions; } - - // Reset the contents of the collection set. - void clear(); + uint optional_region_length() const { return _optional_region_length; } // Incremental collection set support // Initialize incremental collection set info. void start_incremental_building(); - // Start a new collection set increment. - void update_incremental_marker() { _inc_build_state = Active; _inc_part_start = _collection_set_cur_length; } - // Stop adding regions to the current collection set increment. - void stop_incremental_building() { _inc_build_state = Inactive; } - // Iterate over the current collection set increment applying the given HeapRegionClosure - // from a starting position determined by the given worker id. - void iterate_incremental_part_from(HeapRegionClosure* cl, uint worker_id, uint total_workers) const; + // Perform any final calculations on the incremental collection set fields + // before we can use them. + void finalize_incremental_building(); + + // Reset the contents of the collection set. + void clear(); - // Iterate over the entire collection set (all increments calculated so far), applying - // the given HeapRegionClosure on all of them. + // Iterate over the collection set, applying the given HeapRegionClosure on all of them. + // If may_be_aborted is true, iteration may be aborted using the return value of the + // called closure method. void iterate(HeapRegionClosure* cl) const; - void iterate_optional(HeapRegionClosure* cl) const; + // Iterate over the collection set, applying the given HeapRegionClosure on all of them, + // trying to optimally spread out starting position of total_workers workers given the + // caller's worker_id. + void iterate_from(HeapRegionClosure* cl, uint worker_id, uint total_workers) const; + + // Stop adding regions to the incremental collection set. + void stop_incremental_building() { _inc_build_state = Inactive; } size_t recorded_rs_lengths() { return _recorded_rs_lengths; } @@ -297,14 +188,16 @@ _bytes_used_before = 0; } - // Finalize the initial collection set consisting of all young regions potentially a - // few old gen regions. - void finalize_initial_collection_set(double target_pause_time_ms, G1SurvivorRegions* survivor); - // Finalize the next collection set from the set of available optional old gen regions. - bool finalize_optional_for_evacuation(double remaining_pause_time); - // Abandon (clean up) optional collection set regions that were not evacuated in this - // pause. - void abandon_optional_collection_set(G1ParScanThreadStateSet* pss); + // Choose a new collection set. Marks the chosen regions as being + // "in_collection_set". + double finalize_young_part(double target_pause_time_ms, G1SurvivorRegions* survivors); + void finalize_old_part(double time_remaining_ms); + + // Add old region "hr" to the collection set. + void add_old_region(HeapRegion* hr); + + // Add old region "hr" to optional collection set. + void add_optional_region(HeapRegion* hr); // Update information about hr in the aggregated information for // the incrementally built collection set. @@ -321,6 +214,73 @@ void print(outputStream* st); #endif // !PRODUCT + + double predict_region_elapsed_time_ms(HeapRegion* hr); + + void clear_optional_region(const HeapRegion* hr); + + HeapRegion* optional_region_at(uint i) const { + assert(_optional_regions != NULL, "Not yet initialized"); + assert(i < _optional_region_length, "index %u out of bounds (%u)", i, _optional_region_length); + return _optional_regions[i]; + } + + HeapRegion* remove_last_optional_region() { + assert(_optional_regions != NULL, "Not yet initialized"); + assert(_optional_region_length != 0, "No region to remove"); + _optional_region_length--; + HeapRegion* removed = _optional_regions[_optional_region_length]; + _optional_regions[_optional_region_length] = NULL; + return removed; + } + +private: + // Update the incremental collection set information when adding a region. + void add_young_region_common(HeapRegion* hr); +}; + +// Helper class to manage the optional regions in a Mixed collection. +class G1OptionalCSet : public StackObj { +private: + G1CollectionSet* _cset; + G1ParScanThreadStateSet* _pset; + uint _current_index; + uint _current_limit; + bool _prepare_failed; + bool _evacuation_failed; + + void prepare_to_evacuate_optional_region(HeapRegion* hr); + +public: + static const uint InvalidCSetIndex = UINT_MAX; + + G1OptionalCSet(G1CollectionSet* cset, G1ParScanThreadStateSet* pset) : + _cset(cset), + _pset(pset), + _current_index(0), + _current_limit(0), + _prepare_failed(false), + _evacuation_failed(false) { } + // The destructor returns regions to the collection set candidates set and + // frees the optional structure in the collection set. + ~G1OptionalCSet(); + + uint current_index() { return _current_index; } + uint current_limit() { return _current_limit; } + + uint size(); + bool is_empty(); + + HeapRegion* region_at(uint index); + + // Prepare a set of regions for optional evacuation. + void prepare_evacuation(double time_left_ms); + bool prepare_failed(); + + // Complete the evacuation of the previously prepared + // regions by updating their state and check for failures. + void complete_evacuation(); + bool evacuation_failed(); }; #endif // SHARE_GC_G1_G1COLLECTIONSET_HPP --- old/src/hotspot/share/gc/g1/g1CollectionSetCandidates.cpp 2019-05-21 01:01:12.341162932 +0200 +++ new/src/hotspot/share/gc/g1/g1CollectionSetCandidates.cpp 2019-05-21 01:01:12.189163205 +0200 @@ -27,12 +27,26 @@ #include "gc/g1/g1CollectionSetChooser.hpp" #include "gc/g1/heapRegion.inline.hpp" -void G1CollectionSetCandidates::remove(uint num_regions) { - assert(num_regions <= num_remaining(), "Trying to remove more regions (%u) than available (%u)", num_regions, num_remaining()); - for (uint i = 0; i < num_regions; i++) { - _remaining_reclaimable_bytes -= at(_front_idx)->reclaimable_bytes(); - _front_idx++; - } +HeapRegion* G1CollectionSetCandidates::pop_front() { + assert(_front_idx < _num_regions, "pre-condition"); + HeapRegion* hr = _regions[_front_idx]; + assert(hr != NULL, "pre-condition"); + _regions[_front_idx] = NULL; + assert(hr->reclaimable_bytes() <= _remaining_reclaimable_bytes, + "Remaining reclaimable bytes inconsistent " + "from region: " SIZE_FORMAT " remaining: " SIZE_FORMAT, + hr->reclaimable_bytes(), _remaining_reclaimable_bytes); + _remaining_reclaimable_bytes -= hr->reclaimable_bytes(); + _front_idx++; + return hr; +} + +void G1CollectionSetCandidates::push_front(HeapRegion* hr) { + assert(hr != NULL, "Can't put back a NULL region"); + assert(_front_idx >= 1, "Too many regions have been put back."); + _front_idx--; + _regions[_front_idx] = hr; + _remaining_reclaimable_bytes += hr->reclaimable_bytes(); } void G1CollectionSetCandidates::iterate(HeapRegionClosure* cl) { @@ -48,8 +62,13 @@ #ifndef PRODUCT void G1CollectionSetCandidates::verify() const { guarantee(_front_idx <= _num_regions, "Index: %u Num_regions: %u", _front_idx, _num_regions); - uint idx = _front_idx; + uint idx = 0; size_t sum_of_reclaimable_bytes = 0; + while (idx < _front_idx) { + guarantee(_regions[idx] == NULL, "All entries before _front_idx %u should be NULL, but %u is not", + _front_idx, idx); + idx++; + } HeapRegion *prev = NULL; for (; idx < _num_regions; idx++) { HeapRegion *cur = _regions[idx]; --- old/src/hotspot/share/gc/g1/g1CollectionSetCandidates.hpp 2019-05-21 01:01:12.541162573 +0200 +++ new/src/hotspot/share/gc/g1/g1CollectionSetCandidates.hpp 2019-05-21 01:01:12.385162853 +0200 @@ -63,18 +63,22 @@ // Returns the total number of collection set candidate old regions added. uint num_regions() { return _num_regions; } - uint cur_idx() const { return _front_idx; } - - HeapRegion* at(uint idx) const { + // Return the candidate region at the cursor position to be considered for collection without + // removing it. + HeapRegion* peek_front() { HeapRegion* res = NULL; - if (idx < _num_regions) { - res = _regions[idx]; - assert(res != NULL, "Unexpected NULL HeapRegion at index %u", idx); + if (_front_idx < _num_regions) { + res = _regions[_front_idx]; + assert(res != NULL, "Unexpected NULL HeapRegion at index %u", _front_idx); } return res; } - void remove(uint num_regions); + // Remove the given region from the candidates set and move the cursor to the next one. + HeapRegion* pop_front(); + + // Add the given HeapRegion to the front of the collection set candidate set again. + void push_front(HeapRegion* hr); // Iterate over all remaining collection set candidate regions. void iterate(HeapRegionClosure* cl); --- old/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp 2019-05-21 01:01:12.737162221 +0200 +++ new/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp 2019-05-21 01:01:12.577162509 +0200 @@ -1940,10 +1940,9 @@ guarantee(oopDesc::is_oop(task_entry.obj()), "Non-oop " PTR_FORMAT ", phase: %s, info: %d", p2i(task_entry.obj()), _phase, _info); - HeapRegion* r = _g1h->heap_region_containing(task_entry.obj()); - guarantee(!(r->in_collection_set() || r->has_index_in_opt_cset()), - "obj " PTR_FORMAT " from %s (%d) in region %u in (optional) collection set", - p2i(task_entry.obj()), _phase, _info, r->hrm_index()); + guarantee(!_g1h->is_in_cset(task_entry.obj()), + "obj: " PTR_FORMAT " in CSet, phase: %s, info: %d", + p2i(task_entry.obj()), _phase, _info); } }; @@ -1980,11 +1979,11 @@ HeapWord* task_finger = task->finger(); if (task_finger != NULL && task_finger < _heap.end()) { // See above note on the global finger verification. - HeapRegion* r = _g1h->heap_region_containing(task_finger); - guarantee(r == NULL || task_finger == r->bottom() || - !r->in_collection_set() || !r->has_index_in_opt_cset(), + HeapRegion* task_hr = _g1h->heap_region_containing(task_finger); + guarantee(task_hr == NULL || task_finger == task_hr->bottom() || + !task_hr->in_collection_set(), "task finger: " PTR_FORMAT " region: " HR_FORMAT, - p2i(task_finger), HR_FORMAT_PARAMS(r)); + p2i(task_finger), HR_FORMAT_PARAMS(task_hr)); } } } --- old/src/hotspot/share/gc/g1/g1ConcurrentMarkThread.cpp 2019-05-21 01:01:12.953161834 +0200 +++ new/src/hotspot/share/gc/g1/g1ConcurrentMarkThread.cpp 2019-05-21 01:01:12.801162107 +0200 @@ -127,7 +127,7 @@ } void G1ConcurrentMarkThread::delay_to_keep_mmu(G1Policy* g1_policy, bool remark) { - if (g1_policy->use_adaptive_young_list_length()) { + if (g1_policy->adaptive_young_list_length()) { jlong sleep_time_ms = mmu_sleep_time(g1_policy, remark); if (!_cm->has_aborted() && sleep_time_ms > 0) { os::sleep(this, sleep_time_ms, false); --- old/src/hotspot/share/gc/g1/g1EdenRegions.hpp 2019-05-21 01:01:13.157161469 +0200 +++ new/src/hotspot/share/gc/g1/g1EdenRegions.hpp 2019-05-21 01:01:12.997161755 +0200 @@ -31,28 +31,19 @@ class G1EdenRegions { private: - int _length; - // Sum of used bytes from all retired eden regions. - // I.e. updated when mutator regions are retired. - volatile size_t _used_bytes; + int _length; public: - G1EdenRegions() : _length(0), _used_bytes(0) { } + G1EdenRegions() : _length(0) {} void add(HeapRegion* hr) { assert(!hr->is_eden(), "should not already be set"); _length++; } - void clear() { _length = 0; _used_bytes = 0; } + void clear() { _length = 0; } uint length() const { return _length; } - - size_t used_bytes() const { return _used_bytes; } - - void add_used_bytes(size_t used_bytes) { - _used_bytes += used_bytes; - } }; #endif // SHARE_GC_G1_G1EDENREGIONS_HPP --- old/src/hotspot/share/gc/g1/g1EvacFailure.cpp 2019-05-21 01:01:13.349161125 +0200 +++ new/src/hotspot/share/gc/g1/g1EvacFailure.cpp 2019-05-21 01:01:13.197161398 +0200 @@ -228,8 +228,6 @@ if (_hrclaimer->claim_region(hr->hrm_index())) { if (hr->evacuation_failed()) { - hr->clear_index_in_opt_cset(); - bool during_initial_mark = _g1h->collector_state()->in_initial_mark_gc(); bool during_conc_mark = _g1h->collector_state()->mark_or_rebuild_in_progress(); @@ -259,5 +257,5 @@ void G1ParRemoveSelfForwardPtrsTask::work(uint worker_id) { RemoveSelfForwardPtrHRClosure rsfp_cl(worker_id, &_hrclaimer); - _g1h->collection_set_iterate_increment_from(&rsfp_cl, worker_id); + _g1h->collection_set_iterate_from(&rsfp_cl, worker_id); } --- old/src/hotspot/share/gc/g1/g1GCPhaseTimes.cpp 2019-05-21 01:01:13.541160781 +0200 +++ new/src/hotspot/share/gc/g1/g1GCPhaseTimes.cpp 2019-05-21 01:01:13.389161054 +0200 @@ -76,12 +76,10 @@ } _gc_par_phases[ScanRS] = new WorkerDataArray(max_gc_threads, "Scan RS (ms):"); _gc_par_phases[OptScanRS] = new WorkerDataArray(max_gc_threads, "Optional Scan RS (ms):"); - _gc_par_phases[CodeRoots] = new WorkerDataArray(max_gc_threads, "Code Root Scan (ms):"); - _gc_par_phases[OptCodeRoots] = new WorkerDataArray(max_gc_threads, "Optional Code Root Scan (ms):"); + _gc_par_phases[CodeRoots] = new WorkerDataArray(max_gc_threads, "Code Root Scanning (ms):"); _gc_par_phases[ObjCopy] = new WorkerDataArray(max_gc_threads, "Object Copy (ms):"); _gc_par_phases[OptObjCopy] = new WorkerDataArray(max_gc_threads, "Optional Object Copy (ms):"); _gc_par_phases[Termination] = new WorkerDataArray(max_gc_threads, "Termination (ms):"); - _gc_par_phases[OptTermination] = new WorkerDataArray(max_gc_threads, "Optional Termination (ms):"); _gc_par_phases[GCWorkerTotal] = new WorkerDataArray(max_gc_threads, "GC Worker Total (ms):"); _gc_par_phases[GCWorkerEnd] = new WorkerDataArray(max_gc_threads, "GC Worker End (ms):"); _gc_par_phases[Other] = new WorkerDataArray(max_gc_threads, "GC Worker Other (ms):"); @@ -93,16 +91,14 @@ _scan_rs_skipped_cards = new WorkerDataArray(max_gc_threads, "Skipped Cards:"); _gc_par_phases[ScanRS]->link_thread_work_items(_scan_rs_skipped_cards, ScanRSSkippedCards); - _opt_scan_rs_scanned_cards = new WorkerDataArray(max_gc_threads, "Scanned Cards:"); - _gc_par_phases[OptScanRS]->link_thread_work_items(_opt_scan_rs_scanned_cards, ScanRSScannedCards); - _opt_scan_rs_claimed_cards = new WorkerDataArray(max_gc_threads, "Claimed Cards:"); - _gc_par_phases[OptScanRS]->link_thread_work_items(_opt_scan_rs_claimed_cards, ScanRSClaimedCards); - _opt_scan_rs_skipped_cards = new WorkerDataArray(max_gc_threads, "Skipped Cards:"); - _gc_par_phases[OptScanRS]->link_thread_work_items(_opt_scan_rs_skipped_cards, ScanRSSkippedCards); - _opt_scan_rs_scanned_opt_refs = new WorkerDataArray(max_gc_threads, "Scanned Refs:"); - _gc_par_phases[OptScanRS]->link_thread_work_items(_opt_scan_rs_scanned_opt_refs, ScanRSScannedOptRefs); - _opt_scan_rs_used_memory = new WorkerDataArray(max_gc_threads, "Used Memory:"); - _gc_par_phases[OptScanRS]->link_thread_work_items(_opt_scan_rs_used_memory, ScanRSUsedMemory); + _opt_cset_scanned_cards = new WorkerDataArray(max_gc_threads, "Scanned Cards:"); + _gc_par_phases[OptScanRS]->link_thread_work_items(_opt_cset_scanned_cards, OptCSetScannedCards); + _opt_cset_claimed_cards = new WorkerDataArray(max_gc_threads, "Claimed Cards:"); + _gc_par_phases[OptScanRS]->link_thread_work_items(_opt_cset_claimed_cards, OptCSetClaimedCards); + _opt_cset_skipped_cards = new WorkerDataArray(max_gc_threads, "Skipped Cards:"); + _gc_par_phases[OptScanRS]->link_thread_work_items(_opt_cset_skipped_cards, OptCSetSkippedCards); + _opt_cset_used_memory = new WorkerDataArray(max_gc_threads, "Used Memory:"); + _gc_par_phases[OptScanRS]->link_thread_work_items(_opt_cset_used_memory, OptCSetUsedMemory); _update_rs_processed_buffers = new WorkerDataArray(max_gc_threads, "Processed Buffers:"); _gc_par_phases[UpdateRS]->link_thread_work_items(_update_rs_processed_buffers, UpdateRSProcessedBuffers); @@ -116,17 +112,9 @@ _obj_copy_lab_undo_waste = new WorkerDataArray(max_gc_threads, "LAB Undo Waste"); _gc_par_phases[ObjCopy]->link_thread_work_items(_obj_copy_lab_undo_waste, ObjCopyLABUndoWaste); - _opt_obj_copy_lab_waste = new WorkerDataArray(max_gc_threads, "LAB Waste"); - _gc_par_phases[OptObjCopy]->link_thread_work_items(_obj_copy_lab_waste, ObjCopyLABWaste); - _opt_obj_copy_lab_undo_waste = new WorkerDataArray(max_gc_threads, "LAB Undo Waste"); - _gc_par_phases[OptObjCopy]->link_thread_work_items(_obj_copy_lab_undo_waste, ObjCopyLABUndoWaste); - _termination_attempts = new WorkerDataArray(max_gc_threads, "Termination Attempts:"); _gc_par_phases[Termination]->link_thread_work_items(_termination_attempts); - _opt_termination_attempts = new WorkerDataArray(max_gc_threads, "Optional Termination Attempts:"); - _gc_par_phases[OptTermination]->link_thread_work_items(_opt_termination_attempts); - if (UseStringDeduplication) { _gc_par_phases[StringDedupQueueFixup] = new WorkerDataArray(max_gc_threads, "Queue Fixup (ms):"); _gc_par_phases[StringDedupTableFixup] = new WorkerDataArray(max_gc_threads, "Table Fixup (ms):"); @@ -146,7 +134,7 @@ } void G1GCPhaseTimes::reset() { - _cur_collection_initial_evac_time_ms = 0.0; + _cur_collection_par_time_ms = 0.0; _cur_optional_evac_ms = 0.0; _cur_collection_code_root_fixup_time_ms = 0.0; _cur_strong_code_root_purge_time_ms = 0.0; @@ -263,10 +251,6 @@ } } -double G1GCPhaseTimes::get_time_secs(GCParPhases phase, uint worker_i) { - return _gc_par_phases[phase]->get(worker_i); -} - void G1GCPhaseTimes::record_thread_work_item(GCParPhases phase, uint worker_i, size_t count, uint index) { _gc_par_phases[phase]->set_thread_work_item(worker_i, count, index); } @@ -275,10 +259,6 @@ _gc_par_phases[phase]->set_or_add_thread_work_item(worker_i, count, index); } -size_t G1GCPhaseTimes::get_thread_work_item(GCParPhases phase, uint worker_i, uint index) { - return _gc_par_phases[phase]->get_thread_work_item(worker_i, index); -} - // return the average time for a phase in milliseconds double G1GCPhaseTimes::average_time_ms(GCParPhases phase) { return _gc_par_phases[phase]->average() * 1000.0; @@ -394,14 +374,12 @@ info_time("Evacuate Optional Collection Set", sum_ms); debug_phase(_gc_par_phases[OptScanRS]); debug_phase(_gc_par_phases[OptObjCopy]); - debug_phase(_gc_par_phases[OptCodeRoots]); - debug_phase(_gc_par_phases[OptTermination]); } return sum_ms; } double G1GCPhaseTimes::print_evacuate_collection_set() const { - const double sum_ms = _cur_collection_initial_evac_time_ms; + const double sum_ms = _cur_collection_par_time_ms; info_time("Evacuate Collection Set", sum_ms); @@ -539,11 +517,9 @@ "ScanRS", "OptScanRS", "CodeRoots", - "OptCodeRoots", "ObjCopy", "OptObjCopy", "Termination", - "OptTermination", "Other", "GCWorkerTotal", "GCWorkerEnd", --- old/src/hotspot/share/gc/g1/g1GCPhaseTimes.hpp 2019-05-21 01:01:13.745160415 +0200 +++ new/src/hotspot/share/gc/g1/g1GCPhaseTimes.hpp 2019-05-21 01:01:13.589160695 +0200 @@ -67,11 +67,9 @@ ScanRS, OptScanRS, CodeRoots, - OptCodeRoots, ObjCopy, OptObjCopy, Termination, - OptTermination, Other, GCWorkerTotal, GCWorkerEnd, @@ -89,9 +87,7 @@ enum GCScanRSWorkItems { ScanRSScannedCards, ScanRSClaimedCards, - ScanRSSkippedCards, - ScanRSScannedOptRefs, - ScanRSUsedMemory + ScanRSSkippedCards }; enum GCUpdateRSWorkItems { @@ -105,6 +101,13 @@ ObjCopyLABUndoWaste }; + enum GCOptCSetWorkItems { + OptCSetScannedCards, + OptCSetClaimedCards, + OptCSetSkippedCards, + OptCSetUsedMemory + }; + private: // Markers for grouping the phases in the GCPhases enum above static const int GCMainParPhasesLast = GCWorkerEnd; @@ -119,25 +122,19 @@ WorkerDataArray* _scan_rs_claimed_cards; WorkerDataArray* _scan_rs_skipped_cards; - WorkerDataArray* _opt_scan_rs_scanned_cards; - WorkerDataArray* _opt_scan_rs_claimed_cards; - WorkerDataArray* _opt_scan_rs_skipped_cards; - WorkerDataArray* _opt_scan_rs_scanned_opt_refs; - WorkerDataArray* _opt_scan_rs_used_memory; - WorkerDataArray* _obj_copy_lab_waste; WorkerDataArray* _obj_copy_lab_undo_waste; - WorkerDataArray* _opt_obj_copy_lab_waste; - WorkerDataArray* _opt_obj_copy_lab_undo_waste; + WorkerDataArray* _opt_cset_scanned_cards; + WorkerDataArray* _opt_cset_claimed_cards; + WorkerDataArray* _opt_cset_skipped_cards; + WorkerDataArray* _opt_cset_used_memory; WorkerDataArray* _termination_attempts; - WorkerDataArray* _opt_termination_attempts; - WorkerDataArray* _redirtied_cards; - double _cur_collection_initial_evac_time_ms; + double _cur_collection_par_time_ms; double _cur_optional_evac_ms; double _cur_collection_code_root_fixup_time_ms; double _cur_strong_code_root_purge_time_ms; @@ -228,14 +225,10 @@ void record_or_add_time_secs(GCParPhases phase, uint worker_i, double secs); - double get_time_secs(GCParPhases phase, uint worker_i); - void record_thread_work_item(GCParPhases phase, uint worker_i, size_t count, uint index = 0); void record_or_add_thread_work_item(GCParPhases phase, uint worker_i, size_t count, uint index = 0); - size_t get_thread_work_item(GCParPhases phase, uint worker_i, uint index = 0); - // return the average time for a phase in milliseconds double average_time_ms(GCParPhases phase); @@ -263,16 +256,16 @@ _cur_expand_heap_time_ms = ms; } - void record_initial_evac_time(double ms) { - _cur_collection_initial_evac_time_ms = ms; + void record_par_time(double ms) { + _cur_collection_par_time_ms = ms; } - void record_or_add_optional_evac_time(double ms) { - _cur_optional_evac_ms += ms; + void record_optional_evacuation(double ms) { + _cur_optional_evac_ms = ms; } - void record_or_add_code_root_fixup_time(double ms) { - _cur_collection_code_root_fixup_time_ms += ms; + void record_code_root_fixup_time(double ms) { + _cur_collection_code_root_fixup_time_ms = ms; } void record_strong_code_root_purge_time(double ms) { @@ -367,7 +360,7 @@ } double cur_collection_par_time_ms() { - return _cur_collection_initial_evac_time_ms; + return _cur_collection_par_time_ms; } double cur_clear_ct_time_ms() { --- old/src/hotspot/share/gc/g1/g1HeapVerifier.cpp 2019-05-21 01:01:13.965160020 +0200 +++ new/src/hotspot/share/gc/g1/g1HeapVerifier.cpp 2019-05-21 01:01:13.805160307 +0200 @@ -371,7 +371,6 @@ } bool do_heap_region(HeapRegion* r) { - guarantee(!r->has_index_in_opt_cset(), "Region %u still has opt collection set index %u", r->hrm_index(), r->index_in_opt_cset()); guarantee(!r->is_young() || r->rem_set()->is_complete(), "Remembered set for Young region %u must be complete, is %s", r->hrm_index(), r->rem_set()->get_state_str()); // Humongous and old regions regions might be of any state, so can't check here. guarantee(!r->is_free() || !r->rem_set()->is_tracked(), "Remembered set for free region %u must be untracked, is %s", r->hrm_index(), r->rem_set()->get_state_str()); --- old/src/hotspot/share/gc/g1/g1MonitoringSupport.cpp 2019-05-21 01:01:14.189159619 +0200 +++ new/src/hotspot/share/gc/g1/g1MonitoringSupport.cpp 2019-05-21 01:01:14.021159920 +0200 @@ -228,25 +228,23 @@ MutexLockerEx x(MonitoringSupport_lock, Mutex::_no_safepoint_check_flag); // Recalculate all the sizes from scratch. - // This never includes used bytes of current allocating heap region. - _overall_used = _g1h->used_unlocked(); - _eden_space_used = _g1h->eden_regions_used_bytes(); - _survivor_space_used = _g1h->survivor_regions_used_bytes(); - - // _overall_used and _eden_space_used are obtained concurrently so - // may be inconsistent with each other. To prevent _old_gen_used going negative, - // use smaller value to substract. - _old_gen_used = _overall_used - MIN2(_overall_used, _eden_space_used + _survivor_space_used); - + uint young_list_length = _g1h->young_regions_count(); uint survivor_list_length = _g1h->survivor_regions_count(); + assert(young_list_length >= survivor_list_length, "invariant"); + uint eden_list_length = young_list_length - survivor_list_length; // Max length includes any potential extensions to the young gen // we'll do when the GC locker is active. uint young_list_max_length = _g1h->policy()->young_list_max_length(); assert(young_list_max_length >= survivor_list_length, "invariant"); uint eden_list_max_length = young_list_max_length - survivor_list_length; + _overall_used = _g1h->used_unlocked(); + _eden_space_used = (size_t) eden_list_length * HeapRegion::GrainBytes; + _survivor_space_used = (size_t) survivor_list_length * HeapRegion::GrainBytes; + _old_gen_used = subtract_up_to_zero(_overall_used, _eden_space_used + _survivor_space_used); + // First calculate the committed sizes that can be calculated independently. - _survivor_space_committed = survivor_list_length * HeapRegion::GrainBytes; + _survivor_space_committed = _survivor_space_used; _old_gen_committed = HeapRegion::align_up_to_region_byte_size(_old_gen_used); // Next, start with the overall committed size. @@ -276,15 +274,11 @@ // Somewhat defensive: cap the eden used size to make sure it // never exceeds the committed size. _eden_space_used = MIN2(_eden_space_used, _eden_space_committed); - // _survivor_space_used is calculated during a safepoint and _survivor_space_committed - // is calculated from survivor region count * heap region size. - assert(_survivor_space_used <= _survivor_space_committed, "Survivor used bytes(" SIZE_FORMAT - ") should be less than or equal to survivor committed(" SIZE_FORMAT ")", - _survivor_space_used, _survivor_space_committed); - // _old_gen_committed is calculated in terms of _old_gen_used value. - assert(_old_gen_used <= _old_gen_committed, "Old gen used bytes(" SIZE_FORMAT - ") should be less than or equal to old gen committed(" SIZE_FORMAT ")", - _old_gen_used, _old_gen_committed); + // _survivor_committed and _old_committed are calculated in terms of + // the corresponding _*_used value, so the next two conditions + // should hold. + assert(_survivor_space_used <= _survivor_space_committed, "post-condition"); + assert(_old_gen_used <= _old_gen_committed, "post-condition"); } void G1MonitoringSupport::update_sizes() { --- old/src/hotspot/share/gc/g1/g1MonitoringSupport.hpp 2019-05-21 01:01:14.405159232 +0200 +++ new/src/hotspot/share/gc/g1/g1MonitoringSupport.hpp 2019-05-21 01:01:14.245159518 +0200 @@ -174,6 +174,21 @@ size_t _old_gen_used; + // It returns x - y if x > y, 0 otherwise. + // As described in the comment above, some of the inputs to the + // calculations we have to do are obtained concurrently and hence + // may be inconsistent with each other. So, this provides a + // defensive way of performing the subtraction and avoids the value + // going negative (which would mean a very large result, given that + // the parameter are size_t). + static size_t subtract_up_to_zero(size_t x, size_t y) { + if (x > y) { + return x - y; + } else { + return 0; + } + } + // Recalculate all the sizes. void recalculate_sizes(); --- old/src/hotspot/share/gc/g1/g1OopStarChunkedList.cpp 2019-05-21 01:01:14.605158873 +0200 +++ new/src/hotspot/share/gc/g1/g1OopStarChunkedList.cpp 2019-05-21 01:01:14.445159160 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -32,11 +32,9 @@ delete_list(_coops); } -size_t G1OopStarChunkedList::oops_do(OopClosure* obj_cl, OopClosure* root_cl) { - size_t result = 0; - result += chunks_do(_roots, root_cl); - result += chunks_do(_croots, root_cl); - result += chunks_do(_oops, obj_cl); - result += chunks_do(_coops, obj_cl); - return result; +void G1OopStarChunkedList::oops_do(OopClosure* obj_cl, OopClosure* root_cl) { + chunks_do(_roots, root_cl); + chunks_do(_croots, root_cl); + chunks_do(_oops, obj_cl); + chunks_do(_coops, obj_cl); } --- old/src/hotspot/share/gc/g1/g1OopStarChunkedList.hpp 2019-05-21 01:01:14.805158516 +0200 +++ new/src/hotspot/share/gc/g1/g1OopStarChunkedList.hpp 2019-05-21 01:01:14.645158801 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,8 +41,8 @@ template void delete_list(ChunkedList* c); template - size_t chunks_do(ChunkedList* head, - OopClosure* cl); + void chunks_do(ChunkedList* head, + OopClosure* cl); template inline void push(ChunkedList** field, T* p); @@ -53,7 +53,7 @@ size_t used_memory() { return _used_memory; } - size_t oops_do(OopClosure* obj_cl, OopClosure* root_cl); + void oops_do(OopClosure* obj_cl, OopClosure* root_cl); inline void push_oop(oop* p); inline void push_oop(narrowOop* p); --- old/src/hotspot/share/gc/g1/g1OopStarChunkedList.inline.hpp 2019-05-21 01:01:14.997158169 +0200 +++ new/src/hotspot/share/gc/g1/g1OopStarChunkedList.inline.hpp 2019-05-21 01:01:14.849158437 +0200 @@ -72,16 +72,13 @@ } template -size_t G1OopStarChunkedList::chunks_do(ChunkedList* head, OopClosure* cl) { - size_t result = 0; +void G1OopStarChunkedList::chunks_do(ChunkedList* head, OopClosure* cl) { for (ChunkedList* c = head; c != NULL; c = c->next_used()) { - result += c->size(); for (size_t i = 0; i < c->size(); i++) { T* p = c->at(i); cl->do_oop(p); } } - return result; } #endif // SHARE_GC_G1_G1OOPSTARCHUNKEDLIST_INLINE_HPP --- old/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp 2019-05-21 01:01:15.193157820 +0200 +++ new/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp 2019-05-21 01:01:15.037158098 +0200 @@ -372,7 +372,7 @@ } size_t used_memory = pss->oops_into_optional_region(hr)->used_memory(); - _g1h->phase_times()->record_or_add_thread_work_item(G1GCPhaseTimes::OptScanRS, worker_index, used_memory, G1GCPhaseTimes::ScanRSUsedMemory); + _g1h->phase_times()->record_or_add_thread_work_item(G1GCPhaseTimes::OptScanRS, worker_index, used_memory, G1GCPhaseTimes::OptCSetUsedMemory); } } --- old/src/hotspot/share/gc/g1/g1Policy.cpp 2019-05-21 01:01:15.389157468 +0200 +++ new/src/hotspot/share/gc/g1/g1Policy.cpp 2019-05-21 01:01:15.237157741 +0200 @@ -105,7 +105,7 @@ assert(Heap_lock->owned_by_self(), "Locking discipline."); - if (!use_adaptive_young_list_length()) { + if (!adaptive_young_list_length()) { _young_list_fixed_length = _young_gen_sizer->min_desired_young_length(); } _young_gen_sizer->adjust_max_new_size(_g1h->max_expandable_regions()); @@ -195,7 +195,7 @@ uint G1Policy::calculate_young_list_desired_min_length(uint base_min_length) const { uint desired_min_length = 0; - if (use_adaptive_young_list_length()) { + if (adaptive_young_list_length()) { if (_analytics->num_alloc_rate_ms() > 3) { double now_sec = os::elapsedTime(); double when_ms = _mmu_tracker->when_max_gc_sec(now_sec) * 1000.0; @@ -252,7 +252,7 @@ uint desired_max_length = calculate_young_list_desired_max_length(); uint young_list_target_length = 0; - if (use_adaptive_young_list_length()) { + if (adaptive_young_list_length()) { if (collector_state()->in_young_only_phase()) { young_list_target_length = calculate_young_list_target_length(rs_lengths, @@ -304,7 +304,7 @@ uint base_min_length, uint desired_min_length, uint desired_max_length) const { - assert(use_adaptive_young_list_length(), "pre-condition"); + assert(adaptive_young_list_length(), "pre-condition"); assert(collector_state()->in_young_only_phase(), "only call this for young GCs"); // In case some edge-condition makes the desired max length too small... @@ -414,7 +414,7 @@ } void G1Policy::revise_young_list_target_length_if_necessary(size_t rs_lengths) { - guarantee(use_adaptive_young_list_length(), "should not call this otherwise" ); + guarantee( adaptive_young_list_length(), "should not call this otherwise" ); if (rs_lengths > _rs_lengths_prediction) { // add 10% to avoid having to recalculate often @@ -430,7 +430,7 @@ } void G1Policy::update_rs_lengths_prediction(size_t prediction) { - if (collector_state()->in_young_only_phase() && use_adaptive_young_list_length()) { + if (collector_state()->in_young_only_phase() && adaptive_young_list_length()) { _rs_lengths_prediction = prediction; } } @@ -659,11 +659,7 @@ double cost_per_entry_ms = 0.0; if (cards_scanned > 10) { - double avg_time_scan_rs = average_time_ms(G1GCPhaseTimes::ScanRS); - if (this_pause_was_young_only) { - avg_time_scan_rs += average_time_ms(G1GCPhaseTimes::OptScanRS); - } - cost_per_entry_ms = avg_time_scan_rs / cards_scanned; + cost_per_entry_ms = average_time_ms(G1GCPhaseTimes::ScanRS) / (double) cards_scanned; _analytics->report_cost_per_entry_ms(cost_per_entry_ms, this_pause_was_young_only); } @@ -698,7 +694,7 @@ double cost_per_byte_ms = 0.0; if (copied_bytes > 0) { - cost_per_byte_ms = (average_time_ms(G1GCPhaseTimes::ObjCopy) + average_time_ms(G1GCPhaseTimes::OptObjCopy)) / (double) copied_bytes; + cost_per_byte_ms = average_time_ms(G1GCPhaseTimes::ObjCopy) / (double) copied_bytes; _analytics->report_cost_per_byte_ms(cost_per_byte_ms, collector_state()->mark_or_rebuild_in_progress()); } @@ -910,8 +906,8 @@ return young_list_length < young_list_max_length; } -bool G1Policy::use_adaptive_young_list_length() const { - return _young_gen_sizer->use_adaptive_young_list_length(); +bool G1Policy::adaptive_young_list_length() const { + return _young_gen_sizer->adaptive_young_list_length(); } size_t G1Policy::desired_survivor_size(uint max_regions) const { @@ -1192,135 +1188,11 @@ return (uint) result; } -void G1Policy::calculate_old_collection_set_regions(G1CollectionSetCandidates* candidates, - double time_remaining_ms, - uint& num_initial_regions, - uint& num_optional_regions) { - assert(candidates != NULL, "Must be"); - - num_initial_regions = 0; - num_optional_regions = 0; - uint num_expensive_regions = 0; - - double predicted_old_time_ms = 0.0; - double predicted_initial_time_ms = 0.0; - double predicted_optional_time_ms = 0.0; - - double optional_threshold_ms = time_remaining_ms * optional_prediction_fraction(); - - const uint min_old_cset_length = calc_min_old_cset_length(); - const uint max_old_cset_length = MAX2(min_old_cset_length, calc_max_old_cset_length()); - const uint max_optional_regions = max_old_cset_length - min_old_cset_length; - bool check_time_remaining = use_adaptive_young_list_length(); - - uint candidate_idx = candidates->cur_idx(); - - log_debug(gc, ergo, cset)("Start adding old regions to collection set. Min %u regions, max %u regions, " - "time remaining %1.2fms, optional threshold %1.2fms", - min_old_cset_length, max_old_cset_length, time_remaining_ms, optional_threshold_ms); - - HeapRegion* hr = candidates->at(candidate_idx); - while (hr != NULL) { - if (num_initial_regions + num_optional_regions >= max_old_cset_length) { - // Added maximum number of old regions to the CSet. - log_debug(gc, ergo, cset)("Finish adding old regions to collection set (Maximum number of regions). " - "Initial %u regions, optional %u regions", - num_initial_regions, num_optional_regions); - break; - } - - // Stop adding regions if the remaining reclaimable space is - // not above G1HeapWastePercent. - size_t reclaimable_bytes = candidates->remaining_reclaimable_bytes(); - double reclaimable_percent = reclaimable_bytes_percent(reclaimable_bytes); - double threshold = (double) G1HeapWastePercent; - if (reclaimable_percent <= threshold) { - // We've added enough old regions that the amount of uncollected - // reclaimable space is at or below the waste threshold. Stop - // adding old regions to the CSet. - log_debug(gc, ergo, cset)("Finish adding old regions to collection set (Reclaimable percentage below threshold). " - "Reclaimable: " SIZE_FORMAT "%s (%1.2f%%) threshold: " UINTX_FORMAT "%%", - byte_size_in_proper_unit(reclaimable_bytes), proper_unit_for_byte_size(reclaimable_bytes), - reclaimable_percent, G1HeapWastePercent); - break; - } - - double predicted_time_ms = predict_region_elapsed_time_ms(hr, false); - time_remaining_ms = MAX2(time_remaining_ms - predicted_time_ms, 0.0); - // Add regions to old set until we reach the minimum amount - if (num_initial_regions < min_old_cset_length) { - predicted_old_time_ms += predicted_time_ms; - num_initial_regions++; - // Record the number of regions added with no time remaining - if (time_remaining_ms == 0.0) { - num_expensive_regions++; - } - } else if (!check_time_remaining) { - // In the non-auto-tuning case, we'll finish adding regions - // to the CSet if we reach the minimum. - log_debug(gc, ergo, cset)("Finish adding old regions to collection set (Region amount reached min)."); - break; - } else { - // Keep adding regions to old set until we reach the optional threshold - if (time_remaining_ms > optional_threshold_ms) { - predicted_old_time_ms += predicted_time_ms; - num_initial_regions++; - } else if (time_remaining_ms > 0) { - // Keep adding optional regions until time is up. - assert(num_optional_regions < max_optional_regions, "Should not be possible."); - predicted_optional_time_ms += predicted_time_ms; - num_optional_regions++; - } else { - log_debug(gc, ergo, cset)("Finish adding old regions to collection set (Predicted time too high)."); - break; - } - } - hr = candidates->at(++candidate_idx); - } - if (hr == NULL) { - log_debug(gc, ergo, cset)("Old candidate collection set empty."); - } - - if (num_expensive_regions > 0) { - log_debug(gc, ergo, cset)("Added %u initial old regions to collection set although the predicted time was too high.", - num_expensive_regions); - } - - log_debug(gc, ergo, cset)("Finish choosing collection set old regions. Initial: %u, optional: %u, " - "predicted old time: %1.2fms, predicted optional time: %1.2fms, time remaining: %1.2f", - num_initial_regions, num_optional_regions, - predicted_initial_time_ms, predicted_optional_time_ms, time_remaining_ms); -} - -void G1Policy::calculate_optional_collection_set_regions(G1CollectionSetCandidates* candidates, - uint const max_optional_regions, - double time_remaining_ms, - uint& num_optional_regions) { - assert(_g1h->collector_state()->in_mixed_phase(), "Should only be called in mixed phase"); - - num_optional_regions = 0; - double prediction_ms = 0; - uint candidate_idx = candidates->cur_idx(); - - HeapRegion* r = candidates->at(candidate_idx); - while (num_optional_regions < max_optional_regions) { - assert(r != NULL, "Region must exist"); - prediction_ms += predict_region_elapsed_time_ms(r, false); - - if (prediction_ms > time_remaining_ms) { - log_debug(gc, ergo, cset)("Prediction %.3fms for region %u does not fit remaining time: %.3fms.", - prediction_ms, r->hrm_index(), time_remaining_ms); - break; - } - // This region will be included in the next optional evacuation. - - time_remaining_ms -= prediction_ms; - num_optional_regions++; - r = candidates->at(++candidate_idx); - } +uint G1Policy::finalize_collection_set(double target_pause_time_ms, G1SurvivorRegions* survivor) { + double time_remaining_ms = _collection_set->finalize_young_part(target_pause_time_ms, survivor); + _collection_set->finalize_old_part(time_remaining_ms); - log_debug(gc, ergo, cset)("Prepared %u regions out of %u for optional evacuation. Predicted time: %.3fms", - num_optional_regions, max_optional_regions, prediction_ms); + return _collection_set->region_length(); } void G1Policy::transfer_survivors_to_cset(const G1SurvivorRegions* survivors) { --- old/src/hotspot/share/gc/g1/g1Policy.hpp 2019-05-21 01:01:15.593157102 +0200 +++ new/src/hotspot/share/gc/g1/g1Policy.hpp 2019-05-21 01:01:15.441157374 +0200 @@ -44,7 +44,6 @@ class HeapRegion; class G1CollectionSet; -class G1CollectionSetCandidates; class G1CollectionSetChooser; class G1IHOPControl; class G1Analytics; @@ -345,21 +344,7 @@ bool next_gc_should_be_mixed(const char* true_action_str, const char* false_action_str) const; - // Calculate and return the number of initial and optional old gen regions from - // the given collection set candidates and the remaining time. - void calculate_old_collection_set_regions(G1CollectionSetCandidates* candidates, - double time_remaining_ms, - uint& num_initial_regions, - uint& num_optional_regions); - - // Calculate the number of optional regions from the given collection set candidates, - // the remaining time and the maximum number of these regions and return the number - // of actually selected regions in num_optional_regions. - void calculate_optional_collection_set_regions(G1CollectionSetCandidates* candidates, - uint const max_optional_regions, - double time_remaining_ms, - uint& num_optional_regions); - + uint finalize_collection_set(double target_pause_time_ms, G1SurvivorRegions* survivor); private: // Set the state to start a concurrent marking cycle and clear // _initiate_conc_mark_if_possible because it has now been @@ -399,7 +384,7 @@ return _young_list_max_length; } - bool use_adaptive_young_list_length() const; + bool adaptive_young_list_length() const; void transfer_survivors_to_cset(const G1SurvivorRegions* survivors); @@ -418,13 +403,11 @@ AgeTable _survivors_age_table; size_t desired_survivor_size(uint max_regions) const; - +public: // Fraction used when predicting how many optional regions to include in // the CSet. This fraction of the available time is used for optional regions, // the rest is used to add old regions to the normal CSet. double optional_prediction_fraction() { return 0.2; } - -public: // Fraction used when evacuating the optional regions. This fraction of the // remaining time is used to choose what regions to include in the evacuation. double optional_evacuation_fraction() { return 0.75; } --- old/src/hotspot/share/gc/g1/g1RemSet.cpp 2019-05-21 01:01:15.805156722 +0200 +++ new/src/hotspot/share/gc/g1/g1RemSet.cpp 2019-05-21 01:01:15.637157023 +0200 @@ -316,8 +316,6 @@ _scan_state(scan_state), _phase(phase), _worker_i(worker_i), - _opt_refs_scanned(0), - _opt_refs_memory_used(0), _cards_scanned(0), _cards_claimed(0), _cards_skipped(0), @@ -340,19 +338,6 @@ _cards_scanned++; } -void G1ScanRSForRegionClosure::scan_opt_rem_set_roots(HeapRegion* r) { - EventGCPhaseParallel event; - - G1OopStarChunkedList* opt_rem_set_list = _pss->oops_into_optional_region(r); - - G1ScanObjsDuringScanRSClosure scan_cl(_g1h, _pss); - G1ScanRSForOptionalClosure cl(&scan_cl); - _opt_refs_scanned += opt_rem_set_list->oops_do(&cl, _pss->closures()->raw_strong_oops()); - _opt_refs_memory_used += opt_rem_set_list->used_memory(); - - event.commit(GCId::current(), _worker_i, G1GCPhaseTimes::phase_name(_phase)); -} - void G1ScanRSForRegionClosure::scan_rem_set_roots(HeapRegion* r) { EventGCPhaseParallel event; uint const region_idx = r->hrm_index(); @@ -429,16 +414,11 @@ } bool G1ScanRSForRegionClosure::do_heap_region(HeapRegion* r) { - assert(r->in_collection_set(), "Region %u is not in the collection set.", r->hrm_index()); + assert(r->in_collection_set(), + "Should only be called on elements of the collection set but region %u is not.", + r->hrm_index()); uint const region_idx = r->hrm_index(); - // The individual references for the optional remembered set are per-worker, so we - // always need to scan them. - if (r->has_index_in_opt_cset()) { - G1EvacPhaseWithTrimTimeTracker timer(_pss, _rem_set_root_scan_time, _rem_set_trim_partially_time); - scan_opt_rem_set_roots(r); - } - // Do an early out if we know we are complete. if (_scan_state->iter_is_complete(region_idx)) { return false; @@ -457,33 +437,22 @@ return false; } -void G1RemSet::scan_rem_set(G1ParScanThreadState* pss, - uint worker_i, - G1GCPhaseTimes::GCParPhases scan_phase, - G1GCPhaseTimes::GCParPhases objcopy_phase, - G1GCPhaseTimes::GCParPhases coderoots_phase) { - assert(pss->trim_ticks().value() == 0, "Queues must have been trimmed before entering."); - +void G1RemSet::scan_rem_set(G1ParScanThreadState* pss, uint worker_i) { G1ScanObjsDuringScanRSClosure scan_cl(_g1h, pss); - G1ScanRSForRegionClosure cl(_scan_state, &scan_cl, pss, scan_phase, worker_i); - _g1h->collection_set_iterate_increment_from(&cl, worker_i); + G1ScanRSForRegionClosure cl(_scan_state, &scan_cl, pss, G1GCPhaseTimes::ScanRS, worker_i); + _g1h->collection_set_iterate_from(&cl, worker_i); G1GCPhaseTimes* p = _g1p->phase_times(); - p->record_or_add_time_secs(objcopy_phase, worker_i, cl.rem_set_trim_partially_time().seconds()); + p->record_time_secs(G1GCPhaseTimes::ScanRS, worker_i, cl.rem_set_root_scan_time().seconds()); + p->add_time_secs(G1GCPhaseTimes::ObjCopy, worker_i, cl.rem_set_trim_partially_time().seconds()); - p->record_or_add_time_secs(scan_phase, worker_i, cl.rem_set_root_scan_time().seconds()); - p->record_or_add_thread_work_item(scan_phase, worker_i, cl.cards_scanned(), G1GCPhaseTimes::ScanRSScannedCards); - p->record_or_add_thread_work_item(scan_phase, worker_i, cl.cards_claimed(), G1GCPhaseTimes::ScanRSClaimedCards); - p->record_or_add_thread_work_item(scan_phase, worker_i, cl.cards_skipped(), G1GCPhaseTimes::ScanRSSkippedCards); - // At this time we only record some metrics for the optional remembered set. - if (scan_phase == G1GCPhaseTimes::OptScanRS) { - p->record_or_add_thread_work_item(scan_phase, worker_i, cl.opt_refs_scanned(), G1GCPhaseTimes::ScanRSScannedOptRefs); - p->record_or_add_thread_work_item(scan_phase, worker_i, cl.opt_refs_memory_used(), G1GCPhaseTimes::ScanRSUsedMemory); - } + p->record_thread_work_item(G1GCPhaseTimes::ScanRS, worker_i, cl.cards_scanned(), G1GCPhaseTimes::ScanRSScannedCards); + p->record_thread_work_item(G1GCPhaseTimes::ScanRS, worker_i, cl.cards_claimed(), G1GCPhaseTimes::ScanRSClaimedCards); + p->record_thread_work_item(G1GCPhaseTimes::ScanRS, worker_i, cl.cards_skipped(), G1GCPhaseTimes::ScanRSSkippedCards); - p->record_or_add_time_secs(coderoots_phase, worker_i, cl.strong_code_root_scan_time().seconds()); - p->add_time_secs(objcopy_phase, worker_i, cl.strong_code_root_trim_partially_time().seconds()); + p->record_time_secs(G1GCPhaseTimes::CodeRoots, worker_i, cl.strong_code_root_scan_time().seconds()); + p->add_time_secs(G1GCPhaseTimes::ObjCopy, worker_i, cl.strong_code_root_trim_partially_time().seconds()); } // Closure used for updating rem sets. Only called during an evacuation pause. @@ -545,6 +514,11 @@ } } +void G1RemSet::oops_into_collection_set_do(G1ParScanThreadState* pss, uint worker_i) { + update_rem_set(pss, worker_i); + scan_rem_set(pss, worker_i);; +} + void G1RemSet::prepare_for_oops_into_collection_set_do() { G1BarrierSet::dirty_card_queue_set().concatenate_logs(); _scan_state->reset(); --- old/src/hotspot/share/gc/g1/g1RemSet.hpp 2019-05-21 01:01:16.005156363 +0200 +++ new/src/hotspot/share/gc/g1/g1RemSet.hpp 2019-05-21 01:01:15.853156635 +0200 @@ -60,6 +60,14 @@ G1RemSetSummary _prev_period_summary; + // Scan all remembered sets of the collection set for references into the collection + // set. + void scan_rem_set(G1ParScanThreadState* pss, uint worker_i); + + // Flush remaining refinement buffers for cross-region references to either evacuate references + // into the collection set or update the remembered set. + void update_rem_set(G1ParScanThreadState* pss, uint worker_i); + G1CollectedHeap* _g1h; size_t _num_conc_refined_cards; // Number of cards refined concurrently to the mutator. @@ -85,19 +93,12 @@ G1HotCardCache* hot_card_cache); ~G1RemSet(); - // Scan all remembered sets of the collection set for references into the collection - // set. + // Process all oops in the collection set from the cards in the refinement buffers and + // remembered sets using pss. + // // Further applies heap_region_codeblobs on the oops of the unmarked nmethods on the strong code // roots list for each region in the collection set. - void scan_rem_set(G1ParScanThreadState* pss, - uint worker_i, - G1GCPhaseTimes::GCParPhases scan_phase, - G1GCPhaseTimes::GCParPhases objcopy_phase, - G1GCPhaseTimes::GCParPhases coderoots_phase); - - // Flush remaining refinement buffers for cross-region references to either evacuate references - // into the collection set or update the remembered set. - void update_rem_set(G1ParScanThreadState* pss, uint worker_i); + void oops_into_collection_set_do(G1ParScanThreadState* pss, uint worker_i); // Prepare for and cleanup after an oops_into_collection_set_do // call. Must call each of these once before and after (in sequential @@ -143,9 +144,6 @@ uint _worker_i; - size_t _opt_refs_scanned; - size_t _opt_refs_memory_used; - size_t _cards_scanned; size_t _cards_claimed; size_t _cards_skipped; @@ -159,7 +157,6 @@ void claim_card(size_t card_index, const uint region_idx_for_card); void scan_card(MemRegion mr, uint region_idx_for_card); - void scan_opt_rem_set_roots(HeapRegion* r); void scan_rem_set_roots(HeapRegion* r); void scan_strong_code_roots(HeapRegion* r); public: @@ -180,9 +177,6 @@ size_t cards_scanned() const { return _cards_scanned; } size_t cards_claimed() const { return _cards_claimed; } size_t cards_skipped() const { return _cards_skipped; } - - size_t opt_refs_scanned() const { return _opt_refs_scanned; } - size_t opt_refs_memory_used() const { return _opt_refs_memory_used; } }; #endif // SHARE_GC_G1_G1REMSET_HPP --- old/src/hotspot/share/gc/g1/g1SurvivorRegions.cpp 2019-05-21 01:01:16.193156026 +0200 +++ new/src/hotspot/share/gc/g1/g1SurvivorRegions.cpp 2019-05-21 01:01:16.045156291 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,9 +28,7 @@ #include "utilities/growableArray.hpp" #include "utilities/debug.hpp" -G1SurvivorRegions::G1SurvivorRegions() : - _regions(new (ResourceObj::C_HEAP, mtGC) GrowableArray(8, true, mtGC)), - _used_bytes(0) {} +G1SurvivorRegions::G1SurvivorRegions() : _regions(new (ResourceObj::C_HEAP, mtGC) GrowableArray(8, true, mtGC)) {} void G1SurvivorRegions::add(HeapRegion* hr) { assert(hr->is_survivor(), "should be flagged as survivor region"); @@ -53,9 +51,5 @@ void G1SurvivorRegions::clear() { _regions->clear(); - _used_bytes = 0; } -void G1SurvivorRegions::add_used_bytes(size_t used_bytes) { - _used_bytes += used_bytes; -} --- old/src/hotspot/share/gc/g1/g1SurvivorRegions.hpp 2019-05-21 01:01:16.385155682 +0200 +++ new/src/hotspot/share/gc/g1/g1SurvivorRegions.hpp 2019-05-21 01:01:16.233155955 +0200 @@ -34,7 +34,6 @@ class G1SurvivorRegions { private: GrowableArray* _regions; - volatile size_t _used_bytes; public: G1SurvivorRegions(); @@ -50,11 +49,6 @@ const GrowableArray* regions() const { return _regions; } - - // Used bytes of all survivor regions. - size_t used_bytes() const { return _used_bytes; } - - void add_used_bytes(size_t used_bytes); }; #endif // SHARE_GC_G1_G1SURVIVORREGIONS_HPP --- old/src/hotspot/share/gc/g1/g1YoungGenSizer.cpp 2019-05-21 01:01:16.577155338 +0200 +++ new/src/hotspot/share/gc/g1/g1YoungGenSizer.cpp 2019-05-21 01:01:16.425155611 +0200 @@ -30,14 +30,14 @@ #include "logging/log.hpp" G1YoungGenSizer::G1YoungGenSizer() : _sizer_kind(SizerDefaults), - _use_adaptive_sizing(true), _min_desired_young_length(0), _max_desired_young_length(0) { + _adaptive_size(true), _min_desired_young_length(0), _max_desired_young_length(0) { if (FLAG_IS_CMDLINE(NewRatio)) { if (FLAG_IS_CMDLINE(NewSize) || FLAG_IS_CMDLINE(MaxNewSize)) { log_warning(gc, ergo)("-XX:NewSize and -XX:MaxNewSize override -XX:NewRatio"); } else { _sizer_kind = SizerNewRatio; - _use_adaptive_sizing = false; + _adaptive_size = false; return; } } @@ -59,7 +59,7 @@ MAX2((uint) (MaxNewSize / HeapRegion::GrainBytes), 1U); _sizer_kind = SizerMaxAndNewSize; - _use_adaptive_sizing = _min_desired_young_length != _max_desired_young_length; + _adaptive_size = _min_desired_young_length != _max_desired_young_length; } else { _sizer_kind = SizerNewSizeOnly; } --- old/src/hotspot/share/gc/g1/g1YoungGenSizer.hpp 2019-05-21 01:01:16.777154979 +0200 +++ new/src/hotspot/share/gc/g1/g1YoungGenSizer.hpp 2019-05-21 01:01:16.621155259 +0200 @@ -77,7 +77,7 @@ // False when using a fixed young generation size due to command-line options, // true otherwise. - bool _use_adaptive_sizing; + bool _adaptive_size; uint calculate_default_min_length(uint new_number_of_heap_regions); uint calculate_default_max_length(uint new_number_of_heap_regions); @@ -104,8 +104,8 @@ return _max_desired_young_length; } - bool use_adaptive_young_list_length() const { - return _use_adaptive_sizing; + bool adaptive_young_list_length() const { + return _adaptive_size; } static G1YoungGenSizer* create_gen_sizer(G1CollectorPolicy* policy); --- old/src/hotspot/share/gc/g1/g1YoungRemSetSamplingThread.cpp 2019-05-21 01:01:16.977154622 +0200 +++ new/src/hotspot/share/gc/g1/g1YoungRemSetSamplingThread.cpp 2019-05-21 01:01:16.821154900 +0200 @@ -165,7 +165,7 @@ G1CollectedHeap* g1h = G1CollectedHeap::heap(); G1Policy* policy = g1h->policy(); - if (policy->use_adaptive_young_list_length()) { + if (policy->adaptive_young_list_length()) { G1YoungRemSetSamplingClosure cl(&sts); G1CollectionSet* g1cs = g1h->collection_set(); --- old/src/hotspot/share/gc/g1/heapRegion.cpp 2019-05-21 01:01:17.173154270 +0200 +++ new/src/hotspot/share/gc/g1/heapRegion.cpp 2019-05-21 01:01:17.017154548 +0200 @@ -117,7 +117,6 @@ "Should not clear heap region %u in the collection set", hrm_index()); set_young_index_in_cset(-1); - clear_index_in_opt_cset(); uninstall_surv_rate_group(); set_free(); reset_pre_dummy_top(); @@ -242,7 +241,7 @@ _containing_set(NULL), #endif _prev_marked_bytes(0), _next_marked_bytes(0), _gc_efficiency(0.0), - _index_in_opt_cset(InvalidCSetIndex), _young_index_in_cset(-1), + _index_in_opt_cset(G1OptionalCSet::InvalidCSetIndex), _young_index_in_cset(-1), _surv_rate_group(NULL), _age_index(-1), _prev_top_at_mark_start(NULL), _next_top_at_mark_start(NULL), _recorded_rs_length(0), _predicted_elapsed_time_ms(0) --- old/src/hotspot/share/gc/g1/heapRegion.hpp 2019-05-21 01:01:17.369153919 +0200 +++ new/src/hotspot/share/gc/g1/heapRegion.hpp 2019-05-21 01:01:17.217154191 +0200 @@ -250,8 +250,6 @@ // The calculated GC efficiency of the region. double _gc_efficiency; - static const uint InvalidCSetIndex = UINT_MAX; - // The index in the optional regions array, if this region // is considered optional during a mixed collections. uint _index_in_opt_cset; @@ -551,13 +549,8 @@ void calc_gc_efficiency(void); double gc_efficiency() const { return _gc_efficiency;} - uint index_in_opt_cset() const { - assert(has_index_in_opt_cset(), "Opt cset index not set."); - return _index_in_opt_cset; - } - bool has_index_in_opt_cset() const { return _index_in_opt_cset != InvalidCSetIndex; } + uint index_in_opt_cset() const { return _index_in_opt_cset; } void set_index_in_opt_cset(uint index) { _index_in_opt_cset = index; } - void clear_index_in_opt_cset() { _index_in_opt_cset = InvalidCSetIndex; } int young_index_in_cset() const { return _young_index_in_cset; } void set_young_index_in_cset(int index) { --- old/src/hotspot/share/gc/g1/vmStructs_g1.hpp 2019-05-21 01:01:17.577153544 +0200 +++ new/src/hotspot/share/gc/g1/vmStructs_g1.hpp 2019-05-21 01:01:17.417153832 +0200 @@ -52,8 +52,8 @@ nonstatic_field(HeapRegionManager, _regions, G1HeapRegionTable) \ nonstatic_field(HeapRegionManager, _num_committed, uint) \ \ - volatile_nonstatic_field(G1CollectedHeap, _summary_bytes_used, size_t) \ - nonstatic_field(G1CollectedHeap, _hrm, HeapRegionManager*) \ + nonstatic_field(G1CollectedHeap, _summary_bytes_used, size_t) \ + nonstatic_field(G1CollectedHeap, _hrm, HeapRegionManager*) \ nonstatic_field(G1CollectedHeap, _g1mm, G1MonitoringSupport*) \ nonstatic_field(G1CollectedHeap, _old_set, HeapRegionSetBase) \ nonstatic_field(G1CollectedHeap, _archive_set, HeapRegionSetBase) \ --- old/src/hotspot/share/gc/shared/stringdedup/stringDedupTable.cpp 2019-05-21 01:01:17.793153157 +0200 +++ new/src/hotspot/share/gc/shared/stringdedup/stringDedupTable.cpp 2019-05-21 01:01:17.621153465 +0200 @@ -351,14 +351,19 @@ unsigned int hash = 0; if (use_java_hash()) { - if (!java_lang_String::hash_is_set(java_string)) { - stat->inc_hashed(); - } - hash = java_lang_String::hash_code(java_string); - } else { + // Get hash code from cache + hash = java_lang_String::hash(java_string); + } + + if (hash == 0) { // Compute hash hash = hash_code(value, latin1); stat->inc_hashed(); + + if (use_java_hash() && hash != 0) { + // Store hash code in cache + java_lang_String::set_hash(java_string, hash); + } } typeArrayOop existing_value = lookup_or_add(value, latin1, hash); --- old/src/hotspot/share/gc/shared/weakProcessor.cpp 2019-05-21 01:01:18.021152749 +0200 +++ new/src/hotspot/share/gc/shared/weakProcessor.cpp 2019-05-21 01:01:17.845153065 +0200 @@ -31,33 +31,22 @@ #include "gc/shared/weakProcessorPhaseTimes.hpp" #include "memory/allocation.inline.hpp" #include "memory/iterator.hpp" -#include "prims/resolvedMethodTable.hpp" #include "runtime/globals.hpp" #include "utilities/macros.hpp" -template -class OopsDoAndReportCounts { -public: - void operator()(BoolObjectClosure* is_alive, OopClosure* keep_alive, WeakProcessorPhase phase) { - Container::reset_dead_counter(); - - CountingSkippedIsAliveClosure cl(is_alive, keep_alive); - WeakProcessorPhases::oop_storage(phase)->oops_do(&cl); - - Container::inc_dead_counter(cl.num_dead() + cl.num_skipped()); - Container::finish_dead_counter(); - } -}; - void WeakProcessor::weak_oops_do(BoolObjectClosure* is_alive, OopClosure* keep_alive) { FOR_EACH_WEAK_PROCESSOR_PHASE(phase) { if (WeakProcessorPhases::is_serial(phase)) { WeakProcessorPhases::processor(phase)(is_alive, keep_alive); } else { if (WeakProcessorPhases::is_stringtable(phase)) { - OopsDoAndReportCounts()(is_alive, keep_alive, phase); - } else if (WeakProcessorPhases::is_resolved_method_table(phase)){ - OopsDoAndReportCounts()(is_alive, keep_alive, phase); + StringTable::reset_dead_counter(); + + CountingSkippedIsAliveClosure cl(is_alive, keep_alive); + WeakProcessorPhases::oop_storage(phase)->oops_do(&cl); + + StringTable::inc_dead_counter(cl.num_dead() + cl.num_skipped()); + StringTable::finish_dead_counter(); } else { WeakProcessorPhases::oop_storage(phase)->weak_oops_do(is_alive, keep_alive); } @@ -115,7 +104,6 @@ new (states++) StorageState(storage, _nworkers); } StringTable::reset_dead_counter(); - ResolvedMethodTable::reset_dead_counter(); } WeakProcessor::Task::Task(uint nworkers) : @@ -146,7 +134,6 @@ FREE_C_HEAP_ARRAY(StorageState, _storage_states); } StringTable::finish_dead_counter(); - ResolvedMethodTable::finish_dead_counter(); } void WeakProcessor::GangTask::work(uint worker_id) { --- old/src/hotspot/share/gc/shared/weakProcessor.inline.hpp 2019-05-21 01:01:18.221152390 +0200 +++ new/src/hotspot/share/gc/shared/weakProcessor.inline.hpp 2019-05-21 01:01:18.061152678 +0200 @@ -32,7 +32,6 @@ #include "gc/shared/weakProcessorPhases.hpp" #include "gc/shared/weakProcessorPhaseTimes.hpp" #include "gc/shared/workgroup.hpp" -#include "prims/resolvedMethodTable.hpp" #include "utilities/debug.hpp" class BoolObjectClosure; @@ -116,9 +115,6 @@ if (WeakProcessorPhases::is_stringtable(phase)) { StringTable::inc_dead_counter(cl.num_dead() + cl.num_skipped()); } - if (WeakProcessorPhases::is_resolved_method_table(phase)) { - ResolvedMethodTable::inc_dead_counter(cl.num_dead() + cl.num_skipped()); - } } } --- old/src/hotspot/share/gc/shared/weakProcessorPhases.cpp 2019-05-21 01:01:18.409152053 +0200 +++ new/src/hotspot/share/gc/shared/weakProcessorPhases.cpp 2019-05-21 01:01:18.261152318 +0200 @@ -26,7 +26,6 @@ #include "classfile/stringTable.hpp" #include "classfile/systemDictionary.hpp" #include "gc/shared/weakProcessorPhases.hpp" -#include "prims/resolvedMethodTable.hpp" #include "runtime/jniHandles.hpp" #include "utilities/debug.hpp" #include "utilities/macros.hpp" @@ -81,7 +80,6 @@ JFR_ONLY(case jfr: return "JFR weak processing";) case jni: return "JNI weak processing"; case stringtable: return "StringTable weak processing"; - case resolved_method_table: return "ResolvedMethodTable weak processing"; case vm: return "VM weak processing"; default: ShouldNotReachHere(); @@ -103,7 +101,6 @@ switch (phase) { case jni: return JNIHandles::weak_global_handles(); case stringtable: return StringTable::weak_storage(); - case resolved_method_table: return ResolvedMethodTable::weak_storage(); case vm: return SystemDictionary::vm_weak_oop_storage(); default: ShouldNotReachHere(); @@ -114,7 +111,3 @@ bool WeakProcessorPhases::is_stringtable(Phase phase) { return phase == stringtable; } - -bool WeakProcessorPhases::is_resolved_method_table(Phase phase) { - return phase == resolved_method_table; -} --- old/src/hotspot/share/gc/shared/weakProcessorPhases.hpp 2019-05-21 01:01:18.613151689 +0200 +++ new/src/hotspot/share/gc/shared/weakProcessorPhases.hpp 2019-05-21 01:01:18.457151967 +0200 @@ -45,7 +45,6 @@ // OopStorage phases. jni, stringtable, - resolved_method_table, vm }; @@ -69,7 +68,6 @@ static OopStorage* oop_storage(Phase phase); // Precondition: is_oop_storage(phase) static bool is_stringtable(Phase phase); - static bool is_resolved_method_table(Phase phase); }; typedef WeakProcessorPhases::Phase WeakProcessorPhase; --- old/src/hotspot/share/gc/shared/workerDataArray.hpp 2019-05-21 01:01:18.801151350 +0200 +++ new/src/hotspot/share/gc/shared/workerDataArray.hpp 2019-05-21 01:01:18.649151623 +0200 @@ -34,7 +34,7 @@ class WorkerDataArray : public CHeapObj { friend class WDAPrinter; public: - static const uint MaxThreadWorkItems = 5; + static const uint MaxThreadWorkItems = 4; private: T* _data; uint _length; @@ -50,7 +50,6 @@ void set_thread_work_item(uint worker_i, size_t value, uint index = 0); void add_thread_work_item(uint worker_i, size_t value, uint index = 0); void set_or_add_thread_work_item(uint worker_i, size_t value, uint index = 0); - size_t get_thread_work_item(uint worker_i, uint index = 0); WorkerDataArray* thread_work_items(uint index = 0) const { assert(index < MaxThreadWorkItems, "Tried to access thread work item %u max %u", index, MaxThreadWorkItems); --- old/src/hotspot/share/gc/shared/workerDataArray.inline.hpp 2019-05-21 01:01:18.997150998 +0200 +++ new/src/hotspot/share/gc/shared/workerDataArray.inline.hpp 2019-05-21 01:01:18.841151279 +0200 @@ -92,13 +92,6 @@ } template -size_t WorkerDataArray::get_thread_work_item(uint worker_i, uint index) { - assert(index < MaxThreadWorkItems, "Tried to access thread work item %u (max %u)", index, MaxThreadWorkItems); - assert(_thread_work_items[index] != NULL, "No sub count"); - return _thread_work_items[index]->get(worker_i); -} - -template void WorkerDataArray::add(uint worker_i, T value) { assert(worker_i < _length, "Worker %d is greater than max: %d", worker_i, _length); assert(_data[worker_i] != uninitialized(), "No data to add to for worker %d", worker_i); --- old/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp 2019-05-21 01:01:19.193150649 +0200 +++ new/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp 2019-05-21 01:01:19.037150927 +0200 @@ -3133,8 +3133,6 @@ case Op_CompareAndSwapI: case Op_CompareAndSwapB: case Op_CompareAndSwapS: - case Op_CompareAndSwapN: - case Op_CompareAndSwapP: case Op_ShenandoahCompareAndSwapN: case Op_ShenandoahCompareAndSwapP: case Op_ShenandoahWeakCompareAndSwapN: --- old/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.cpp 2019-05-21 01:01:19.425150231 +0200 +++ new/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.cpp 2019-05-21 01:01:19.261150527 +0200 @@ -72,7 +72,7 @@ // we hit max_cset. When max_cset is hit, we terminate the cset selection. Note that in this scheme, // ShenandoahGarbageThreshold is the soft threshold which would be ignored until min_garbage is hit. - size_t capacity = ShenandoahHeap::heap()->max_capacity(); + size_t capacity = ShenandoahHeap::heap()->capacity(); size_t free_target = ShenandoahMinFreeThreshold * capacity / 100; size_t min_garbage = free_target > actual_free ? (free_target - actual_free) : 0; size_t max_cset = (size_t)(1.0 * ShenandoahEvacReserve * capacity / 100 / ShenandoahEvacWaste); @@ -123,12 +123,12 @@ bool ShenandoahAdaptiveHeuristics::should_start_normal_gc() const { ShenandoahHeap* heap = ShenandoahHeap::heap(); - size_t capacity = heap->max_capacity(); + size_t capacity = heap->capacity(); size_t available = heap->free_set()->available(); // Check if we are falling below the worst limit, time to trigger the GC, regardless of // anything else. - size_t min_threshold = ShenandoahMinFreeThreshold * heap->max_capacity() / 100; + size_t min_threshold = ShenandoahMinFreeThreshold * heap->capacity() / 100; if (available < min_threshold) { log_info(gc)("Trigger: Free (" SIZE_FORMAT "M) is below minimum threshold (" SIZE_FORMAT "M)", available / M, min_threshold / M); @@ -138,7 +138,7 @@ // Check if are need to learn a bit about the application const size_t max_learn = ShenandoahLearningSteps; if (_gc_times_learned < max_learn) { - size_t init_threshold = ShenandoahInitFreeThreshold * heap->max_capacity() / 100; + size_t init_threshold = ShenandoahInitFreeThreshold * heap->capacity() / 100; if (available < init_threshold) { log_info(gc)("Trigger: Learning " SIZE_FORMAT " of " SIZE_FORMAT ". Free (" SIZE_FORMAT "M) is below initial threshold (" SIZE_FORMAT "M)", _gc_times_learned + 1, max_learn, available / M, init_threshold / M); --- old/src/hotspot/share/gc/shenandoah/heuristics/shenandoahCompactHeuristics.cpp 2019-05-21 01:01:19.621149882 +0200 +++ new/src/hotspot/share/gc/shenandoah/heuristics/shenandoahCompactHeuristics.cpp 2019-05-21 01:01:19.469150152 +0200 @@ -53,8 +53,8 @@ ShenandoahHeap* heap = ShenandoahHeap::heap(); size_t available = heap->free_set()->available(); - size_t threshold_bytes_allocated = heap->max_capacity() * ShenandoahAllocationThreshold / 100; - size_t min_threshold = ShenandoahMinFreeThreshold * heap->max_capacity() / 100; + size_t threshold_bytes_allocated = heap->capacity() * ShenandoahAllocationThreshold / 100; + size_t min_threshold = ShenandoahMinFreeThreshold * heap->capacity() / 100; if (available < min_threshold) { log_info(gc)("Trigger: Free (" SIZE_FORMAT "M) is below minimum threshold (" SIZE_FORMAT "M)", --- old/src/hotspot/share/gc/shenandoah/heuristics/shenandoahPassiveHeuristics.cpp 2019-05-21 01:01:19.821149523 +0200 +++ new/src/hotspot/share/gc/shenandoah/heuristics/shenandoahPassiveHeuristics.cpp 2019-05-21 01:01:19.665149803 +0200 @@ -81,7 +81,7 @@ // Do not select too large CSet that would overflow the available free space. // Take at least the entire evacuation reserve, and be free to overflow to free space. - size_t capacity = ShenandoahHeap::heap()->max_capacity(); + size_t capacity = ShenandoahHeap::heap()->capacity(); size_t available = MAX2(ShenandoahEvacReserve * capacity / 100, actual_free); size_t max_cset = (size_t)(available / ShenandoahEvacWaste); --- old/src/hotspot/share/gc/shenandoah/heuristics/shenandoahStaticHeuristics.cpp 2019-05-21 01:01:20.017149171 +0200 +++ new/src/hotspot/share/gc/shenandoah/heuristics/shenandoahStaticHeuristics.cpp 2019-05-21 01:01:19.865149444 +0200 @@ -52,7 +52,7 @@ bool ShenandoahStaticHeuristics::should_start_normal_gc() const { ShenandoahHeap* heap = ShenandoahHeap::heap(); - size_t capacity = heap->max_capacity(); + size_t capacity = heap->capacity(); size_t available = heap->free_set()->available(); size_t threshold_available = (capacity * ShenandoahFreeThreshold) / 100; --- old/src/hotspot/share/gc/shenandoah/heuristics/shenandoahTraversalHeuristics.cpp 2019-05-21 01:01:20.213148819 +0200 +++ new/src/hotspot/share/gc/shenandoah/heuristics/shenandoahTraversalHeuristics.cpp 2019-05-21 01:01:20.057149100 +0200 @@ -41,6 +41,13 @@ FLAG_SET_DEFAULT(ShenandoahKeepAliveBarrier, false); FLAG_SET_DEFAULT(ShenandoahAllowMixedAllocs, false); + SHENANDOAH_ERGO_OVERRIDE_DEFAULT(ShenandoahRefProcFrequency, 1); + + // Adjust class unloading settings only if globally enabled. + if (ClassUnloadingWithConcurrentMark) { + SHENANDOAH_ERGO_OVERRIDE_DEFAULT(ShenandoahUnloadClassesFrequency, 1); + } + SHENANDOAH_ERGO_ENABLE_FLAG(ExplicitGCInvokesConcurrent); SHENANDOAH_ERGO_ENABLE_FLAG(ShenandoahImplicitGCInvokesConcurrent); @@ -117,7 +124,7 @@ // The significant complication is that liveness data was collected at the previous cycle, and only // for those regions that were allocated before previous cycle started. - size_t capacity = heap->max_capacity(); + size_t capacity = heap->capacity(); size_t actual_free = heap->free_set()->available(); size_t free_target = ShenandoahMinFreeThreshold * capacity / 100; size_t min_garbage = free_target > actual_free ? (free_target - actual_free) : 0; @@ -206,12 +213,12 @@ ShenandoahHeap* heap = ShenandoahHeap::heap(); assert(!heap->has_forwarded_objects(), "no forwarded objects here"); - size_t capacity = heap->max_capacity(); + size_t capacity = heap->capacity(); size_t available = heap->free_set()->available(); // Check if we are falling below the worst limit, time to trigger the GC, regardless of // anything else. - size_t min_threshold = ShenandoahMinFreeThreshold * heap->max_capacity() / 100; + size_t min_threshold = ShenandoahMinFreeThreshold * heap->capacity() / 100; if (available < min_threshold) { log_info(gc)("Trigger: Free (" SIZE_FORMAT "M) is below minimum threshold (" SIZE_FORMAT "M)", available / M, min_threshold / M); @@ -221,7 +228,7 @@ // Check if are need to learn a bit about the application const size_t max_learn = ShenandoahLearningSteps; if (_gc_times_learned < max_learn) { - size_t init_threshold = ShenandoahInitFreeThreshold * heap->max_capacity() / 100; + size_t init_threshold = ShenandoahInitFreeThreshold * heap->capacity() / 100; if (available < init_threshold) { log_info(gc)("Trigger: Learning " SIZE_FORMAT " of " SIZE_FORMAT ". Free (" SIZE_FORMAT "M) is below initial threshold (" SIZE_FORMAT "M)", _gc_times_learned + 1, max_learn, available / M, init_threshold / M); --- old/src/hotspot/share/gc/shenandoah/shenandoahArguments.cpp 2019-05-21 01:01:20.409148468 +0200 +++ new/src/hotspot/share/gc/shenandoah/shenandoahArguments.cpp 2019-05-21 01:01:20.257148740 +0200 @@ -139,11 +139,6 @@ FLAG_SET_DEFAULT(ShenandoahUncommit, false); } - if ((InitialHeapSize == MaxHeapSize) && ShenandoahUncommit) { - log_info(gc)("Min heap equals to max heap, disabling ShenandoahUncommit"); - FLAG_SET_DEFAULT(ShenandoahUncommit, false); - } - // If class unloading is disabled, no unloading for concurrent cycles as well. // If class unloading is enabled, users should opt-in for unloading during // concurrent cycles. --- old/src/hotspot/share/gc/shenandoah/shenandoahClosures.hpp 2019-05-21 01:01:20.605148116 +0200 +++ /dev/null 2019-04-27 15:49:57.376009302 +0200 @@ -1,82 +0,0 @@ -/* - * Copyright (c) 2019, Red Hat, Inc. All rights reserved. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ -#ifndef SHARE_GC_SHENANDOAH_SHENANDOAHCLOSURES_HPP -#define SHARE_GC_SHENANDOAH_SHENANDOAHCLOSURES_HPP - -#include "memory/iterator.hpp" - -class ShenandoahHeap; -class ShenandoahMarkingContext; -class Thread; - -class ShenandoahForwardedIsAliveClosure: public BoolObjectClosure { -private: - ShenandoahMarkingContext* const _mark_context; -public: - inline ShenandoahForwardedIsAliveClosure(); - inline bool do_object_b(oop obj); -}; - -class ShenandoahIsAliveClosure: public BoolObjectClosure { -private: - ShenandoahMarkingContext* const _mark_context; -public: - inline ShenandoahIsAliveClosure(); - inline bool do_object_b(oop obj); -}; - -class ShenandoahIsAliveSelector : public StackObj { -private: - ShenandoahIsAliveClosure _alive_cl; - ShenandoahForwardedIsAliveClosure _fwd_alive_cl; -public: - inline BoolObjectClosure* is_alive_closure(); -}; - -class ShenandoahUpdateRefsClosure: public OopClosure { -private: - ShenandoahHeap* _heap; -public: - inline ShenandoahUpdateRefsClosure(); - inline void do_oop(oop* p); - inline void do_oop(narrowOop* p); -private: - template - inline void do_oop_work(T* p); -}; - -class ShenandoahEvacuateUpdateRootsClosure: public BasicOopIterateClosure { -private: - ShenandoahHeap* _heap; - Thread* _thread; -public: - inline ShenandoahEvacuateUpdateRootsClosure(); - inline void do_oop(oop* p); - inline void do_oop(narrowOop* p); - -private: - template - inline void do_oop_work(T* p); -}; - -#endif // SHARE_GC_SHENANDOAH_SHENANDOAHCLOSURES_HPP --- old/src/hotspot/share/gc/shenandoah/shenandoahClosures.inline.hpp 2019-05-21 01:01:20.777147808 +0200 +++ /dev/null 2019-04-27 15:49:57.376009302 +0200 @@ -1,110 +0,0 @@ -/* - * Copyright (c) 2019, Red Hat, Inc. All rights reserved. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ -#ifndef SHARE_GC_SHENANDOAH_SHENANDOAHCLOSURES_INLINE_HPP -#define SHARE_GC_SHENANDOAH_SHENANDOAHCLOSURES_INLINE_HPP - -#include "gc/shenandoah/shenandoahAsserts.hpp" -#include "gc/shenandoah/shenandoahClosures.hpp" -#include "gc/shenandoah/shenandoahHeap.inline.hpp" -#include "oops/compressedOops.inline.hpp" -#include "runtime/thread.hpp" - -ShenandoahForwardedIsAliveClosure::ShenandoahForwardedIsAliveClosure() : - _mark_context(ShenandoahHeap::heap()->marking_context()) { -} - -bool ShenandoahForwardedIsAliveClosure::do_object_b(oop obj) { - if (CompressedOops::is_null(obj)) { - return false; - } - obj = ShenandoahBarrierSet::resolve_forwarded_not_null(obj); - shenandoah_assert_not_forwarded_if(NULL, obj, - (ShenandoahHeap::heap()->is_concurrent_mark_in_progress() || - ShenandoahHeap::heap()->is_concurrent_traversal_in_progress())); - return _mark_context->is_marked(obj); -} - -ShenandoahIsAliveClosure::ShenandoahIsAliveClosure() : - _mark_context(ShenandoahHeap::heap()->marking_context()) { -} - -bool ShenandoahIsAliveClosure::do_object_b(oop obj) { - if (CompressedOops::is_null(obj)) { - return false; - } - shenandoah_assert_not_forwarded(NULL, obj); - return _mark_context->is_marked(obj); -} - -BoolObjectClosure* ShenandoahIsAliveSelector::is_alive_closure() { - return ShenandoahHeap::heap()->has_forwarded_objects() ? - reinterpret_cast(&_fwd_alive_cl) : - reinterpret_cast(&_alive_cl); -} - -ShenandoahUpdateRefsClosure::ShenandoahUpdateRefsClosure() : - _heap(ShenandoahHeap::heap()) { -} - -template -void ShenandoahUpdateRefsClosure::do_oop_work(T* p) { - T o = RawAccess<>::oop_load(p); - if (!CompressedOops::is_null(o)) { - oop obj = CompressedOops::decode_not_null(o); - _heap->update_with_forwarded_not_null(p, obj); - } -} - -void ShenandoahUpdateRefsClosure::do_oop(oop* p) { do_oop_work(p); } -void ShenandoahUpdateRefsClosure::do_oop(narrowOop* p) { do_oop_work(p); } - -ShenandoahEvacuateUpdateRootsClosure::ShenandoahEvacuateUpdateRootsClosure() : - _heap(ShenandoahHeap::heap()), _thread(Thread::current()) { -} - -template -void ShenandoahEvacuateUpdateRootsClosure::do_oop_work(T* p) { - assert(_heap->is_evacuation_in_progress(), "Only do this when evacuation is in progress"); - - T o = RawAccess<>::oop_load(p); - if (! CompressedOops::is_null(o)) { - oop obj = CompressedOops::decode_not_null(o); - if (_heap->in_collection_set(obj)) { - shenandoah_assert_marked(p, obj); - oop resolved = ShenandoahBarrierSet::resolve_forwarded_not_null(obj); - if (oopDesc::equals_raw(resolved, obj)) { - resolved = _heap->evacuate_object(obj, _thread); - } - RawAccess::oop_store(p, resolved); - } - } -} -void ShenandoahEvacuateUpdateRootsClosure::do_oop(oop* p) { - do_oop_work(p); -} - -void ShenandoahEvacuateUpdateRootsClosure::do_oop(narrowOop* p) { - do_oop_work(p); -} - -#endif // SHARE_GC_SHENANDOAH_SHENANDOAHCLOSURES_HPP --- old/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp 2019-05-21 01:01:20.973147456 +0200 +++ new/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp 2019-05-21 01:01:20.813147744 +0200 @@ -33,7 +33,6 @@ #include "gc/shared/referenceProcessorPhaseTimes.hpp" #include "gc/shenandoah/shenandoahBarrierSet.inline.hpp" -#include "gc/shenandoah/shenandoahClosures.inline.hpp" #include "gc/shenandoah/shenandoahConcurrentMark.inline.hpp" #include "gc/shenandoah/shenandoahMarkCompact.hpp" #include "gc/shenandoah/shenandoahHeap.inline.hpp" --- old/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp 2019-05-21 01:01:21.177147091 +0200 +++ new/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp 2019-05-21 01:01:21.025147364 +0200 @@ -462,11 +462,9 @@ void ShenandoahControlThread::service_uncommit(double shrink_before) { ShenandoahHeap* heap = ShenandoahHeap::heap(); - // Determine if there is work to do. This avoids taking heap lock if there is - // no work available, avoids spamming logs with superfluous logging messages, - // and minimises the amount of work while locks are taken. - - if (heap->committed() <= heap->min_capacity()) return; + // Scan through the heap and determine if there is work to do. This avoids taking + // heap lock if there is no work available, avoids spamming logs with superfluous + // logging messages, and minimises the amount of work while locks are taken. bool has_work = false; for (size_t i = 0; i < heap->num_regions(); i++) { --- old/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp 2019-05-21 01:01:21.385146719 +0200 +++ new/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp 2019-05-21 01:01:21.225147005 +0200 @@ -430,7 +430,7 @@ } // Evac reserve: reserve trailing space for evacuations - size_t to_reserve = ShenandoahEvacReserve * _heap->max_capacity() / 100; + size_t to_reserve = ShenandoahEvacReserve * _heap->capacity() / 100; size_t reserved = 0; for (size_t idx = _heap->num_regions() - 1; idx > 0; idx--) { --- old/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp 2019-05-21 01:01:21.593146345 +0200 +++ new/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp 2019-05-21 01:01:21.437146625 +0200 @@ -33,7 +33,6 @@ #include "gc/shenandoah/shenandoahAllocTracker.hpp" #include "gc/shenandoah/shenandoahBarrierSet.hpp" #include "gc/shenandoah/shenandoahBrooksPointer.hpp" -#include "gc/shenandoah/shenandoahClosures.inline.hpp" #include "gc/shenandoah/shenandoahCollectionSet.hpp" #include "gc/shenandoah/shenandoahCollectorPolicy.hpp" #include "gc/shenandoah/shenandoahConcurrentMark.inline.hpp" @@ -71,6 +70,8 @@ #include "runtime/vmThread.hpp" #include "services/mallocTracker.hpp" +ShenandoahUpdateRefsClosure::ShenandoahUpdateRefsClosure() : _heap(ShenandoahHeap::heap()) {} + #ifdef ASSERT template void ShenandoahAssertToSpaceClosure::do_oop_work(T* p) { @@ -140,7 +141,6 @@ // size_t init_byte_size = collector_policy()->initial_heap_byte_size(); - size_t min_byte_size = collector_policy()->min_heap_byte_size(); size_t max_byte_size = collector_policy()->max_heap_byte_size(); size_t heap_alignment = collector_policy()->heap_alignment(); @@ -159,13 +159,8 @@ size_t num_committed_regions = init_byte_size / reg_size_bytes; num_committed_regions = MIN2(num_committed_regions, _num_regions); assert(num_committed_regions <= _num_regions, "sanity"); - _initial_size = num_committed_regions * reg_size_bytes; - - size_t num_min_regions = min_byte_size / reg_size_bytes; - num_min_regions = MIN2(num_min_regions, _num_regions); - assert(num_min_regions <= _num_regions, "sanity"); - _minimum_size = num_min_regions * reg_size_bytes; + _initial_size = num_committed_regions * reg_size_bytes; _committed = _initial_size; size_t heap_page_size = UseLargePages ? (size_t)os::large_page_size() : (size_t)os::vm_page_size(); @@ -356,11 +351,8 @@ _control_thread = new ShenandoahControlThread(); - log_info(gc, init)("Initialize Shenandoah heap: " SIZE_FORMAT "%s initial, " SIZE_FORMAT "%s min, " SIZE_FORMAT "%s max", - byte_size_in_proper_unit(_initial_size), proper_unit_for_byte_size(_initial_size), - byte_size_in_proper_unit(_minimum_size), proper_unit_for_byte_size(_minimum_size), - byte_size_in_proper_unit(max_capacity()), proper_unit_for_byte_size(max_capacity()) - ); + log_info(gc, init)("Initialize Shenandoah heap with initial size " SIZE_FORMAT "%s", + byte_size_in_proper_unit(_initial_size), proper_unit_for_byte_size(_initial_size)); log_info(gc, init)("Safepointing mechanism: %s", SafepointMechanism::uses_thread_local_poll() ? "thread-local poll" : @@ -458,8 +450,8 @@ _max_workers = MAX2(_max_workers, 1U); _workers = new ShenandoahWorkGang("Shenandoah GC Threads", _max_workers, - /* are_GC_task_threads */ true, - /* are_ConcurrentGC_threads */ true); + /* are_GC_task_threads */true, + /* are_ConcurrentGC_threads */false); if (_workers == NULL) { vm_exit_during_initialization("Failed necessary allocation."); } else { @@ -469,8 +461,7 @@ if (ShenandoahParallelSafepointThreads > 1) { _safepoint_workers = new ShenandoahWorkGang("Safepoint Cleanup Thread", ShenandoahParallelSafepointThreads, - /* are_GC_task_threads */ false, - /* are_ConcurrentGC_threads */ false); + false, false); _safepoint_workers->initialize_workers(); } } @@ -511,7 +502,7 @@ void ShenandoahHeap::print_on(outputStream* st) const { st->print_cr("Shenandoah Heap"); st->print_cr(" " SIZE_FORMAT "K total, " SIZE_FORMAT "K committed, " SIZE_FORMAT "K used", - max_capacity() / K, committed() / K, used() / K); + capacity() / K, committed() / K, used() / K); st->print_cr(" " SIZE_FORMAT " x " SIZE_FORMAT"K regions", num_regions(), ShenandoahHeapRegion::region_size_bytes() / K); @@ -624,17 +615,13 @@ } size_t ShenandoahHeap::capacity() const { - return committed(); + return num_regions() * ShenandoahHeapRegion::region_size_bytes(); } size_t ShenandoahHeap::max_capacity() const { return _num_regions * ShenandoahHeapRegion::region_size_bytes(); } -size_t ShenandoahHeap::min_capacity() const { - return _minimum_size; -} - size_t ShenandoahHeap::initial_capacity() const { return _initial_size; } @@ -648,22 +635,12 @@ void ShenandoahHeap::op_uncommit(double shrink_before) { assert (ShenandoahUncommit, "should be enabled"); - // Application allocates from the beginning of the heap, and GC allocates at - // the end of it. It is more efficient to uncommit from the end, so that applications - // could enjoy the near committed regions. GC allocations are much less frequent, - // and therefore can accept the committing costs. - size_t count = 0; - for (size_t i = num_regions(); i > 0; i--) { // care about size_t underflow - ShenandoahHeapRegion* r = get_region(i - 1); + for (size_t i = 0; i < num_regions(); i++) { + ShenandoahHeapRegion* r = get_region(i); if (r->is_empty_committed() && (r->empty_time() < shrink_before)) { ShenandoahHeapLocker locker(lock()); if (r->is_empty_committed()) { - // Do not uncommit below minimal capacity - if (committed() < min_capacity() + ShenandoahHeapRegion::region_size_bytes()) { - break; - } - r->make_uncommitted(); count++; } @@ -672,6 +649,8 @@ } if (count > 0) { + log_info(gc)("Uncommitted " SIZE_FORMAT "M. Heap: " SIZE_FORMAT "M reserved, " SIZE_FORMAT "M committed, " SIZE_FORMAT "M used", + count * ShenandoahHeapRegion::region_size_bytes() / M, capacity() / M, committed() / M, used() / M); control_thread()->notify_heap_changed(); } } @@ -939,6 +918,43 @@ return CollectedHeap::min_dummy_object_size() + ShenandoahBrooksPointer::word_size(); } +class ShenandoahEvacuateUpdateRootsClosure: public BasicOopIterateClosure { +private: + ShenandoahHeap* _heap; + Thread* _thread; +public: + ShenandoahEvacuateUpdateRootsClosure() : + _heap(ShenandoahHeap::heap()), _thread(Thread::current()) { + } + +private: + template + void do_oop_work(T* p) { + assert(_heap->is_evacuation_in_progress(), "Only do this when evacuation is in progress"); + + T o = RawAccess<>::oop_load(p); + if (! CompressedOops::is_null(o)) { + oop obj = CompressedOops::decode_not_null(o); + if (_heap->in_collection_set(obj)) { + shenandoah_assert_marked(p, obj); + oop resolved = ShenandoahBarrierSet::resolve_forwarded_not_null(obj); + if (oopDesc::equals_raw(resolved, obj)) { + resolved = _heap->evacuate_object(obj, _thread); + } + RawAccess::oop_store(p, resolved); + } + } + } + +public: + void do_oop(oop* p) { + do_oop_work(p); + } + void do_oop(narrowOop* p) { + do_oop_work(p); + } +}; + class ShenandoahConcurrentEvacuateRegionObjectClosure : public ObjectClosure { private: ShenandoahHeap* const _heap; @@ -1188,9 +1204,7 @@ void ShenandoahHeap::gc_threads_do(ThreadClosure* tcl) const { workers()->threads_do(tcl); - if (_safepoint_workers != NULL) { - _safepoint_workers->threads_do(tcl); - } + _safepoint_workers->threads_do(tcl); if (ShenandoahStringDedup::is_enabled()) { ShenandoahStringDedup::threads_do(tcl); } @@ -1531,10 +1545,6 @@ if (ShenandoahPacing) { pacer()->setup_for_evac(); } - - if (ShenandoahVerify) { - verifier()->verify_during_evacuation(); - } } else { if (ShenandoahVerify) { verifier()->verify_after_concmark(); @@ -1846,6 +1856,31 @@ return result; } +ShenandoahForwardedIsAliveClosure::ShenandoahForwardedIsAliveClosure() : + _mark_context(ShenandoahHeap::heap()->marking_context()) { +} + +ShenandoahIsAliveClosure::ShenandoahIsAliveClosure() : + _mark_context(ShenandoahHeap::heap()->marking_context()) { +} + +bool ShenandoahForwardedIsAliveClosure::do_object_b(oop obj) { + if (CompressedOops::is_null(obj)) { + return false; + } + obj = ShenandoahBarrierSet::resolve_forwarded_not_null(obj); + shenandoah_assert_not_forwarded_if(NULL, obj, ShenandoahHeap::heap()->is_concurrent_mark_in_progress() || ShenandoahHeap::heap()->is_concurrent_traversal_in_progress()); + return _mark_context->is_marked(obj); +} + +bool ShenandoahIsAliveClosure::do_object_b(oop obj) { + if (CompressedOops::is_null(obj)) { + return false; + } + shenandoah_assert_not_forwarded(NULL, obj); + return _mark_context->is_marked(obj); +} + void ShenandoahHeap::ref_processing_init() { assert(_max_workers > 0, "Sanity"); @@ -2816,3 +2851,8 @@ ptrdiff_t ShenandoahHeap::cell_header_size() const { return ShenandoahBrooksPointer::byte_size(); } + +BoolObjectClosure* ShenandoahIsAliveSelector::is_alive_closure() { + return ShenandoahHeap::heap()->has_forwarded_objects() ? reinterpret_cast(&_fwd_alive_cl) + : reinterpret_cast(&_alive_cl); +} --- old/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp 2019-05-21 01:01:21.817145945 +0200 +++ new/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp 2019-05-21 01:01:21.661146223 +0200 @@ -91,6 +91,19 @@ virtual bool is_thread_safe() { return false; } }; +class ShenandoahUpdateRefsClosure: public OopClosure { +private: + ShenandoahHeap* _heap; + + template + inline void do_oop_work(T* p); + +public: + ShenandoahUpdateRefsClosure(); + inline void do_oop(oop* p); + inline void do_oop(narrowOop* p); +}; + #ifdef ASSERT class ShenandoahAssertToSpaceClosure : public OopClosure { private: @@ -102,6 +115,34 @@ }; #endif +class ShenandoahAlwaysTrueClosure : public BoolObjectClosure { +public: + bool do_object_b(oop p) { return true; } +}; + +class ShenandoahForwardedIsAliveClosure: public BoolObjectClosure { +private: + ShenandoahMarkingContext* const _mark_context; +public: + ShenandoahForwardedIsAliveClosure(); + bool do_object_b(oop obj); +}; + +class ShenandoahIsAliveClosure: public BoolObjectClosure { +private: + ShenandoahMarkingContext* const _mark_context; +public: + ShenandoahIsAliveClosure(); + bool do_object_b(oop obj); +}; + +class ShenandoahIsAliveSelector : public StackObj { +private: + ShenandoahIsAliveClosure _alive_cl; + ShenandoahForwardedIsAliveClosure _fwd_alive_cl; +public: + BoolObjectClosure* is_alive_closure(); +}; // Shenandoah GC is low-pause concurrent GC that uses Brooks forwarding pointers // to encode forwarding data. See BrooksPointer for details on forwarding data encoding. @@ -157,7 +198,6 @@ // private: size_t _initial_size; - size_t _minimum_size; DEFINE_PAD_MINUS_SIZE(0, DEFAULT_CACHE_LINE_SIZE, sizeof(volatile size_t)); volatile size_t _used; volatile size_t _committed; @@ -176,7 +216,6 @@ size_t bytes_allocated_since_gc_start(); void reset_bytes_allocated_since_gc_start(); - size_t min_capacity() const; size_t max_capacity() const; size_t initial_capacity() const; size_t capacity() const; --- old/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp 2019-05-21 01:01:22.017145585 +0200 +++ new/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp 2019-05-21 01:01:21.865145858 +0200 @@ -46,6 +46,17 @@ #include "utilities/copy.hpp" #include "utilities/globalDefinitions.hpp" +template +void ShenandoahUpdateRefsClosure::do_oop_work(T* p) { + T o = RawAccess<>::oop_load(p); + if (!CompressedOops::is_null(o)) { + oop obj = CompressedOops::decode_not_null(o); + _heap->update_with_forwarded_not_null(p, obj); + } +} + +void ShenandoahUpdateRefsClosure::do_oop(oop* p) { do_oop_work(p); } +void ShenandoahUpdateRefsClosure::do_oop(narrowOop* p) { do_oop_work(p); } inline ShenandoahHeapRegion* ShenandoahRegionIterator::next() { size_t new_index = Atomic::add((size_t) 1, &_index); --- old/src/hotspot/share/gc/shenandoah/shenandoahMonitoringSupport.cpp 2019-05-21 01:01:22.229145206 +0200 +++ new/src/hotspot/share/gc/shenandoah/shenandoahMonitoringSupport.cpp 2019-05-21 01:01:22.077145478 +0200 @@ -46,12 +46,12 @@ ShenandoahHeap* _heap; public: ShenandoahGenerationCounters(ShenandoahHeap* heap) : - GenerationCounters("Heap", 1, 1, heap->initial_capacity(), heap->max_capacity(), heap->capacity()), + GenerationCounters("Heap", 1, 1, heap->initial_capacity(), heap->max_capacity(), heap->committed()), _heap(heap) {}; virtual void update_all() { - _current_size->set_value(_heap->capacity()); + _current_size->set_value(_heap->committed()); } }; @@ -94,7 +94,7 @@ if (UsePerfData) { ShenandoahHeap* heap = ShenandoahHeap::heap(); size_t used = heap->used(); - size_t capacity = heap->max_capacity(); + size_t capacity = heap->capacity(); _heap_counters->update_all(); _space_counters->update_all(capacity, used); _heap_region_counters->update(); --- old/src/hotspot/share/gc/shenandoah/shenandoahPacer.cpp 2019-05-21 01:01:22.425144854 +0200 +++ new/src/hotspot/share/gc/shenandoah/shenandoahPacer.cpp 2019-05-21 01:01:22.273145127 +0200 @@ -153,7 +153,7 @@ void ShenandoahPacer::setup_for_idle() { assert(ShenandoahPacing, "Only be here when pacing is enabled"); - size_t initial = _heap->max_capacity() * ShenandoahPacingIdleSlack / 100; + size_t initial = _heap->capacity() * ShenandoahPacingIdleSlack / 100; double tax = 1; restart_with(initial, tax); @@ -166,7 +166,7 @@ if (_progress == -1) { // First initialization, report some prior Atomic::store((intptr_t)PACING_PROGRESS_ZERO, &_progress); - return (size_t) (_heap->max_capacity() * 0.1); + return (size_t) (_heap->capacity() * 0.1); } else { // Record history, and reply historical data _progress_history->add(_progress); --- old/src/hotspot/share/gc/shenandoah/shenandoahPhaseTimings.hpp 2019-05-21 01:01:22.621144502 +0200 +++ new/src/hotspot/share/gc/shenandoah/shenandoahPhaseTimings.hpp 2019-05-21 01:01:22.465144783 +0200 @@ -51,7 +51,6 @@ f(scan_jfr_weak_roots, " S: JFR Weak Roots") \ f(scan_jni_weak_roots, " S: JNI Weak Roots") \ f(scan_stringtable_roots, " S: String Table Roots") \ - f(scan_resolved_method_table_roots, " S: Resolved Table Roots") \ f(scan_vm_weak_roots, " S: VM Weak Roots") \ f(scan_synchronizer_roots, " S: Synchronizer Roots") \ f(scan_management_roots, " S: Management Roots") \ @@ -77,7 +76,6 @@ f(update_jfr_weak_roots, " U: JFR Weak Roots") \ f(update_jni_weak_roots, " U: JNI Weak Roots") \ f(update_stringtable_roots, " U: String Table Roots") \ - f(update_resolved_method_table_roots, " U: Resolved Table Roots") \ f(update_vm_weak_roots, " U: VM Weak Roots") \ f(update_synchronizer_roots, " U: Synchronizer Roots") \ f(update_management_roots, " U: Management Roots") \ @@ -111,7 +109,6 @@ f(evac_jfr_weak_roots, " E: JFR Weak Roots") \ f(evac_jni_weak_roots, " E: JNI Weak Roots") \ f(evac_stringtable_roots, " E: String Table Roots") \ - f(evac_resolved_method_table_roots, " E: Resolved Table Roots") \ f(evac_vm_weak_roots, " E: VM Weak Roots") \ f(evac_synchronizer_roots, " E: Synchronizer Roots") \ f(evac_management_roots, " E: Management Roots") \ @@ -142,7 +139,6 @@ f(final_update_jfr_weak_roots, " UR: JFR Weak Roots") \ f(final_update_jni_weak_roots, " UR: JNI Weak Roots") \ f(final_update_stringtable_roots, " UR: String Table Roots") \ - f(final_update_resolved_method_table_roots, " UR: Resolved Table Roots") \ f(final_update_vm_weak_roots, " UR: VM Weak Roots") \ f(final_update_refs_synchronizer_roots, " UR: Synchronizer Roots") \ f(final_update_refs_management_roots, " UR: Management Roots") \ @@ -168,7 +164,6 @@ f(degen_gc_update_jfr_weak_roots, " DU: JFR Weak Roots") \ f(degen_gc_update_jni_weak_roots, " DU: JNI Weak Roots") \ f(degen_gc_update_stringtable_roots, " DU: String Table Roots") \ - f(degen_gc_update_resolved_method_table_roots, " DU: Resolved Table Roots") \ f(degen_gc_update_vm_weak_roots, " DU: VM Weak Roots") \ f(degen_gc_update_synchronizer_roots, " DU: Synchronizer Roots") \ f(degen_gc_update_management_roots, " DU: Management Roots") \ @@ -195,7 +190,6 @@ f(init_traversal_gc_jfr_weak_roots, " TI: JFR Weak Roots") \ f(init_traversal_gc_jni_weak_roots, " TI: JNI Weak Roots") \ f(init_traversal_gc_stringtable_roots, " TI: String Table Roots") \ - f(init_traversal_gc_resolved_method_table_roots, " TI: Resolved Table Roots") \ f(init_traversal_gc_vm_weak_roots, " TI: VM Weak Roots") \ f(init_traversal_gc_synchronizer_roots, " TI: Synchronizer Roots") \ f(init_traversal_gc_management_roots, " TI: Management Roots") \ @@ -219,7 +213,6 @@ f(final_traversal_gc_jfr_weak_roots, " TF: JFR Weak Roots") \ f(final_traversal_gc_jni_weak_roots, " TF: JNI Weak Roots") \ f(final_traversal_gc_stringtable_roots, " TF: String Table Roots") \ - f(final_traversal_gc_resolved_method_table_roots, " TF: Resolved Table Roots") \ f(final_traversal_gc_vm_weak_roots, " TF: VM Weak Roots") \ f(final_traversal_gc_synchronizer_roots, " TF: Synchronizer Roots") \ f(final_traversal_gc_management_roots, " TF: Management Roots") \ @@ -232,25 +225,24 @@ f(final_traversal_gc_termination, " TF: Termination") \ \ /* Per-thread timer block, should have "roots" counters in consistent order */ \ - f(final_traversal_update_roots, " Update Roots") \ - f(final_traversal_update_thread_roots, " TU: Thread Roots") \ - f(final_traversal_update_code_roots, " TU: Code Cache Roots") \ - f(final_traversal_update_universe_roots, " TU: Universe Roots") \ - f(final_traversal_update_jni_roots, " TU: JNI Roots") \ - f(final_traversal_update_jvmti_weak_roots, " TU: JVMTI Weak Roots") \ - f(final_traversal_update_jfr_weak_roots, " TU: JFR Weak Roots") \ - f(final_traversal_update_jni_weak_roots, " TU: JNI Weak Roots") \ - f(final_traversal_update_stringtable_roots, " TU: String Table Roots") \ - f(final_traversal_update_resolved_method_table_roots, " TU: Resolved Table Roots") \ - f(final_traversal_update_vm_weak_roots, " TU: VM Weak Roots") \ - f(final_traversal_update_synchronizer_roots, " TU: Synchronizer Roots") \ - f(final_traversal_update_management_roots, " TU: Management Roots") \ - f(final_traversal_update_system_dict_roots, " TU: System Dict Roots") \ - f(final_traversal_update_cldg_roots, " TU: CLDG Roots") \ - f(final_traversal_update_jvmti_roots, " TU: JVMTI Roots") \ - f(final_traversal_update_string_dedup_table_roots, " TU: Dedup Table Roots") \ - f(final_traversal_update_string_dedup_queue_roots, " TU: Dedup Queue Roots") \ - f(final_traversal_update_finish_queues, " TU: Finish Queues") \ + f(final_traversal_update_roots, " Update Roots") \ + f(final_traversal_update_thread_roots, " TU: Thread Roots") \ + f(final_traversal_update_code_roots, " TU: Code Cache Roots") \ + f(final_traversal_update_universe_roots, " TU: Universe Roots") \ + f(final_traversal_update_jni_roots, " TU: JNI Roots") \ + f(final_traversal_update_jvmti_weak_roots, " TU: JVMTI Weak Roots") \ + f(final_traversal_update_jfr_weak_roots, " TU: JFR Weak Roots") \ + f(final_traversal_update_jni_weak_roots, " TU: JNI Weak Roots") \ + f(final_traversal_update_stringtable_roots, " TU: String Table Roots") \ + f(final_traversal_update_vm_weak_roots, " TU: VM Weak Roots") \ + f(final_traversal_update_synchronizer_roots, " TU: Synchronizer Roots") \ + f(final_traversal_update_management_roots, " TU: Management Roots") \ + f(final_traversal_update_system_dict_roots, " TU: System Dict Roots") \ + f(final_traversal_update_cldg_roots, " TU: CLDG Roots") \ + f(final_traversal_update_jvmti_roots, " TU: JVMTI Roots") \ + f(final_traversal_update_string_dedup_table_roots, " TU: Dedup Table Roots") \ + f(final_traversal_update_string_dedup_queue_roots, " TU: Dedup Queue Roots") \ + f(final_traversal_update_finish_queues, " TU: Finish Queues") \ \ f(traversal_gc_cleanup, " Cleanup") \ \ @@ -269,7 +261,6 @@ f(full_gc_jfr_weak_roots, " F: JFR Weak Roots") \ f(full_gc_jni_weak_roots, " F: JNI Weak Roots") \ f(full_gc_stringtable_roots, " F: String Table Roots") \ - f(full_gc_resolved_method_table_roots, " F: Resolved Table Roots") \ f(full_gc_vm_weak_roots, " F: VM Weak Roots") \ f(full_gc_synchronizer_roots, " F: Synchronizer Roots") \ f(full_gc_management_roots, " F: Management Roots") \ @@ -320,24 +311,23 @@ // end #define SHENANDOAH_GC_PAR_PHASE_DO(f) \ - f(ThreadRoots, "Thread Roots (ms):") \ - f(CodeCacheRoots, "CodeCache Roots (ms):") \ - f(UniverseRoots, "Universe Roots (ms):") \ - f(JNIRoots, "JNI Handles Roots (ms):") \ - f(JVMTIWeakRoots, "JVMTI Weak Roots (ms):") \ - f(JFRWeakRoots, "JFR Weak Roots (ms):") \ - f(JNIWeakRoots, "JNI Weak Roots (ms):") \ - f(StringTableRoots, "StringTable Roots(ms):") \ - f(ResolvedMethodTableRoots, "Resolved Table Roots(ms):") \ - f(VMWeakRoots, "VM Weak Roots(ms)") \ - f(ObjectSynchronizerRoots, "ObjectSynchronizer Roots (ms):") \ - f(ManagementRoots, "Management Roots (ms):") \ - f(SystemDictionaryRoots, "SystemDictionary Roots (ms):") \ - f(CLDGRoots, "CLDG Roots (ms):") \ - f(JVMTIRoots, "JVMTI Roots (ms):") \ - f(StringDedupTableRoots, "String Dedup Table Roots (ms):") \ - f(StringDedupQueueRoots, "String Dedup Queue Roots (ms):") \ - f(FinishQueues, "Finish Queues (ms):") \ + f(ThreadRoots, "Thread Roots (ms):") \ + f(CodeCacheRoots, "CodeCache Roots (ms):") \ + f(UniverseRoots, "Universe Roots (ms):") \ + f(JNIRoots, "JNI Handles Roots (ms):") \ + f(JVMTIWeakRoots, "JVMTI Weak Roots (ms):") \ + f(JFRWeakRoots, "JFR Weak Roots (ms):") \ + f(JNIWeakRoots, "JNI Weak Roots (ms):") \ + f(StringTableRoots, "StringTable Roots(ms):") \ + f(VMWeakRoots, "VM Weak Roots(ms)") \ + f(ObjectSynchronizerRoots, "ObjectSynchronizer Roots (ms):") \ + f(ManagementRoots, "Management Roots (ms):") \ + f(SystemDictionaryRoots, "SystemDictionary Roots (ms):") \ + f(CLDGRoots, "CLDG Roots (ms):") \ + f(JVMTIRoots, "JVMTI Roots (ms):") \ + f(StringDedupTableRoots, "String Dedup Table Roots (ms):") \ + f(StringDedupQueueRoots, "String Dedup Queue Roots (ms):") \ + f(FinishQueues, "Finish Queues (ms):") \ // end class ShenandoahPhaseTimings : public CHeapObj { --- old/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.cpp 2019-05-21 01:01:22.825144138 +0200 +++ new/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.cpp 2019-05-21 01:01:22.673144410 +0200 @@ -27,7 +27,6 @@ #include "classfile/stringTable.hpp" #include "classfile/systemDictionary.hpp" #include "code/codeCache.hpp" -#include "gc/shenandoah/shenandoahClosures.inline.hpp" #include "gc/shenandoah/shenandoahRootProcessor.hpp" #include "gc/shenandoah/shenandoahHeap.hpp" #include "gc/shenandoah/shenandoahPhaseTimings.hpp" @@ -49,15 +48,14 @@ static const struct PhaseMap phase_mapping[] = { #if INCLUDE_JVMTI - {WeakProcessorPhases::jvmti, ShenandoahPhaseTimings::JVMTIWeakRoots}, + {WeakProcessorPhases::jvmti, ShenandoahPhaseTimings::JVMTIWeakRoots}, #endif #if INCLUDE_JFR - {WeakProcessorPhases::jfr, ShenandoahPhaseTimings::JFRWeakRoots}, + {WeakProcessorPhases::jfr, ShenandoahPhaseTimings::JFRWeakRoots}, #endif - {WeakProcessorPhases::jni, ShenandoahPhaseTimings::JNIWeakRoots}, - {WeakProcessorPhases::stringtable, ShenandoahPhaseTimings::StringTableRoots}, - {WeakProcessorPhases::resolved_method_table, ShenandoahPhaseTimings::ResolvedMethodTableRoots}, - {WeakProcessorPhases::vm, ShenandoahPhaseTimings::VMWeakRoots} + {WeakProcessorPhases::jni, ShenandoahPhaseTimings::JNIWeakRoots}, + {WeakProcessorPhases::stringtable, ShenandoahPhaseTimings::StringTableRoots}, + {WeakProcessorPhases::vm, ShenandoahPhaseTimings::VMWeakRoots} }; STATIC_ASSERT(sizeof(phase_mapping) / sizeof(PhaseMap) == WeakProcessorPhases::phase_count); @@ -66,6 +64,7 @@ ShenandoahPhaseTimings::Phase phase) : _process_strong_tasks(new SubTasksDone(SHENANDOAH_RP_PS_NumElements)), _srs(n_workers), + _par_state_string(StringTable::weak_storage()), _phase(phase), _coderoots_all_iterator(ShenandoahCodeRoots::iterator()), _weak_processor_timings(n_workers), @@ -243,7 +242,10 @@ _evacuation_tasks(new SubTasksDone(SHENANDOAH_EVAC_NumElements)), _srs(n_workers), _phase(phase), - _coderoots_cset_iterator(ShenandoahCodeRoots::cset_iterator()) { + _coderoots_cset_iterator(ShenandoahCodeRoots::cset_iterator()), + _par_state_string(StringTable::weak_storage()) + +{ heap->phase_timings()->record_workers_start(_phase); if (ShenandoahStringDedup::is_enabled()) { StringDedup::gc_prologue(false); --- old/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.hpp 2019-05-21 01:01:23.021143786 +0200 +++ new/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.hpp 2019-05-21 01:01:22.865144064 +0200 @@ -56,6 +56,7 @@ class ShenandoahRootProcessor : public StackObj { SubTasksDone* _process_strong_tasks; StrongRootsScope _srs; + OopStorage::ParState _par_state_string; ShenandoahPhaseTimings::Phase _phase; ParallelCLDRootIterator _cld_iterator; ShenandoahAllCodeRootsIterator _coderoots_all_iterator; @@ -119,6 +120,7 @@ StrongRootsScope _srs; ShenandoahPhaseTimings::Phase _phase; ShenandoahCsetCodeRootsIterator _coderoots_cset_iterator; + OopStorage::ParState _par_state_string; enum Shenandoah_evacuate_roots_tasks { SHENANDOAH_EVAC_Universe_oops_do, --- old/src/hotspot/share/gc/shenandoah/shenandoahStringDedup.cpp 2019-05-21 01:01:23.217143434 +0200 +++ new/src/hotspot/share/gc/shenandoah/shenandoahStringDedup.cpp 2019-05-21 01:01:23.065143707 +0200 @@ -92,7 +92,7 @@ void ShenandoahStringDedup::oops_do_slow(OopClosure* cl) { assert(SafepointSynchronize::is_at_safepoint(), "Must be at a safepoint"); assert(is_enabled(), "String deduplication not enabled"); - AlwaysTrueClosure always_true; + ShenandoahAlwaysTrueClosure always_true; StringDedupUnlinkOrOopsDoClosure sd_cl(&always_true, cl); StringDedupQueue::unlink_or_oops_do(&sd_cl); StringDedupTable::unlink_or_oops_do(&sd_cl, 0); --- old/src/hotspot/share/gc/shenandoah/shenandoahTimingTracker.cpp 2019-05-21 01:01:23.413143083 +0200 +++ new/src/hotspot/share/gc/shenandoah/shenandoahTimingTracker.cpp 2019-05-21 01:01:23.257143363 +0200 @@ -76,11 +76,8 @@ phase == ShenandoahPhaseTimings::full_gc_weakrefs_termination, "Only these phases"); - assert(!Thread::current()->is_Worker_thread() && - (Thread::current()->is_VM_thread() || - Thread::current()->is_ConcurrentGC_thread()), - "Called from wrong thread"); - + assert(Thread::current()->is_VM_thread() || Thread::current()->is_ConcurrentGC_thread(), + "Called from wrong thread"); _current_termination_phase = phase; ShenandoahHeap::heap()->phase_timings()->termination_times()->reset(); } --- old/src/hotspot/share/gc/shenandoah/shenandoahTraversalGC.cpp 2019-05-21 01:01:23.605142739 +0200 +++ new/src/hotspot/share/gc/shenandoah/shenandoahTraversalGC.cpp 2019-05-21 01:01:23.449143019 +0200 @@ -30,7 +30,6 @@ #include "gc/shared/workgroup.hpp" #include "gc/shared/weakProcessor.inline.hpp" #include "gc/shenandoah/shenandoahBarrierSet.hpp" -#include "gc/shenandoah/shenandoahClosures.inline.hpp" #include "gc/shenandoah/shenandoahCodeRoots.hpp" #include "gc/shenandoah/shenandoahCollectionSet.hpp" #include "gc/shenandoah/shenandoahCollectorPolicy.hpp" @@ -197,10 +196,6 @@ } else { _rp->process_all_roots(&roots_cl, &cld_cl, &code_cl, NULL, worker_id); } - if (ShenandoahStringDedup::is_enabled()) { - AlwaysTrueClosure is_alive; - ShenandoahStringDedup::parallel_oops_do(&is_alive, &roots_cl, worker_id); - } } } }; @@ -600,10 +595,11 @@ } if (!_heap->cancelled_gc()) { - fixup_roots(); if (_heap->unload_classes()) { _heap->unload_classes_and_cleanup_tables(false); } + + fixup_roots(); } if (!_heap->cancelled_gc()) { @@ -773,6 +769,29 @@ void do_oop(oop* p) { do_oop_work(p); } }; +class ShenandoahTraversalWeakUpdateClosure : public OopClosure { +private: + template + inline void do_oop_work(T* p) { + // Cannot call maybe_update_with_forwarded, because on traversal-degen + // path the collection set is already dropped. Instead, do the unguarded store. + // TODO: This can be fixed after degen-traversal stops dropping cset. + T o = RawAccess<>::oop_load(p); + if (!CompressedOops::is_null(o)) { + oop obj = CompressedOops::decode_not_null(o); + obj = ShenandoahBarrierSet::resolve_forwarded_not_null(obj); + shenandoah_assert_marked(p, obj); + RawAccess::oop_store(p, obj); + } + } + +public: + ShenandoahTraversalWeakUpdateClosure() {} + + void do_oop(narrowOop* p) { do_oop_work(p); } + void do_oop(oop* p) { do_oop_work(p); } +}; + class ShenandoahTraversalKeepAliveUpdateDegenClosure : public OopClosure { private: ShenandoahObjToScanQueue* _queue; @@ -1085,6 +1104,16 @@ &pt); } - pt.print_all_references(); - assert(task_queues()->is_empty() || _heap->cancelled_gc(), "Should be empty"); + { + ShenandoahGCPhase phase(phase_process); + ShenandoahTerminationTracker termination(ShenandoahPhaseTimings::weakrefs_termination); + + // Process leftover weak oops (using parallel version) + ShenandoahTraversalWeakUpdateClosure cl; + WeakProcessor::weak_oops_do(workers, &is_alive, &cl, 1); + + pt.print_all_references(); + + assert(task_queues()->is_empty() || _heap->cancelled_gc(), "Should be empty"); + } } --- old/src/hotspot/share/gc/shenandoah/shenandoahUtils.cpp 2019-05-21 01:01:23.805142380 +0200 +++ new/src/hotspot/share/gc/shenandoah/shenandoahUtils.cpp 2019-05-21 01:01:23.649142660 +0200 @@ -100,10 +100,9 @@ ShenandoahGCPhase::ShenandoahGCPhase(const ShenandoahPhaseTimings::Phase phase) : _heap(ShenandoahHeap::heap()), _phase(phase) { - assert(!Thread::current()->is_Worker_thread() && - (Thread::current()->is_VM_thread() || - Thread::current()->is_ConcurrentGC_thread()), - "Must be set by these threads"); + assert(Thread::current()->is_VM_thread() || + Thread::current()->is_ConcurrentGC_thread(), + "Must be set by these threads"); _parent_phase = _current_phase; _current_phase = phase; --- old/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp 2019-05-21 01:01:24.001142028 +0200 +++ new/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp 2019-05-21 01:01:23.845142308 +0200 @@ -628,10 +628,6 @@ enabled = true; expected = ShenandoahHeap::HAS_FORWARDED; break; - case _verify_gcstate_evacuation: - enabled = true; - expected = ShenandoahHeap::HAS_FORWARDED | ShenandoahHeap::EVACUATION; - break; case _verify_gcstate_stable: enabled = true; expected = ShenandoahHeap::STABLE; @@ -812,18 +808,6 @@ ); } -void ShenandoahVerifier::verify_during_evacuation() { - verify_at_safepoint( - "During Evacuation", - _verify_forwarded_allow, // some forwarded references are allowed - _verify_marked_disable, // walk only roots - _verify_cset_disable, // some cset references are not forwarded yet - _verify_liveness_disable, // liveness data might be already stale after pre-evacs - _verify_regions_disable, // trash regions not yet recycled - _verify_gcstate_evacuation // evacuation is in progress - ); -} - void ShenandoahVerifier::verify_after_evacuation() { verify_at_safepoint( "After Evacuation", --- old/src/hotspot/share/gc/shenandoah/shenandoahVerifier.hpp 2019-05-21 01:01:24.197141676 +0200 +++ new/src/hotspot/share/gc/shenandoah/shenandoahVerifier.hpp 2019-05-21 01:01:24.045141949 +0200 @@ -135,9 +135,6 @@ // Nothing is in progress, some objects are forwarded _verify_gcstate_forwarded, - - // Evacuation is in progress, some objects are forwarded - _verify_gcstate_evacuation, } VerifyGCState; struct VerifyOptions { @@ -176,7 +173,6 @@ void verify_before_concmark(); void verify_after_concmark(); void verify_before_evacuation(); - void verify_during_evacuation(); void verify_after_evacuation(); void verify_before_updaterefs(); void verify_after_updaterefs(); --- old/src/hotspot/share/gc/z/zBarrier.cpp 2019-05-21 01:01:24.393141325 +0200 +++ new/src/hotspot/share/gc/z/zBarrier.cpp 2019-05-21 01:01:24.237141605 +0200 @@ -123,7 +123,7 @@ } void ZBarrier::load_barrier_on_oop_fields(oop o) { - assert(ZAddress::is_good(ZOop::to_address(o)), "Should be good"); + assert(ZOop::is_good(o), "Should be good"); ZLoadBarrierOopClosure cl; o->oop_iterate(&cl); } --- old/src/hotspot/share/gc/z/zBarrier.inline.hpp 2019-05-21 01:01:24.589140975 +0200 +++ new/src/hotspot/share/gc/z/zBarrier.inline.hpp 2019-05-21 01:01:24.433141253 +0200 @@ -37,7 +37,7 @@ retry: // Fast path if (fast_path(addr)) { - return ZOop::from_address(addr); + return ZOop::to_oop(addr); } // Slow path @@ -56,7 +56,7 @@ } } - return ZOop::from_address(good_addr); + return ZOop::to_oop(good_addr); } template @@ -67,7 +67,7 @@ if (fast_path(addr)) { // Return the good address instead of the weak good address // to ensure that the currently active heap view is used. - return ZOop::from_address(ZAddress::good_or_null(addr)); + return ZOop::to_oop(ZAddress::good_or_null(addr)); } // Slow path @@ -95,7 +95,7 @@ } } - return ZOop::from_address(good_addr); + return ZOop::to_oop(good_addr); } template @@ -117,7 +117,7 @@ // to heal the same root if it is aligned, since they would always heal // the root in the same way and it does not matter in which order it // happens. For misaligned oops, there needs to be mutual exclusion. - *p = ZOop::from_address(good_addr); + *p = ZOop::to_oop(good_addr); } inline bool ZBarrier::is_null_fast_path(uintptr_t addr) { --- old/src/hotspot/share/gc/z/zBarrierSetNMethod.cpp 2019-05-21 01:01:24.789140616 +0200 +++ new/src/hotspot/share/gc/z/zBarrierSetNMethod.cpp 2019-05-21 01:01:24.629140902 +0200 @@ -55,7 +55,11 @@ // Heal oops and disarm ZNMethodOopClosure cl; - ZNMethod::nmethod_oops_do(nm, &cl); + nm->oops_do(&cl); + nm->fix_oop_relocations(); + + OrderAccess::release(); + disarm(nm); return true; --- old/src/hotspot/share/gc/z/zForwarding.cpp 2019-05-21 01:01:24.985140264 +0200 +++ new/src/hotspot/share/gc/z/zForwarding.cpp 2019-05-21 01:01:24.829140545 +0200 @@ -69,11 +69,6 @@ // Check for duplicates for (ZForwardingCursor j = i + 1; j < _entries.length(); j++) { const ZForwardingEntry other = at(&j); - if (!other.populated()) { - // Skip empty entries - continue; - } - guarantee(entry.from_index() != other.from_index(), "Duplicate from"); guarantee(entry.to_offset() != other.to_offset(), "Duplicate to"); } --- old/src/hotspot/share/gc/z/zHeap.inline.hpp 2019-05-21 01:01:25.177139920 +0200 +++ new/src/hotspot/share/gc/z/zHeap.inline.hpp 2019-05-21 01:01:25.021140200 +0200 @@ -135,7 +135,7 @@ } inline bool ZHeap::is_oop(oop object) const { - return ZAddress::is_good(ZOop::to_address(object)); + return ZOop::is_good(object); } #endif // SHARE_GC_Z_ZHEAP_INLINE_HPP --- old/src/hotspot/share/gc/z/zLiveMap.inline.hpp 2019-05-21 01:01:25.377139561 +0200 +++ new/src/hotspot/share/gc/z/zLiveMap.inline.hpp 2019-05-21 01:01:25.221139841 +0200 @@ -144,7 +144,7 @@ const uintptr_t addr = page_start + ((index / 2) << page_object_alignment_shift); // Apply closure - cl->do_object(ZOop::from_address(addr)); + cl->do_object(ZOop::to_oop(addr)); // Find next bit after this object const size_t size = ZUtils::object_size(addr); --- old/src/hotspot/share/gc/z/zMark.cpp 2019-05-21 01:01:25.589139181 +0200 +++ new/src/hotspot/share/gc/z/zMark.cpp 2019-05-21 01:01:25.417139490 +0200 @@ -200,7 +200,7 @@ } bool ZMark::is_array(uintptr_t addr) const { - return ZOop::from_address(addr)->is_objArray(); + return ZOop::to_oop(addr)->is_objArray(); } void ZMark::push_partial_array(uintptr_t addr, size_t size, bool finalizable) { @@ -347,9 +347,9 @@ } if (is_array(addr)) { - follow_array_object(objArrayOop(ZOop::from_address(addr)), finalizable); + follow_array_object(objArrayOop(ZOop::to_oop(addr)), finalizable); } else { - follow_object(ZOop::from_address(addr), finalizable); + follow_object(ZOop::to_oop(addr), finalizable); } } --- old/src/hotspot/share/gc/z/zOop.hpp 2019-05-21 01:01:25.785138830 +0200 +++ new/src/hotspot/share/gc/z/zOop.hpp 2019-05-21 01:01:25.633139102 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2019, 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 @@ -29,8 +29,13 @@ class ZOop : public AllStatic { public: - static oop from_address(uintptr_t addr); + static oop to_oop(uintptr_t value); static uintptr_t to_address(oop o); + + static bool is_good(oop o); + static bool is_finalizable_good(oop o); + + static oop good(oop); }; #endif // SHARE_GC_Z_ZOOP_HPP --- old/src/hotspot/share/gc/z/zOop.inline.hpp 2019-05-21 01:01:25.985138473 +0200 +++ new/src/hotspot/share/gc/z/zOop.inline.hpp 2019-05-21 01:01:25.825138758 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2019, 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 @@ -24,14 +24,28 @@ #ifndef SHARE_GC_Z_ZOOP_INLINE_HPP #define SHARE_GC_Z_ZOOP_INLINE_HPP +#include "gc/z/zAddress.inline.hpp" #include "gc/z/zOop.hpp" +#include "oops/oopsHierarchy.hpp" -inline oop ZOop::from_address(uintptr_t addr) { - return cast_to_oop(addr); +inline oop ZOop::to_oop(uintptr_t value) { + return cast_to_oop(value); } inline uintptr_t ZOop::to_address(oop o) { return cast_from_oop(o); } +inline bool ZOop::is_good(oop o) { + return ZAddress::is_good(to_address(o)); +} + +inline bool ZOop::is_finalizable_good(oop o) { + return ZAddress::is_finalizable_good(to_address(o)); +} + +inline oop ZOop::good(oop o) { + return to_oop(ZAddress::good(to_address(o))); +} + #endif // SHARE_GC_Z_ZOOP_INLINE_HPP --- old/src/hotspot/share/gc/z/zOopClosures.cpp 2019-05-21 01:01:26.185138113 +0200 +++ new/src/hotspot/share/gc/z/zOopClosures.cpp 2019-05-21 01:01:26.029138394 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2019, 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,14 +39,12 @@ const oop o = RawAccess<>::oop_load(p); if (o != NULL) { - const uintptr_t addr = ZOop::to_address(o); - const uintptr_t good_addr = ZAddress::good(addr); - guarantee(ZAddress::is_good(addr) || ZAddress::is_finalizable_good(addr), + guarantee(ZOop::is_good(o) || ZOop::is_finalizable_good(o), "Bad oop " PTR_FORMAT " found at " PTR_FORMAT ", expected " PTR_FORMAT, - addr, p2i(p), good_addr); - guarantee(oopDesc::is_oop(ZOop::from_address(good_addr)), + p2i(o), p2i(p), p2i(ZOop::good(o))); + guarantee(oopDesc::is_oop(ZOop::good(o)), "Bad object " PTR_FORMAT " found at " PTR_FORMAT, - addr, p2i(p)); + p2i(o), p2i(p)); } } --- old/src/hotspot/share/gc/z/zRootsIterator.cpp 2019-05-21 01:01:26.381137762 +0200 +++ new/src/hotspot/share/gc/z/zRootsIterator.cpp 2019-05-21 01:01:26.225138042 +0200 @@ -41,7 +41,6 @@ #include "memory/resourceArea.hpp" #include "memory/universe.hpp" #include "prims/jvmtiExport.hpp" -#include "prims/resolvedMethodTable.hpp" #include "runtime/atomic.hpp" #include "runtime/jniHandles.hpp" #include "runtime/thread.hpp" @@ -81,7 +80,6 @@ static const ZStatSubPhase ZSubPhaseConcurrentWeakRootsVMWeakHandles("Concurrent Weak Roots VMWeakHandles"); static const ZStatSubPhase ZSubPhaseConcurrentWeakRootsJNIWeakHandles("Concurrent Weak Roots JNIWeakHandles"); static const ZStatSubPhase ZSubPhaseConcurrentWeakRootsStringTable("Concurrent Weak Roots StringTable"); -static const ZStatSubPhase ZSubPhaseConcurrentWeakRootsResolvedMethodTable("Concurrent Weak Roots ResolvedMethodTable"); template ZSerialOopsDo::ZSerialOopsDo(T* iter) : @@ -343,18 +341,14 @@ _vm_weak_handles_iter(SystemDictionary::vm_weak_oop_storage()), _jni_weak_handles_iter(JNIHandles::weak_global_handles()), _string_table_iter(StringTable::weak_storage()), - _resolved_method_table_iter(ResolvedMethodTable::weak_storage()), _vm_weak_handles(this), _jni_weak_handles(this), - _string_table(this), - _resolved_method_table(this) { + _string_table(this) { StringTable::reset_dead_counter(); - ResolvedMethodTable::reset_dead_counter(); } ZConcurrentWeakRootsIterator::~ZConcurrentWeakRootsIterator() { StringTable::finish_dead_counter(); - ResolvedMethodTable::finish_dead_counter(); } void ZConcurrentWeakRootsIterator::do_vm_weak_handles(ZRootsIteratorClosure* cl) { @@ -367,19 +361,18 @@ _jni_weak_handles_iter.oops_do(cl); } -template -class ZDeadCounterClosure : public ZRootsIteratorClosure { +class ZStringTableDeadCounterClosure : public ZRootsIteratorClosure { private: ZRootsIteratorClosure* const _cl; size_t _ndead; public: - ZDeadCounterClosure(ZRootsIteratorClosure* cl) : + ZStringTableDeadCounterClosure(ZRootsIteratorClosure* cl) : _cl(cl), _ndead(0) {} - ~ZDeadCounterClosure() { - Container::inc_dead_counter(_ndead); + ~ZStringTableDeadCounterClosure() { + StringTable::inc_dead_counter(_ndead); } virtual void do_oop(oop* p) { @@ -396,22 +389,15 @@ void ZConcurrentWeakRootsIterator::do_string_table(ZRootsIteratorClosure* cl) { ZStatTimer timer(ZSubPhaseConcurrentWeakRootsStringTable); - ZDeadCounterClosure counter_cl(cl); + ZStringTableDeadCounterClosure counter_cl(cl); _string_table_iter.oops_do(&counter_cl); } -void ZConcurrentWeakRootsIterator::do_resolved_method_table(ZRootsIteratorClosure* cl) { - ZStatTimer timer(ZSubPhaseConcurrentWeakRootsResolvedMethodTable); - ZDeadCounterClosure counter_cl(cl); - _resolved_method_table_iter.oops_do(&counter_cl); -} - void ZConcurrentWeakRootsIterator::oops_do(ZRootsIteratorClosure* cl) { ZStatTimer timer(ZSubPhaseConcurrentWeakRoots); _vm_weak_handles.oops_do(cl); _jni_weak_handles.oops_do(cl); _string_table.oops_do(cl); - _resolved_method_table.oops_do(cl); } ZThreadRootsIterator::ZThreadRootsIterator() : --- old/src/hotspot/share/gc/z/zRootsIterator.hpp 2019-05-21 01:01:26.581137403 +0200 +++ new/src/hotspot/share/gc/z/zRootsIterator.hpp 2019-05-21 01:01:26.425137683 +0200 @@ -149,17 +149,14 @@ ZOopStorageIterator _vm_weak_handles_iter; ZOopStorageIterator _jni_weak_handles_iter; ZOopStorageIterator _string_table_iter; - ZOopStorageIterator _resolved_method_table_iter; void do_vm_weak_handles(ZRootsIteratorClosure* cl); void do_jni_weak_handles(ZRootsIteratorClosure* cl); void do_string_table(ZRootsIteratorClosure* cl); - void do_resolved_method_table(ZRootsIteratorClosure* cl); - ZParallelOopsDo _vm_weak_handles; - ZParallelOopsDo _jni_weak_handles; - ZParallelOopsDo _string_table; - ZParallelOopsDo _resolved_method_table; + ZParallelOopsDo _vm_weak_handles; + ZParallelOopsDo _jni_weak_handles; + ZParallelOopsDo _string_table; public: ZConcurrentWeakRootsIterator(); --- old/src/hotspot/share/gc/z/zUnload.cpp 2019-05-21 01:01:26.785137038 +0200 +++ new/src/hotspot/share/gc/z/zUnload.cpp 2019-05-21 01:01:26.621137331 +0200 @@ -71,7 +71,7 @@ ZReentrantLock* const lock = ZNMethod::lock_for_nmethod(nm); ZLocker locker(lock); ZIsUnloadingOopClosure cl; - ZNMethod::nmethod_oops_do(nm, &cl); + nm->oops_do(&cl, true /* allow_zombie */); return cl.is_unloading(); } }; --- old/src/hotspot/share/gc/z/zUtils.inline.hpp 2019-05-21 01:01:26.985136679 +0200 +++ new/src/hotspot/share/gc/z/zUtils.inline.hpp 2019-05-21 01:01:26.825136967 +0200 @@ -57,7 +57,7 @@ } inline size_t ZUtils::object_size(uintptr_t addr) { - return words_to_bytes(ZOop::from_address(addr)->size()); + return words_to_bytes(ZOop::to_oop(addr)->size()); } inline void ZUtils::object_copy(uintptr_t from, uintptr_t to, size_t size) { --- old/src/hotspot/share/interpreter/interpreterRuntime.cpp 2019-05-21 01:01:27.237136228 +0200 +++ new/src/hotspot/share/interpreter/interpreterRuntime.cpp 2019-05-21 01:01:27.057136549 +0200 @@ -156,7 +156,7 @@ // Constants -JRT_ENTRY(void, InterpreterRuntime::ldc(JavaThread* thread, bool wide)) +IRT_ENTRY(void, InterpreterRuntime::ldc(JavaThread* thread, bool wide)) // access constant pool LastFrameAccessor last_frame(thread); ConstantPool* pool = last_frame.method()->constants(); @@ -167,9 +167,9 @@ Klass* klass = pool->klass_at(index, CHECK); oop java_class = klass->java_mirror(); thread->set_vm_result(java_class); -JRT_END +IRT_END -JRT_ENTRY(void, InterpreterRuntime::resolve_ldc(JavaThread* thread, Bytecodes::Code bytecode)) { +IRT_ENTRY(void, InterpreterRuntime::resolve_ldc(JavaThread* thread, Bytecodes::Code bytecode)) { assert(bytecode == Bytecodes::_ldc || bytecode == Bytecodes::_ldc_w || bytecode == Bytecodes::_ldc2_w || @@ -219,13 +219,13 @@ thread->set_vm_result_2((Metadata*)flags); } } -JRT_END +IRT_END //------------------------------------------------------------------------------------------------------------------------ // Allocation -JRT_ENTRY(void, InterpreterRuntime::_new(JavaThread* thread, ConstantPool* pool, int index)) +IRT_ENTRY(void, InterpreterRuntime::_new(JavaThread* thread, ConstantPool* pool, int index)) Klass* k = pool->klass_at(index, CHECK); InstanceKlass* klass = InstanceKlass::cast(k); @@ -251,23 +251,23 @@ // because the _breakpoint bytecode would be lost. oop obj = klass->allocate_instance(CHECK); thread->set_vm_result(obj); -JRT_END +IRT_END -JRT_ENTRY(void, InterpreterRuntime::newarray(JavaThread* thread, BasicType type, jint size)) +IRT_ENTRY(void, InterpreterRuntime::newarray(JavaThread* thread, BasicType type, jint size)) oop obj = oopFactory::new_typeArray(type, size, CHECK); thread->set_vm_result(obj); -JRT_END +IRT_END -JRT_ENTRY(void, InterpreterRuntime::anewarray(JavaThread* thread, ConstantPool* pool, int index, jint size)) +IRT_ENTRY(void, InterpreterRuntime::anewarray(JavaThread* thread, ConstantPool* pool, int index, jint size)) Klass* klass = pool->klass_at(index, CHECK); objArrayOop obj = oopFactory::new_objArray(klass, size, CHECK); thread->set_vm_result(obj); -JRT_END +IRT_END -JRT_ENTRY(void, InterpreterRuntime::multianewarray(JavaThread* thread, jint* first_size_address)) +IRT_ENTRY(void, InterpreterRuntime::multianewarray(JavaThread* thread, jint* first_size_address)) // We may want to pass in more arguments - could make this slightly faster LastFrameAccessor last_frame(thread); ConstantPool* constants = last_frame.method()->constants(); @@ -292,18 +292,18 @@ } oop obj = ArrayKlass::cast(klass)->multi_allocate(nof_dims, dims, CHECK); thread->set_vm_result(obj); -JRT_END +IRT_END -JRT_ENTRY(void, InterpreterRuntime::register_finalizer(JavaThread* thread, oopDesc* obj)) +IRT_ENTRY(void, InterpreterRuntime::register_finalizer(JavaThread* thread, oopDesc* obj)) assert(oopDesc::is_oop(obj), "must be a valid oop"); assert(obj->klass()->has_finalizer(), "shouldn't be here otherwise"); InstanceKlass::register_finalizer(instanceOop(obj), CHECK); -JRT_END +IRT_END // Quicken instance-of and check-cast bytecodes -JRT_ENTRY(void, InterpreterRuntime::quicken_io_cc(JavaThread* thread)) +IRT_ENTRY(void, InterpreterRuntime::quicken_io_cc(JavaThread* thread)) // Force resolving; quicken the bytecode LastFrameAccessor last_frame(thread); int which = last_frame.get_index_u2(Bytecodes::_checkcast); @@ -314,7 +314,7 @@ // assert( cpool->tag_at(which).is_unresolved_klass(), "should only come here to quicken bytecodes" ); Klass* klass = cpool->klass_at(which, CHECK); thread->set_vm_result_2(klass); -JRT_END +IRT_END //------------------------------------------------------------------------------------------------------------------------ @@ -354,10 +354,10 @@ #ifdef CC_INTERP // As legacy note_trap, but we have more arguments. -JRT_ENTRY(void, InterpreterRuntime::note_trap(JavaThread* thread, int reason, Method *method, int trap_bci)) +IRT_ENTRY(void, InterpreterRuntime::note_trap(JavaThread* thread, int reason, Method *method, int trap_bci)) methodHandle trap_method(method); note_trap_inner(thread, reason, trap_method, trap_bci, THREAD); -JRT_END +IRT_END // Class Deoptimization is not visible in BytecodeInterpreter, so we need a wrapper // for each exception. @@ -394,16 +394,16 @@ // space left we use the pre-allocated & pre-initialized StackOverflowError // klass to create an stack overflow error instance. We do not call its // constructor for the same reason (it is empty, anyway). -JRT_ENTRY(void, InterpreterRuntime::throw_StackOverflowError(JavaThread* thread)) +IRT_ENTRY(void, InterpreterRuntime::throw_StackOverflowError(JavaThread* thread)) Handle exception = get_preinitialized_exception( SystemDictionary::StackOverflowError_klass(), CHECK); // Increment counter for hs_err file reporting Atomic::inc(&Exceptions::_stack_overflow_errors); THROW_HANDLE(exception); -JRT_END +IRT_END -JRT_ENTRY(void, InterpreterRuntime::throw_delayed_StackOverflowError(JavaThread* thread)) +IRT_ENTRY(void, InterpreterRuntime::throw_delayed_StackOverflowError(JavaThread* thread)) Handle exception = get_preinitialized_exception( SystemDictionary::StackOverflowError_klass(), CHECK); @@ -412,9 +412,9 @@ // Increment counter for hs_err file reporting Atomic::inc(&Exceptions::_stack_overflow_errors); THROW_HANDLE(exception); -JRT_END +IRT_END -JRT_ENTRY(void, InterpreterRuntime::create_exception(JavaThread* thread, char* name, char* message)) +IRT_ENTRY(void, InterpreterRuntime::create_exception(JavaThread* thread, char* name, char* message)) // lookup exception klass TempNewSymbol s = SymbolTable::new_symbol(name, CHECK); if (ProfileTraps) { @@ -427,10 +427,10 @@ // create exception Handle exception = Exceptions::new_exception(thread, s, message); thread->set_vm_result(exception()); -JRT_END +IRT_END -JRT_ENTRY(void, InterpreterRuntime::create_klass_exception(JavaThread* thread, char* name, oopDesc* obj)) +IRT_ENTRY(void, InterpreterRuntime::create_klass_exception(JavaThread* thread, char* name, oopDesc* obj)) // Produce the error message first because note_trap can safepoint ResourceMark rm(thread); const char* klass_name = obj->klass()->external_name(); @@ -442,9 +442,9 @@ // create exception, with klass name as detail message Handle exception = Exceptions::new_exception(thread, s, klass_name); thread->set_vm_result(exception()); -JRT_END +IRT_END -JRT_ENTRY(void, InterpreterRuntime::throw_ArrayIndexOutOfBoundsException(JavaThread* thread, arrayOopDesc* a, jint index)) +IRT_ENTRY(void, InterpreterRuntime::throw_ArrayIndexOutOfBoundsException(JavaThread* thread, arrayOopDesc* a, jint index)) // Produce the error message first because note_trap can safepoint ResourceMark rm(thread); stringStream ss; @@ -455,9 +455,9 @@ } THROW_MSG(vmSymbols::java_lang_ArrayIndexOutOfBoundsException(), ss.as_string()); -JRT_END +IRT_END -JRT_ENTRY(void, InterpreterRuntime::throw_ClassCastException( +IRT_ENTRY(void, InterpreterRuntime::throw_ClassCastException( JavaThread* thread, oopDesc* obj)) // Produce the error message first because note_trap can safepoint @@ -471,7 +471,7 @@ // create exception THROW_MSG(vmSymbols::java_lang_ClassCastException(), message); -JRT_END +IRT_END // exception_handler_for_exception(...) returns the continuation address, // the exception oop (via TLS) and sets the bci/bcp for the continuation. @@ -481,7 +481,7 @@ // bci where the exception happened. If the exception was propagated back // from a call, the expression stack contains the values for the bci at the // invoke w/o arguments (i.e., as if one were inside the call). -JRT_ENTRY(address, InterpreterRuntime::exception_handler_for_exception(JavaThread* thread, oopDesc* exception)) +IRT_ENTRY(address, InterpreterRuntime::exception_handler_for_exception(JavaThread* thread, oopDesc* exception)) LastFrameAccessor last_frame(thread); Handle h_exception(thread, exception); @@ -622,18 +622,18 @@ thread->set_vm_result(h_exception()); return continuation; -JRT_END +IRT_END -JRT_ENTRY(void, InterpreterRuntime::throw_pending_exception(JavaThread* thread)) +IRT_ENTRY(void, InterpreterRuntime::throw_pending_exception(JavaThread* thread)) assert(thread->has_pending_exception(), "must only ne called if there's an exception pending"); // nothing to do - eventually we should remove this code entirely (see comments @ call sites) -JRT_END +IRT_END -JRT_ENTRY(void, InterpreterRuntime::throw_AbstractMethodError(JavaThread* thread)) +IRT_ENTRY(void, InterpreterRuntime::throw_AbstractMethodError(JavaThread* thread)) THROW(vmSymbols::java_lang_AbstractMethodError()); -JRT_END +IRT_END // This method is called from the "abstract_entry" of the interpreter. // At that point, the arguments have already been removed from the stack @@ -641,28 +641,28 @@ // on some platforms the receiver still resides in a register...). Thus, // we have no choice but print an error message not containing the receiver // type. -JRT_ENTRY(void, InterpreterRuntime::throw_AbstractMethodErrorWithMethod(JavaThread* thread, +IRT_ENTRY(void, InterpreterRuntime::throw_AbstractMethodErrorWithMethod(JavaThread* thread, Method* missingMethod)) ResourceMark rm(thread); assert(missingMethod != NULL, "sanity"); methodHandle m(thread, missingMethod); LinkResolver::throw_abstract_method_error(m, THREAD); -JRT_END +IRT_END -JRT_ENTRY(void, InterpreterRuntime::throw_AbstractMethodErrorVerbose(JavaThread* thread, +IRT_ENTRY(void, InterpreterRuntime::throw_AbstractMethodErrorVerbose(JavaThread* thread, Klass* recvKlass, Method* missingMethod)) ResourceMark rm(thread); methodHandle mh = methodHandle(thread, missingMethod); LinkResolver::throw_abstract_method_error(mh, recvKlass, THREAD); -JRT_END +IRT_END -JRT_ENTRY(void, InterpreterRuntime::throw_IncompatibleClassChangeError(JavaThread* thread)) +IRT_ENTRY(void, InterpreterRuntime::throw_IncompatibleClassChangeError(JavaThread* thread)) THROW(vmSymbols::java_lang_IncompatibleClassChangeError()); -JRT_END +IRT_END -JRT_ENTRY(void, InterpreterRuntime::throw_IncompatibleClassChangeErrorVerbose(JavaThread* thread, +IRT_ENTRY(void, InterpreterRuntime::throw_IncompatibleClassChangeErrorVerbose(JavaThread* thread, Klass* recvKlass, Klass* interfaceKlass)) ResourceMark rm(thread); @@ -673,7 +673,7 @@ recvKlass ? recvKlass->external_name() : "NULL", interfaceKlass ? interfaceKlass->external_name() : "NULL"); THROW_MSG(vmSymbols::java_lang_IncompatibleClassChangeError(), buf); -JRT_END +IRT_END //------------------------------------------------------------------------------------------------------------------------ // Fields @@ -760,7 +760,7 @@ //%note synchronization_3 //%note monitor_1 -JRT_ENTRY_NO_ASYNC(void, InterpreterRuntime::monitorenter(JavaThread* thread, BasicObjectLock* elem)) +IRT_ENTRY_NO_ASYNC(void, InterpreterRuntime::monitorenter(JavaThread* thread, BasicObjectLock* elem)) #ifdef ASSERT thread->last_frame().interpreter_frame_verify_monitor(elem); #endif @@ -781,11 +781,11 @@ #ifdef ASSERT thread->last_frame().interpreter_frame_verify_monitor(elem); #endif -JRT_END +IRT_END //%note monitor_1 -JRT_ENTRY_NO_ASYNC(void, InterpreterRuntime::monitorexit(JavaThread* thread, BasicObjectLock* elem)) +IRT_ENTRY_NO_ASYNC(void, InterpreterRuntime::monitorexit(JavaThread* thread, BasicObjectLock* elem)) #ifdef ASSERT thread->last_frame().interpreter_frame_verify_monitor(elem); #endif @@ -802,15 +802,15 @@ #ifdef ASSERT thread->last_frame().interpreter_frame_verify_monitor(elem); #endif -JRT_END +IRT_END -JRT_ENTRY(void, InterpreterRuntime::throw_illegal_monitor_state_exception(JavaThread* thread)) +IRT_ENTRY(void, InterpreterRuntime::throw_illegal_monitor_state_exception(JavaThread* thread)) THROW(vmSymbols::java_lang_IllegalMonitorStateException()); -JRT_END +IRT_END -JRT_ENTRY(void, InterpreterRuntime::new_illegal_monitor_state_exception(JavaThread* thread)) +IRT_ENTRY(void, InterpreterRuntime::new_illegal_monitor_state_exception(JavaThread* thread)) // Returns an illegal exception to install into the current thread. The // pending_exception flag is cleared so normal exception handling does not // trigger. Any current installed exception will be overwritten. This @@ -826,23 +826,23 @@ CATCH); } thread->set_vm_result(exception()); -JRT_END +IRT_END //------------------------------------------------------------------------------------------------------------------------ // Invokes -JRT_ENTRY(Bytecodes::Code, InterpreterRuntime::get_original_bytecode_at(JavaThread* thread, Method* method, address bcp)) +IRT_ENTRY(Bytecodes::Code, InterpreterRuntime::get_original_bytecode_at(JavaThread* thread, Method* method, address bcp)) return method->orig_bytecode_at(method->bci_from(bcp)); -JRT_END +IRT_END -JRT_ENTRY(void, InterpreterRuntime::set_original_bytecode_at(JavaThread* thread, Method* method, address bcp, Bytecodes::Code new_code)) +IRT_ENTRY(void, InterpreterRuntime::set_original_bytecode_at(JavaThread* thread, Method* method, address bcp, Bytecodes::Code new_code)) method->set_orig_bytecode_at(method->bci_from(bcp), new_code); -JRT_END +IRT_END -JRT_ENTRY(void, InterpreterRuntime::_breakpoint(JavaThread* thread, Method* method, address bcp)) +IRT_ENTRY(void, InterpreterRuntime::_breakpoint(JavaThread* thread, Method* method, address bcp)) JvmtiExport::post_raw_breakpoint(thread, method, bcp); -JRT_END +IRT_END void InterpreterRuntime::resolve_invoke(JavaThread* thread, Bytecodes::Code bytecode) { Thread* THREAD = thread; @@ -998,7 +998,7 @@ // This function is the interface to the assembly code. It returns the resolved // cpCache entry. This doesn't safepoint, but the helper routines safepoint. // This function will check for redefinition! -JRT_ENTRY(void, InterpreterRuntime::resolve_from_cache(JavaThread* thread, Bytecodes::Code bytecode)) { +IRT_ENTRY(void, InterpreterRuntime::resolve_from_cache(JavaThread* thread, Bytecodes::Code bytecode)) { switch (bytecode) { case Bytecodes::_getstatic: case Bytecodes::_putstatic: @@ -1023,7 +1023,7 @@ break; } } -JRT_END +IRT_END //------------------------------------------------------------------------------------------------------------------------ // Miscellaneous @@ -1069,7 +1069,7 @@ return nm; } -JRT_ENTRY(nmethod*, +IRT_ENTRY(nmethod*, InterpreterRuntime::frequency_counter_overflow_inner(JavaThread* thread, address branch_bcp)) // use UnlockFlagSaver to clear and restore the _do_not_unlock_if_synchronized // flag, in case this method triggers classloading which will call into Java. @@ -1113,17 +1113,17 @@ } } return osr_nm; -JRT_END +IRT_END -JRT_LEAF(jint, InterpreterRuntime::bcp_to_di(Method* method, address cur_bcp)) +IRT_LEAF(jint, InterpreterRuntime::bcp_to_di(Method* method, address cur_bcp)) assert(ProfileInterpreter, "must be profiling interpreter"); int bci = method->bci_from(cur_bcp); MethodData* mdo = method->method_data(); if (mdo == NULL) return 0; return mdo->bci_to_di(bci); -JRT_END +IRT_END -JRT_ENTRY(void, InterpreterRuntime::profile_method(JavaThread* thread)) +IRT_ENTRY(void, InterpreterRuntime::profile_method(JavaThread* thread)) // use UnlockFlagSaver to clear and restore the _do_not_unlock_if_synchronized // flag, in case this method triggers classloading which will call into Java. UnlockFlagSaver fs(thread); @@ -1138,11 +1138,11 @@ CLEAR_PENDING_EXCEPTION; // and fall through... } -JRT_END +IRT_END #ifdef ASSERT -JRT_LEAF(void, InterpreterRuntime::verify_mdp(Method* method, address bcp, address mdp)) +IRT_LEAF(void, InterpreterRuntime::verify_mdp(Method* method, address bcp, address mdp)) assert(ProfileInterpreter, "must be profiling interpreter"); MethodData* mdo = method->method_data(); @@ -1169,10 +1169,10 @@ method->print_codes(); } assert(mdp == mdp2, "wrong mdp"); -JRT_END +IRT_END #endif // ASSERT -JRT_ENTRY(void, InterpreterRuntime::update_mdp_for_ret(JavaThread* thread, int return_bci)) +IRT_ENTRY(void, InterpreterRuntime::update_mdp_for_ret(JavaThread* thread, int return_bci)) assert(ProfileInterpreter, "must be profiling interpreter"); ResourceMark rm(thread); HandleMark hm(thread); @@ -1191,24 +1191,24 @@ RetData* rdata = data->as_RetData(); address new_mdp = rdata->fixup_ret(return_bci, h_mdo); last_frame.set_mdp(new_mdp); -JRT_END +IRT_END -JRT_ENTRY(MethodCounters*, InterpreterRuntime::build_method_counters(JavaThread* thread, Method* m)) +IRT_ENTRY(MethodCounters*, InterpreterRuntime::build_method_counters(JavaThread* thread, Method* m)) MethodCounters* mcs = Method::build_method_counters(m, thread); if (HAS_PENDING_EXCEPTION) { assert((PENDING_EXCEPTION->is_a(SystemDictionary::OutOfMemoryError_klass())), "we expect only an OOM error here"); CLEAR_PENDING_EXCEPTION; } return mcs; -JRT_END +IRT_END -JRT_ENTRY(void, InterpreterRuntime::at_safepoint(JavaThread* thread)) +IRT_ENTRY(void, InterpreterRuntime::at_safepoint(JavaThread* thread)) // We used to need an explict preserve_arguments here for invoke bytecodes. However, // stack traversal automatically takes care of preserving arguments for invoke, so // this is no longer needed. - // JRT_END does an implicit safepoint check, hence we are guaranteed to block + // IRT_END does an implicit safepoint check, hence we are guaranteed to block // if this is called during a safepoint if (JvmtiExport::should_post_single_step()) { @@ -1218,9 +1218,9 @@ LastFrameAccessor last_frame(thread); JvmtiExport::at_single_stepping_point(thread, last_frame.method(), last_frame.bcp()); } -JRT_END +IRT_END -JRT_ENTRY(void, InterpreterRuntime::post_field_access(JavaThread *thread, oopDesc* obj, +IRT_ENTRY(void, InterpreterRuntime::post_field_access(JavaThread *thread, oopDesc* obj, ConstantPoolCacheEntry *cp_entry)) // check the access_flags for the field in the klass @@ -1241,9 +1241,9 @@ jfieldID fid = jfieldIDWorkaround::to_jfieldID(cp_entry_f1, cp_entry->f2_as_index(), is_static); LastFrameAccessor last_frame(thread); JvmtiExport::post_field_access(thread, last_frame.method(), last_frame.bcp(), cp_entry_f1, h_obj, fid); -JRT_END +IRT_END -JRT_ENTRY(void, InterpreterRuntime::post_field_modification(JavaThread *thread, +IRT_ENTRY(void, InterpreterRuntime::post_field_modification(JavaThread *thread, oopDesc* obj, ConstantPoolCacheEntry *cp_entry, jvalue *value)) Klass* k = cp_entry->f1_as_klass(); @@ -1298,24 +1298,24 @@ LastFrameAccessor last_frame(thread); JvmtiExport::post_raw_field_modification(thread, last_frame.method(), last_frame.bcp(), ik, h_obj, fid, sig_type, &fvalue); -JRT_END +IRT_END -JRT_ENTRY(void, InterpreterRuntime::post_method_entry(JavaThread *thread)) +IRT_ENTRY(void, InterpreterRuntime::post_method_entry(JavaThread *thread)) LastFrameAccessor last_frame(thread); JvmtiExport::post_method_entry(thread, last_frame.method(), last_frame.get_frame()); -JRT_END +IRT_END -JRT_ENTRY(void, InterpreterRuntime::post_method_exit(JavaThread *thread)) +IRT_ENTRY(void, InterpreterRuntime::post_method_exit(JavaThread *thread)) LastFrameAccessor last_frame(thread); JvmtiExport::post_method_exit(thread, last_frame.method(), last_frame.get_frame()); -JRT_END +IRT_END -JRT_LEAF(int, InterpreterRuntime::interpreter_contains(address pc)) +IRT_LEAF(int, InterpreterRuntime::interpreter_contains(address pc)) { return (Interpreter::contains(pc) ? 1 : 0); } -JRT_END +IRT_END // Implementation of SignatureHandlerLibrary @@ -1508,7 +1508,7 @@ address SignatureHandlerLibrary::_buffer = NULL; -JRT_ENTRY(void, InterpreterRuntime::prepare_native_call(JavaThread* thread, Method* method)) +IRT_ENTRY(void, InterpreterRuntime::prepare_native_call(JavaThread* thread, Method* method)) methodHandle m(thread, method); assert(m->is_native(), "sanity check"); // lookup native function entry point if it doesn't exist @@ -1522,10 +1522,10 @@ // before trying to fetch the native entry point and klass mirror. // We must set the signature handler last, so that multiple processors // preparing the same method will be sure to see non-null entry & mirror. -JRT_END +IRT_END #if defined(IA32) || defined(AMD64) || defined(ARM) -JRT_LEAF(void, InterpreterRuntime::popframe_move_outgoing_args(JavaThread* thread, void* src_address, void* dest_address)) +IRT_LEAF(void, InterpreterRuntime::popframe_move_outgoing_args(JavaThread* thread, void* src_address, void* dest_address)) if (src_address == dest_address) { return; } @@ -1541,7 +1541,7 @@ int size_of_arguments = (asc.size() + (invoke.has_receiver() ? 1 : 0)); // receiver Copy::conjoint_jbytes(src_address, dest_address, size_of_arguments * Interpreter::stackElementSize); -JRT_END +IRT_END #endif #if INCLUDE_JVMTI @@ -1551,7 +1551,7 @@ // The member_name argument is a saved reference (in local#0) to the member_name. // For backward compatibility with some JDK versions (7, 8) it can also be a direct method handle. // FIXME: remove DMH case after j.l.i.InvokerBytecodeGenerator code shape is updated. -JRT_ENTRY(void, InterpreterRuntime::member_name_arg_or_null(JavaThread* thread, address member_name, +IRT_ENTRY(void, InterpreterRuntime::member_name_arg_or_null(JavaThread* thread, address member_name, Method* method, address bcp)) Bytecodes::Code code = Bytecodes::code_at(method, bcp); if (code != Bytecodes::_invokestatic) { @@ -1572,19 +1572,19 @@ } else { thread->set_vm_result(NULL); } -JRT_END +IRT_END #endif // INCLUDE_JVMTI #ifndef PRODUCT -// This must be a JRT_LEAF function because the interpreter must save registers on x86 to +// This must be a IRT_LEAF function because the interpreter must save registers on x86 to // call this, which changes rsp and makes the interpreter's expression stack not walkable. // The generated code still uses call_VM because that will set up the frame pointer for // bcp and method. -JRT_LEAF(intptr_t, InterpreterRuntime::trace_bytecode(JavaThread* thread, intptr_t preserve_this_value, intptr_t tos, intptr_t tos2)) +IRT_LEAF(intptr_t, InterpreterRuntime::trace_bytecode(JavaThread* thread, intptr_t preserve_this_value, intptr_t tos, intptr_t tos2)) LastFrameAccessor last_frame(thread); assert(last_frame.is_interpreted_frame(), "must be an interpreted frame"); methodHandle mh(thread, last_frame.method()); BytecodeTracer::trace(mh, last_frame.bcp(), tos, tos2); return preserve_this_value; -JRT_END +IRT_END #endif // !PRODUCT --- old/src/hotspot/share/interpreter/linkResolver.cpp 2019-05-21 01:01:27.473135805 +0200 +++ new/src/hotspot/share/interpreter/linkResolver.cpp 2019-05-21 01:01:27.321136077 +0200 @@ -264,6 +264,10 @@ _check_access = true; } +char* LinkInfo::method_string() const { + return Method::name_and_sig_as_C_string(_resolved_klass, _name, _signature); +} + #ifndef PRODUCT void LinkInfo::print() { ResourceMark rm; @@ -589,12 +593,14 @@ Exceptions::fthrow( THREAD_AND_LOCATION, vmSymbols::java_lang_IllegalAccessError(), - "class %s tried to access %s%s%smethod '%s' (%s%s%s)", + "class %s tried to access %s%s%smethod %s.%s%s (%s%s%s)", ref_klass->external_name(), sel_method->is_abstract() ? "abstract " : "", sel_method->is_protected() ? "protected " : "", sel_method->is_private() ? "private " : "", - sel_method->external_name(), + sel_klass->external_name(), + sel_method->name()->as_C_string(), + sel_method->signature()->as_C_string(), (same_module) ? ref_klass->joint_in_module_of_loader(sel_klass) : ref_klass->class_in_module_of_loader(), (same_module) ? "" : "; ", (same_module) ? "" : sel_klass->class_in_module_of_loader() @@ -664,11 +670,12 @@ assert(target_loader_data != NULL, "resolved method's class has no class loader data"); stringStream ss; - ss.print("loader constraint violation: when resolving %s '", method_type); - Method::print_external_name(&ss, link_info.resolved_klass(), link_info.name(), link_info.signature()); - ss.print("' the class loader %s of the current class, %s," + ss.print("loader constraint violation: when resolving %s" + " \"%s\" the class loader %s of the current class, %s," " and the class loader %s for the method's defining class, %s, have" " different Class objects for the type %s used in the signature (%s; %s)", + method_type, + link_info.method_string(), current_loader_data->loader_name_and_id(), current_class->name()->as_C_string(), target_loader_data->loader_name_and_id(), @@ -732,11 +739,9 @@ // 2. check constant pool tag for called method - must be JVM_CONSTANT_Methodref if (!link_info.tag().is_invalid() && !link_info.tag().is_method()) { ResourceMark rm(THREAD); - stringStream ss; - ss.print("Method '"); - Method::print_external_name(&ss, link_info.resolved_klass(), link_info.name(), link_info.signature()); - ss.print("' must be Methodref constant"); - THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), ss.as_string()); + char buf[200]; + jio_snprintf(buf, sizeof(buf), "Method %s must be Methodref constant", link_info.method_string()); + THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), buf); } // 3. lookup method in resolved klass and its super klasses @@ -759,12 +764,11 @@ // 5. method lookup failed if (resolved_method.is_null()) { ResourceMark rm(THREAD); - stringStream ss; - ss.print("'"); - Method::print_external_name(&ss, resolved_klass, link_info.name(), link_info.signature()); - ss.print("'"); THROW_MSG_CAUSE_(vmSymbols::java_lang_NoSuchMethodError(), - ss.as_string(), nested_exception, NULL); + Method::name_and_sig_as_C_string(resolved_klass, + link_info.name(), + link_info.signature()), + nested_exception, NULL); } // 6. access checks, access checking may be turned off when calling from within the VM. @@ -836,11 +840,9 @@ // check constant pool tag for called method - must be JVM_CONSTANT_InterfaceMethodref if (!link_info.tag().is_invalid() && !link_info.tag().is_interface_method()) { ResourceMark rm(THREAD); - stringStream ss; - ss.print("Method '"); - Method::print_external_name(&ss, link_info.resolved_klass(), link_info.name(), link_info.signature()); - ss.print("' must be InterfaceMethodref constant"); - THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), ss.as_string()); + char buf[200]; + jio_snprintf(buf, sizeof(buf), "Method %s must be InterfaceMethodref constant", link_info.method_string()); + THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), buf); } // lookup method in this interface or its super, java.lang.Object @@ -855,11 +857,10 @@ if (resolved_method.is_null()) { // no method found ResourceMark rm(THREAD); - stringStream ss; - ss.print("'"); - Method::print_external_name(&ss, resolved_klass, link_info.name(), link_info.signature()); - ss.print("'"); - THROW_MSG_NULL(vmSymbols::java_lang_NoSuchMethodError(), ss.as_string()); + THROW_MSG_NULL(vmSymbols::java_lang_NoSuchMethodError(), + Method::name_and_sig_as_C_string(resolved_klass, + link_info.name(), + link_info.signature())); } if (link_info.check_access()) { @@ -880,12 +881,11 @@ if (code != Bytecodes::_invokestatic && resolved_method->is_static()) { ResourceMark rm(THREAD); - stringStream ss; - ss.print("Expected instance not static method '"); - Method::print_external_name(&ss, resolved_klass, - resolved_method->name(), resolved_method->signature()); - ss.print("'"); - THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), ss.as_string()); + char buf[200]; + jio_snprintf(buf, sizeof(buf), "Expected instance not static method %s", + Method::name_and_sig_as_C_string(resolved_klass, + resolved_method->name(), resolved_method->signature())); + THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), buf); } if (log_develop_is_enabled(Trace, itables)) { @@ -1086,11 +1086,11 @@ // check if static if (!resolved_method->is_static()) { ResourceMark rm(THREAD); - stringStream ss; - ss.print("Expected static method '"); - resolved_method()->print_external_name(&ss); - ss.print("'"); - THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), ss.as_string()); + char buf[200]; + jio_snprintf(buf, sizeof(buf), "Expected static method %s", Method::name_and_sig_as_C_string(resolved_klass, + resolved_method->name(), + resolved_method->signature())); + THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), buf); } return resolved_method; } @@ -1127,16 +1127,14 @@ if (resolved_method->name() == vmSymbols::object_initializer_name() && resolved_method->method_holder() != resolved_klass) { ResourceMark rm(THREAD); - stringStream ss; - ss.print("%s: method '", resolved_klass->external_name()); - resolved_method->signature()->print_as_signature_external_return_type(&ss); - ss.print(" %s(", resolved_method->name()->as_C_string()); - resolved_method->signature()->print_as_signature_external_parameters(&ss); - ss.print(")' not found"); Exceptions::fthrow( THREAD_AND_LOCATION, vmSymbols::java_lang_NoSuchMethodError(), - "%s", ss.as_string()); + "%s: method %s%s not found", + resolved_klass->external_name(), + resolved_method->name()->as_C_string(), + resolved_method->signature()->as_C_string() + ); return NULL; } @@ -1155,23 +1153,27 @@ if (!is_reflect && !klass_to_check->is_same_or_direct_interface(resolved_klass)) { ResourceMark rm(THREAD); - stringStream ss; - ss.print("Interface method reference: '"); - resolved_method->print_external_name(&ss); - ss.print("', is in an indirect superinterface of %s", - current_klass->external_name()); - THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), ss.as_string()); + char buf[200]; + jio_snprintf(buf, sizeof(buf), + "Interface method reference: %s, is in an indirect superinterface of %s", + Method::name_and_sig_as_C_string(resolved_klass, + resolved_method->name(), + resolved_method->signature()), + current_klass->external_name()); + THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), buf); } } // check if not static if (resolved_method->is_static()) { ResourceMark rm(THREAD); - stringStream ss; - ss.print("Expecting non-static method '"); - resolved_method->print_external_name(&ss); - ss.print("'"); - THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), ss.as_string()); + char buf[200]; + jio_snprintf(buf, sizeof(buf), + "Expecting non-static method %s", + Method::name_and_sig_as_C_string(resolved_klass, + resolved_method->name(), + resolved_method->signature())); + THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), buf); } if (log_develop_is_enabled(Trace, itables)) { @@ -1217,11 +1219,10 @@ // check if found if (sel_method.is_null()) { ResourceMark rm(THREAD); - stringStream ss; - ss.print("'"); - resolved_method->print_external_name(&ss); - ss.print("'"); - THROW_MSG(vmSymbols::java_lang_AbstractMethodError(), ss.as_string()); + THROW_MSG(vmSymbols::java_lang_AbstractMethodError(), + Method::name_and_sig_as_C_string(resolved_klass, + resolved_method->name(), + resolved_method->signature())); // check loader constraints if found a different method } else if (sel_method() != resolved_method()) { check_method_loader_constraints(link_info, sel_method, "method", CHECK); @@ -1243,8 +1244,8 @@ char buf[500]; jio_snprintf(buf, sizeof(buf), "Receiver class %s must be the current class or a subtype of interface %s", - receiver_klass->external_name(), - sender->external_name()); + receiver_klass->name()->as_C_string(), + sender->name()->as_C_string()); THROW_MSG(vmSymbols::java_lang_IllegalAccessError(), buf); } } @@ -1253,21 +1254,20 @@ // check if not static if (sel_method->is_static()) { ResourceMark rm(THREAD); - stringStream ss; - ss.print("Expecting non-static method '"); - resolved_method->print_external_name(&ss); - ss.print("'"); - THROW_MSG(vmSymbols::java_lang_IncompatibleClassChangeError(), ss.as_string()); + char buf[200]; + jio_snprintf(buf, sizeof(buf), "Expecting non-static method %s", Method::name_and_sig_as_C_string(resolved_klass, + resolved_method->name(), + resolved_method->signature())); + THROW_MSG(vmSymbols::java_lang_IncompatibleClassChangeError(), buf); } // check if abstract if (sel_method->is_abstract()) { ResourceMark rm(THREAD); - stringStream ss; - ss.print("'"); - Method::print_external_name(&ss, resolved_klass, sel_method->name(), sel_method->signature()); - ss.print("'"); - THROW_MSG(vmSymbols::java_lang_AbstractMethodError(), ss.as_string()); + THROW_MSG(vmSymbols::java_lang_AbstractMethodError(), + Method::name_and_sig_as_C_string(resolved_klass, + sel_method->name(), + sel_method->signature())); } if (log_develop_is_enabled(Trace, itables)) { @@ -1305,22 +1305,23 @@ // This is impossible, if resolve_klass is an interface, we've thrown icce in resolve_method if (resolved_klass->is_interface() && resolved_method->is_private()) { ResourceMark rm(THREAD); - stringStream ss; - ss.print("private interface method requires invokespecial, not invokevirtual: method '"); - resolved_method->print_external_name(&ss); - ss.print("', caller-class: %s", - (current_klass == NULL ? "" : current_klass->internal_name())); - THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), ss.as_string()); + char buf[200]; + jio_snprintf(buf, sizeof(buf), "private interface method requires invokespecial, not invokevirtual: method %s, caller-class:%s", + Method::name_and_sig_as_C_string(resolved_klass, + resolved_method->name(), + resolved_method->signature()), + (current_klass == NULL ? "" : current_klass->internal_name())); + THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), buf); } // check if not static if (resolved_method->is_static()) { ResourceMark rm(THREAD); - stringStream ss; - ss.print("Expecting non-static method '"); - resolved_method->print_external_name(&ss); - ss.print("'"); - THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), ss.as_string()); + char buf[200]; + jio_snprintf(buf, sizeof(buf), "Expecting non-static method %s", Method::name_and_sig_as_C_string(resolved_klass, + resolved_method->name(), + resolved_method->signature())); + THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), buf); } if (log_develop_is_enabled(Trace, vtables)) { @@ -1469,11 +1470,10 @@ // Throw Illegal Access Error if selected_method is not public. if (!selected_method->is_public()) { ResourceMark rm(THREAD); - stringStream ss; - ss.print("'"); - Method::print_external_name(&ss, recv_klass, selected_method->name(), selected_method->signature()); - ss.print("'"); - THROW_MSG(vmSymbols::java_lang_IllegalAccessError(), ss.as_string()); + THROW_MSG(vmSymbols::java_lang_IllegalAccessError(), + Method::name_and_sig_as_C_string(recv_klass, + selected_method->name(), + selected_method->signature())); } // check if abstract if (check_null_and_abstract && selected_method->is_abstract()) { @@ -1806,22 +1806,19 @@ } assert(resolved_method.not_null(), "Sanity"); - ss.print(" resolved method '%s%s", + ss.print(" resolved method %s%s%s%s of %s %s.", resolved_method->is_abstract() ? "abstract " : "", - resolved_method->is_private() ? "private " : ""); - resolved_method->signature()->print_as_signature_external_return_type(&ss); - ss.print(" %s(", resolved_method->name()->as_C_string()); - resolved_method->signature()->print_as_signature_external_parameters(&ss); - ss.print(")' of %s %s.", + resolved_method->is_private() ? "private " : "", + resolved_method->name()->as_C_string(), + resolved_method->signature()->as_C_string(), resolved_klass->external_kind(), resolved_klass->external_name()); if (selected_method.not_null() && !(resolved_method == selected_method)) { - ss.print(" Selected method is '%s%s", + ss.print(" Selected method is %s%s%s.", selected_method->is_abstract() ? "abstract " : "", - selected_method->is_private() ? "private " : ""); - selected_method->print_external_name(&ss); - ss.print("'."); + selected_method->is_private() ? "private " : "", + selected_method->name_and_sig_as_C_string()); } THROW_MSG(vmSymbols::java_lang_AbstractMethodError(), ss.as_string()); --- old/src/hotspot/share/interpreter/linkResolver.hpp 2019-05-21 01:01:27.705135389 +0200 +++ new/src/hotspot/share/interpreter/linkResolver.hpp 2019-05-21 01:01:27.545135675 +0200 @@ -182,6 +182,7 @@ methodHandle current_method() const { return _current_method; } constantTag tag() const { return _tag; } bool check_access() const { return _check_access; } + char* method_string() const; void print() PRODUCT_RETURN; }; --- old/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampler.cpp 2019-05-21 01:01:27.917135007 +0200 +++ new/src/hotspot/share/jfr/periodic/sampling/jfrThreadSampler.cpp 2019-05-21 01:01:27.753135303 +0200 @@ -359,7 +359,7 @@ } bool ret = false; - thread->set_trace_flag(); // Provides StoreLoad, needed to keep read of thread state from floating up. + thread->set_trace_flag(); if (JAVA_SAMPLE == type) { if (thread_state_in_java(thread)) { ret = sample_thread_in_java(thread, frames, max_frames); --- old/src/hotspot/share/memory/allocation.cpp 2019-05-21 01:01:28.113134656 +0200 +++ new/src/hotspot/share/memory/allocation.cpp 2019-05-21 01:01:27.961134928 +0200 @@ -84,14 +84,8 @@ return Metaspace::allocate(loader_data, word_size, type, THREAD); } -bool MetaspaceObj::is_valid(const MetaspaceObj* p) { - // Weed out obvious bogus values first without traversing metaspace - if ((size_t)p < os::min_page_size()) { - return false; - } else if (!is_aligned((address)p, sizeof(MetaWord))) { - return false; - } - return Metaspace::contains((void*)p); +bool MetaspaceObj::is_metaspace_object() const { + return Metaspace::contains((void*)this); } void MetaspaceObj::print_address_on(outputStream* st) const { --- old/src/hotspot/share/memory/allocation.hpp 2019-05-21 01:01:28.309134306 +0200 +++ new/src/hotspot/share/memory/allocation.hpp 2019-05-21 01:01:28.157134579 +0200 @@ -258,19 +258,12 @@ static void* _shared_metaspace_top; // (exclusive) high address public: - - // Returns true if the pointer points to a valid MetaspaceObj. A valid - // MetaspaceObj is MetaWord-aligned and contained within either - // non-shared or shared metaspace. - static bool is_valid(const MetaspaceObj* p); - - static bool is_shared(const MetaspaceObj* p) { + bool is_metaspace_object() const; + bool is_shared() const { // If no shared metaspace regions are mapped, _shared_metaspace_{base,top} will // both be NULL and all values of p will be rejected quickly. - return (((void*)p) < _shared_metaspace_top && ((void*)p) >= _shared_metaspace_base); + return (((void*)this) < _shared_metaspace_top && ((void*)this) >= _shared_metaspace_base); } - bool is_shared() const { return MetaspaceObj::is_shared(this); } - void print_address_on(outputStream* st) const; // nonvirtual address printing static void set_shared_metaspace_range(void* base, void* top) { --- old/src/hotspot/share/memory/metaspace/virtualSpaceList.cpp 2019-05-21 01:01:28.509133947 +0200 +++ new/src/hotspot/share/memory/metaspace/virtualSpaceList.cpp 2019-05-21 01:01:28.353134227 +0200 @@ -92,9 +92,9 @@ assert_lock_strong(MetaspaceExpand_lock); // Don't use a VirtualSpaceListIterator because this // list is being changed and a straightforward use of an iterator is not safe. + VirtualSpaceNode* purged_vsl = NULL; VirtualSpaceNode* prev_vsl = virtual_space_list(); VirtualSpaceNode* next_vsl = prev_vsl; - int num_purged_nodes = 0; while (next_vsl != NULL) { VirtualSpaceNode* vsl = next_vsl; DEBUG_ONLY(vsl->verify(false);) @@ -118,17 +118,20 @@ dec_reserved_words(vsl->reserved_words()); dec_committed_words(vsl->committed_words()); dec_virtual_space_count(); + purged_vsl = vsl; delete vsl; - num_purged_nodes ++; } else { prev_vsl = vsl; } } - - // Verify list #ifdef ASSERT - if (num_purged_nodes > 0) { - verify(false); + if (purged_vsl != NULL) { + // List should be stable enough to use an iterator here. + VirtualSpaceListIterator iter(virtual_space_list()); + while (iter.repeat()) { + VirtualSpaceNode* vsl = iter.get_next(); + assert(vsl != purged_vsl, "Purge of vsl failed"); + } } #endif } @@ -140,13 +143,11 @@ VirtualSpaceNode* VirtualSpaceList::find_enclosing_space(const void* ptr) { // List should be stable enough to use an iterator here because removing virtual // space nodes is only allowed at a safepoint. - if (is_within_envelope((address)ptr)) { - VirtualSpaceListIterator iter(virtual_space_list()); - while (iter.repeat()) { - VirtualSpaceNode* vsn = iter.get_next(); - if (vsn->contains(ptr)) { - return vsn; - } + VirtualSpaceListIterator iter(virtual_space_list()); + while (iter.repeat()) { + VirtualSpaceNode* vsn = iter.get_next(); + if (vsn->contains(ptr)) { + return vsn; } } return NULL; @@ -169,9 +170,7 @@ _is_class(false), _reserved_words(0), _committed_words(0), - _virtual_space_count(0), - _envelope_lo((address)max_uintx), - _envelope_hi(NULL) { + _virtual_space_count(0) { MutexLockerEx cl(MetaspaceExpand_lock, Mutex::_no_safepoint_check_flag); create_new_virtual_space(word_size); @@ -183,17 +182,12 @@ _is_class(true), _reserved_words(0), _committed_words(0), - _virtual_space_count(0), - _envelope_lo((address)max_uintx), - _envelope_hi(NULL) { + _virtual_space_count(0) { MutexLockerEx cl(MetaspaceExpand_lock, Mutex::_no_safepoint_check_flag); VirtualSpaceNode* class_entry = new VirtualSpaceNode(is_class(), rs); bool succeeded = class_entry->initialize(); if (succeeded) { - expand_envelope_to_include_node(class_entry); - // ensure lock-free iteration sees fully initialized node - OrderAccess::storestore(); link_vs(class_entry); } } @@ -230,16 +224,12 @@ } else { assert(new_entry->reserved_words() == vs_word_size, "Reserved memory size differs from requested memory size"); - expand_envelope_to_include_node(new_entry); // ensure lock-free iteration sees fully initialized node OrderAccess::storestore(); link_vs(new_entry); DEBUG_ONLY(Atomic::inc(&g_internal_statistics.num_vsnodes_created)); return true; } - - DEBUG_ONLY(verify(false);) - } void VirtualSpaceList::link_vs(VirtualSpaceNode* new_entry) { @@ -409,41 +399,5 @@ } } -// Given a node, expand range such that it includes the node. -void VirtualSpaceList::expand_envelope_to_include_node(const VirtualSpaceNode* node) { - _envelope_lo = MIN2(_envelope_lo, (address)node->low_boundary()); - _envelope_hi = MAX2(_envelope_hi, (address)node->high_boundary()); -} - - -#ifdef ASSERT -void VirtualSpaceList::verify(bool slow) { - VirtualSpaceNode* list = virtual_space_list(); - VirtualSpaceListIterator iter(list); - size_t reserved = 0; - size_t committed = 0; - size_t node_count = 0; - while (iter.repeat()) { - VirtualSpaceNode* node = iter.get_next(); - if (slow) { - node->verify(true); - } - // Check that the node resides fully within our envelope. - assert((address)node->low_boundary() >= _envelope_lo && (address)node->high_boundary() <= _envelope_hi, - "Node " SIZE_FORMAT " [" PTR_FORMAT ", " PTR_FORMAT ") outside envelope [" PTR_FORMAT ", " PTR_FORMAT ").", - node_count, p2i(node->low_boundary()), p2i(node->high_boundary()), p2i(_envelope_lo), p2i(_envelope_hi)); - reserved += node->reserved_words(); - committed += node->committed_words(); - node_count ++; - } - assert(reserved == reserved_words() && committed == committed_words() && node_count == _virtual_space_count, - "Mismatch: reserved real: " SIZE_FORMAT " expected: " SIZE_FORMAT - ", committed real: " SIZE_FORMAT " expected: " SIZE_FORMAT - ", node count real: " SIZE_FORMAT " expected: " SIZE_FORMAT ".", - reserved, reserved_words(), committed, committed_words(), - node_count, _virtual_space_count); -} -#endif // ASSERT - } // namespace metaspace --- old/src/hotspot/share/memory/metaspace/virtualSpaceList.hpp 2019-05-21 01:01:28.721133567 +0200 +++ new/src/hotspot/share/memory/metaspace/virtualSpaceList.hpp 2019-05-21 01:01:28.553133868 +0200 @@ -58,19 +58,6 @@ // Number of virtual spaces size_t _virtual_space_count; - // Optimization: we keep an address range to quickly exclude pointers - // which are clearly not pointing into metaspace. This is an optimization for - // VirtualSpaceList::contains(). - address _envelope_lo; - address _envelope_hi; - - bool is_within_envelope(address p) const { - return p >= _envelope_lo && p < _envelope_hi; - } - - // Given a node, expand range such that it includes the node. - void expand_envelope_to_include_node(const VirtualSpaceNode* node); - ~VirtualSpaceList(); VirtualSpaceNode* virtual_space_list() const { return _virtual_space_list; } @@ -93,8 +80,6 @@ // virtual space and add the chunks to the free list. void retire_current_virtual_space(); - DEBUG_ONLY(bool contains_node(const VirtualSpaceNode* node) const;) - public: VirtualSpaceList(size_t word_size); VirtualSpaceList(ReservedSpace rs); @@ -141,8 +126,6 @@ void print_on(outputStream* st, size_t scale) const; void print_map(outputStream* st) const; - DEBUG_ONLY(void verify(bool slow);) - class VirtualSpaceListIterator : public StackObj { VirtualSpaceNode* _virtual_spaces; public: --- old/src/hotspot/share/memory/metaspace/virtualSpaceNode.hpp 2019-05-21 01:01:28.917133215 +0200 +++ new/src/hotspot/share/memory/metaspace/virtualSpaceNode.hpp 2019-05-21 01:01:28.765133488 +0200 @@ -60,8 +60,6 @@ // Convenience functions to access the _virtual_space char* low() const { return virtual_space()->low(); } char* high() const { return virtual_space()->high(); } - char* low_boundary() const { return virtual_space()->low_boundary(); } - char* high_boundary() const { return virtual_space()->high_boundary(); } // The first Metachunk will be allocated at the bottom of the // VirtualSpace --- old/src/hotspot/share/oops/constantPool.cpp 2019-05-21 01:01:29.113132864 +0200 +++ new/src/hotspot/share/oops/constantPool.cpp 2019-05-21 01:01:28.957133144 +0200 @@ -1000,17 +1000,14 @@ if ((callee->is_interface() && m_tag.is_method()) || ((!callee->is_interface() && m_tag.is_interface_method()))) { ResourceMark rm(THREAD); - stringStream ss; - ss.print("Inconsistent constant pool data in classfile for class %s. " - "Method '", callee->name()->as_C_string()); - signature->print_as_signature_external_return_type(&ss); - ss.print(" %s(", name->as_C_string()); - signature->print_as_signature_external_parameters(&ss); - ss.print(")' at index %d is %s and should be %s", - index, - callee->is_interface() ? "CONSTANT_MethodRef" : "CONSTANT_InterfaceMethodRef", - callee->is_interface() ? "CONSTANT_InterfaceMethodRef" : "CONSTANT_MethodRef"); - THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), ss.as_string()); + char buf[400]; + jio_snprintf(buf, sizeof(buf), + "Inconsistent constant pool data in classfile for class %s. " + "Method %s%s at index %d is %s and should be %s", + callee->name()->as_C_string(), name->as_C_string(), signature->as_C_string(), index, + callee->is_interface() ? "CONSTANT_MethodRef" : "CONSTANT_InterfaceMethodRef", + callee->is_interface() ? "CONSTANT_InterfaceMethodRef" : "CONSTANT_MethodRef"); + THROW_MSG_NULL(vmSymbols::java_lang_IncompatibleClassChangeError(), buf); } Klass* klass = this_cp->pool_holder(); --- old/src/hotspot/share/oops/instanceKlass.cpp 2019-05-21 01:01:29.325132484 +0200 +++ new/src/hotspot/share/oops/instanceKlass.cpp 2019-05-21 01:01:29.173132757 +0200 @@ -3104,7 +3104,7 @@ for (int i = 0; i < len; i++) { intptr_t e = start[i]; st->print("%d : " INTPTR_FORMAT, i, e); - if (MetaspaceObj::is_valid((Metadata*)e)) { + if (e != 0 && ((Metadata*)e)->is_metaspace_object()) { st->print(" "); ((Metadata*)e)->print_value_on(st); } --- old/src/hotspot/share/oops/klassVtable.cpp 2019-05-21 01:01:29.545132089 +0200 +++ new/src/hotspot/share/oops/klassVtable.cpp 2019-05-21 01:01:29.393132362 +0200 @@ -500,11 +500,11 @@ if (failed_type_symbol != NULL) { stringStream ss; ss.print("loader constraint violation for class %s: when selecting " - "overriding method '", klass->external_name()); - target_method()->print_external_name(&ss), - ss.print("' the class loader %s of the " + "overriding method %s the class loader %s of the " "selected method's type %s, and the class loader %s for its super " "type %s have different Class objects for the type %s used in the signature (%s; %s)", + klass->external_name(), + target_method()->name_and_sig_as_C_string(), target_klass->class_loader_data()->loader_name_and_id(), target_klass->external_name(), super_klass->class_loader_data()->loader_name_and_id(), @@ -1227,16 +1227,15 @@ if (failed_type_symbol != NULL) { stringStream ss; ss.print("loader constraint violation in interface itable" - " initialization for class %s: when selecting method '", - _klass->external_name()); - m->print_external_name(&ss), - ss.print("' the class loader %s for super interface %s, and the class" - " loader %s of the selected method's %s, %s have" + " initialization for class %s: when selecting method %s the" + " class loader %s for super interface %s, and the class" + " loader %s of the selected method's type, %s have" " different Class objects for the type %s used in the signature (%s; %s)", + _klass->external_name(), + m->name_and_sig_as_C_string(), interf->class_loader_data()->loader_name_and_id(), interf->external_name(), target()->method_holder()->class_loader_data()->loader_name_and_id(), - target()->method_holder()->external_kind(), target()->method_holder()->external_name(), failed_type_symbol->as_klass_external_name(), interf->class_in_module_of_loader(false, true), --- old/src/hotspot/share/oops/method.cpp 2019-05-21 01:01:29.753131717 +0200 +++ new/src/hotspot/share/oops/method.cpp 2019-05-21 01:01:29.597131995 +0200 @@ -178,27 +178,6 @@ return buf; } -const char* Method::external_name() const { - return external_name(constants()->pool_holder(), name(), signature()); -} - -void Method::print_external_name(outputStream *os) const { - print_external_name(os, constants()->pool_holder(), name(), signature()); -} - -const char* Method::external_name(Klass* klass, Symbol* method_name, Symbol* signature) { - stringStream ss; - print_external_name(&ss, klass, method_name, signature); - return ss.as_string(); -} - -void Method::print_external_name(outputStream *os, Klass* klass, Symbol* method_name, Symbol* signature) { - signature->print_as_signature_external_return_type(os); - os->print(" %s.%s(", klass->external_name(), method_name->as_C_string()); - signature->print_as_signature_external_parameters(os); - os->print(")"); -} - int Method::fast_exception_handler_bci_for(const methodHandle& mh, Klass* ex_klass, int throw_bci, TRAPS) { // exception table holds quadruple entries of the form (beg_bci, end_bci, handler_bci, klass_index) // access exception table --- old/src/hotspot/share/oops/method.hpp 2019-05-21 01:01:29.969131330 +0200 +++ new/src/hotspot/share/oops/method.hpp 2019-05-21 01:01:29.809131615 +0200 @@ -180,8 +180,8 @@ } // Helper routine: get klass name + "." + method name + signature as - // C string, for the purpose of providing more useful - // fatal error handling. The string is allocated in resource + // C string, for the purpose of providing more useful NoSuchMethodErrors + // and fatal error handling. The string is allocated in resource // area if a buffer is not provided by the caller. char* name_and_sig_as_C_string() const; char* name_and_sig_as_C_string(char* buf, int size) const; @@ -190,18 +190,6 @@ static char* name_and_sig_as_C_string(Klass* klass, Symbol* method_name, Symbol* signature); static char* name_and_sig_as_C_string(Klass* klass, Symbol* method_name, Symbol* signature, char* buf, int size); - // Get return type + klass name + "." + method name + ( parameters types ) - // as a C string or print it to an outputStream. - // This is to be used to assemble strings passed to Java, so that - // the text more resembles Java code. Used in exception messages. - // Memory is allocated in the resource area; the caller needs - // a ResourceMark. - const char* external_name() const; - void print_external_name(outputStream *os) const; - - static const char* external_name( Klass* klass, Symbol* method_name, Symbol* signature); - static void print_external_name(outputStream *os, Klass* klass, Symbol* method_name, Symbol* signature); - Bytecodes::Code java_code_at(int bci) const { return Bytecodes::java_code_at(this, bcp_from(bci)); } --- old/src/hotspot/share/oops/symbol.cpp 2019-05-21 01:01:30.173130963 +0200 +++ new/src/hotspot/share/oops/symbol.cpp 2019-05-21 01:01:30.017131243 +0200 @@ -200,66 +200,6 @@ return str; } -static void print_class(outputStream *os, char *class_str, int len) { - for (int i = 0; i < len; ++i) { - if (class_str[i] == '/') { - os->put('.'); - } else { - os->put(class_str[i]); - } - } -} - -static void print_array(outputStream *os, char *array_str, int len) { - int dimensions = 0; - for (int i = 0; i < len; ++i) { - if (array_str[i] == '[') { - dimensions++; - } else if (array_str[i] == 'L') { - // Expected format: L;. Skip 'L' and ';' delimiting the type name. - print_class(os, array_str+i+1, len-i-2); - break; - } else { - os->print("%s", type2name(char2type(array_str[i]))); - } - } - for (int i = 0; i < dimensions; ++i) { - os->print("[]"); - } -} - -void Symbol::print_as_signature_external_return_type(outputStream *os) { - for (SignatureStream ss(this); !ss.is_done(); ss.next()) { - if (ss.at_return_type()) { - if (ss.is_array()) { - print_array(os, (char*)ss.raw_bytes(), (int)ss.raw_length()); - } else if (ss.is_object()) { - // Expected format: L;. Skip 'L' and ';' delimiting the class name. - print_class(os, (char*)ss.raw_bytes()+1, (int)ss.raw_length()-2); - } else { - os->print("%s", type2name(ss.type())); - } - } - } -} - -void Symbol::print_as_signature_external_parameters(outputStream *os) { - bool first = true; - for (SignatureStream ss(this); !ss.is_done(); ss.next()) { - if (ss.at_return_type()) break; - if (!first) { os->print(", "); } - if (ss.is_array()) { - print_array(os, (char*)ss.raw_bytes(), (int)ss.raw_length()); - } else if (ss.is_object()) { - // Skip 'L' and ';'. - print_class(os, (char*)ss.raw_bytes()+1, (int)ss.raw_length()-2); - } else { - os->print("%s", type2name(ss.type())); - } - first = false; - } -} - // Increment refcount while checking for zero. If the Symbol's refcount becomes zero // a thread could be concurrently removing the Symbol. This is used during SymbolTable // lookup to avoid reviving a dead Symbol. --- old/src/hotspot/share/oops/symbol.hpp 2019-05-21 01:01:30.369130611 +0200 +++ new/src/hotspot/share/oops/symbol.hpp 2019-05-21 01:01:30.217130884 +0200 @@ -229,15 +229,6 @@ const char* as_klass_external_name() const; const char* as_klass_external_name(char* buf, int size) const; - // Treating the symbol as a signature, print the return - // type to the outputStream. Prints external names as 'double' or - // 'java.lang.Object[][]'. - void print_as_signature_external_return_type(outputStream *os); - // Treating the symbol as a signature, print the parameter types - // seperated by ', ' to the outputStream. Prints external names as - // 'double' or 'java.lang.Object[][]'. - void print_as_signature_external_parameters(outputStream *os); - void metaspace_pointers_do(MetaspaceClosure* it); MetaspaceObj::Type type() const { return SymbolType; } --- old/src/hotspot/share/oops/weakHandle.cpp 2019-05-21 01:01:30.573130247 +0200 +++ new/src/hotspot/share/oops/weakHandle.cpp 2019-05-21 01:01:30.413130532 +0200 @@ -29,7 +29,6 @@ #include "oops/access.inline.hpp" #include "oops/oop.hpp" #include "oops/weakHandle.inline.hpp" -#include "prims/resolvedMethodTable.hpp" #include "utilities/debug.hpp" #include "utilities/ostream.hpp" @@ -41,10 +40,6 @@ return StringTable::weak_storage(); } -template <> OopStorage* WeakHandle::get_storage() { - return ResolvedMethodTable::weak_storage(); -} - template WeakHandle WeakHandle::create(Handle obj) { assert(obj() != NULL, "no need to create weak null oop"); @@ -79,4 +74,4 @@ // Provide instantiation. template class WeakHandle; template class WeakHandle; -template class WeakHandle; + --- old/src/hotspot/share/oops/weakHandle.hpp 2019-05-21 01:01:30.769129895 +0200 +++ new/src/hotspot/share/oops/weakHandle.hpp 2019-05-21 01:01:30.613130175 +0200 @@ -39,7 +39,7 @@ // This is the vm version of jweak but has different GC lifetimes and policies, // depending on the type. -enum WeakHandleType { vm_class_loader_data, vm_string_table_data, vm_resolved_method_table_data }; +enum WeakHandleType { vm_class_loader_data, vm_string_table_data }; template class WeakHandle { @@ -64,4 +64,6 @@ void print_on(outputStream* st) const; }; +typedef WeakHandle ClassLoaderWeakHandle; + #endif // SHARE_OOPS_WEAKHANDLE_HPP --- old/src/hotspot/share/prims/jni.cpp 2019-05-21 01:01:30.965129543 +0200 +++ new/src/hotspot/share/prims/jni.cpp 2019-05-21 01:01:30.809129824 +0200 @@ -2955,9 +2955,8 @@ if (method == NULL) { ResourceMark rm; stringStream st; - st.print("Method '"); - Method::print_external_name(&st, k, name, signature); - st.print("' name or signature does not match"); + st.print("Method %s name or signature does not match", + Method::name_and_sig_as_C_string(k, name, signature)); THROW_MSG_(vmSymbols::java_lang_NoSuchMethodError(), st.as_string(), false); } if (!method->is_native()) { @@ -2966,9 +2965,8 @@ if (method == NULL) { ResourceMark rm; stringStream st; - st.print("Method '"); - Method::print_external_name(&st, k, name, signature); - st.print("' is not declared as native"); + st.print("Method %s is not declared as native", + Method::name_and_sig_as_C_string(k, name, signature)); THROW_MSG_(vmSymbols::java_lang_NoSuchMethodError(), st.as_string(), false); } } @@ -3971,7 +3969,7 @@ #endif // Since this is not a JVM_ENTRY we have to set the thread state manually before leaving. - ThreadStateTransition::transition(thread, _thread_in_vm, _thread_in_native); + ThreadStateTransition::transition_and_fence(thread, _thread_in_vm, _thread_in_native); } else { // If create_vm exits because of a pending exception, exit with that // exception. In the future when we figure out how to reclaim memory, @@ -4073,7 +4071,7 @@ res = JNI_OK; return res; } else { - ThreadStateTransition::transition(thread, _thread_in_vm, _thread_in_native); + ThreadStateTransition::transition_and_fence(thread, _thread_in_vm, _thread_in_native); res = JNI_ERR; return res; } @@ -4195,7 +4193,7 @@ // using ThreadStateTransition::transition, we do a callback to the safepoint code if // needed. - ThreadStateTransition::transition(thread, _thread_in_vm, _thread_in_native); + ThreadStateTransition::transition_and_fence(thread, _thread_in_vm, _thread_in_native); // Perform any platform dependent FPU setup os::setup_fpu(); --- old/src/hotspot/share/prims/jvmtiCodeBlobEvents.cpp 2019-05-21 01:01:31.213129100 +0200 +++ new/src/hotspot/share/prims/jvmtiCodeBlobEvents.cpp 2019-05-21 01:01:31.045129401 +0200 @@ -236,7 +236,7 @@ // Don't hold the lock over the notify or jmethodID creation MutexUnlockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); current->get_and_cache_jmethod_id(); - JvmtiExport::post_compiled_method_load(env, current); + JvmtiExport::post_compiled_method_load(current); } return JVMTI_ERROR_NONE; } --- old/src/hotspot/share/prims/jvmtiExport.cpp 2019-05-21 01:01:31.413128741 +0200 +++ new/src/hotspot/share/prims/jvmtiExport.cpp 2019-05-21 01:01:31.253129026 +0200 @@ -2170,37 +2170,61 @@ JvmtiEnvIterator it; for (JvmtiEnv* env = it.first(); env != NULL; env = it.next(env)) { - post_compiled_method_load(env, nm); + if (env->is_enabled(JVMTI_EVENT_COMPILED_METHOD_LOAD)) { + if (env->phase() == JVMTI_PHASE_PRIMORDIAL) { + continue; + } + EVT_TRACE(JVMTI_EVENT_COMPILED_METHOD_LOAD, + ("[%s] class compile method load event sent %s.%s ", + JvmtiTrace::safe_get_thread_name(thread), + (nm->method() == NULL) ? "NULL" : nm->method()->klass_name()->as_C_string(), + (nm->method() == NULL) ? "NULL" : nm->method()->name()->as_C_string())); + ResourceMark rm(thread); + HandleMark hm(thread); + + // Add inlining information + jvmtiCompiledMethodLoadInlineRecord* inlinerecord = create_inline_record(nm); + // Pass inlining information through the void pointer + JvmtiCompiledMethodLoadEventMark jem(thread, nm, inlinerecord); + JvmtiJavaThreadEventTransition jet(thread); + jvmtiEventCompiledMethodLoad callback = env->callbacks()->CompiledMethodLoad; + if (callback != NULL) { + (*callback)(env->jvmti_external(), jem.jni_methodID(), + jem.code_size(), jem.code_data(), jem.map_length(), + jem.map(), jem.compile_info()); + } + } } } + // post a COMPILED_METHOD_LOAD event for a given environment -void JvmtiExport::post_compiled_method_load(JvmtiEnv* env, nmethod *nm) { - if (env->phase() == JVMTI_PHASE_PRIMORDIAL || !env->is_enabled(JVMTI_EVENT_COMPILED_METHOD_LOAD)) { - return; - } - jvmtiEventCompiledMethodLoad callback = env->callbacks()->CompiledMethodLoad; - if (callback == NULL) { +void JvmtiExport::post_compiled_method_load(JvmtiEnv* env, const jmethodID method, const jint length, + const void *code_begin, const jint map_length, + const jvmtiAddrLocationMap* map) +{ + if (env->phase() <= JVMTI_PHASE_PRIMORDIAL) { return; } JavaThread* thread = JavaThread::current(); + EVT_TRIG_TRACE(JVMTI_EVENT_COMPILED_METHOD_LOAD, + ("[%s] method compile load event triggered (by GenerateEvents)", + JvmtiTrace::safe_get_thread_name(thread))); + if (env->is_enabled(JVMTI_EVENT_COMPILED_METHOD_LOAD)) { + + EVT_TRACE(JVMTI_EVENT_COMPILED_METHOD_LOAD, + ("[%s] class compile method load event sent (by GenerateEvents), jmethodID=" PTR_FORMAT, + JvmtiTrace::safe_get_thread_name(thread), p2i(method))); - EVT_TRACE(JVMTI_EVENT_COMPILED_METHOD_LOAD, - ("[%s] method compile load event sent %s.%s ", - JvmtiTrace::safe_get_thread_name(thread), - (nm->method() == NULL) ? "NULL" : nm->method()->klass_name()->as_C_string(), - (nm->method() == NULL) ? "NULL" : nm->method()->name()->as_C_string())); - ResourceMark rm(thread); - HandleMark hm(thread); - - // Add inlining information - jvmtiCompiledMethodLoadInlineRecord* inlinerecord = create_inline_record(nm); - // Pass inlining information through the void pointer - JvmtiCompiledMethodLoadEventMark jem(thread, nm, inlinerecord); - JvmtiJavaThreadEventTransition jet(thread); - (*callback)(env->jvmti_external(), jem.jni_methodID(), - jem.code_size(), jem.code_data(), jem.map_length(), - jem.map(), jem.compile_info()); + JvmtiEventMark jem(thread); + JvmtiJavaThreadEventTransition jet(thread); + jvmtiEventCompiledMethodLoad callback = env->callbacks()->CompiledMethodLoad; + if (callback != NULL) { + (*callback)(env->jvmti_external(), method, + length, code_begin, map_length, + map, NULL); + } + } } void JvmtiExport::post_dynamic_code_generated_internal(const char *name, const void *code_begin, const void *code_end) { --- old/src/hotspot/share/prims/jvmtiExport.hpp 2019-05-21 01:01:31.637128338 +0200 +++ new/src/hotspot/share/prims/jvmtiExport.hpp 2019-05-21 01:01:31.481128618 +0200 @@ -165,7 +165,9 @@ // DynamicCodeGenerated events for a given environment. friend class JvmtiCodeBlobEvents; - static void post_compiled_method_load(JvmtiEnv* env, nmethod *nm) NOT_JVMTI_RETURN; + static void post_compiled_method_load(JvmtiEnv* env, const jmethodID method, const jint length, + const void *code_begin, const jint map_length, + const jvmtiAddrLocationMap* map) NOT_JVMTI_RETURN; static void post_dynamic_code_generated(JvmtiEnv* env, const char *name, const void *code_begin, const void *code_end) NOT_JVMTI_RETURN; --- old/src/hotspot/share/prims/jvmtiRawMonitor.cpp 2019-05-21 01:01:31.833127986 +0200 +++ new/src/hotspot/share/prims/jvmtiRawMonitor.cpp 2019-05-21 01:01:31.681128259 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -167,12 +167,7 @@ RawMonitor_lock->unlock() ; if (w != NULL) { guarantee (w ->TState == ObjectWaiter::TS_ENTER, "invariant") ; - // Once we set TState to TS_RUN the waiting thread can complete - // SimpleEnter and 'w' is pointing into random stack space. So we have - // to ensure we extract the ParkEvent (which is in type-stable memory) - // before we set the state, and then don't access 'w'. ParkEvent * ev = w->_event ; - OrderAccess::loadstore(); w->TState = ObjectWaiter::TS_RUN ; OrderAccess::fence() ; ev->unpark() ; @@ -205,7 +200,7 @@ // If thread still resides on the waitset then unlink it. // Double-checked locking -- the usage is safe in this context - // as TState is volatile and the lock-unlock operators are + // as we TState is volatile and the lock-unlock operators are // serializing (barrier-equivalent). if (Node.TState == ObjectWaiter::TS_WAIT) { --- old/src/hotspot/share/prims/nativeLookup.cpp 2019-05-21 01:01:32.037127622 +0200 +++ new/src/hotspot/share/prims/nativeLookup.cpp 2019-05-21 01:01:31.881127902 +0200 @@ -380,11 +380,8 @@ if (entry != NULL) return entry; // Native function not found, throw UnsatisfiedLinkError - stringStream ss; - ss.print("'"); - method->print_external_name(&ss); - ss.print("'"); - THROW_MSG_0(vmSymbols::java_lang_UnsatisfiedLinkError(), ss.as_string()); + THROW_MSG_0(vmSymbols::java_lang_UnsatisfiedLinkError(), + method->name_and_sig_as_C_string()); } --- old/src/hotspot/share/prims/resolvedMethodTable.cpp 2019-05-21 01:01:32.233127270 +0200 +++ new/src/hotspot/share/prims/resolvedMethodTable.cpp 2019-05-21 01:01:32.081127543 +0200 @@ -24,422 +24,226 @@ #include "precompiled.hpp" #include "classfile/javaClasses.hpp" -#include "gc/shared/oopStorage.inline.hpp" #include "logging/log.hpp" #include "memory/allocation.hpp" #include "memory/resourceArea.hpp" #include "oops/access.inline.hpp" #include "oops/oop.inline.hpp" #include "oops/method.hpp" +#include "oops/symbol.hpp" #include "oops/weakHandle.inline.hpp" #include "prims/resolvedMethodTable.hpp" #include "runtime/handles.inline.hpp" -#include "runtime/interfaceSupport.inline.hpp" #include "runtime/mutexLocker.hpp" #include "runtime/safepointVerifiers.hpp" -#include "runtime/timerTrace.hpp" -#include "utilities/concurrentHashTable.inline.hpp" -#include "utilities/concurrentHashTableTasks.inline.hpp" +#include "utilities/hashtable.inline.hpp" #include "utilities/macros.hpp" -// 2^24 is max size -static const size_t END_SIZE = 24; -// If a chain gets to 32 something might be wrong -static const size_t GROW_HINT = 32; -static const size_t ResolvedMethodTableSizeLog = 10; - -unsigned int method_hash(const Method* method) { - unsigned int name_hash = method->name()->identity_hash(); - unsigned int signature_hash = method->signature()->identity_hash(); - return name_hash ^ signature_hash; +oop ResolvedMethodEntry::object() { + return literal().resolve(); } -class ResolvedMethodTableConfig : public ResolvedMethodTableHash::BaseConfig { - private: - public: - static uintx get_hash(WeakHandle const& value, - bool* is_dead) { - EXCEPTION_MARK; - oop val_oop = value.peek(); - if (val_oop == NULL) { - *is_dead = true; - return 0; - } - *is_dead = false; - Method* method = java_lang_invoke_ResolvedMethodName::vmtarget(val_oop); - return method_hash(method); - } - - // We use default allocation/deallocation but counted - static void* allocate_node(size_t size, WeakHandle const& value) { - ResolvedMethodTable::item_added(); - return ResolvedMethodTableHash::BaseConfig::allocate_node(size, value); - } - static void free_node(void* memory, WeakHandle const& value) { - value.release(); - ResolvedMethodTableHash::BaseConfig::free_node(memory, value); - ResolvedMethodTable::item_removed(); - } -}; - -ResolvedMethodTableHash* ResolvedMethodTable::_local_table = NULL; -size_t ResolvedMethodTable::_current_size = (size_t)1 << ResolvedMethodTableSizeLog; - -OopStorage* ResolvedMethodTable::_weak_handles = NULL; - -volatile bool ResolvedMethodTable::_has_work = false; -volatile size_t ResolvedMethodTable::_items_count = 0; -volatile size_t ResolvedMethodTable::_uncleaned_items_count = 0; - -void ResolvedMethodTable::create_table() { - _local_table = new ResolvedMethodTableHash(ResolvedMethodTableSizeLog, END_SIZE, GROW_HINT); - _weak_handles = new OopStorage("ResolvedMethodTable weak", - ResolvedMethodTableWeakAlloc_lock, - ResolvedMethodTableWeakActive_lock); - log_trace(membername, table)("Start size: " SIZE_FORMAT " (" SIZE_FORMAT ")", - _current_size, ResolvedMethodTableSizeLog); -} - -size_t ResolvedMethodTable::table_size() { - return (size_t)1 << _local_table->get_size_log2(Thread::current()); -} - -class ResolvedMethodTableLookup : StackObj { - private: - Thread* _thread; - uintx _hash; - const Method* _method; - Handle _found; - - public: - ResolvedMethodTableLookup(Thread* thread, uintx hash, const Method* key) - : _thread(thread), _hash(hash), _method(key) { - } - uintx get_hash() const { - return _hash; - } - bool equals(WeakHandle* value, bool* is_dead) { - oop val_oop = value->peek(); - if (val_oop == NULL) { - // dead oop, mark this hash dead for cleaning - *is_dead = true; - return false; - } - bool equals = _method == java_lang_invoke_ResolvedMethodName::vmtarget(val_oop); - if (!equals) { - return false; - } - // Need to resolve weak handle and Handleize through possible safepoint. - _found = Handle(_thread, value->resolve()); - return true; - } -}; - - -class ResolvedMethodGet : public StackObj { - Thread* _thread; - const Method* _method; - Handle _return; -public: - ResolvedMethodGet(Thread* thread, const Method* method) : _thread(thread), _method(method) {} - void operator()(WeakHandle* val) { - oop result = val->resolve(); - assert(result != NULL, "Result should be reachable"); - _return = Handle(_thread, result); - log_get(); - } - oop get_res_oop() { - return _return(); - } - void log_get() { - LogTarget(Trace, membername, table) log; - if (log.is_enabled()) { - ResourceMark rm; - log.print("ResolvedMethod entry found for %s", - _method->name_and_sig_as_C_string()); +oop ResolvedMethodEntry::object_no_keepalive() { + // The AS_NO_KEEPALIVE peeks at the oop without keeping it alive. + // This is dangerous in general but is okay if the loaded oop does + // not leak out past a thread transition where a safepoint can happen. + // A subsequent oop_load without AS_NO_KEEPALIVE (the object() accessor) + // keeps the oop alive before doing so. + return literal().peek(); +} + +ResolvedMethodTable::ResolvedMethodTable() + : Hashtable(_table_size, sizeof(ResolvedMethodEntry)) { } + +oop ResolvedMethodTable::lookup(int index, unsigned int hash, Method* method) { + assert_locked_or_safepoint(ResolvedMethodTable_lock); + for (ResolvedMethodEntry* p = bucket(index); p != NULL; p = p->next()) { + if (p->hash() == hash) { + + // Peek the object to check if it is the right target. + oop target = p->object_no_keepalive(); + + // The method is in the table as a target already + if (target != NULL && java_lang_invoke_ResolvedMethodName::vmtarget(target) == method) { + ResourceMark rm; + log_debug(membername, table) ("ResolvedMethod entry found for %s index %d", + method->name_and_sig_as_C_string(), index); + // The object() accessor makes sure the target object is kept alive before + // leaking out. + return p->object(); + } } } -}; - -oop ResolvedMethodTable::find_method(const Method* method) { - Thread* thread = Thread::current(); - - ResolvedMethodTableLookup lookup(thread, method_hash(method), method); - ResolvedMethodGet rmg(thread, method); - _local_table->get(thread, lookup, rmg); - - return rmg.get_res_oop(); + return NULL; } -static void log_insert(const Method* method) { - LogTarget(Debug, membername, table) log; - if (log.is_enabled()) { - ResourceMark rm; - log_debug(membername, table) ("ResolvedMethod entry added for %s", - method->name_and_sig_as_C_string()); - } +unsigned int ResolvedMethodTable::compute_hash(Method* method) { + unsigned int name_hash = method->name()->identity_hash(); + unsigned int signature_hash = method->signature()->identity_hash(); + return name_hash ^ signature_hash; } -oop ResolvedMethodTable::add_method(const Method* method, Handle rmethod_name) { - Thread* thread = Thread::current(); - - ResolvedMethodTableLookup lookup(thread, method_hash(method), method); - ResolvedMethodGet rmg(thread, method); - - while (true) { - if (_local_table->get(thread, lookup, rmg)) { - return rmg.get_res_oop(); - } - WeakHandle wh = WeakHandle::create(rmethod_name); - // The hash table takes ownership of the WeakHandle, even if it's not inserted. - if (_local_table->insert(thread, lookup, wh)) { - log_insert(method); - return wh.resolve(); - } - } +oop ResolvedMethodTable::lookup(Method* method) { + unsigned int hash = compute_hash(method); + int index = hash_to_index(hash); + return lookup(index, hash, method); +} + +oop ResolvedMethodTable::basic_add(Method* method, Handle rmethod_name) { + assert_locked_or_safepoint(ResolvedMethodTable_lock); + + unsigned int hash = compute_hash(method); + int index = hash_to_index(hash); + + // One was added while aquiring the lock + oop entry = lookup(index, hash, method); + if (entry != NULL) { + return entry; + } + + ClassLoaderWeakHandle w = ClassLoaderWeakHandle::create(rmethod_name); + ResolvedMethodEntry* p = (ResolvedMethodEntry*) Hashtable::new_entry(hash, w); + Hashtable::add_entry(index, p); + ResourceMark rm; + log_debug(membername, table) ("ResolvedMethod entry added for %s index %d", + method->name_and_sig_as_C_string(), index); return rmethod_name(); } -void ResolvedMethodTable::item_added() { - Atomic::inc(&_items_count); -} +ResolvedMethodTable* ResolvedMethodTable::_the_table = NULL; -void ResolvedMethodTable::item_removed() { - Atomic::dec(&_items_count); - log_trace(membername, table) ("ResolvedMethod entry removed"); +oop ResolvedMethodTable::find_method(Method* method) { + MutexLocker ml(ResolvedMethodTable_lock); + oop entry = _the_table->lookup(method); + return entry; } -bool ResolvedMethodTable::has_work() { - return _has_work; -} +oop ResolvedMethodTable::add_method(const methodHandle& m, Handle resolved_method_name) { + MutexLocker ml(ResolvedMethodTable_lock); + DEBUG_ONLY(NoSafepointVerifier nsv); -OopStorage* ResolvedMethodTable::weak_storage() { - return _weak_handles; -} - -double ResolvedMethodTable::get_load_factor() { - return (double)_items_count/_current_size; -} + Method* method = m(); + // Check if method has been redefined while taking out ResolvedMethodTable_lock, if so + // use new method. The old method won't be deallocated because it's passed in as a Handle. + if (method->is_old()) { + // Replace method with redefined version + InstanceKlass* holder = method->method_holder(); + method = holder->method_with_idnum(method->method_idnum()); + if (method == NULL) { + // Replace deleted method with NSME. + method = Universe::throw_no_such_method_error(); + } + java_lang_invoke_ResolvedMethodName::set_vmtarget(resolved_method_name(), method); + } + // Set flag in class to indicate this InstanceKlass has entries in the table + // to avoid walking table during redefinition if none of the redefined classes + // have any membernames in the table. + method->method_holder()->set_has_resolved_methods(); -double ResolvedMethodTable::get_dead_factor() { - return (double)_uncleaned_items_count/_current_size; + return _the_table->basic_add(method, resolved_method_name); } -static const double PREF_AVG_LIST_LEN = 2.0; -// If we have as many dead items as 50% of the number of bucket -static const double CLEAN_DEAD_HIGH_WATER_MARK = 0.5; +// Removing entries +int ResolvedMethodTable::_total_oops_removed = 0; -void ResolvedMethodTable::check_concurrent_work() { - if (_has_work) { - return; - } +// There are no dead entries at start +bool ResolvedMethodTable::_dead_entries = false; - double load_factor = get_load_factor(); - double dead_factor = get_dead_factor(); - // We should clean/resize if we have more dead than alive, - // more items than preferred load factor or - // more dead items than water mark. - if ((dead_factor > load_factor) || - (load_factor > PREF_AVG_LIST_LEN) || - (dead_factor > CLEAN_DEAD_HIGH_WATER_MARK)) { - log_debug(membername, table)("Concurrent work triggered, live factor: %g dead factor: %g", - load_factor, dead_factor); - trigger_concurrent_work(); - } -} - -void ResolvedMethodTable::trigger_concurrent_work() { +void ResolvedMethodTable::trigger_cleanup() { MutexLockerEx ml(Service_lock, Mutex::_no_safepoint_check_flag); - _has_work = true; + _dead_entries = true; Service_lock->notify_all(); } -void ResolvedMethodTable::do_concurrent_work(JavaThread* jt) { - _has_work = false; - double load_factor = get_load_factor(); - log_debug(membername, table)("Concurrent work, live factor: %g", load_factor); - // We prefer growing, since that also removes dead items - if (load_factor > PREF_AVG_LIST_LEN && !_local_table->is_max_size_reached()) { - grow(jt); - } else { - clean_dead_entries(jt); - } -} - -void ResolvedMethodTable::grow(JavaThread* jt) { - ResolvedMethodTableHash::GrowTask gt(_local_table); - if (!gt.prepare(jt)) { - return; - } - log_trace(membername, table)("Started to grow"); - { - TraceTime timer("Grow", TRACETIME_LOG(Debug, membername, table, perf)); - while (gt.do_task(jt)) { - gt.pause(jt); - { - ThreadBlockInVM tbivm(jt); +// Serially invoke removed unused oops from the table. +// This is done by the ServiceThread after being notified on class unloading +void ResolvedMethodTable::unlink() { + MutexLocker ml(ResolvedMethodTable_lock); + int _oops_removed = 0; + int _oops_counted = 0; + for (int i = 0; i < _the_table->table_size(); ++i) { + ResolvedMethodEntry** p = _the_table->bucket_addr(i); + ResolvedMethodEntry* entry = _the_table->bucket(i); + while (entry != NULL) { + _oops_counted++; + oop l = entry->object_no_keepalive(); + if (l != NULL) { + p = entry->next_addr(); + } else { + // Entry has been removed. + _oops_removed++; + if (log_is_enabled(Debug, membername, table)) { + log_debug(membername, table) ("ResolvedMethod entry removed for index %d", i); + } + entry->literal().release(); + *p = entry->next(); + _the_table->free_entry(entry); } - gt.cont(jt); - } - } - gt.done(jt); - _current_size = table_size(); - log_info(membername, table)("Grown to size:" SIZE_FORMAT, _current_size); -} - -struct ResolvedMethodTableDoDelete : StackObj { - void operator()(WeakHandle* val) { - /* do nothing */ - } -}; - -struct ResolvedMethodTableDeleteCheck : StackObj { - long _count; - long _item; - ResolvedMethodTableDeleteCheck() : _count(0), _item(0) {} - bool operator()(WeakHandle* val) { - ++_item; - oop tmp = val->peek(); - if (tmp == NULL) { - ++_count; - return true; - } else { - return false; + // get next entry + entry = (ResolvedMethodEntry*)HashtableEntry::make_ptr(*p); } } -}; - -void ResolvedMethodTable::clean_dead_entries(JavaThread* jt) { - ResolvedMethodTableHash::BulkDeleteTask bdt(_local_table); - if (!bdt.prepare(jt)) { - return; - } - ResolvedMethodTableDeleteCheck stdc; - ResolvedMethodTableDoDelete stdd; - { - TraceTime timer("Clean", TRACETIME_LOG(Debug, membername, table, perf)); - while(bdt.do_task(jt, stdc, stdd)) { - bdt.pause(jt); - { - ThreadBlockInVM tbivm(jt); + log_debug(membername, table) ("ResolvedMethod entries counted %d removed %d", + _oops_counted, _oops_removed); + _total_oops_removed += _oops_removed; + _dead_entries = false; +} + +#ifndef PRODUCT +void ResolvedMethodTable::print() { + MutexLocker ml(ResolvedMethodTable_lock); + for (int i = 0; i < table_size(); ++i) { + ResolvedMethodEntry* entry = bucket(i); + while (entry != NULL) { + tty->print("%d : ", i); + oop rmethod_name = entry->object_no_keepalive(); + if (rmethod_name != NULL) { + rmethod_name->print(); + Method* m = (Method*)java_lang_invoke_ResolvedMethodName::vmtarget(rmethod_name); + m->print(); } - bdt.cont(jt); + entry = entry->next(); } - bdt.done(jt); } - log_info(membername, table)("Cleaned %ld of %ld", stdc._count, stdc._item); -} -void ResolvedMethodTable::reset_dead_counter() { - _uncleaned_items_count = 0; -} - -void ResolvedMethodTable::inc_dead_counter(size_t ndead) { - size_t total = Atomic::add(ndead, &_uncleaned_items_count); - log_trace(membername, table)( - "Uncleaned items:" SIZE_FORMAT " added: " SIZE_FORMAT " total:" SIZE_FORMAT, - _uncleaned_items_count, ndead, total); -} - -// After the parallel walk this method must be called to trigger -// cleaning. Note it might trigger a resize instead. -void ResolvedMethodTable::finish_dead_counter() { - check_concurrent_work(); - -#ifdef ASSERT - if (SafepointSynchronize::is_at_safepoint()) { - size_t fail_cnt = verify_and_compare_entries(); - if (fail_cnt != 0) { - tty->print_cr("ERROR: fail_cnt=" SIZE_FORMAT, fail_cnt); - guarantee(fail_cnt == 0, "unexpected ResolvedMethodTable verification failures"); - } - } -#endif // ASSERT } +#endif // PRODUCT #if INCLUDE_JVMTI -class AdjustMethodEntries : public StackObj { - bool* _trace_name_printed; -public: - AdjustMethodEntries(bool* trace_name_printed) : _trace_name_printed(trace_name_printed) {}; - bool operator()(WeakHandle* entry) { - oop mem_name = entry->peek(); - if (mem_name == NULL) { - // Removed - return true; - } - - Method* old_method = (Method*)java_lang_invoke_ResolvedMethodName::vmtarget(mem_name); - - if (old_method->is_old()) { - - Method* new_method = (old_method->is_deleted()) ? - Universe::throw_no_such_method_error() : - old_method->get_new_method(); - java_lang_invoke_ResolvedMethodName::set_vmtarget(mem_name, new_method); - - ResourceMark rm; - if (!(*_trace_name_printed)) { - log_info(redefine, class, update)("adjust: name=%s", old_method->method_holder()->external_name()); - *_trace_name_printed = true; - } - log_debug(redefine, class, update, constantpool) - ("ResolvedMethod method update: %s(%s)", - new_method->name()->as_C_string(), new_method->signature()->as_C_string()); - } - - return true; - } -}; - // It is called at safepoint only for RedefineClasses void ResolvedMethodTable::adjust_method_entries(bool * trace_name_printed) { assert(SafepointSynchronize::is_at_safepoint(), "only called at safepoint"); // For each entry in RMT, change to new method - AdjustMethodEntries adjust(trace_name_printed); - _local_table->do_safepoint_scan(adjust); -} -#endif // INCLUDE_JVMTI + for (int i = 0; i < _the_table->table_size(); ++i) { + for (ResolvedMethodEntry* entry = _the_table->bucket(i); + entry != NULL; + entry = entry->next()) { + + oop mem_name = entry->object_no_keepalive(); + // except ones removed + if (mem_name == NULL) { + continue; + } + Method* old_method = (Method*)java_lang_invoke_ResolvedMethodName::vmtarget(mem_name); -// Verification and comp -class VerifyCompResolvedMethod : StackObj { - GrowableArray* _oops; - public: - size_t _errors; - VerifyCompResolvedMethod(GrowableArray* oops) : _oops(oops), _errors(0) {} - bool operator()(WeakHandle* val) { - oop s = val->peek(); - if (s == NULL) { - return true; - } - int len = _oops->length(); - for (int i = 0; i < len; i++) { - bool eq = s == _oops->at(i); - assert(!eq, "Duplicate entries"); - if (eq) { - _errors++; + if (old_method->is_old()) { + + Method* new_method = (old_method->is_deleted()) ? + Universe::throw_no_such_method_error() : + old_method->get_new_method(); + java_lang_invoke_ResolvedMethodName::set_vmtarget(mem_name, new_method); + + ResourceMark rm; + if (!(*trace_name_printed)) { + log_info(redefine, class, update)("adjust: name=%s", old_method->method_holder()->external_name()); + *trace_name_printed = true; + } + log_debug(redefine, class, update, constantpool) + ("ResolvedMethod method update: %s(%s)", + new_method->name()->as_C_string(), new_method->signature()->as_C_string()); } } - _oops->push(s); - return true; - }; -}; - -size_t ResolvedMethodTable::items_count() { - return _items_count; -} - -size_t ResolvedMethodTable::verify_and_compare_entries() { - Thread* thr = Thread::current(); - GrowableArray* oops = - new (ResourceObj::C_HEAP, mtInternal) - GrowableArray((int)_current_size, true); - - VerifyCompResolvedMethod vcs(oops); - if (!_local_table->try_scan(thr, vcs)) { - log_info(membername, table)("verify unavailable at this moment"); } - delete oops; - return vcs._errors; } +#endif // INCLUDE_JVMTI --- old/src/hotspot/share/prims/resolvedMethodTable.hpp 2019-05-21 01:01:32.441126898 +0200 +++ new/src/hotspot/share/prims/resolvedMethodTable.hpp 2019-05-21 01:01:32.281127184 +0200 @@ -25,78 +25,89 @@ #ifndef SHARE_PRIMS_RESOLVEDMETHODTABLE_HPP #define SHARE_PRIMS_RESOLVEDMETHODTABLE_HPP -#include "gc/shared/oopStorage.hpp" -#include "gc/shared/oopStorageParState.hpp" -#include "memory/allocation.hpp" #include "oops/symbol.hpp" #include "oops/weakHandle.hpp" -#include "utilities/concurrentHashTable.hpp" #include "utilities/hashtable.hpp" -class ResolvedMethodTable; -class ResolvedMethodTableConfig; -typedef ConcurrentHashTable, ResolvedMethodTableConfig, mtClass> ResolvedMethodTableHash; +// Hashtable to record Method* used in ResolvedMethods, via. ResolvedMethod oops. +// This is needed for redefinition to replace Method* with redefined versions. -class ResolvedMethodTable : public AllStatic { - static ResolvedMethodTableHash* _local_table; - static size_t _current_size; +// Entry in a ResolvedMethodTable, mapping a ClassLoaderWeakHandle for a single oop of +// java_lang_invoke_ResolvedMethodName which holds JVM Method* in vmtarget. - static OopStorage* _weak_handles; +class ResolvedMethodEntry : public HashtableEntry { + public: + ResolvedMethodEntry* next() const { + return (ResolvedMethodEntry*)HashtableEntry::next(); + } + + ResolvedMethodEntry** next_addr() { + return (ResolvedMethodEntry**)HashtableEntry::next_addr(); + } - static volatile bool _has_work; + oop object(); + oop object_no_keepalive(); - static volatile size_t _items_count; - static volatile size_t _uncleaned_items_count; - -public: - // Initialization - static void create_table(); - - static size_t table_size(); - - // Lookup and inserts - static oop find_method(const Method* method); - static oop add_method(const Method* method, Handle rmethod_name); - - // Callbacks - static void item_added(); - static void item_removed(); + void print_on(outputStream* st) const; +}; - // Cleaning - static bool has_work(); +class ResolvedMethodTable : public Hashtable { + enum Constants { + _table_size = 1007 + }; - // GC Support - Backing storage for the oop*s - static OopStorage* weak_storage(); + static int _total_oops_removed; - // Cleaning and table management + static bool _dead_entries; - static double get_load_factor(); - static double get_dead_factor(); + static ResolvedMethodTable* _the_table; +private: + ResolvedMethodEntry* bucket(int i) { + return (ResolvedMethodEntry*) Hashtable::bucket(i); + } - static void check_concurrent_work(); - static void trigger_concurrent_work(); - static void do_concurrent_work(JavaThread* jt); + ResolvedMethodEntry** bucket_addr(int i) { + return (ResolvedMethodEntry**) Hashtable::bucket_addr(i); + } - static void grow(JavaThread* jt); - static void clean_dead_entries(JavaThread* jt); + unsigned int compute_hash(Method* method); - // GC Notification + // need not be locked; no state change + oop lookup(int index, unsigned int hash, Method* method); + oop lookup(Method* method); - // Must be called before a parallel walk where objects might die. - static void reset_dead_counter(); - // After the parallel walk this method must be called to trigger - // cleaning. Note it might trigger a resize instead. - static void finish_dead_counter(); - // If GC uses ParState directly it should add the number of cleared - // entries to this method. - static void inc_dead_counter(size_t ndead); + // must be done under ResolvedMethodTable_lock + oop basic_add(Method* method, Handle rmethod_name); - // JVMTI Support - It is called at safepoint only for RedefineClasses - JVMTI_ONLY(static void adjust_method_entries(bool * trace_name_printed);) +public: + ResolvedMethodTable(); - // Debugging - static size_t items_count(); - static size_t verify_and_compare_entries(); + static void create_table() { + assert(_the_table == NULL, "One symbol table allowed."); + _the_table = new ResolvedMethodTable(); + } + + // Called from java_lang_invoke_ResolvedMethodName + static oop find_method(Method* method); + static oop add_method(const methodHandle& method, Handle rmethod_name); + + static bool has_work() { return _dead_entries; } + static void trigger_cleanup(); + + static int removed_entries_count() { return _total_oops_removed; }; + +#if INCLUDE_JVMTI + // It is called at safepoint only for RedefineClasses + static void adjust_method_entries(bool * trace_name_printed); +#endif // INCLUDE_JVMTI + + // Cleanup cleared entries + static void unlink(); + +#ifndef PRODUCT + void print(); +#endif + void verify(); }; #endif // SHARE_PRIMS_RESOLVEDMETHODTABLE_HPP --- old/src/hotspot/share/prims/stackwalk.cpp 2019-05-21 01:01:32.637126546 +0200 +++ new/src/hotspot/share/prims/stackwalk.cpp 2019-05-21 01:01:32.481126827 +0200 @@ -151,8 +151,8 @@ index == start_index && method->caller_sensitive()) { ResourceMark rm(THREAD); THROW_MSG_0(vmSymbols::java_lang_UnsupportedOperationException(), - err_msg("StackWalker::getCallerClass called from @CallerSensitive '%s' method", - method->external_name())); + err_msg("StackWalker::getCallerClass called from @CallerSensitive %s method", + method->name_and_sig_as_C_string())); } // fill in StackFrameInfo and initialize MemberName stream.fill_frame(index, frames_array, method, CHECK_0); --- old/src/hotspot/share/prims/unsafe.cpp 2019-05-21 01:01:32.837126187 +0200 +++ new/src/hotspot/share/prims/unsafe.cpp 2019-05-21 01:01:32.681126467 +0200 @@ -292,6 +292,18 @@ return JNIHandles::make_local(env, v); } UNSAFE_END +UNSAFE_LEAF(jboolean, Unsafe_isBigEndian0(JNIEnv *env, jobject unsafe)) { +#ifdef VM_LITTLE_ENDIAN + return false; +#else + return true; +#endif +} UNSAFE_END + +UNSAFE_LEAF(jint, Unsafe_unalignedAccess0(JNIEnv *env, jobject unsafe)) { + return UseUnalignedAccesses; +} UNSAFE_END + #define DEFINE_GETSETOOP(java_type, Type) \ \ UNSAFE_ENTRY(java_type, Unsafe_Get##Type(JNIEnv *env, jobject unsafe, jobject obj, jlong offset)) { \ @@ -434,6 +446,14 @@ ////// Random queries +UNSAFE_LEAF(jint, Unsafe_AddressSize0(JNIEnv *env, jobject unsafe)) { + return sizeof(void*); +} UNSAFE_END + +UNSAFE_LEAF(jint, Unsafe_PageSize()) { + return os::vm_page_size(); +} UNSAFE_END + static jlong find_field_offset(jclass clazz, jstring name, TRAPS) { assert(clazz != NULL, "clazz must not be NULL"); assert(name != NULL, "name must not be NULL"); @@ -1053,6 +1073,8 @@ {CC "ensureClassInitialized0", CC "(" CLS ")V", FN_PTR(Unsafe_EnsureClassInitialized0)}, {CC "arrayBaseOffset0", CC "(" CLS ")I", FN_PTR(Unsafe_ArrayBaseOffset0)}, {CC "arrayIndexScale0", CC "(" CLS ")I", FN_PTR(Unsafe_ArrayIndexScale0)}, + {CC "addressSize0", CC "()I", FN_PTR(Unsafe_AddressSize0)}, + {CC "pageSize", CC "()I", FN_PTR(Unsafe_PageSize)}, {CC "defineClass0", CC "(" DC_Args ")" CLS, FN_PTR(Unsafe_DefineClass0)}, {CC "allocateInstance", CC "(" CLS ")" OBJ, FN_PTR(Unsafe_AllocateInstance)}, @@ -1080,6 +1102,9 @@ {CC "loadFence", CC "()V", FN_PTR(Unsafe_LoadFence)}, {CC "storeFence", CC "()V", FN_PTR(Unsafe_StoreFence)}, {CC "fullFence", CC "()V", FN_PTR(Unsafe_FullFence)}, + + {CC "isBigEndian0", CC "()Z", FN_PTR(Unsafe_isBigEndian0)}, + {CC "unalignedAccess0", CC "()Z", FN_PTR(Unsafe_unalignedAccess0)} }; #undef CC --- old/src/hotspot/share/prims/whitebox.cpp 2019-05-21 01:01:33.041125823 +0200 +++ new/src/hotspot/share/prims/whitebox.cpp 2019-05-21 01:01:32.885126101 +0200 @@ -2092,8 +2092,8 @@ #endif WB_END -WB_ENTRY(jlong, WB_ResolvedMethodItemsCount(JNIEnv* env, jobject o)) - return (jlong) ResolvedMethodTable::items_count(); +WB_ENTRY(jint, WB_ResolvedMethodRemovedCount(JNIEnv* env, jobject o)) + return (jint) ResolvedMethodTable::removed_entries_count(); WB_END WB_ENTRY(jint, WB_ProtectionDomainRemovedCount(JNIEnv* env, jobject o)) @@ -2337,7 +2337,7 @@ {CC"isContainerized", CC"()Z", (void*)&WB_IsContainerized }, {CC"printOsInfo", CC"()V", (void*)&WB_PrintOsInfo }, {CC"disableElfSectionCache", CC"()V", (void*)&WB_DisableElfSectionCache }, - {CC"resolvedMethodItemsCount", CC"()J", (void*)&WB_ResolvedMethodItemsCount }, + {CC"resolvedMethodRemovedCount", CC"()I", (void*)&WB_ResolvedMethodRemovedCount }, {CC"protectionDomainRemovedCount", CC"()I", (void*)&WB_ProtectionDomainRemovedCount }, {CC"aotLibrariesCount", CC"()I", (void*)&WB_AotLibrariesCount }, }; --- old/src/hotspot/share/runtime/interfaceSupport.inline.hpp 2019-05-21 01:01:33.253125441 +0200 +++ new/src/hotspot/share/runtime/interfaceSupport.inline.hpp 2019-05-21 01:01:33.097125721 +0200 @@ -66,6 +66,22 @@ static void verify_stack(); static void verify_last_frame(); # endif + + public: + static void serialize_thread_state_with_handler(JavaThread* thread) { + serialize_thread_state_internal(thread, true); + } + + // Should only call this if we know that we have a proper SEH set up. + static void serialize_thread_state(JavaThread* thread) { + serialize_thread_state_internal(thread, false); + } + + private: + static void serialize_thread_state_internal(JavaThread* thread, bool needs_exception_handler) { + // Make sure new state is seen by VM thread + OrderAccess::fence(); + } }; @@ -87,8 +103,28 @@ assert(from != _thread_in_native, "use transition_from_native"); assert((from & 1) == 0 && (to & 1) == 0, "odd numbers are transitions states"); assert(thread->thread_state() == from, "coming from wrong thread state"); - // Change to transition state and ensure it is seen by the VM thread. - thread->set_thread_state_fence((JavaThreadState)(from + 1)); + // Change to transition state + thread->set_thread_state((JavaThreadState)(from + 1)); + + InterfaceSupport::serialize_thread_state(thread); + + SafepointMechanism::block_if_requested(thread); + thread->set_thread_state(to); + + CHECK_UNHANDLED_OOPS_ONLY(thread->clear_unhandled_oops();) + } + + // transition_and_fence must be used on any thread state transition + // where there might not be a Java call stub on the stack, in + // particular on Windows where the Structured Exception Handler is + // set up in the call stub. + static inline void transition_and_fence(JavaThread *thread, JavaThreadState from, JavaThreadState to) { + assert(thread->thread_state() == from, "coming from wrong thread state"); + assert((from & 1) == 0 && (to & 1) == 0, "odd numbers are transitions states"); + // Change to transition state + thread->set_thread_state((JavaThreadState)(from + 1)); + + InterfaceSupport::serialize_thread_state_with_handler(thread); SafepointMechanism::block_if_requested(thread); thread->set_thread_state(to); @@ -107,14 +143,19 @@ static inline void transition_from_native(JavaThread *thread, JavaThreadState to) { assert((to & 1) == 0, "odd numbers are transitions states"); assert(thread->thread_state() == _thread_in_native, "coming from wrong thread state"); - // Change to transition state and ensure it is seen by the VM thread. - thread->set_thread_state_fence(_thread_in_native_trans); + // Change to transition state + thread->set_thread_state(_thread_in_native_trans); + + InterfaceSupport::serialize_thread_state_with_handler(thread); // We never install asynchronous exceptions when coming (back) in // to the runtime from native code because the runtime is not set // up to handle exceptions floating around at arbitrary points. if (SafepointMechanism::should_block(thread) || thread->is_suspend_after_native()) { JavaThread::check_safepoint_and_suspend_for_native_trans(thread); + + // Clear unhandled oops anywhere where we could block, even if we don't. + CHECK_UNHANDLED_OOPS_ONLY(thread->clear_unhandled_oops();) } thread->set_thread_state(to); @@ -123,6 +164,7 @@ void trans(JavaThreadState from, JavaThreadState to) { transition(_thread, from, to); } void trans_from_java(JavaThreadState to) { transition_from_java(_thread, to); } void trans_from_native(JavaThreadState to) { transition_from_native(_thread, to); } + void trans_and_fence(JavaThreadState from, JavaThreadState to) { transition_and_fence(_thread, from, to); } }; class ThreadInVMForHandshake : public ThreadStateTransition { @@ -131,8 +173,9 @@ void transition_back() { // This can be invoked from transition states and must return to the original state properly assert(_thread->thread_state() == _thread_in_vm, "should only call when leaving VM after handshake"); - // Change to transition state and ensure it is seen by the VM thread. - _thread->set_thread_state_fence(_thread_in_vm_trans); + _thread->set_thread_state(_thread_in_vm_trans); + + InterfaceSupport::serialize_thread_state(_thread); SafepointMechanism::block_if_requested(_thread); @@ -174,6 +217,7 @@ class ThreadInVMfromUnknown { + private: JavaThread* _thread; public: ThreadInVMfromUnknown() : _thread(NULL) { @@ -192,7 +236,7 @@ } ~ThreadInVMfromUnknown() { if (_thread) { - ThreadStateTransition::transition(_thread, _thread_in_vm, _thread_in_native); + ThreadStateTransition::transition_and_fence(_thread, _thread_in_vm, _thread_in_native); } } }; @@ -204,7 +248,7 @@ trans_from_native(_thread_in_vm); } ~ThreadInVMfromNative() { - trans(_thread_in_vm, _thread_in_native); + trans_and_fence(_thread_in_vm, _thread_in_native); } }; @@ -216,7 +260,7 @@ // Block, if we are in the middle of a safepoint synchronization. assert(!thread->owns_locks(), "must release all locks when leaving VM"); thread->frame_anchor()->make_walkable(thread); - trans(_thread_in_vm, _thread_in_native); + trans_and_fence(_thread_in_vm, _thread_in_native); // Check for pending. async. exceptions or suspends. if (_thread->has_special_runtime_exit_condition()) _thread->handle_special_runtime_exit_condition(false); } @@ -235,10 +279,10 @@ : ThreadStateTransition(thread) { // Once we are blocked vm expects stack to be walkable thread->frame_anchor()->make_walkable(thread); - trans(_thread_in_vm, _thread_blocked); + trans_and_fence(_thread_in_vm, _thread_blocked); } ~ThreadBlockInVM() { - trans(_thread_blocked, _thread_in_vm); + trans_and_fence(_thread_blocked, _thread_in_vm); OrderAccess::cross_modify_fence(); // We don't need to clear_walkable because it will happen automagically when we return to java } @@ -278,10 +322,14 @@ OrderAccess::storestore(); thread->set_thread_state(_thread_blocked); + + CHECK_UNHANDLED_OOPS_ONLY(_thread->clear_unhandled_oops();) } ~ThreadBlockInVMWithDeadlockCheck() { - // Change to transition state and ensure it is seen by the VM thread. - _thread->set_thread_state_fence((JavaThreadState)(_thread_blocked_trans)); + // Change to transition state + _thread->set_thread_state((JavaThreadState)(_thread_blocked_trans)); + + InterfaceSupport::serialize_thread_state_with_handler(_thread); if (SafepointMechanism::should_block(_thread)) { release_monitor(); @@ -289,6 +337,8 @@ } _thread->set_thread_state(_thread_in_vm); + CHECK_UNHANDLED_OOPS_ONLY(_thread->clear_unhandled_oops();) + OrderAccess::cross_modify_fence(); } }; @@ -422,6 +472,30 @@ /* begin of body */ +// Definitions for IRT (Interpreter Runtime) +// (thread is an argument passed in to all these routines) + +#define IRT_ENTRY(result_type, header) \ + result_type header { \ + ThreadInVMfromJava __tiv(thread); \ + VM_ENTRY_BASE(result_type, header, thread) \ + debug_only(VMEntryWrapper __vew;) + + +#define IRT_LEAF(result_type, header) \ + result_type header { \ + VM_LEAF_BASE(result_type, header) \ + debug_only(NoSafepointVerifier __nspv(true);) + + +#define IRT_ENTRY_NO_ASYNC(result_type, header) \ + result_type header { \ + ThreadInVMfromJavaNoAsyncException __tiv(thread); \ + VM_ENTRY_BASE(result_type, header, thread) \ + debug_only(VMEntryWrapper __vew;) + +#define IRT_END } + #define JRT_ENTRY(result_type, header) \ result_type header { \ ThreadInVMfromJava __tiv(thread); \ --- old/src/hotspot/share/runtime/mutex.cpp 2019-05-21 01:01:33.453125084 +0200 +++ new/src/hotspot/share/runtime/mutex.cpp 2019-05-21 01:01:33.297125364 +0200 @@ -159,7 +159,7 @@ // !no_safepoint_check logically implies java_thread guarantee(no_safepoint_check || self->is_Java_thread(), "invariant"); -#ifdef ASSERT + #ifdef ASSERT Monitor * least = get_least_ranked_lock_besides_this(self->owned_locks()); assert(least != this, "Specification of get_least_... call above"); if (least != NULL && least->rank() <= special) { @@ -168,14 +168,7 @@ name(), rank(), least->name(), least->rank()); assert(false, "Shouldn't block(wait) while holding a lock of rank special"); } -#endif // ASSERT - -#ifdef CHECK_UNHANDLED_OOPS - // Clear unhandled oops in JavaThreads so we get a crash right away. - if (self->is_Java_thread() && !no_safepoint_check) { - self->clear_unhandled_oops(); - } -#endif // CHECK_UNHANDLED_OOPS + #endif // ASSERT int wait_status; // conceptually set the owner to NULL in anticipation of --- old/src/hotspot/share/runtime/mutexLocker.cpp 2019-05-21 01:01:33.657124717 +0200 +++ new/src/hotspot/share/runtime/mutexLocker.cpp 2019-05-21 01:01:33.501124997 +0200 @@ -54,8 +54,7 @@ Mutex* JNIHandleBlockFreeList_lock = NULL; Mutex* VMWeakAlloc_lock = NULL; Mutex* VMWeakActive_lock = NULL; -Mutex* ResolvedMethodTableWeakAlloc_lock = NULL; -Mutex* ResolvedMethodTableWeakActive_lock = NULL; +Mutex* ResolvedMethodTable_lock = NULL; Mutex* JmethodIdCreation_lock = NULL; Mutex* JfieldIdCreation_lock = NULL; Monitor* JNICritical_lock = NULL; @@ -213,9 +212,6 @@ def(StringTableWeakAlloc_lock , PaddedMutex , vmweak, true, Monitor::_safepoint_check_never); def(StringTableWeakActive_lock , PaddedMutex , vmweak-1, true, Monitor::_safepoint_check_never); - def(ResolvedMethodTableWeakAlloc_lock , PaddedMutex , vmweak, true, Monitor::_safepoint_check_never); - def(ResolvedMethodTableWeakActive_lock , PaddedMutex , vmweak-1, true, Monitor::_safepoint_check_never); - if (UseConcMarkSweepGC || UseG1GC) { def(FullGCCount_lock , PaddedMonitor, leaf, true, Monitor::_safepoint_check_never); // in support of ExplicitGCInvokesConcurrent } @@ -302,6 +298,7 @@ def(Heap_lock , PaddedMonitor, nonleaf+1, false, Monitor::_safepoint_check_sometimes); def(JfieldIdCreation_lock , PaddedMutex , nonleaf+1, true, Monitor::_safepoint_check_always); // jfieldID, Used in VM_Operation + def(ResolvedMethodTable_lock , PaddedMutex , nonleaf+1, false, Monitor::_safepoint_check_always); // Used to protect ResolvedMethodTable def(CompiledIC_lock , PaddedMutex , nonleaf+2, false, Monitor::_safepoint_check_never); // locks VtableStubs_lock, InlineCacheBuffer_lock def(CompileTaskAlloc_lock , PaddedMutex , nonleaf+2, true, Monitor::_safepoint_check_always); --- old/src/hotspot/share/runtime/mutexLocker.hpp 2019-05-21 01:01:33.857124360 +0200 +++ new/src/hotspot/share/runtime/mutexLocker.hpp 2019-05-21 01:01:33.697124645 +0200 @@ -48,8 +48,7 @@ extern Mutex* JNIHandleBlockFreeList_lock; // a lock on the JNI handle block free list extern Mutex* VMWeakAlloc_lock; // VM Weak Handles storage allocate list lock extern Mutex* VMWeakActive_lock; // VM Weak Handles storage active list lock -extern Mutex* ResolvedMethodTableWeakAlloc_lock; // ResolvedMethodTable weak storage allocate list -extern Mutex* ResolvedMethodTableWeakActive_lock; // ResolvedMethodTable weak storage active list +extern Mutex* ResolvedMethodTable_lock; // a lock on the ResolvedMethodTable updates extern Mutex* JmethodIdCreation_lock; // a lock on creating JNI method identifiers extern Mutex* JfieldIdCreation_lock; // a lock on creating JNI static field identifiers extern Monitor* JNICritical_lock; // a lock used while entering and exiting JNI critical regions, allows GC to sometimes get in --- old/src/hotspot/share/runtime/os.cpp 2019-05-21 01:01:34.057124001 +0200 +++ new/src/hotspot/share/runtime/os.cpp 2019-05-21 01:01:33.901124281 +0200 @@ -1024,9 +1024,8 @@ } bool os::is_readable_range(const void* from, const void* to) { - if ((uintptr_t)from >= (uintptr_t)to) return false; - for (uintptr_t p = align_down((uintptr_t)from, min_page_size()); p < (uintptr_t)to; p += min_page_size()) { - if (!is_readable_pointer((const void*)p)) { + for (address p = align_down((address)from, min_page_size()); p < to; p += min_page_size()) { + if (!is_readable_pointer(p)) { return false; } } --- old/src/hotspot/share/runtime/reflection.cpp 2019-05-21 01:01:34.265123628 +0200 +++ new/src/hotspot/share/runtime/reflection.cpp 2019-05-21 01:01:34.109123907 +0200 @@ -1085,12 +1085,11 @@ if (method->is_abstract()) { // new default: 6531596 ResourceMark rm(THREAD); - stringStream ss; - ss.print("'"); - Method::print_external_name(&ss, target_klass, method->name(), method->signature()); - ss.print("'"); Handle h_origexception = Exceptions::new_exception(THREAD, - vmSymbols::java_lang_AbstractMethodError(), ss.as_string()); + vmSymbols::java_lang_AbstractMethodError(), + Method::name_and_sig_as_C_string(target_klass, + method->name(), + method->signature())); JavaCallArguments args(h_origexception); THROW_ARG_0(vmSymbols::java_lang_reflect_InvocationTargetException(), vmSymbols::throwable_void_signature(), @@ -1105,13 +1104,10 @@ // an internal vtable bug. If you ever get this please let Karen know. if (method.is_null()) { ResourceMark rm(THREAD); - stringStream ss; - ss.print("'"); - Method::print_external_name(&ss, klass, - reflected_method->name(), - reflected_method->signature()); - ss.print("'"); - THROW_MSG_0(vmSymbols::java_lang_NoSuchMethodError(), ss.as_string()); + THROW_MSG_0(vmSymbols::java_lang_NoSuchMethodError(), + Method::name_and_sig_as_C_string(klass, + reflected_method->name(), + reflected_method->signature())); } assert(ptypes->is_objArray(), "just checking"); --- old/src/hotspot/share/runtime/safepoint.cpp 2019-05-21 01:01:34.477123246 +0200 +++ new/src/hotspot/share/runtime/safepoint.cpp 2019-05-21 01:01:34.317123534 +0200 @@ -805,9 +805,9 @@ // This part we can skip if we notice we miss or are in a future safepoint. OrderAccess::storestore(); - // Load in wait barrier should not float up - thread->set_thread_state_fence(_thread_blocked); + thread->set_thread_state(_thread_blocked); + OrderAccess::fence(); // Load in wait barrier should not float up _wait_barrier->wait(static_cast(safepoint_id)); assert(_state != _synchronized, "Can't be"); --- old/src/hotspot/share/runtime/serviceThread.cpp 2019-05-21 01:01:34.685122874 +0200 +++ new/src/hotspot/share/runtime/serviceThread.cpp 2019-05-21 01:01:34.525123162 +0200 @@ -190,7 +190,7 @@ } if (resolved_method_table_work) { - ResolvedMethodTable::do_concurrent_work(jt); + ResolvedMethodTable::unlink(); } if (protection_domain_table_work) { --- old/src/hotspot/share/runtime/sharedRuntime.cpp 2019-05-21 01:01:34.881122523 +0200 +++ new/src/hotspot/share/runtime/sharedRuntime.cpp 2019-05-21 01:01:34.725122803 +0200 @@ -1918,7 +1918,7 @@ // where we went int -> i2c -> c2i and so the caller could in fact be // interpreted. If the caller is compiled we attempt to patch the caller // so he no longer calls into the interpreter. -JRT_LEAF(void, SharedRuntime::fixup_callers_callsite(Method* method, address caller_pc)) +IRT_LEAF(void, SharedRuntime::fixup_callers_callsite(Method* method, address caller_pc)) Method* moop(method); address entry_point = moop->from_compiled_entry_no_trampoline(); @@ -1987,7 +1987,7 @@ } } } -JRT_END +IRT_END // same as JVM_Arraycopy, but called directly from compiled code --- old/src/hotspot/share/runtime/thread.cpp 2019-05-21 01:01:35.101122128 +0200 +++ new/src/hotspot/share/runtime/thread.cpp 2019-05-21 01:01:34.945122408 +0200 @@ -1837,7 +1837,7 @@ // Thread is now sufficiently initialized to be handled by the safepoint code as being // in the VM. Change thread state from _thread_new to _thread_in_vm - ThreadStateTransition::transition(this, _thread_new, _thread_in_vm); + ThreadStateTransition::transition_and_fence(this, _thread_new, _thread_in_vm); // Before a thread is on the threads list it is always safe, so after leaving the // _thread_new we should emit a instruction barrier. The distance to modified code // from here is probably far enough, but this is consistent and safe. @@ -2475,10 +2475,11 @@ JavaThreadState state = thread_state(); set_thread_state(_thread_blocked); java_suspend_self(); - set_thread_state_fence(state); + set_thread_state(state); // Since we are not using a regular thread-state transition helper here, // we must manually emit the instruction barrier after leaving a safe state. OrderAccess::cross_modify_fence(); + InterfaceSupport::serialize_thread_state_with_handler(this); if (state != _thread_in_native) { SafepointMechanism::block_if_requested(this); } @@ -3627,7 +3628,6 @@ initialize_class(vmSymbols::java_lang_Thread(), CHECK); oop thread_object = create_initial_thread(thread_group, main_thread, CHECK); main_thread->set_threadObj(thread_object); - // Set thread status to running since main thread has // been started and running. java_lang_Thread::set_thread_status(thread_object, @@ -3636,15 +3636,6 @@ // The VM creates objects of this class. initialize_class(vmSymbols::java_lang_Module(), CHECK); -#ifdef ASSERT - InstanceKlass *k = SystemDictionary::UnsafeConstants_klass(); - assert(k->is_not_initialized(), "UnsafeConstants should not already be initialized"); -#endif - - // initialize the hardware-specific constants needed by Unsafe - initialize_class(vmSymbols::jdk_internal_misc_UnsafeConstants(), CHECK); - jdk_internal_misc_UnsafeConstants::set_unsafe_constants(); - // The VM preresolves methods to these classes. Make sure that they get initialized initialize_class(vmSymbols::java_lang_reflect_Method(), CHECK); initialize_class(vmSymbols::java_lang_ref_Finalizer(), CHECK); --- old/src/hotspot/share/runtime/thread.hpp 2019-05-21 01:01:35.333121712 +0200 +++ new/src/hotspot/share/runtime/thread.hpp 2019-05-21 01:01:35.177121993 +0200 @@ -1288,7 +1288,6 @@ // Safepoint support inline JavaThreadState thread_state() const; inline void set_thread_state(JavaThreadState s); - inline void set_thread_state_fence(JavaThreadState s); // fence after setting thread state inline ThreadSafepointState* safepoint_state() const; inline void set_safepoint_state(ThreadSafepointState* state); inline bool is_at_poll_safepoint(); @@ -1415,7 +1414,7 @@ // Whenever a thread transitions from native to vm/java it must suspend // if external|deopt suspend is present. bool is_suspend_after_native() const { - return (_suspend_flags & (_external_suspend | _deopt_suspend JFR_ONLY(| _trace_flag))) != 0; + return (_suspend_flags & (_external_suspend | _deopt_suspend)) != 0; } // external suspend request is completed --- old/src/hotspot/share/runtime/thread.inline.hpp 2019-05-21 01:01:35.549121325 +0200 +++ new/src/hotspot/share/runtime/thread.inline.hpp 2019-05-21 01:01:35.393121605 +0200 @@ -141,11 +141,6 @@ #endif } -inline void JavaThread::set_thread_state_fence(JavaThreadState s) { - set_thread_state(s); - OrderAccess::fence(); -} - ThreadSafepointState* JavaThread::safepoint_state() const { return _safepoint_state; } --- old/src/hotspot/share/runtime/threadSMR.cpp 2019-05-21 01:01:35.745120973 +0200 +++ new/src/hotspot/share/runtime/threadSMR.cpp 2019-05-21 01:01:35.589121254 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -590,9 +590,12 @@ } void ThreadsList::dec_nested_handle_cnt() { - // The decrement only needs to be MO_ACQ_REL since the reference - // counter is volatile (and the hazard ptr is already NULL). - Atomic::dec(&_nested_handle_cnt); + // The decrement needs to be MO_ACQ_REL. At the moment, the Atomic::dec + // backend on PPC does not yet conform to these requirements. Therefore + // the decrement is simulated with an Atomic::sub(1, &addr). + // Without this MO_ACQ_REL Atomic::dec simulation, the nested SMR mechanism + // is not generally safe to use. + Atomic::sub(1, &_nested_handle_cnt); } int ThreadsList::find_index_of_JavaThread(JavaThread *target) { @@ -623,9 +626,19 @@ } void ThreadsList::inc_nested_handle_cnt() { - // The increment needs to be MO_SEQ_CST so that the reference counter - // update is seen before the subsequent hazard ptr update. - Atomic::inc(&_nested_handle_cnt); + // The increment needs to be MO_SEQ_CST. At the moment, the Atomic::inc + // backend on PPC does not yet conform to these requirements. Therefore + // the increment is simulated with a load phi; cas phi + 1; loop. + // Without this MO_SEQ_CST Atomic::inc simulation, the nested SMR mechanism + // is not generally safe to use. + intx sample = OrderAccess::load_acquire(&_nested_handle_cnt); + for (;;) { + if (Atomic::cmpxchg(sample + 1, &_nested_handle_cnt, sample) == sample) { + return; + } else { + sample = OrderAccess::load_acquire(&_nested_handle_cnt); + } + } } bool ThreadsList::includes(const JavaThread * const p) const { --- old/src/hotspot/share/runtime/vm_version.cpp 2019-05-21 01:01:35.949120609 +0200 +++ new/src/hotspot/share/runtime/vm_version.cpp 2019-05-21 01:01:35.797120881 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -44,8 +44,6 @@ unsigned int Abstract_VM_Version::_logical_processors_per_package = 1U; unsigned int Abstract_VM_Version::_L1_data_cache_line_size = 0; -VirtualizationType Abstract_VM_Version::_detected_virtualization = NoDetectedVirtualization; - #ifndef HOTSPOT_VERSION_STRING #error HOTSPOT_VERSION_STRING must be defined #endif @@ -297,6 +295,7 @@ (Abstract_VM_Version::vm_build_number() & 0xFF); } + void VM_Version_init() { VM_Version::initialize(); @@ -307,27 +306,3 @@ os::print_cpu_info(&ls, buf, sizeof(buf)); } } - -bool Abstract_VM_Version::print_matching_lines_from_file(const char* filename, outputStream* st, const char* keywords_to_match[]) { - char line[500]; - FILE* fp = fopen(filename, "r"); - if (fp == NULL) { - return false; - } - - st->print_cr("Virtualization information:"); - while (fgets(line, sizeof(line), fp) != NULL) { - int i = 0; - while (keywords_to_match[i] != NULL) { - if (strncmp(line, keywords_to_match[i], strlen(keywords_to_match[i])) == 0) { - st->print("%s", line); - break; - } - i++; - } - } - fclose(fp); - return true; -} - - --- old/src/hotspot/share/runtime/vm_version.hpp 2019-05-21 01:01:36.153120242 +0200 +++ new/src/hotspot/share/runtime/vm_version.hpp 2019-05-21 01:01:35.993120530 +0200 @@ -29,14 +29,6 @@ #include "utilities/ostream.hpp" #include "utilities/macros.hpp" -typedef enum { - NoDetectedVirtualization, - XenHVM, - KVM, - VMWare, - HyperV -} VirtualizationType; - // VM_Version provides information about the VM. class Abstract_VM_Version: AllStatic { @@ -65,8 +57,6 @@ static int _vm_patch_version; static int _vm_build_number; - static VirtualizationType _detected_virtualization; - public: // Called as part of the runtime services initialization which is // called from the management module initialization (via init_globals()) @@ -121,14 +111,6 @@ return _features_string; } - static VirtualizationType get_detected_virtualization() { - return _detected_virtualization; - } - - // platforms that need to specialize this - // define VM_Version::print_platform_virtualization_info() - static void print_platform_virtualization_info(outputStream*) { } - // does HW support an 8-byte compare-exchange operation? static bool supports_cx8() { #ifdef SUPPORTS_NATIVE_CX8 @@ -167,8 +149,6 @@ // Does this CPU support spin wait instruction? static bool supports_on_spin_wait() { return false; } - - static bool print_matching_lines_from_file(const char* filename, outputStream* st, const char* keywords_to_match[]); }; #include CPU_HEADER(vm_version) --- old/src/hotspot/share/utilities/exceptions.hpp 2019-05-21 01:01:36.357119877 +0200 +++ new/src/hotspot/share/utilities/exceptions.hpp 2019-05-21 01:01:36.205120150 +0200 @@ -237,7 +237,11 @@ // visible within the scope containing the THROW. Usually this is achieved by declaring the function // with a TRAPS argument. +#ifdef THIS_FILE +#define THREAD_AND_LOCATION THREAD, THIS_FILE, __LINE__ +#else #define THREAD_AND_LOCATION THREAD, __FILE__, __LINE__ +#endif #define THROW_OOP(e) \ { Exceptions::_throw_oop(THREAD_AND_LOCATION, e); return; } --- old/src/java.base/share/classes/java/io/File.java 2019-05-21 01:01:36.561119511 +0200 +++ new/src/java.base/share/classes/java/io/File.java 2019-05-21 01:01:36.405119791 +0200 @@ -1869,7 +1869,7 @@ * *

The returned number of available bytes is a hint, but not a * guarantee, that it is possible to use most or any of these bytes. The - * number of available bytes is most likely to be accurate immediately + * number of unallocated bytes is most likely to be accurate immediately * after this call. It is likely to be made inaccurate by any external * I/O operations including those made on the system outside of this * virtual machine. This method makes no guarantee that write operations --- old/src/java.base/share/classes/java/lang/AbstractStringBuilder.java 2019-05-21 01:01:36.773119131 +0200 +++ new/src/java.base/share/classes/java/lang/AbstractStringBuilder.java 2019-05-21 01:01:36.621119403 +0200 @@ -92,57 +92,19 @@ } /** - * Constructs an AbstractStringBuilder that contains the same characters - * as the specified {@code String}. The initial capacity of - * the string builder is {@code 16} plus the length of the - * {@code String} argument. - * - * @param str the string to copy. + * Creates an AbstractStringBuilder with the specified coder and with + * the initial capacity equal to the smaller of (length + addition) + * and Integer.MAX_VALUE. */ - AbstractStringBuilder(String str) { - int length = str.length(); - int capacity = (length < Integer.MAX_VALUE - 16) - ? length + 16 : Integer.MAX_VALUE; - final byte initCoder = str.coder(); - coder = initCoder; - value = (initCoder == LATIN1) - ? new byte[capacity] : StringUTF16.newBytesFor(capacity); - append(str); - } - - /** - * Constructs an AbstractStringBuilder that contains the same characters - * as the specified {@code CharSequence}. The initial capacity of - * the string builder is {@code 16} plus the length of the - * {@code CharSequence} argument. - * - * @param seq the sequence to copy. - */ - AbstractStringBuilder(CharSequence seq) { - int length = seq.length(); + AbstractStringBuilder(byte coder, int length, int addition) { if (length < 0) { throw new NegativeArraySizeException("Negative length: " + length); } - int capacity = (length < Integer.MAX_VALUE - 16) - ? length + 16 : Integer.MAX_VALUE; - - final byte initCoder; - if (COMPACT_STRINGS) { - if (seq instanceof AbstractStringBuilder) { - initCoder = ((AbstractStringBuilder)seq).getCoder(); - } else if (seq instanceof String) { - initCoder = ((String)seq).coder(); - } else { - initCoder = LATIN1; - } - } else { - initCoder = UTF16; - } - - coder = initCoder; - value = (initCoder == LATIN1) + this.coder = coder; + int capacity = (length < Integer.MAX_VALUE - addition) + ? length + addition : Integer.MAX_VALUE; + value = (coder == LATIN1) ? new byte[capacity] : StringUTF16.newBytesFor(capacity); - append(seq); } /** --- old/src/java.base/share/classes/java/lang/Class.java 2019-05-21 01:01:36.981118759 +0200 +++ new/src/java.base/share/classes/java/lang/Class.java 2019-05-21 01:01:36.829119031 +0200 @@ -277,7 +277,8 @@ .collect(Collectors.joining(",", "<", ">"))); } - if (arrayDepth > 0) sb.append("[]".repeat(arrayDepth)); + for (int i = 0; i < arrayDepth; i++) + sb.append("[]"); return sb.toString(); } @@ -1588,7 +1589,12 @@ dimensions++; cl = cl.getComponentType(); } while (cl.isArray()); - return cl.getName() + "[]".repeat(dimensions); + StringBuilder sb = new StringBuilder(); + sb.append(cl.getName()); + for (int i = 0; i < dimensions; i++) { + sb.append("[]"); + } + return sb.toString(); } catch (Throwable e) { /*FALLTHRU*/ } } return getName(); @@ -3412,12 +3418,15 @@ * Helper method to get the method name from arguments. */ private String methodToString(String name, Class[] argTypes) { - return getName() + '.' + name + - ((argTypes == null || argTypes.length == 0) ? - "()" : - Arrays.stream(argTypes) - .map(c -> c == null ? "null" : c.getName()) - .collect(Collectors.joining(",", "(", ")"))); + StringBuilder sb = new StringBuilder(); + sb.append(getName() + "." + name + "("); + if (argTypes != null) { + sb.append(Arrays.stream(argTypes) + .map(c -> (c == null) ? "null" : c.getName()) + .collect(Collectors.joining(","))); + } + sb.append(")"); + return sb.toString(); } /** use serialVersionUID from JDK 1.1 for interoperability */ --- old/src/java.base/share/classes/java/lang/Enum.java 2019-05-21 01:01:37.209118348 +0200 +++ new/src/java.base/share/classes/java/lang/Enum.java 2019-05-21 01:01:37.053118629 +0200 @@ -25,6 +25,8 @@ package java.lang; +import jdk.internal.lang.annotation.Foldable; + import java.io.IOException; import java.io.InvalidObjectException; import java.io.ObjectInputStream; @@ -32,6 +34,7 @@ import java.io.Serializable; import java.lang.constant.ClassDesc; import java.lang.constant.Constable; +import java.lang.constant.ConstantDesc; import java.lang.constant.ConstantDescs; import java.lang.constant.DynamicConstantDesc; import java.lang.invoke.MethodHandles; @@ -316,6 +319,7 @@ * @jvms 4.2.2 Unqualified Names * @since 12 */ + @Foldable public static> EnumDesc of(ClassDesc enumClass, String constantName) { return new EnumDesc<>(enumClass, constantName); @@ -332,5 +336,10 @@ public String toString() { return String.format("EnumDesc[%s.%s]", constantType().displayName(), constantName()); } + + @Override + public Optional describeConstable() { + return Optional.empty(); + } } } --- old/src/java.base/share/classes/java/lang/Math.java 2019-05-21 01:01:37.405117999 +0200 +++ new/src/java.base/share/classes/java/lang/Math.java 2019-05-21 01:01:37.249118277 +0200 @@ -1274,12 +1274,7 @@ * @since 1.8 */ public static int floorMod(int x, int y) { - int mod = x % y; - // if the signs are different and modulo not zero, adjust result - if ((mod ^ y) < 0 && mod != 0) { - mod += y; - } - return mod; + return x - floorDiv(x, y) * y; } /** @@ -1306,7 +1301,7 @@ */ public static int floorMod(long x, int y) { // Result cannot overflow the range of int. - return (int)floorMod(x, (long)y); + return (int)(x - floorDiv(x, y) * y); } /** @@ -1332,12 +1327,7 @@ * @since 1.8 */ public static long floorMod(long x, long y) { - long mod = x % y; - // if the signs are different and modulo not zero, adjust result - if ((x ^ y) < 0 && mod != 0) { - mod += y; - } - return mod; + return x - floorDiv(x, y) * y; } /** --- old/src/java.base/share/classes/java/lang/String.java 2019-05-21 01:01:37.621117612 +0200 +++ new/src/java.base/share/classes/java/lang/String.java 2019-05-21 01:01:37.465117890 +0200 @@ -164,12 +164,6 @@ /** Cache the hash code for the string */ private int hash; // Default to 0 - /** - * Cache if the hash has been calculated as actually being zero, enabling - * us to avoid recalculating this. - */ - private boolean hashIsZero; // Default to false; - /** use serialVersionUID from JDK 1.0.2 for interoperability */ private static final long serialVersionUID = -6849794470754667710L; @@ -1514,21 +1508,14 @@ * @return a hash code value for this object. */ public int hashCode() { - // The hash or hashIsZero fields are subject to a benign data race, - // making it crucial to ensure that any observable result of the - // calculation in this method stays correct under any possible read of - // these fields. Necessary restrictions to allow this to be correct - // without explicit memory fences or similar concurrency primitives is - // that we can ever only write to one of these two fields for a given - // String instance, and that the computation is idempotent and derived - // from immutable state int h = hash; - if (h == 0 && !hashIsZero) { + if (h == 0 && value.length > 0) { h = isLatin1() ? StringLatin1.hashCode(value) : StringUTF16.hashCode(value); - if (h == 0) { - hashIsZero = true; - } else { + // Avoid issuing a store if the calculated value is also zero: + // in addition to a minor performance benefit, this allows storing + // Strings with zero hash code in read-only memory. + if (h != 0) { hash = h; } } @@ -1965,7 +1952,20 @@ if (str.isEmpty()) { return this; } - return StringConcatHelper.simpleConcat(this, str); + if (coder() == str.coder()) { + byte[] val = this.value; + byte[] oval = str.value; + int len = val.length + oval.length; + byte[] buf = Arrays.copyOf(val, len); + System.arraycopy(oval, 0, buf, val.length, oval.length); + return new String(buf, coder); + } + int len = length(); + int olen = str.length(); + byte[] buf = StringUTF16.newBytesFor(len + olen); + getBytes(buf, 0, UTF16); + str.getBytes(buf, len, UTF16); + return new String(buf, UTF16); } /** --- old/src/java.base/share/classes/java/lang/StringBuffer.java 2019-05-21 01:01:37.845117209 +0200 +++ new/src/java.base/share/classes/java/lang/StringBuffer.java 2019-05-21 01:01:37.689117489 +0200 @@ -148,7 +148,8 @@ */ @HotSpotIntrinsicCandidate public StringBuffer(String str) { - super(str); + super(str.coder(), str.length(), 16); + append(str); } /** @@ -161,7 +162,8 @@ * @since 1.5 */ public StringBuffer(CharSequence seq) { - super(seq); + super(String.LATIN1, seq.length(), 16); + append(seq); } /** --- old/src/java.base/share/classes/java/lang/StringBuilder.java 2019-05-21 01:01:38.041116858 +0200 +++ new/src/java.base/share/classes/java/lang/StringBuilder.java 2019-05-21 01:01:37.889117130 +0200 @@ -121,7 +121,8 @@ */ @HotSpotIntrinsicCandidate public StringBuilder(String str) { - super(str); + super(str.coder(), str.length(), 16); + append(str); } /** @@ -133,7 +134,8 @@ * @param seq the sequence to copy. */ public StringBuilder(CharSequence seq) { - super(seq); + super(String.LATIN1, seq.length(), 16); + append(seq); } /** --- old/src/java.base/share/classes/java/lang/StringConcatHelper.java 2019-05-21 01:01:38.249116485 +0200 +++ new/src/java.base/share/classes/java/lang/StringConcatHelper.java 2019-05-21 01:01:38.093116766 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2019, 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 @@ -25,9 +25,6 @@ package java.lang; -import jdk.internal.misc.Unsafe; -import jdk.internal.vm.annotation.ForceInline; - /** * Helper for string concatenation. These methods are mostly looked up with private lookups * from {@link java.lang.invoke.StringConcatFactory}, and used in {@link java.lang.invoke.MethodHandle} @@ -41,10 +38,8 @@ /** * Check for overflow, throw exception on overflow. - * - * @param lengthCoder String length with coder packed into higher bits - * the upper word. - * @return the given parameter value, if valid + * @param lengthCoder String length and coder + * @return lengthCoder */ private static long checkOverflow(long lengthCoder) { if ((int)lengthCoder >= 0) { @@ -55,83 +50,76 @@ /** * Mix value length and coder into current length and coder. - * @param lengthCoder String length with coder packed into higher bits - * the upper word. - * @param value value to mix in - * @return new length and coder + * @param current current length + * @param value value to mix in + * @return new length and coder */ - static long mix(long lengthCoder, boolean value) { - return checkOverflow(lengthCoder + (value ? 4 : 5)); + static long mix(long current, boolean value) { + return checkOverflow(current + (value ? 4 : 5)); } /** * Mix value length and coder into current length and coder. - * @param lengthCoder String length with coder packed into higher bits - * the upper word. - * @param value value to mix in - * @return new length and coder + * @param current current length + * @param value value to mix in + * @return new length and coder */ - static long mix(long lengthCoder, byte value) { - return mix(lengthCoder, (int)value); + static long mix(long current, byte value) { + return mix(current, (int)value); } /** * Mix value length and coder into current length and coder. - * @param lengthCoder String length with coder packed into higher bits - * the upper word. - * @param value value to mix in - * @return new length and coder + * @param current current length + * @param value value to mix in + * @return new length and coder */ - static long mix(long lengthCoder, char value) { - return checkOverflow(lengthCoder + 1) | (StringLatin1.canEncode(value) ? 0 : UTF16); + static long mix(long current, char value) { + return checkOverflow(current + 1) | (StringLatin1.canEncode(value) ? 0 : UTF16); } /** * Mix value length and coder into current length and coder. - * @param lengthCoder String length with coder packed into higher bits - * the upper word. - * @param value value to mix in - * @return new length and coder + * @param current current length + * @param value value to mix in + * @return new length and coder */ - static long mix(long lengthCoder, short value) { - return mix(lengthCoder, (int)value); + static long mix(long current, short value) { + return mix(current, (int)value); } /** * Mix value length and coder into current length and coder. - * @param lengthCoder String length with coder packed into higher bits - * the upper word. - * @param value value to mix in - * @return new length and coder + * @param current current length + * @param value value to mix in + * @return new length and coder */ - static long mix(long lengthCoder, int value) { - return checkOverflow(lengthCoder + Integer.stringSize(value)); + static long mix(long current, int value) { + return checkOverflow(current + Integer.stringSize(value)); } /** * Mix value length and coder into current length and coder. - * @param lengthCoder String length with coder packed into higher bits - * the upper word. - * @param value value to mix in - * @return new length and coder + * @param current current length + * @param value value to mix in + * @return new length and coder */ - static long mix(long lengthCoder, long value) { - return checkOverflow(lengthCoder + Long.stringSize(value)); + static long mix(long current, long value) { + return checkOverflow(current + Long.stringSize(value)); } /** * Mix value length and coder into current length and coder. - * @param lengthCoder String length with coder packed into higher bits - * the upper word. - * @param value value to mix in - * @return new length and coder + * @param current current length + * @param value value to mix in + * @return new length and coder */ - static long mix(long lengthCoder, String value) { - lengthCoder += value.length(); + static long mix(long current, String value) { + current += value.length(); if (value.coder() == String.UTF16) { - lengthCoder |= UTF16; + current |= UTF16; } - return checkOverflow(lengthCoder); + return checkOverflow(current); } /** @@ -297,62 +285,10 @@ } } - /** - * Perform a simple concatenation between two objects. Added for startup - * performance, but also demonstrates the code that would be emitted by - * {@code java.lang.invoke.StringConcatFactory$MethodHandleInlineCopyStrategy} - * for two Object arguments. - * - * @param first first argument - * @param second second argument - * @return String resulting string - */ - @ForceInline - static String simpleConcat(Object first, Object second) { - String s1 = stringOf(first); - String s2 = stringOf(second); - // start "mixing" in length and coder or arguments, order is not - // important - long indexCoder = mix(initialCoder(), s2); - indexCoder = mix(indexCoder, s1); - byte[] buf = newArray(indexCoder); - // prepend each argument in reverse order, since we prepending - // from the end of the byte array - indexCoder = prepend(indexCoder, buf, s2); - indexCoder = prepend(indexCoder, buf, s1); - return newString(buf, indexCoder); - } - - /** - * We need some additional conversion for Objects in general, because - * {@code String.valueOf(Object)} may return null. String conversion rules - * in Java state we need to produce "null" String in this case, so we - * provide a customized version that deals with this problematic corner case. - */ - static String stringOf(Object value) { - String s; - return (value == null || (s = value.toString()) == null) ? "null" : s; - } - private static final long LATIN1 = (long)String.LATIN1 << 32; private static final long UTF16 = (long)String.UTF16 << 32; - private static final Unsafe UNSAFE = Unsafe.getUnsafe(); - - /** - * Allocates an uninitialized byte array based on the length and coder information - * in indexCoder - * @param indexCoder - * @return the newly allocated byte array - */ - @ForceInline - static byte[] newArray(long indexCoder) { - byte coder = (byte)(indexCoder >> 32); - int index = (int)indexCoder; - return (byte[]) UNSAFE.allocateUninitializedArray(byte.class, index << coder); - } - /** * Provides the initial coder for the String. * @return initial coder, adjusted into the upper half --- old/src/java.base/share/classes/java/lang/constant/AsTypeMethodHandleDesc.java 2019-05-21 01:01:38.449116126 +0200 +++ new/src/java.base/share/classes/java/lang/constant/AsTypeMethodHandleDesc.java 2019-05-21 01:01:38.293116406 +0200 @@ -24,9 +24,12 @@ */ package java.lang.constant; +import jdk.internal.lang.annotation.Foldable; + import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; +import java.util.Optional; import static java.lang.constant.ConstantDescs.BSM_INVOKE; import static java.lang.constant.ConstantDescs.CD_MethodHandle; @@ -51,6 +54,7 @@ } @Override + @Foldable public MethodTypeDesc invocationType() { return type; } @@ -67,4 +71,9 @@ public String toString() { return String.format("%s.asType%s", underlying.toString(), type.displayDescriptor()); } + + @Override + public Optional describeConstable() { + return Optional.empty(); + } } --- old/src/java.base/share/classes/java/lang/constant/ClassDesc.java 2019-05-21 01:01:38.649115767 +0200 +++ new/src/java.base/share/classes/java/lang/constant/ClassDesc.java 2019-05-21 01:01:38.489116055 +0200 @@ -24,6 +24,8 @@ */ package java.lang.constant; +import jdk.internal.lang.annotation.Foldable; +import java.lang.invoke.MethodHandles; import java.lang.invoke.TypeDescriptor; import java.util.stream.Stream; @@ -60,6 +62,7 @@ */ public interface ClassDesc extends ConstantDesc, + Constable, TypeDescriptor.OfField { /** @@ -76,6 +79,7 @@ * @throws IllegalArgumentException if the name string is not in the * correct format */ + @Foldable static ClassDesc of(String name) { ConstantUtils.validateBinaryClassName(requireNonNull(name)); return ClassDesc.ofDescriptor("L" + binaryToInternal(name) + ";"); @@ -95,6 +99,7 @@ * @throws IllegalArgumentException if the package name or class name are * not in the correct format */ + @Foldable static ClassDesc of(String packageName, String className) { ConstantUtils.validateBinaryClassName(requireNonNull(packageName)); if (packageName.isEmpty()) { @@ -129,6 +134,7 @@ * @jvms 4.3.2 Field Descriptors * @jvms 4.4.1 The CONSTANT_Class_info Structure */ + @Foldable static ClassDesc ofDescriptor(String descriptor) { requireNonNull(descriptor); if (descriptor.isEmpty()) { @@ -154,6 +160,7 @@ * @throws IllegalStateException if the resulting {@linkplain ClassDesc} would have an array rank of greater than 255 * @jvms 4.4.1 The CONSTANT_Class_info Structure */ + @Foldable default ClassDesc arrayType() { int depth = ConstantUtils.arrayDepth(descriptorString()); if (depth >= ConstantUtils.MAX_ARRAY_TYPE_DESC_DIMENSIONS) { @@ -174,6 +181,7 @@ * greater than 255 * @jvms 4.4.1 The CONSTANT_Class_info Structure */ + @Foldable default ClassDesc arrayType(int rank) { int currentDepth = ConstantUtils.arrayDepth(descriptorString()); if (rank <= 0 || currentDepth + rank > ConstantUtils.MAX_ARRAY_TYPE_DESC_DIMENSIONS) @@ -198,6 +206,7 @@ * describe a class or interface type * @throws IllegalArgumentException if the nested class name is invalid */ + @Foldable default ClassDesc nested(String nestedName) { validateMemberName(nestedName, false); if (!isClassOrInterface()) @@ -218,6 +227,7 @@ * describe a class or interface type * @throws IllegalArgumentException if the nested class name is invalid */ + @Foldable default ClassDesc nested(String firstNestedName, String... moreNestedNames) { if (!isClassOrInterface()) throw new IllegalStateException("Outer class is not a class or interface type"); @@ -260,6 +270,7 @@ * @return a {@linkplain ClassDesc} describing the component type, or {@code null} * if this descriptor does not describe an array type */ + @Foldable default ClassDesc componentType() { return isArray() ? ClassDesc.ofDescriptor(descriptorString().substring(1)) : null; } @@ -314,6 +325,7 @@ * @return the descriptor string * @jvms 4.3.2 Field Descriptors */ + @Foldable String descriptorString(); /** --- old/src/java.base/share/classes/java/lang/constant/ConstantDesc.java 2019-05-21 01:01:38.853115402 +0200 +++ new/src/java.base/share/classes/java/lang/constant/ConstantDesc.java 2019-05-21 01:01:38.697115683 +0200 @@ -24,6 +24,7 @@ */ package java.lang.constant; +import java.lang.invoke.Intrinsics; import java.lang.Enum.EnumDesc; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; @@ -54,6 +55,9 @@ * dynamic constants and {@code invokedynamic} instructions, and other * bytecodes or classfile structures that make use of the constant pool. * + *

The {@linkplain ConstantDesc} types are also used by {@link Intrinsics} + * to express {@code ldc} instructions. + * *

Constants describing various common constants (such as {@link ClassDesc} * instances for platform types) can be found in {@link ConstantDescs}. * @@ -78,6 +82,7 @@ * changes to the constant pool format as defined in JVMS 4.4. * * @see Constable + * @see Intrinsics * @see ConstantDescs * * @jvms 4.4 The Constant Pool --- old/src/java.base/share/classes/java/lang/constant/ConstantDescs.java 2019-05-21 01:01:39.057115036 +0200 +++ new/src/java.base/share/classes/java/lang/constant/ConstantDescs.java 2019-05-21 01:01:38.897115323 +0200 @@ -24,6 +24,8 @@ */ package java.lang.constant; +import jdk.internal.lang.annotation.Foldable; + import java.lang.Enum.EnumDesc; import java.lang.invoke.CallSite; import java.lang.invoke.ConstantBootstraps; @@ -64,114 +66,151 @@ // Don't change the order of these declarations! /** {@link ClassDesc} representing {@link Object} */ + @Foldable public static final ClassDesc CD_Object = ClassDesc.of("java.lang.Object"); /** {@link ClassDesc} representing {@link String} */ + @Foldable public static final ClassDesc CD_String = ClassDesc.of("java.lang.String"); /** {@link ClassDesc} representing {@link Class} */ + @Foldable public static final ClassDesc CD_Class = ClassDesc.of("java.lang.Class"); /** {@link ClassDesc} representing {@link Number} */ + @Foldable public static final ClassDesc CD_Number = ClassDesc.of("java.lang.Number"); /** {@link ClassDesc} representing {@link Integer} */ + @Foldable public static final ClassDesc CD_Integer = ClassDesc.of("java.lang.Integer"); /** {@link ClassDesc} representing {@link Long} */ + @Foldable public static final ClassDesc CD_Long = ClassDesc.of("java.lang.Long"); /** {@link ClassDesc} representing {@link Float} */ + @Foldable public static final ClassDesc CD_Float = ClassDesc.of("java.lang.Float"); /** {@link ClassDesc} representing {@link Double} */ + @Foldable public static final ClassDesc CD_Double = ClassDesc.of("java.lang.Double"); /** {@link ClassDesc} representing {@link Short} */ + @Foldable public static final ClassDesc CD_Short = ClassDesc.of("java.lang.Short"); /** {@link ClassDesc} representing {@link Byte} */ + @Foldable public static final ClassDesc CD_Byte = ClassDesc.of("java.lang.Byte"); /** {@link ClassDesc} representing {@link Character} */ + @Foldable public static final ClassDesc CD_Character = ClassDesc.of("java.lang.Character"); /** {@link ClassDesc} representing {@link Boolean} */ + @Foldable public static final ClassDesc CD_Boolean = ClassDesc.of("java.lang.Boolean"); /** {@link ClassDesc} representing {@link Void} */ + @Foldable public static final ClassDesc CD_Void = ClassDesc.of("java.lang.Void"); /** {@link ClassDesc} representing {@link Throwable} */ + @Foldable public static final ClassDesc CD_Throwable = ClassDesc.of("java.lang.Throwable"); /** {@link ClassDesc} representing {@link Exception} */ + @Foldable public static final ClassDesc CD_Exception = ClassDesc.of("java.lang.Exception"); /** {@link ClassDesc} representing {@link Enum} */ + @Foldable public static final ClassDesc CD_Enum = ClassDesc.of("java.lang.Enum"); /** {@link ClassDesc} representing {@link VarHandle} */ + @Foldable public static final ClassDesc CD_VarHandle = ClassDesc.of("java.lang.invoke.VarHandle"); /** {@link ClassDesc} representing {@link MethodHandles} */ + @Foldable public static final ClassDesc CD_MethodHandles = ClassDesc.of("java.lang.invoke.MethodHandles"); /** {@link ClassDesc} representing {@link MethodHandles.Lookup} */ + @Foldable public static final ClassDesc CD_MethodHandles_Lookup = CD_MethodHandles.nested("Lookup"); /** {@link ClassDesc} representing {@link MethodHandle} */ + @Foldable public static final ClassDesc CD_MethodHandle = ClassDesc.of("java.lang.invoke.MethodHandle"); /** {@link ClassDesc} representing {@link MethodType} */ + @Foldable public static final ClassDesc CD_MethodType = ClassDesc.of("java.lang.invoke.MethodType"); /** {@link ClassDesc} representing {@link CallSite} */ + @Foldable public static final ClassDesc CD_CallSite = ClassDesc.of("java.lang.invoke.CallSite"); /** {@link ClassDesc} representing {@link Collection} */ + @Foldable public static final ClassDesc CD_Collection = ClassDesc.of("java.util.Collection"); /** {@link ClassDesc} representing {@link List} */ + @Foldable public static final ClassDesc CD_List = ClassDesc.of("java.util.List"); /** {@link ClassDesc} representing {@link Set} */ + @Foldable public static final ClassDesc CD_Set = ClassDesc.of("java.util.Set"); /** {@link ClassDesc} representing {@link Map} */ + @Foldable public static final ClassDesc CD_Map = ClassDesc.of("java.util.Map"); /** {@link ClassDesc} representing {@link ConstantDesc} */ + @Foldable public static final ClassDesc CD_ConstantDesc = ClassDesc.of("java.lang.constant.ConstantDesc"); /** {@link ClassDesc} representing {@link ClassDesc} */ + @Foldable public static final ClassDesc CD_ClassDesc = ClassDesc.of("java.lang.constant.ClassDesc"); /** {@link ClassDesc} representing {@link EnumDesc} */ + @Foldable public static final ClassDesc CD_EnumDesc = CD_Enum.nested("EnumDesc"); /** {@link ClassDesc} representing {@link MethodTypeDesc} */ + @Foldable public static final ClassDesc CD_MethodTypeDesc = ClassDesc.of("java.lang.constant.MethodTypeDesc"); /** {@link ClassDesc} representing {@link MethodHandleDesc} */ + @Foldable public static final ClassDesc CD_MethodHandleDesc = ClassDesc.of("java.lang.constant.MethodHandleDesc"); /** {@link ClassDesc} representing {@link DirectMethodHandleDesc} */ + @Foldable public static final ClassDesc CD_DirectMethodHandleDesc = ClassDesc.of("java.lang.constant.DirectMethodHandleDesc"); /** {@link ClassDesc} representing {@link VarHandleDesc} */ + @Foldable public static final ClassDesc CD_VarHandleDesc = CD_VarHandle.nested("VarHandleDesc"); /** {@link ClassDesc} representing {@link DirectMethodHandleDesc.Kind} */ + @Foldable public static final ClassDesc CD_MethodHandleDesc_Kind = CD_DirectMethodHandleDesc.nested("Kind"); /** {@link ClassDesc} representing {@link DynamicConstantDesc} */ + @Foldable public static final ClassDesc CD_DynamicConstantDesc = ClassDesc.of("java.lang.constant.DynamicConstantDesc"); /** {@link ClassDesc} representing {@link DynamicCallSiteDesc} */ + @Foldable public static final ClassDesc CD_DynamicCallSiteDesc = ClassDesc.of("java.lang.constant.DynamicCallSiteDesc"); /** {@link ClassDesc} representing {@link ConstantBootstraps} */ + @Foldable public static final ClassDesc CD_ConstantBootstraps = ClassDesc.of("java.lang.invoke.ConstantBootstraps"); private static final ClassDesc[] INDY_BOOTSTRAP_ARGS = { @@ -185,68 +224,85 @@ ConstantDescs.CD_Class}; /** {@link MethodHandleDesc} representing {@link ConstantBootstraps#primitiveClass(Lookup, String, Class) ConstantBootstraps.primitiveClass} */ + @Foldable public static final DirectMethodHandleDesc BSM_PRIMITIVE_CLASS = ofConstantBootstrap(CD_ConstantBootstraps, "primitiveClass", CD_Class); /** {@link MethodHandleDesc} representing {@link ConstantBootstraps#enumConstant(Lookup, String, Class) ConstantBootstraps.enumConstant} */ + @Foldable public static final DirectMethodHandleDesc BSM_ENUM_CONSTANT = ofConstantBootstrap(CD_ConstantBootstraps, "enumConstant", CD_Enum); /** {@link MethodHandleDesc} representing {@link ConstantBootstraps#nullConstant(Lookup, String, Class) ConstantBootstraps.nullConstant} */ + @Foldable public static final DirectMethodHandleDesc BSM_NULL_CONSTANT = ofConstantBootstrap(CD_ConstantBootstraps, "nullConstant", ConstantDescs.CD_Object); /** {@link MethodHandleDesc} representing {@link ConstantBootstraps#fieldVarHandle(Lookup, String, Class, Class, Class) ConstantBootstraps.fieldVarHandle} */ + @Foldable public static final DirectMethodHandleDesc BSM_VARHANDLE_FIELD = ofConstantBootstrap(CD_ConstantBootstraps, "fieldVarHandle", CD_VarHandle, CD_Class, CD_Class); /** {@link MethodHandleDesc} representing {@link ConstantBootstraps#staticFieldVarHandle(Lookup, String, Class, Class, Class) ConstantBootstraps.staticVarHandle} */ + @Foldable public static final DirectMethodHandleDesc BSM_VARHANDLE_STATIC_FIELD = ofConstantBootstrap(CD_ConstantBootstraps, "staticFieldVarHandle", CD_VarHandle, CD_Class, CD_Class); /** {@link MethodHandleDesc} representing {@link ConstantBootstraps#arrayVarHandle(Lookup, String, Class, Class) ConstantBootstraps.arrayVarHandle} */ + @Foldable public static final DirectMethodHandleDesc BSM_VARHANDLE_ARRAY = ofConstantBootstrap(CD_ConstantBootstraps, "arrayVarHandle", CD_VarHandle, CD_Class); /** {@link MethodHandleDesc} representing {@link ConstantBootstraps#invoke(Lookup, String, Class, MethodHandle, Object...) ConstantBootstraps.invoke} */ + @Foldable public static final DirectMethodHandleDesc BSM_INVOKE = ofConstantBootstrap(CD_ConstantBootstraps, "invoke", CD_Object, CD_MethodHandle, CD_Object.arrayType()); /** {@link ClassDesc} representing the primitive type {@code int} */ + @Foldable public static final ClassDesc CD_int = ClassDesc.ofDescriptor("I"); /** {@link ClassDesc} representing the primitive type {@code long} */ + @Foldable public static final ClassDesc CD_long = ClassDesc.ofDescriptor("J"); /** {@link ClassDesc} representing the primitive type {@code float} */ + @Foldable public static final ClassDesc CD_float = ClassDesc.ofDescriptor("F"); /** {@link ClassDesc} representing the primitive type {@code double} */ + @Foldable public static final ClassDesc CD_double = ClassDesc.ofDescriptor("D"); /** {@link ClassDesc} representing the primitive type {@code short} */ + @Foldable public static final ClassDesc CD_short = ClassDesc.ofDescriptor("S"); /** {@link ClassDesc} representing the primitive type {@code byte} */ + @Foldable public static final ClassDesc CD_byte = ClassDesc.ofDescriptor("B"); /** {@link ClassDesc} representing the primitive type {@code char} */ + @Foldable public static final ClassDesc CD_char = ClassDesc.ofDescriptor("C"); /** {@link ClassDesc} representing the primitive type {@code boolean} */ + @Foldable public static final ClassDesc CD_boolean = ClassDesc.ofDescriptor("Z"); /** {@link ClassDesc} representing the primitive type {@code void} */ + @Foldable public static final ClassDesc CD_void = ClassDesc.ofDescriptor("V"); /** Nominal descriptor representing the constant {@code null} */ + @Foldable public static final ConstantDesc NULL = DynamicConstantDesc.ofNamed(ConstantDescs.BSM_NULL_CONSTANT, DEFAULT_NAME, ConstantDescs.CD_Object); @@ -267,6 +323,7 @@ * @throws NullPointerException if any of the arguments are null * @jvms 4.2.2 Unqualified Names */ + @Foldable public static DirectMethodHandleDesc ofCallsiteBootstrap(ClassDesc owner, String name, ClassDesc returnType, @@ -288,6 +345,7 @@ * @throws NullPointerException if any of the arguments are null * @jvms 4.2.2 Unqualified Names */ + @Foldable public static DirectMethodHandleDesc ofConstantBootstrap(ClassDesc owner, String name, ClassDesc returnType, --- old/src/java.base/share/classes/java/lang/constant/DirectMethodHandleDesc.java 2019-05-21 01:01:39.253114684 +0200 +++ new/src/java.base/share/classes/java/lang/constant/DirectMethodHandleDesc.java 2019-05-21 01:01:39.101114957 +0200 @@ -31,6 +31,8 @@ import jdk.internal.vm.annotation.Stable; +import jdk.internal.lang.annotation.Foldable; + import static java.lang.invoke.MethodHandleInfo.REF_getField; import static java.lang.invoke.MethodHandleInfo.REF_getStatic; import static java.lang.invoke.MethodHandleInfo.REF_invokeInterface; @@ -61,27 +63,27 @@ */ enum Kind { /** A method handle for a method invoked as with {@code invokestatic} */ - STATIC(REF_invokeStatic), + @Foldable STATIC(REF_invokeStatic), /** A method handle for a method invoked as with {@code invokestatic} */ - INTERFACE_STATIC(REF_invokeStatic, true), + @Foldable INTERFACE_STATIC(REF_invokeStatic, true), /** A method handle for a method invoked as with {@code invokevirtual} */ - VIRTUAL(REF_invokeVirtual), + @Foldable VIRTUAL(REF_invokeVirtual), /** A method handle for a method invoked as with {@code invokeinterface} */ - INTERFACE_VIRTUAL(REF_invokeInterface, true), + @Foldable INTERFACE_VIRTUAL(REF_invokeInterface, true), /** A method handle for a method invoked as with {@code invokespecial} */ - SPECIAL(REF_invokeSpecial), + @Foldable SPECIAL(REF_invokeSpecial), /** A method handle for an interface method invoked as with {@code invokespecial} */ - INTERFACE_SPECIAL(REF_invokeSpecial, true), + @Foldable INTERFACE_SPECIAL(REF_invokeSpecial, true), /** A method handle for a constructor */ - CONSTRUCTOR(REF_newInvokeSpecial), + @Foldable CONSTRUCTOR(REF_newInvokeSpecial), /** A method handle for a read accessor for an instance field */ - GETTER(REF_getField), + @Foldable GETTER(REF_getField), /** A method handle for a write accessor for an instance field */ - SETTER(REF_putField), + @Foldable SETTER(REF_putField), /** A method handle for a read accessor for a static field */ - STATIC_GETTER(REF_getStatic), + @Foldable STATIC_GETTER(REF_getStatic), /** A method handle for a write accessor for a static field */ - STATIC_SETTER(REF_putStatic); + @Foldable STATIC_SETTER(REF_putStatic); /** The corresponding {@code refKind} value for this kind of method handle, * as defined by {@link MethodHandleInfo} @@ -215,6 +217,7 @@ * * @return the {@link Kind} */ + @Foldable Kind kind(); /** @@ -223,6 +226,7 @@ * * @return the reference kind */ + @Foldable int refKind(); /** @@ -238,6 +242,7 @@ * * @return the class declaring the method or field */ + @Foldable ClassDesc owner(); /** @@ -246,6 +251,7 @@ * * @return the name of the method or field */ + @Foldable String methodName(); /** @@ -257,5 +263,6 @@ * * @return the lookup descriptor string */ + @Foldable String lookupDescriptor(); } --- old/src/java.base/share/classes/java/lang/constant/DirectMethodHandleDescImpl.java 2019-05-21 01:01:39.453114327 +0200 +++ new/src/java.base/share/classes/java/lang/constant/DirectMethodHandleDescImpl.java 2019-05-21 01:01:39.297114605 +0200 @@ -28,6 +28,7 @@ import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; import java.util.Objects; +import java.util.Optional; import static java.lang.constant.ConstantDescs.CD_void; import static java.lang.constant.ConstantUtils.validateClassOrInterface; @@ -217,4 +218,9 @@ public String toString() { return String.format("MethodHandleDesc[%s/%s::%s%s]", kind, owner.displayName(), name, invocationType.displayDescriptor()); } + + @Override + public Optional describeConstable() { + return null; + } } --- old/src/java.base/share/classes/java/lang/constant/DynamicCallSiteDesc.java 2019-05-21 01:01:39.653113968 +0200 +++ new/src/java.base/share/classes/java/lang/constant/DynamicCallSiteDesc.java 2019-05-21 01:01:39.501114240 +0200 @@ -24,6 +24,8 @@ */ package java.lang.constant; +import jdk.internal.lang.annotation.Foldable; + import java.lang.invoke.CallSite; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; @@ -102,6 +104,7 @@ * format * @jvms 4.2.2 Unqualified Names */ + @Foldable public static DynamicCallSiteDesc of(DirectMethodHandleDesc bootstrapMethod, String invocationName, MethodTypeDesc invocationType, @@ -123,6 +126,7 @@ * @throws IllegalArgumentException if the invocation name has the incorrect * format */ + @Foldable public static DynamicCallSiteDesc of(DirectMethodHandleDesc bootstrapMethod, String invocationName, MethodTypeDesc invocationType) { @@ -142,6 +146,7 @@ * @return the nominal descriptor * @throws NullPointerException if any parameter is null */ + @Foldable public static DynamicCallSiteDesc of(DirectMethodHandleDesc bootstrapMethod, MethodTypeDesc invocationType) { return of(bootstrapMethod, ConstantDescs.DEFAULT_NAME, invocationType); @@ -158,6 +163,7 @@ * @return the nominal descriptor * @throws NullPointerException if any parameter is null */ + @Foldable public DynamicCallSiteDesc withArgs(ConstantDesc... bootstrapArgs) { return new DynamicCallSiteDesc(bootstrapMethod, invocationName, invocationType, bootstrapArgs); } @@ -178,6 +184,7 @@ * format * @jvms 4.2.2 Unqualified Names */ + @Foldable public DynamicCallSiteDesc withNameAndType(String invocationName, MethodTypeDesc invocationType) { return new DynamicCallSiteDesc(bootstrapMethod, invocationName, invocationType, bootstrapArgs); @@ -189,6 +196,7 @@ * * @return the invocation name */ + @Foldable public String invocationName() { return invocationName; } @@ -199,6 +207,7 @@ * * @return the invocation type */ + @Foldable public MethodTypeDesc invocationType() { return invocationType; } @@ -209,6 +218,7 @@ * * @return the bootstrap method for the {@code invokedynamic} */ + @Foldable public MethodHandleDesc bootstrapMethod() { return bootstrapMethod; } /** --- old/src/java.base/share/classes/java/lang/constant/DynamicConstantDesc.java 2019-05-21 01:01:39.853113608 +0200 +++ new/src/java.base/share/classes/java/lang/constant/DynamicConstantDesc.java 2019-05-21 01:01:39.697113889 +0200 @@ -33,9 +33,12 @@ import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Optional; import java.util.function.Function; import java.util.stream.Stream; +import jdk.internal.lang.annotation.Foldable; + import static java.lang.constant.ConstantDescs.CD_Class; import static java.lang.constant.ConstantDescs.CD_VarHandle; import static java.lang.constant.ConstantDescs.DEFAULT_NAME; @@ -57,7 +60,7 @@ * @since 12 */ public abstract class DynamicConstantDesc - implements ConstantDesc { + implements ConstantDesc, Constable { private final DirectMethodHandleDesc bootstrapMethod; private final ConstantDesc[] bootstrapArgs; @@ -137,6 +140,7 @@ * format * @jvms 4.2.2 Unqualified Names */ + @Foldable public static ConstantDesc ofCanonical(DirectMethodHandleDesc bootstrapMethod, String constantName, ClassDesc constantType, @@ -165,7 +169,7 @@ * format * @jvms 4.2.2 Unqualified Names */ - + @Foldable public static DynamicConstantDesc ofNamed(DirectMethodHandleDesc bootstrapMethod, String constantName, ClassDesc constantType, @@ -188,6 +192,7 @@ * @throws NullPointerException if any argument is null * @jvms 4.2.2 Unqualified Names */ + @Foldable public static DynamicConstantDesc of(DirectMethodHandleDesc bootstrapMethod, ConstantDesc... bootstrapArgs) { return ofNamed(bootstrapMethod, DEFAULT_NAME, bootstrapMethod.invocationType().returnType(), bootstrapArgs); @@ -204,6 +209,7 @@ * @return the nominal descriptor * @throws NullPointerException if any argument is null */ + @Foldable public static DynamicConstantDesc of(DirectMethodHandleDesc bootstrapMethod) { return of(bootstrapMethod, EMPTY_CONSTANTDESC); } @@ -214,6 +220,7 @@ * * @return the constant name */ + @Foldable public String constantName() { return constantName; } @@ -224,6 +231,7 @@ * * @return the constant type */ + @Foldable public ClassDesc constantType() { return constantType; } @@ -234,6 +242,7 @@ * * @return the bootstrap method */ + @Foldable public DirectMethodHandleDesc bootstrapMethod() { return bootstrapMethod; } @@ -393,5 +402,10 @@ AnonymousDynamicConstantDesc(DirectMethodHandleDesc bootstrapMethod, String constantName, ClassDesc constantType, ConstantDesc... bootstrapArgs) { super(bootstrapMethod, constantName, constantType, bootstrapArgs); } + + @Override + public Optional describeConstable() { + return Optional.empty(); + } } } --- old/src/java.base/share/classes/java/lang/constant/MethodHandleDesc.java 2019-05-21 01:01:40.049113257 +0200 +++ new/src/java.base/share/classes/java/lang/constant/MethodHandleDesc.java 2019-05-21 01:01:39.897113530 +0200 @@ -28,6 +28,8 @@ import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; +import jdk.internal.lang.annotation.Foldable; + import static java.lang.constant.ConstantDescs.CD_void; import static java.lang.constant.DirectMethodHandleDesc.Kind.CONSTRUCTOR; @@ -43,7 +45,7 @@ * @since 12 */ public interface MethodHandleDesc - extends ConstantDesc { + extends ConstantDesc, Constable { /** * Creates a {@linkplain MethodHandleDesc} corresponding to an invocation of a @@ -75,6 +77,7 @@ * @jvms 4.3.2 Field Descriptors * @jvms 4.3.3 Method Descriptors */ + @Foldable static DirectMethodHandleDesc of(DirectMethodHandleDesc.Kind kind, ClassDesc owner, String name, @@ -115,6 +118,7 @@ * format, or the kind is invalid * @jvms 4.2.2 Unqualified Names */ + @Foldable static DirectMethodHandleDesc ofMethod(DirectMethodHandleDesc.Kind kind, ClassDesc owner, String name, @@ -153,6 +157,7 @@ * valid values or if the field name is not valid * @jvms 4.2.2 Unqualified Names */ + @Foldable static DirectMethodHandleDesc ofField(DirectMethodHandleDesc.Kind kind, ClassDesc owner, String fieldName, @@ -179,6 +184,7 @@ * @return the {@linkplain MethodHandleDesc} * @throws NullPointerException if any of the arguments are null */ + @Foldable static DirectMethodHandleDesc ofConstructor(ClassDesc owner, ClassDesc... paramTypes) { return MethodHandleDesc.ofMethod(CONSTRUCTOR, owner, ConstantDescs.DEFAULT_NAME, @@ -192,6 +198,7 @@ * @param type a {@link MethodHandleDesc} describing the new method type * @return a {@linkplain MethodHandleDesc} for the adapted method handle */ + @Foldable default MethodHandleDesc asType(MethodTypeDesc type) { return (invocationType().equals(type)) ? this : new AsTypeMethodHandleDesc(this, type); } @@ -204,6 +211,7 @@ * * @return a {@linkplain MethodHandleDesc} describing the method handle type */ + @Foldable MethodTypeDesc invocationType(); /** --- old/src/java.base/share/classes/java/lang/constant/MethodTypeDesc.java 2019-05-21 01:01:40.249112900 +0200 +++ new/src/java.base/share/classes/java/lang/constant/MethodTypeDesc.java 2019-05-21 01:01:40.093113178 +0200 @@ -24,12 +24,17 @@ */ package java.lang.constant; +import jdk.internal.lang.annotation.Foldable; + +import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; import java.lang.invoke.TypeDescriptor; import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; +import static java.util.Objects.requireNonNull; + /** * A nominal descriptor for a * {@linkplain MethodType} constant. @@ -43,6 +48,7 @@ */ public interface MethodTypeDesc extends ConstantDesc, + Constable, TypeDescriptor.OfMethod { /** * Creates a {@linkplain MethodTypeDesc} given a method descriptor string. @@ -54,6 +60,7 @@ * method descriptor * @jvms 4.3.3 Method Descriptors */ + @Foldable static MethodTypeDesc ofDescriptor(String descriptor) { return MethodTypeDescImpl.ofDescriptor(descriptor); } @@ -67,6 +74,7 @@ * @return a {@linkplain MethodTypeDesc} describing the desired method type * @throws NullPointerException if any argument is {@code null} */ + @Foldable static MethodTypeDesc of(ClassDesc returnDesc, ClassDesc... paramDescs) { return new MethodTypeDescImpl(returnDesc, paramDescs); } @@ -76,6 +84,7 @@ * * @return a {@link ClassDesc} describing the return type of the method type */ + @Foldable ClassDesc returnType(); /** @@ -83,6 +92,7 @@ * this {@linkplain MethodTypeDesc}. * @return the number of parameters */ + @Foldable int parameterCount(); /** @@ -94,6 +104,7 @@ * @throws IndexOutOfBoundsException if the index is outside the half-open * range {[0, parameterCount())} */ + @Foldable ClassDesc parameterType(int index); /** @@ -118,6 +129,7 @@ * @return a {@linkplain MethodTypeDesc} describing the desired method type * @throws NullPointerException if any argument is {@code null} */ + @Foldable MethodTypeDesc changeReturnType(ClassDesc returnType); /** @@ -131,6 +143,7 @@ * @throws IndexOutOfBoundsException if the index is outside the half-open * range {[0, parameterCount)} */ + @Foldable MethodTypeDesc changeParameterType(int index, ClassDesc paramType); /** @@ -144,6 +157,7 @@ * range {[0, parameterCount)}, or {@code end} is outside the closed range * {@code [0, parameterCount]} */ + @Foldable MethodTypeDesc dropParameterTypes(int start, int end); /** @@ -158,6 +172,7 @@ * @throws IndexOutOfBoundsException if {@code pos} is outside the closed * range {[0, parameterCount]} */ + @Foldable MethodTypeDesc insertParameterTypes(int pos, ClassDesc... paramTypes); /** --- old/src/java.base/share/classes/java/lang/constant/MethodTypeDescImpl.java 2019-05-21 01:01:40.441112556 +0200 +++ new/src/java.base/share/classes/java/lang/constant/MethodTypeDescImpl.java 2019-05-21 01:01:40.289112828 +0200 @@ -28,7 +28,10 @@ import java.lang.invoke.MethodType; import java.util.Arrays; import java.util.List; +import java.util.Optional; +import jdk.internal.lang.annotation.Foldable; +import static java.lang.constant.ConstantDescs.BSM_INVOKE; import static java.util.Objects.requireNonNull; /** @@ -65,6 +68,7 @@ * method descriptor * @jvms 4.3.3 Method Descriptors */ + @Foldable static MethodTypeDescImpl ofDescriptor(String descriptor) { requireNonNull(descriptor); List types = ConstantUtils.parseMethodDescriptor(descriptor); @@ -72,16 +76,19 @@ return new MethodTypeDescImpl(ClassDesc.ofDescriptor(types.get(0)), paramTypes); } + @Foldable @Override public ClassDesc returnType() { return returnType; } + @Foldable @Override public int parameterCount() { return argTypes.length; } + @Foldable @Override public ClassDesc parameterType(int index) { return argTypes[index]; @@ -97,11 +104,13 @@ return argTypes.clone(); } + @Foldable @Override public MethodTypeDesc changeReturnType(ClassDesc returnType) { return MethodTypeDesc.of(returnType, argTypes); } + @Foldable @Override public MethodTypeDesc changeParameterType(int index, ClassDesc paramType) { ClassDesc[] newArgs = argTypes.clone(); @@ -109,6 +118,7 @@ return MethodTypeDesc.of(returnType, newArgs); } + @Foldable @Override public MethodTypeDesc dropParameterTypes(int start, int end) { if (start < 0 || start >= argTypes.length || end < 0 || end > argTypes.length) @@ -121,6 +131,7 @@ return MethodTypeDesc.of(returnType, newArgs); } + @Foldable @Override public MethodTypeDesc insertParameterTypes(int pos, ClassDesc... paramTypes) { if (pos < 0 || pos > argTypes.length) @@ -170,4 +181,9 @@ public String toString() { return String.format("MethodTypeDesc[%s]", displayDescriptor()); } + + @Override + public Optional describeConstable() { + return Optional.empty(); + } } --- old/src/java.base/share/classes/java/lang/constant/PrimitiveClassDescImpl.java 2019-05-21 01:01:40.641112197 +0200 +++ new/src/java.base/share/classes/java/lang/constant/PrimitiveClassDescImpl.java 2019-05-21 01:01:40.489112469 +0200 @@ -25,6 +25,7 @@ package java.lang.constant; import java.lang.invoke.MethodHandles; +import java.util.Optional; import sun.invoke.util.Wrapper; @@ -71,4 +72,9 @@ public String toString() { return String.format("PrimitiveClassDesc[%s]", displayName()); } + + @Override + public Optional describeConstable() { + return Optional.empty(); + } } --- old/src/java.base/share/classes/java/lang/constant/ReferenceClassDescImpl.java 2019-05-21 01:01:40.841111837 +0200 +++ new/src/java.base/share/classes/java/lang/constant/ReferenceClassDescImpl.java 2019-05-21 01:01:40.685112118 +0200 @@ -26,6 +26,10 @@ import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodHandles; +import java.util.Optional; + +import static java.lang.constant.ConstantDescs.BSM_INVOKE; import static java.lang.constant.ConstantUtils.dropFirstAndLastChar; import static java.lang.constant.ConstantUtils.internalToBinary; import static java.util.Objects.requireNonNull; @@ -108,4 +112,9 @@ public String toString() { return String.format("ClassDesc[%s]", displayName()); } + + @Override + public Optional describeConstable() { + return Optional.empty(); + } } --- old/src/java.base/share/classes/java/lang/invoke/AbstractValidatingLambdaMetafactory.java 2019-05-21 01:01:41.041111480 +0200 +++ new/src/java.base/share/classes/java/lang/invoke/AbstractValidatingLambdaMetafactory.java 2019-05-21 01:01:40.885111759 +0200 @@ -200,6 +200,17 @@ throws LambdaConversionException; /** + * Builds an instance of the functional interface directly. + * + * @return an instance of the functional interface + * @throws ReflectiveOperationException + * @throws LambdaConversionException If properly formed functional interface + * is not found or if creating the functional interface requires parameters + */ + abstract Object buildFunctionalInterfaceInstance() + throws LambdaConversionException; + + /** * Check the meta-factory arguments for errors * @throws LambdaConversionException if there are improper conversions */ --- old/src/java.base/share/classes/java/lang/invoke/BootstrapCallInfo.java 2019-05-21 01:01:41.245111114 +0200 +++ new/src/java.base/share/classes/java/lang/invoke/BootstrapCallInfo.java 2019-05-21 01:01:41.093111386 +0200 @@ -26,6 +26,8 @@ package java.lang.invoke; import java.lang.invoke.MethodHandles.Lookup; +import java.util.Arrays; +import java.util.List; /** * An interface providing full static information about a particular @@ -73,7 +75,7 @@ args.add(bsci.invocationName()); args.add(bsci.invocationType()); MethodHandle bsm = (MethodHandle) bsci.get(0); - List restOfArgs = bsci.asList().subList(1, bsci.size(); + List restOfArgs = bsci.asList().subList(1, bsci.size()); // the next line eagerly resolves all remaining static arguments: args.addAll(restOfArgs); return bsm.invokeWithArguments(args); @@ -96,16 +98,148 @@ static Object genericBSM(Lookup lookup, String name, Object type, MethodHandle bsm, Object... args) throws Throwable { - ConstantGroup cons = ConstantGroup.makeConstantGroup(Arrays.asList(args)); - BootstrapCallInfo bsci = makeBootstrapCallInfo(bsm, name, type, cons); + BootstrapCallInfo bsci = makeBootstrapCallInfo(bsm, name, type, args); return bsm.invoke(lookup, bsci); } * } * - * @since 1.10 + * @since 11 */ -// public +public interface BootstrapCallInfo extends ConstantGroup { + + /// Access + + /** + * Returns the number of static arguments. + * @return the number of static arguments + */ + int size(); + + /** + * Returns the selected static argument, resolving it if necessary. + * Throws a linkage error if resolution proves impossible. + * @param index which static argument to select + * @return the selected static argument + * @throws LinkageError if the selected static argument needs resolution + * and cannot be resolved + */ + Object get(int index) throws LinkageError; + + /** + * Returns the selected static argument, + * or the given sentinel value if there is none available. + * If the static argument cannot be resolved, the sentinel will be returned. + * If the static argument can (perhaps) be resolved, but has not yet been resolved, + * then the sentinel may be returned, at the implementation's discretion. + * To force resolution (and a possible exception), call {@link #get(int)}. + * @param index the selected constant + * @param ifNotPresent the sentinel value to return if the static argument is not present + * @return the selected static argument, if available, else the sentinel value + */ + Object get(int index, Object ifNotPresent); + + /** + * Returns an indication of whether a static argument may be available. + * If it returns {@code true}, it will always return true in the future, + * and a call to {@link #get(int)} will never throw an exception. + *

+ * After a normal return from {@link #get(int)} or a present + * value is reported from {@link #get(int,Object)}, this method + * must always return true. + *

+ * If this method returns {@code false}, nothing in particular + * can be inferred, since the query only concerns the internal + * logic of the {@code BootstrapCallInfo} object which ensures that a + * successful query to a constant will always remain successful. + * The only way to force a permanent decision about whether + * a static argument is available is to call {@link #get(int)} and + * be ready for an exception if the constant is unavailable. + * @param index the selected constant + * @return {@code true} if the selected static argument is known by + * this object to be present, {@code false} if it is known + * not to be present or + */ + boolean isPresent(int index); + + + /// Views + + /** + * Create a view on the static arguments as a {@link List} view. + * Any request for a static argument through this view will + * force resolution. + * @return a {@code List} view on the static arguments which will force resolution + */ + default List asList() { + return new AbstractConstantGroup.AsList(this, 0, size()); + } + + /** + * Create a view on the static argument as a {@link List} view. + * Any request for a static argument through this view will + * return the given sentinel value, if the corresponding + * call to {@link #get(int,Object)} would do so. + * @param ifNotPresent the sentinel value to return if a static argument is not present + * @return a {@code List} view on the static arguments which will not force resolution + */ + default List asList(Object ifNotPresent) { + return new AbstractConstantGroup.AsList(this, 0, size(), ifNotPresent); + } + + + /// Bulk operations + + /** + * Copy a sequence of static arguments into a given buffer. + * This is equivalent to {@code end-offset} separate calls to {@code get}, + * for each index in the range from {@code offset} up to but not including {@code end}. + * For the first static argument that cannot be resolved, + * a {@code LinkageError} is thrown, but only after + * preceding static arguments have been stored. + * @param start index of first static argument to retrieve + * @param end limiting index of static arguments to retrieve + * @param buf array to receive the requested static arguments + * @param pos position in the array to offset storing the static arguments + * @return the limiting index, {@code end} + * @throws LinkageError if a static argument cannot be resolved + */ + default int copyArguments(int start, int end, + Object[] buf, int pos) + throws LinkageError + { + int bufBase = pos - start; // buf[bufBase + i] = get(i) + for (int i = start; i < end; i++) { + buf[bufBase + i] = get(i); + } + return end; + } + + /** + * Copy a sequence of static arguments into a given buffer. + * This is equivalent to {@code end-offset} separate calls to {@code get}, + * for each index in the range from {@code offset} up to but not including {@code end}. + * Any static arguments that cannot be resolved are replaced by the + * given sentinel value. + * @param start index of first static argument to retrieve + * @param end limiting index of static arguments to retrieve + * @param buf array to receive the requested values + * @param pos position in the array to offset storing the static arguments + * @param ifNotPresent sentinel value to store if a static argument is not available + * @return the limiting index, {@code end} + * @throws LinkageError if {@code resolve} is true and a static argument cannot be resolved + */ + default int copyConstants(int start, int end, + Object[] buf, int pos, + Object ifNotPresent) { + int bufBase = pos - start; // buf[bufBase + i] = get(i) + for (int i = start; i < end; i++) { + buf[bufBase + i] = get(i, ifNotPresent); + } + return end; + } + + /** Returns the bootstrap method for this call. * @return the bootstrap method */ @@ -126,17 +260,126 @@ * @param bsm bootstrap method * @param name invocation name * @param type invocation type - * @param constants the additional static arguments for the bootstrap method + * @param args the additional static arguments for the bootstrap method * @param the type of the invocation type, either {@link MethodHandle} or {@link Class} * @return a new bootstrap call descriptor with the given components */ static BootstrapCallInfo makeBootstrapCallInfo(MethodHandle bsm, String name, T type, - ConstantGroup constants) { - AbstractConstantGroup.BSCIWithCache bsci = new AbstractConstantGroup.BSCIWithCache<>(bsm, name, type, constants.size()); + Object... args) { + AbstractConstantGroup.BSCIWithCache bsci = new AbstractConstantGroup.BSCIWithCache<>(bsm, name, type, args.length); final Object NP = AbstractConstantGroup.BSCIWithCache.NOT_PRESENT; - bsci.initializeCache(constants.asList(NP), NP); + bsci.initializeCache(Arrays.asList(args), NP); return bsci; } -} + + /** + * Invoke a bootstrap method handle with arguments obtained by resolving + * the sequence of constants supplied by a given bootstrap call descriptor, + * {@code bci}. + * The first argument to the method will be {@code lookup}. + * The second argument will be the invocation name of {@code bci}. + * The third argument will be the invocation type of {@code bci}. + * The fourth and subsequent arguments (if any) will be the resolved + * constants, in order, supplied by {@code bci}. + *

+ * @apiNote + * This method behaves like the following but may be more optimal: + *

{@code
+     *   ArrayList args = new ArrayList<>();
+     *   args.add(lookup);
+     *   args.add(bsci.invocationName());
+     *   args.add(bsci.invocationType());
+     *   List constantArgs = bsci.asList();
+     *   args.addAll(constantArgs);
+     *   return handle.invokeWithArguments(args);
+     * }
+     *
+     * @param handle the bootstrap method handle to be invoked with resolved
+     *        constants supplied by {@code bci}
+     * @param lookup the lookup
+     * @param bsci the bootstrap call descriptor
+     * @return the result of invocation
+     * @throws Throwable if an error occurs when resolving the constants from
+     *         the bootstrap call descriptor or invoking the method handle
+     */
+    // @@@ More stuff to add as api note
+    // This method is static so that it's possible to look it up and bind
+    // to a method handle, thereby viewing that method handle as if accepts
+    // a BootstrapCallInfo
+    static Object invokeFromCallInfoToArguments(MethodHandle handle,
+                                                MethodHandles.Lookup lookup,
+                                                BootstrapCallInfo bsci) throws Throwable {
+        int argc = bsci.size();
+        switch (argc) {
+            case 0:
+                return handle.invoke(lookup, bsci.invocationName(), bsci.invocationType());
+            case 1:
+                return handle.invoke(lookup, bsci.invocationName(), bsci.invocationType(),
+                                     bsci.get(0));
+            case 2:
+                return handle.invoke(lookup, bsci.invocationName(), bsci.invocationType(),
+                                     bsci.get(0), bsci.get(1));
+            case 3:
+                return handle.invoke(lookup, bsci.invocationName(), bsci.invocationType(),
+                                     bsci.get(0), bsci.get(1), bsci.get(2));
+            case 4:
+                return handle.invoke(lookup, bsci.invocationName(), bsci.invocationType(),
+                                     bsci.get(0), bsci.get(1), bsci.get(2), bsci.get(3));
+            case 5:
+                return handle.invoke(lookup, bsci.invocationName(), bsci.invocationType(),
+                                     bsci.get(0), bsci.get(1), bsci.get(2), bsci.get(3), bsci.get(4));
+            case 6:
+                return handle.invoke(lookup, bsci.invocationName(), bsci.invocationType(),
+                                     bsci.get(0), bsci.get(1), bsci.get(2), bsci.get(3), bsci.get(4), bsci.get(5));
+            default:
+                final int NON_SPREAD_ARG_COUNT = 3;  // (lookup, name, type)
+                final int MAX_SAFE_SIZE = MethodType.MAX_MH_ARITY / 2 - NON_SPREAD_ARG_COUNT;
+                if (argc >= MAX_SAFE_SIZE) {
+                    // to be on the safe side, use invokeWithArguments which handles jumbo lists
+                    Object[] newargv = new Object[NON_SPREAD_ARG_COUNT + argc];
+                    newargv[0] = lookup;
+                    newargv[1] = bsci.invocationName();
+                    newargv[2] = bsci.invocationType();
+                    bsci.copyArguments(0, argc, newargv, NON_SPREAD_ARG_COUNT);
+                    return handle.invokeWithArguments(newargv);
+                }
+                MethodType invocationType = MethodType.genericMethodType(NON_SPREAD_ARG_COUNT + argc);
+                MethodHandle typedBSM = handle.asType(invocationType);
+                MethodHandle spreader = invocationType.invokers().spreadInvoker(NON_SPREAD_ARG_COUNT);
+                Object[] argv = new Object[argc];
+                bsci.copyArguments(0, argc, argv, 0);
+                return spreader.invokeExact(typedBSM, (Object) lookup, (Object) bsci.invocationName(), bsci.invocationType(), argv);
+        }
+    }
+
+    /**
+     * Invoke a bootstrap method handle with a bootstrap call descriptor
+     * argument composed from a given sequence of arguments.
+     * 

+ * @apiNote + * This method behaves like the following but may be more optimal: + *

{@code
+     *   BootstrapCallInfo bsci = makeBootstrapCallInfo(handle, name, type, args);
+     *   return handle.invoke(lookup, bsci);
+     * }
+     *
+     * @param handle the bootstrap method handle to be invoked with a bootstrap
+     *        call descriptor composed from the sequence of arguments
+     * @param lookup the lookup
+     * @param name the method name or constant name
+     * @param type the method type or constant type
+     * @param args the sequence of arguments
+     * @return the result of invocation
+     * @throws Throwable if an error occurs when invoking the method handle
+     */
+    static Object invokeFromArgumentsToCallInfo(MethodHandle handle,
+                                                MethodHandles.Lookup lookup,
+                                                String name,
+                                                Object type,
+                                                Object... args) throws Throwable {
+        BootstrapCallInfo bsci = makeBootstrapCallInfo(handle, name, type, args);
+        return handle.invoke(lookup, bsci);
+    }
+}
\ No newline at end of file
--- old/src/java.base/share/classes/java/lang/invoke/BootstrapMethodInvoker.java	2019-05-21 01:01:41.509110640 +0200
+++ new/src/java.base/share/classes/java/lang/invoke/BootstrapMethodInvoker.java	2019-05-21 01:01:41.341110943 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -47,6 +47,8 @@
      * @param type the method type or constant type
      * @param info information passed up from the JVM, to derive static arguments
      * @param callerClass the class containing the resolved method call or constant load
+     * @param includeMetadata true if the lookup, name and type metadata arguments should
+     *                        be included when invoking the BSM
      * @param  the expected return type
      * @return the expected value, either a CallSite or a constant value
      */
@@ -57,24 +59,30 @@
                         // Extra arguments for BSM, if any:
                         Object info,
                         // Caller information:
-                        Class callerClass) {
+                        Class callerClass,
+                        boolean includeMetadata) {
         MethodHandles.Lookup caller = IMPL_LOOKUP.in(callerClass);
+        MethodType bsmType = bootstrapMethod.type();
         Object result;
         boolean pullMode = isPullModeBSM(bootstrapMethod);  // default value is false
         boolean vmIsPushing = !staticArgumentsPulled(info); // default value is true
         MethodHandle pullModeBSM;
+
         // match the VM with the BSM
         if (vmIsPushing) {
             // VM is pushing arguments at us
+            // Need to transform if pull-mode BSM
             pullModeBSM = null;
             if (pullMode) {
-                bootstrapMethod = pushMePullYou(bootstrapMethod, true);
+                bootstrapMethod = PushAdapter.toPullBootstrapMethod(bootstrapMethod);
+                bsmType = bootstrapMethod.type();
             }
-        } else {
+        }
+        else {
             // VM wants us to pull args from it
+            // Need to transform if push-mode BSM
             pullModeBSM = pullMode ? bootstrapMethod :
-                    pushMePullYou(bootstrapMethod, false);
-            bootstrapMethod = null;
+                    PullAdapter.toPushBootstrapMethod(bootstrapMethod, includeMetadata);
         }
         try {
             // As an optimization we special case various known BSMs,
@@ -86,21 +94,30 @@
             // checking.
             info = maybeReBox(info);
             if (info == null) {
-                // VM is allowed to pass up a null meaning no BSM args
-                result = invoke(bootstrapMethod, caller, name, type);
+                if (includeMetadata) {
+                    // VM is allowed to pass up a null meaning no BSM args
+                    result = invoke(bootstrapMethod, caller, name, type);
+                }
+                else {
+                    result = bootstrapMethod.invoke();
+                }
             }
             else if (!info.getClass().isArray()) {
                 // VM is allowed to pass up a single BSM arg directly
 
                 // Call to StringConcatFactory::makeConcatWithConstants
                 // with empty constant arguments?
-                if (isStringConcatFactoryBSM(bootstrapMethod.type())) {
+                if (isStringConcatFactoryBSM(bsmType)) {
                     result = (CallSite)bootstrapMethod
                             .invokeExact(caller, name, (MethodType)type,
                                          (String)info, new Object[0]);
-                } else {
+                }
+                else if (includeMetadata) {
                     result = invoke(bootstrapMethod, caller, name, type, info);
                 }
+                else {
+                    result = bootstrapMethod.invoke(info);
+                }
             }
             else if (info.getClass() == int[].class) {
                 // VM is allowed to pass up a pair {argc, index}
@@ -113,30 +130,39 @@
                 // The code in this method makes up for any mismatches.
                 BootstrapCallInfo bsci
                     = new VM_BSCI<>(bootstrapMethod, name, type, caller, (int[])info);
-                // Pull-mode API is (Lookup, BootstrapCallInfo) -> Object
-                result = pullModeBSM.invoke(caller, bsci);
+                if (includeMetadata) {
+                    // Pull-mode API is (Lookup, BootstrapCallInfo) -> Object
+                    result = pullModeBSM.invoke(caller, bsci);
+                }
+                else {
+                    // Pull-mode API is (BootstrapCallInfo) -> Object
+                    result = pullModeBSM.invoke(bsci);
+                }
             }
             else {
                 // VM is allowed to pass up a full array of resolved BSM args
                 Object[] argv = (Object[]) info;
                 maybeReBoxElements(argv);
 
-                MethodType bsmType = bootstrapMethod.type();
                 if (isLambdaMetafactoryIndyBSM(bsmType) && argv.length == 3) {
                     result = (CallSite)bootstrapMethod
                             .invokeExact(caller, name, (MethodType)type, (MethodType)argv[0],
                                     (MethodHandle)argv[1], (MethodType)argv[2]);
-                } else if (isLambdaMetafactoryCondyBSM(bsmType) && argv.length == 3) {
+                }
+                else if (isLambdaMetafactoryCondyBSM(bsmType) && argv.length == 3) {
                     result = bootstrapMethod
                             .invokeExact(caller, name, (Class)type, (MethodType)argv[0],
                                     (MethodHandle)argv[1], (MethodType)argv[2]);
-                } else if (isStringConcatFactoryBSM(bsmType) && argv.length >= 1) {
+                }
+                else if (isStringConcatFactoryBSM(bsmType) && argv.length >= 1) {
                     String recipe = (String)argv[0];
                     Object[] shiftedArgs = Arrays.copyOfRange(argv, 1, argv.length);
                     result = (CallSite)bootstrapMethod.invokeExact(caller, name, (MethodType)type, recipe, shiftedArgs);
-                } else if (isLambdaMetafactoryAltMetafactoryBSM(bsmType)) {
+                }
+                else if (isLambdaMetafactoryAltMetafactoryBSM(bsmType)) {
                     result = (CallSite)bootstrapMethod.invokeExact(caller, name, (MethodType)type, argv);
-                } else {
+                }
+                else if (includeMetadata) {
                     switch (argv.length) {
                         case 0:
                             result = invoke(bootstrapMethod, caller, name, type);
@@ -169,6 +195,39 @@
                             result = invokeWithManyArguments(bootstrapMethod, caller, name, type, argv);
                     }
                 }
+                else {
+                    switch (argv.length) {
+                        case 0:
+                            result = bootstrapMethod.invoke();
+                            break;
+                        case 1:
+                            result = bootstrapMethod.invoke(
+                                            argv[0]);
+                            break;
+                        case 2:
+                            result = bootstrapMethod.invoke(
+                                            argv[0], argv[1]);
+                            break;
+                        case 3:
+                            result = bootstrapMethod.invoke(
+                                            argv[0], argv[1], argv[2]);
+                            break;
+                        case 4:
+                            result = bootstrapMethod.invoke(
+                                            argv[0], argv[1], argv[2], argv[3]);
+                            break;
+                        case 5:
+                            result = bootstrapMethod.invoke(
+                                            argv[0], argv[1], argv[2], argv[3], argv[4]);
+                            break;
+                        case 6:
+                            result = bootstrapMethod.invoke(
+                                            argv[0], argv[1], argv[2], argv[3], argv[4], argv[5]);
+                            break;
+                        default:
+                            result = invokeWithManyArguments(bootstrapMethod, argv);
+                    }
+                }
             }
             if (resultType.isPrimitive()) {
                 // Non-reference conversions are more than just plain casts.
@@ -202,7 +261,8 @@
                                  String name, Object type) throws Throwable {
         if (type instanceof Class) {
             return bootstrapMethod.invoke(caller, name, (Class)type);
-        } else {
+        }
+        else {
             return bootstrapMethod.invoke(caller, name, (MethodType)type);
         }
     }
@@ -211,7 +271,8 @@
                                  String name, Object type, Object arg0) throws Throwable {
         if (type instanceof Class) {
             return bootstrapMethod.invoke(caller, name, (Class)type, arg0);
-        } else {
+        }
+        else {
             return bootstrapMethod.invoke(caller, name, (MethodType)type, arg0);
         }
     }
@@ -220,7 +281,8 @@
                                  Object type, Object arg0, Object arg1) throws Throwable {
         if (type instanceof Class) {
             return bootstrapMethod.invoke(caller, name, (Class)type, arg0, arg1);
-        } else {
+        }
+        else {
             return bootstrapMethod.invoke(caller, name, (MethodType)type, arg0, arg1);
         }
     }
@@ -230,7 +292,8 @@
                                  Object arg2) throws Throwable {
         if (type instanceof Class) {
             return bootstrapMethod.invoke(caller, name, (Class)type, arg0, arg1, arg2);
-        } else {
+        }
+        else {
             return bootstrapMethod.invoke(caller, name, (MethodType)type, arg0, arg1, arg2);
         }
     }
@@ -240,7 +303,8 @@
                                  Object arg2, Object arg3) throws Throwable {
         if (type instanceof Class) {
             return bootstrapMethod.invoke(caller, name, (Class)type, arg0, arg1, arg2, arg3);
-        } else {
+        }
+        else {
             return bootstrapMethod.invoke(caller, name, (MethodType)type, arg0, arg1, arg2, arg3);
         }
     }
@@ -250,7 +314,8 @@
                                  Object arg2, Object arg3, Object arg4) throws Throwable {
         if (type instanceof Class) {
             return bootstrapMethod.invoke(caller, name, (Class)type, arg0, arg1, arg2, arg3, arg4);
-        } else {
+        }
+        else {
             return bootstrapMethod.invoke(caller, name, (MethodType)type, arg0, arg1, arg2, arg3, arg4);
         }
     }
@@ -277,7 +342,8 @@
             newargv[2] = type;
             System.arraycopy(argv, 0, newargv, NON_SPREAD_ARG_COUNT, argv.length);
             return bootstrapMethod.invokeWithArguments(newargv);
-        } else {
+        }
+        else {
             MethodType invocationType = MethodType.genericMethodType(NON_SPREAD_ARG_COUNT + argv.length);
             MethodHandle typedBSM = bootstrapMethod.asType(invocationType);
             MethodHandle spreader = invocationType.invokers().spreadInvoker(NON_SPREAD_ARG_COUNT);
@@ -285,6 +351,20 @@
         }
     }
 
+    private static Object invokeWithManyArguments(MethodHandle bootstrapMethod, Object[] argv) throws Throwable {
+        final int MAX_SAFE_SIZE = MethodType.MAX_MH_ARITY / 2;
+        if (argv.length >= MAX_SAFE_SIZE) {
+            // to be on the safe side, use invokeWithArguments which handles jumbo lists
+            return bootstrapMethod.invokeWithArguments(argv);
+        }
+        else {
+            MethodType invocationType = MethodType.genericMethodType(argv.length);
+            MethodHandle typedBSM = bootstrapMethod.asType(invocationType);
+            MethodHandle spreader = invocationType.invokers().spreadInvoker(0);
+            return spreader.invokeExact(typedBSM, argv);
+        }
+    }
+
     private static final MethodType LMF_INDY_MT = MethodType.methodType(CallSite.class,
             Lookup.class, String.class, MethodType.class, MethodType.class, MethodHandle.class, MethodType.class);
 
@@ -374,7 +454,7 @@
 
         @Override Object fillCache(int i) {
             Object[] buf = { null };
-            copyConstants(i, i+1, buf, 0);
+            copyArguments(i, i+1, buf, 0);
             Object res = wrapNull(buf[0]);
             cache[i] = res;
             int next = i + 1;
@@ -383,7 +463,7 @@
             return res;
         }
 
-        @Override public int copyConstants(int start, int end,
+        @Override public int copyArguments(int start, int end,
                                            Object[] buf, int pos) {
             int i = start, bufi = pos;
             while (i < end) {
@@ -462,29 +542,31 @@
 
     /*non-public*/ static final
     class PushAdapter {
-        // skeleton for push-mode BSM which wraps a pull-mode BSM:
-        static Object pushToBootstrapMethod(MethodHandle pullModeBSM,
-                                            MethodHandles.Lookup lookup, String name, Object type,
-                                            Object... arguments) throws Throwable {
-            ConstantGroup cons = makeConstantGroup(Arrays.asList(arguments));
-            BootstrapCallInfo bsci = makeBootstrapCallInfo(pullModeBSM, name, type, cons);
-            if (TRACE_METHOD_LINKAGE)
-                System.out.println("pull-mode BSM gets pushed arguments from fake BSCI");
-            return pullModeBSM.invoke(lookup, bsci);
-        }
-
         static final MethodHandle MH_pushToBootstrapMethod;
         static {
-            final Class THIS_CLASS = PushAdapter.class;
             try {
                 MH_pushToBootstrapMethod = IMPL_LOOKUP
-                    .findStatic(THIS_CLASS, "pushToBootstrapMethod",
+                        .findStatic(BootstrapCallInfo.class, "invokeFromArgumentsToCallInfo",
                                 MethodType.methodType(Object.class, MethodHandle.class,
                                         Lookup.class, String.class, Object.class, Object[].class));
-            } catch (Throwable ex) {
+            }
+            catch (Throwable ex) {
                 throw new InternalError(ex);
             }
         }
+
+        /**
+         * Given a push-mode BSM (taking one BSCI argument) convert it to a
+         * pull-mode BSM (taking N pre-resolved arguments).  This method is used
+         * when the JVM is passing up pre-resolved arguments, but the BSM is
+         * expecting to BSCI to resolve arguments lazily.
+         */
+        static MethodHandle toPullBootstrapMethod(MethodHandle bsm) {
+            if (TRACE_METHOD_LINKAGE) {
+                System.out.println("converting a push-mode BSM of type " + bsm.type() + " to pull-mode");
+            }
+            return MH_pushToBootstrapMethod.bindTo(bsm).withVarargs(true);
+        }
     }
 
     /*non-public*/ static final
@@ -537,8 +619,46 @@
                 }
         }
 
+        static Object pullFromBootstrapMethodExclude(MethodHandle pushModeBSM,
+                                                     BootstrapCallInfo bsci)
+                throws Throwable {
+            int argc = bsci.size();
+            switch (argc) {
+                case 0:
+                    return pushModeBSM.invoke();
+                case 1:
+                    return pushModeBSM.invoke(bsci.get(0));
+                case 2:
+                    return pushModeBSM.invoke(bsci.get(0), bsci.get(1));
+                case 3:
+                    return pushModeBSM.invoke(bsci.get(0), bsci.get(1), bsci.get(2));
+                case 4:
+                    return pushModeBSM.invoke(bsci.get(0), bsci.get(1), bsci.get(2), bsci.get(3));
+                case 5:
+                    return pushModeBSM.invoke(bsci.get(0), bsci.get(1), bsci.get(2), bsci.get(3), bsci.get(4));
+                case 6:
+                    return pushModeBSM.invoke(bsci.get(0), bsci.get(1), bsci.get(2), bsci.get(3), bsci.get(4), bsci.get(5));
+                default:
+                    final int MAX_SAFE_SIZE = MethodType.MAX_MH_ARITY / 2;
+                    if (argc >= MAX_SAFE_SIZE) {
+                        // to be on the safe side, use invokeWithArguments which handles jumbo lists
+                        Object[] argv = new Object[argc];
+                        bsci.copyConstants(0, argc, argv, 0);
+                        return pushModeBSM.invokeWithArguments(argv);
+                    }
+                    MethodType invocationType = MethodType.genericMethodType(argc);
+                    MethodHandle typedBSM = pushModeBSM.asType(invocationType);
+                    MethodHandle spreader = invocationType.invokers().spreadInvoker(0);
+                    Object[] argv = new Object[argc];
+                    bsci.copyConstants(0, argc, argv, 0);
+                    return spreader.invokeExact(typedBSM, argv);
+            }
+        }
+
         static final MethodHandle MH_pullFromBootstrapMethod;
 
+        static final MethodHandle MH_pullFromBootstrapMethodExclude;
+
         static {
             final Class THIS_CLASS = PullAdapter.class;
             try {
@@ -546,29 +666,34 @@
                     .findStatic(THIS_CLASS, "pullFromBootstrapMethod",
                                 MethodType.methodType(Object.class, MethodHandle.class,
                                         Lookup.class, BootstrapCallInfo.class));
-            } catch (Throwable ex) {
+
+                MH_pullFromBootstrapMethodExclude = IMPL_LOOKUP
+                        .findStatic(THIS_CLASS, "pullFromBootstrapMethodExclude",
+                                    MethodType.methodType(Object.class, MethodHandle.class,
+                                                          BootstrapCallInfo.class));
+            }
+            catch (Throwable ex) {
                 throw new InternalError(ex);
             }
         }
-    }
 
-    /** Given a push-mode BSM (taking one argument) convert it to a
-     *  pull-mode BSM (taking N pre-resolved arguments).
-     *  This method is used when, in fact, the JVM is passing up
-     *  pre-resolved arguments, but the BSM is expecting lazy stuff.
-     *  Or, when goToPushMode is true, do the reverse transform.
-     *  (The two transforms are exactly inverse.)
-     */
-    static MethodHandle pushMePullYou(MethodHandle bsm, boolean goToPushMode) {
-        if (TRACE_METHOD_LINKAGE) {
-            System.out.println("converting BSM of type " + bsm.type() + " to "
-                    + (goToPushMode ? "push mode" : "pull mode"));
-        }
-        assert(isPullModeBSM(bsm) == goToPushMode); // there must be a change
-        if (goToPushMode) {
-            return PushAdapter.MH_pushToBootstrapMethod.bindTo(bsm).withVarargs(true);
-        } else {
-            return PullAdapter.MH_pullFromBootstrapMethod.bindTo(bsm).withVarargs(false);
+        /**
+         * Given a pull-mode BSM (taking N pre-resolved arguments) convert it to
+         * a push-mode BSM (taking one BSCI argument).  This method is used when
+         * the JVM is passing up indexes to constant pool entries (possibly
+         * unresolved), but the BSM is expecting pre-resolved arguments.
+         */
+        static MethodHandle toPushBootstrapMethod(MethodHandle bsm, boolean includeMetaData) {
+            if (TRACE_METHOD_LINKAGE) {
+                System.out.println("converting a pull-mode BSM of type " + bsm.type() + " to push-mode"
+                                   + (!includeMetaData ? ", exluding meta-data" : ""));
+            }
+            if (includeMetaData) {
+                return PullAdapter.MH_pullFromBootstrapMethod.bindTo(bsm).withVarargs(false);
+            }
+            else {
+                return PullAdapter.MH_pullFromBootstrapMethodExclude.bindTo(bsm).withVarargs(false);
+            }
         }
     }
 }
--- old/src/java.base/share/classes/java/lang/invoke/CallSite.java	2019-05-21 01:01:41.713110275 +0200
+++ new/src/java.base/share/classes/java/lang/invoke/CallSite.java	2019-05-21 01:01:41.561110548 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -305,7 +305,8 @@
         CallSite site;
         try {
             Object binding = BootstrapMethodInvoker.invoke(
-                    CallSite.class, bootstrapMethod, name, type, info, callerClass);
+                    CallSite.class, bootstrapMethod, name, type, info, callerClass,
+                    true);
             if (binding instanceof CallSite) {
                 site = (CallSite) binding;
             } else {
--- old/src/java.base/share/classes/java/lang/invoke/ConstantBootstraps.java	2019-05-21 01:01:41.917109908 +0200
+++ new/src/java.base/share/classes/java/lang/invoke/ConstantBootstraps.java	2019-05-21 01:01:41.757110196 +0200
@@ -41,31 +41,36 @@
  */
 public final class ConstantBootstraps {
     // implements the upcall from the JVM, MethodHandleNatives.linkDynamicConstant:
-    /*non-public*/
-    static Object makeConstant(MethodHandle bootstrapMethod,
-                               // Callee information:
-                               String name, Class type,
-                               // Extra arguments for BSM, if any:
-                               Object info,
-                               // Caller information:
-                               Class callerClass) {
-        // Restrict bootstrap methods to those whose first parameter is Lookup
-        // The motivation here is, in the future, to possibly support BSMs
-        // that do not accept the meta-data of lookup/name/type, thereby
-        // allowing the co-opting of existing methods to be used as BSMs as
-        // long as the static arguments can be passed as method arguments
-        MethodType mt = bootstrapMethod.type();
-        if (mt.parameterCount() < 2 ||
-            !MethodHandles.Lookup.class.isAssignableFrom(mt.parameterType(0))) {
-            throw new BootstrapMethodError(
-                    "Invalid bootstrap method declared for resolving a dynamic constant: " + bootstrapMethod);
-        }
+    /**
+     * makeConstant
+     *
+     * @param bootstrapMethod doc
+     * @param name doc
+     * @param type doc
+     * @param info doc
+     * @param callerClass doc
+     * @return doc
+     */
+    /*non-public*/ static Object makeConstant(MethodHandle bootstrapMethod,
+                                              // Callee information:
+                                              String name, Class type,
+                                              // Extra arguments for BSM, if any:
+                                              Object info,
+                                              // Caller information:
+                                              Class callerClass) {
+        // Lookup, name and type argument metadata should be included when
+        // invoking the BSM if there are one or more parameters and the first
+        // parameter type is MethodHandles.Lookup
+        MethodType bsmType = bootstrapMethod.type();
+        boolean includeMetadata = (bsmType.parameterCount() > 0 &&
+                                   MethodHandles.Lookup.class.isAssignableFrom(bsmType.parameterType(0)));
 
         // BSMI.invoke handles all type checking and exception translation.
         // If type is not a reference type, the JVM is expecting a boxed
         // version, and will manage unboxing on the other side.
         return BootstrapMethodInvoker.invoke(
-                type, bootstrapMethod, name, type, info, callerClass);
+                type, bootstrapMethod, name, type, info, callerClass,
+                includeMetadata);
     }
 
     /**
--- old/src/java.base/share/classes/java/lang/invoke/ConstantGroup.java	2019-05-21 01:01:42.117109551 +0200
+++ new/src/java.base/share/classes/java/lang/invoke/ConstantGroup.java	2019-05-21 01:01:41.961109829 +0200
@@ -90,9 +90,9 @@
  * a resolved from an unresolved constant in the group.
  * The most reliable sentinel is a privately created object,
  * or perhaps the {@code ConstantGroup} itself.
- * @since 1.10
+ *
+ * @since 11
  */
-// public
 interface ConstantGroup {
     /// Access
 
--- old/src/java.base/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java	2019-05-21 01:01:42.317109192 +0200
+++ new/src/java.base/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java	2019-05-21 01:01:42.157109478 +0200
@@ -188,26 +188,8 @@
     CallSite buildCallSite() throws LambdaConversionException {
         final Class innerClass = spinInnerClass();
         if (invokedType.parameterCount() == 0) {
-            final Constructor[] ctrs = AccessController.doPrivileged(
-                    new PrivilegedAction<>() {
-                @Override
-                public Constructor[] run() {
-                    Constructor[] ctrs = innerClass.getDeclaredConstructors();
-                    if (ctrs.length == 1) {
-                        // The lambda implementing inner class constructor is private, set
-                        // it accessible (by us) before creating the constant sole instance
-                        ctrs[0].setAccessible(true);
-                    }
-                    return ctrs;
-                }
-                    });
-            if (ctrs.length != 1) {
-                throw new LambdaConversionException("Expected one lambda constructor for "
-                        + innerClass.getCanonicalName() + ", got " + ctrs.length);
-            }
-
             try {
-                Object inst = ctrs[0].newInstance();
+                Object inst = getConstructor(innerClass).newInstance();
                 return new ConstantCallSite(MethodHandles.constant(samBase, inst));
             }
             catch (ReflectiveOperationException e) {
@@ -227,6 +209,55 @@
     }
 
     /**
+     * Builds an instance of the functional interface directly.
+     *
+     * Generate a class file which implements the functional interface, define
+     * the class, create an instance of the class.
+     *
+     * @return an instance of the functional interface
+     * @throws ReflectiveOperationException
+     * @throws LambdaConversionException If properly formed functional interface
+     * is not found or if the functional interface expects parameters
+     */
+    @Override
+    Object buildFunctionalInterfaceInstance() throws LambdaConversionException {
+        if (invokedType.parameterCount() == 0) {
+            final Class innerClass = spinInnerClass();
+            try {
+                return getConstructor(innerClass).newInstance();
+            }
+            catch (ReflectiveOperationException e) {
+                throw new LambdaConversionException("Exception instantiating lambda object", e);
+            }
+        } else {
+            throw new LambdaConversionException("Building functional interface instances directly " +
+                    "only supported when there are no parameters");
+        }
+    }
+
+    private Constructor getConstructor(Class innerClass) throws LambdaConversionException {
+        final Constructor[] ctrs = AccessController.doPrivileged(
+                new PrivilegedAction<>() {
+                    @Override
+                    public Constructor[] run() {
+                        Constructor[] ctrs1 = innerClass.getDeclaredConstructors();
+                        if (ctrs1.length == 1) {
+                            // The lambda implementing inner class constructor is private, set
+                            // it accessible (by us) before creating the constant sole instance
+                            ctrs1[0].setAccessible(true);
+                        }
+                        return ctrs1;
+                    }
+                });
+
+        if (ctrs.length != 1) {
+            throw new LambdaConversionException("Expected one lambda constructor for "
+                    + innerClass.getCanonicalName() + ", got " + ctrs.length);
+        }
+        return ctrs[0];
+    }
+
+    /**
      * Generate a class file which implements the functional
      * interface, define and return the class.
      *
--- /dev/null	2019-04-27 15:49:57.376009302 +0200
+++ new/src/java.base/share/classes/java/lang/invoke/Intrinsics.java	2019-05-21 01:01:42.373109090 +0200
@@ -0,0 +1,81 @@
+/*
+ * 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package java.lang.invoke;
+
+import java.lang.constant.ConstantDesc;
+import java.lang.constant.DynamicCallSiteDesc;
+
+/**
+ * Intrinsics
+ *
+ * @author Brian Goetz
+ */
+public final class Intrinsics {
+    /**
+     * Instructs the compiler to generate an {@code ldc} instruction for the
+     * constant described by the given {@link ConstantDesc}. A compile-time error
+     * will be issued if this {@code ConstantRef} is not itself a constant.
+     *
+     * @implNote The implementation of this method always throws an
+     * {@link UnsupportedOperationException} at runtime and therefore cannot be
+     * called reflectively; invocations of this method should always be
+     * intrinsified at compile time.
+     *
+     * @param constant a nominal descriptor for the constant to be loaded
+     * @return the constant value
+     */
+    public static Object ldc(ConstantDesc constant) {
+        throw new UnsupportedOperationException("no reflective access");
+    }
+
+    /**
+     * Instructs the compiler to generate an {@code invokedynamic} instruction given
+     * nominal descriptions of a {@link DynamicCallSiteDesc} and a set of boostrap
+     * arguments. A compile-time error will be issued if the {@link DynamicCallSiteDesc}
+     * is not itself a constant.
+     *
+     * 

Like {@link MethodHandle.PolymorphicSignature} methods such as + * {@link MethodHandle#invoke(Object...)}, the signature of parameters and + * return value of {@linkplain #invokedynamic(DynamicCallSiteDesc, Object...)} + * is specified as {@linkplain Object}, but the invocation type of the + * {@code invokedynamic} instruction will be derived from the {@code callSiteRef} + * and will not necessarily requiring boxing of arguments and return value. + * + * @implNote The implementation of this method always throws an + * {@link UnsupportedOperationException} at runtime and therefore cannot be + * called reflectively; invocations of this method should always be + * intrinsified at compile time. + * + * @param callSiteRef a nominal descriptor for a dynamic call site + * @param args the dynamic arguments to the {@code invokedynamic} instruction + * @return the result of the invocation + * @throws java.lang.Throwable the targeted method throws any exception + */ + public static Object invokedynamic(DynamicCallSiteDesc callSiteRef, + Object... args) + throws Throwable { + throw new UnsupportedOperationException("no reflective access"); + } +} --- old/src/java.base/share/classes/java/lang/invoke/LambdaMetafactory.java 2019-05-21 01:01:42.753108410 +0200 +++ new/src/java.base/share/classes/java/lang/invoke/LambdaMetafactory.java 2019-05-21 01:01:42.597108690 +0200 @@ -330,6 +330,71 @@ } /** + * Special-case case version of {@link LambdaMetafactory#metafactory(MethodHandles.Lookup, String, Class, MethodType, MethodHandle, MethodType)} + * that is restricted to non-capturing lambdas. Rather than returning a + * {@link CallSite}, the function object itself is returned. + * Typically used as a bootstrap method for {@code Dynamic} + * constants, to support the lambda expression and method + * reference expression features of the Java Programming Language. + * + *

The function object returned is an instance of a class which + * implements the interface named by {@code functionalInterface}, + * declares a method with the name given by {@code invokedName} and the + * signature given by {@code samMethodType}. It may also override additional + * methods from {@code Object}. + * + * @param caller Represents a lookup context with the accessibility + * privileges of the caller. When used with {@code invokedynamic}, + * this is stacked automatically by the VM. + * @param invokedName The name of the method to implement. When used with + * {@code Dynamic} constants, this is provided by the + * {@code NameAndType} of the {@code InvokeDynamic} + * structure and is stacked automatically by the VM. + * @param functionalInterface The functional interface the function object + * should implement. When used with {@code invokedynamic}, + * this is provided by the {@code NameAndType} of + * the {@code InvokeDynamic} structure and is + * stacked automatically by the VM. In the event + * that the implementation method is an instance + * method and this signature has any parameters, + * the first parameter in the invocation signature + * must correspond to the receiver. + * @param samMethodType Signature and return type of method to be implemented + * by the function object. + * @param implMethod A direct method handle describing the implementation + * method which should be called (with suitable adaptation + * of argument types, return types, and with captured + * arguments prepended to the invocation arguments) at + * invocation time. + * @param instantiatedMethodType The signature and return type that should + * be enforced dynamically at invocation time. + * This may be the same as {@code samMethodType}, + * or may be a specialization of it. + * @return a CallSite whose target can be used to perform capture, generating + * instances of the interface named by {@code invokedType} + * @throws LambdaConversionException If any of the linkage invariants + * described {@link LambdaMetafactory above} + * are violated + */ + public static Object metafactory(MethodHandles.Lookup caller, + String invokedName, + Class functionalInterface, + MethodType samMethodType, + MethodHandle implMethod, + MethodType instantiatedMethodType) + throws LambdaConversionException { + AbstractValidatingLambdaMetafactory mf; + mf = new InnerClassLambdaMetafactory(caller, MethodType.methodType(functionalInterface), + invokedName, samMethodType, + implMethod, instantiatedMethodType, + false, EMPTY_CLASS_ARRAY, EMPTY_MT_ARRAY); + mf.validateMetafactoryArgs(); + return mf.buildFunctionalInterfaceInstance(); + } + + // @@@ Special case version of altMetafactory, supporting FLAG_METHODREF + + /** * Facilitates the creation of simple "function objects" that implement one * or more interfaces by delegation to a provided {@link MethodHandle}, * after appropriate type adaptation and partial evaluation of arguments. @@ -503,4 +568,61 @@ mf.validateMetafactoryArgs(); return mf.buildCallSite(); } + + /** + * Special-case case version of {@link LambdaMetafactory#altMetafactory(MethodHandles.Lookup, String, MethodType, Object...)}. + * Rather than returning a {@link CallSite}, the function object itself is returned. + * Typically used as a bootstrap method for {@code Dynamic} + * constants, to support the lambda expression and method + * reference expression features of the Java Programming Language. + * + *

The function object returned is an instance of a class which + * implements the interface named by {@code functionalInterface}, + * declares a method with the name given by {@code invokedName} and the + * signature given by {@code samMethodType}. It may also override additional + * methods from {@code Object}. + * + * @param caller Represents a lookup context with the accessibility + * privileges of the caller. When used with {@code invokedynamic}, + * this is stacked automatically by the VM. + * @param invokedName The name of the method to implement. When used with + * {@code Dynamic} constants, this is provided by the + * {@code NameAndType} of the {@code InvokeDynamic} + * structure and is stacked automatically by the VM. + * @param functionalInterface The functional interface the function object + * should implement. When used with {@code invokedynamic}, + * this is provided by the {@code NameAndType} of + * the {@code InvokeDynamic} structure and is + * stacked automatically by the VM. In the event + * that the implementation method is an instance + * method and this signature has any parameters, + * the first parameter in the invocation signature + * must correspond to the receiver. + * @param args An {@code Object[]} array containing the required + * arguments {@code samMethodType}, {@code implMethod}, + * {@code instantiatedMethodType}, {@code flags}, and any + * optional arguments, as described + * {@link #altMetafactory(MethodHandles.Lookup, String, functionalInterface, Object...)} above} + * @return a function object which is an instance of a class which implements the interface named + * by {@code functionalInterface} + * @throws LambdaConversionException If any of the linkage invariants + * described {@link LambdaMetafactory above} + * are violated + */ + public static Object altMetafactory(MethodHandles.Lookup caller, + String invokedName, + Class functionalInterface, + Object... args) + throws LambdaConversionException { + try { + return altMetafactory(caller, invokedName, + MethodType.methodType(functionalInterface), args).getTarget().invoke(); + } + catch (LambdaConversionException | LinkageError e) { + throw e; + } + catch (Throwable e) { + throw new LambdaConversionException("Exception invoking lambda metafactory", e); + } + } } --- old/src/java.base/share/classes/java/lang/invoke/MethodHandleNatives.java 2019-05-21 01:01:42.965108030 +0200 +++ new/src/java.base/share/classes/java/lang/invoke/MethodHandleNatives.java 2019-05-21 01:01:42.809108310 +0200 @@ -366,8 +366,8 @@ * replaced with currently commented out code. */ static boolean isPullModeBSM(MethodHandle bsm) { - return false; -// return bsm.type().parameterCount() == 2 && !bsm.isVarargsCollector(); + return bsm.type().parameterCount() == 2 && !bsm.isVarargsCollector() + && BootstrapCallInfo.class.isAssignableFrom(bsm.type().parameterType(1)); } /** --- old/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java 2019-05-21 01:01:43.161107678 +0200 +++ new/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java 2019-05-21 01:01:43.009107951 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,7 +26,6 @@ package java.lang.invoke; import jdk.internal.misc.Unsafe; -import jdk.internal.misc.VM; import jdk.internal.org.objectweb.asm.ClassWriter; import jdk.internal.org.objectweb.asm.Label; import jdk.internal.org.objectweb.asm.MethodVisitor; @@ -192,8 +191,6 @@ */ private static final ProxyClassesDumper DUMPER; - private static final Class STRING_HELPER; - static { // In case we need to double-back onto the StringConcatFactory during this // static initialization, make sure we have the reasonable defaults to complete @@ -205,20 +202,15 @@ // DEBUG = false; // implied // DUMPER = null; // implied - try { - STRING_HELPER = Class.forName("java.lang.StringConcatHelper"); - } catch (Throwable e) { - throw new AssertionError(e); - } - + Properties props = GetPropertyAction.privilegedGetProperties(); final String strategy = - VM.getSavedProperty("java.lang.invoke.stringConcat"); + props.getProperty("java.lang.invoke.stringConcat"); CACHE_ENABLE = Boolean.parseBoolean( - VM.getSavedProperty("java.lang.invoke.stringConcat.cache")); + props.getProperty("java.lang.invoke.stringConcat.cache")); DEBUG = Boolean.parseBoolean( - VM.getSavedProperty("java.lang.invoke.stringConcat.debug")); + props.getProperty("java.lang.invoke.stringConcat.debug")); final String dumpPath = - VM.getSavedProperty("java.lang.invoke.stringConcat.dumpClasses"); + props.getProperty("java.lang.invoke.stringConcat.dumpClasses"); STRATEGY = (strategy == null) ? DEFAULT_STRATEGY : Strategy.valueOf(strategy); CACHE = CACHE_ENABLE ? new ConcurrentHashMap<>() : null; @@ -1527,33 +1519,6 @@ static MethodHandle generate(MethodType mt, Recipe recipe) throws Throwable { - // Fast-path two-argument Object + Object concatenations - if (recipe.getElements().size() == 2) { - // Two object arguments - if (mt.parameterCount() == 2 && - !mt.parameterType(0).isPrimitive() && - !mt.parameterType(1).isPrimitive()) { - return SIMPLE; - } - // One element is a constant - if (mt.parameterCount() == 1 && !mt.parameterType(0).isPrimitive()) { - MethodHandle mh = SIMPLE; - // Insert constant element - - // First recipe element is a constant - if (recipe.getElements().get(0).getTag() == TAG_CONST && - recipe.getElements().get(1).getTag() != TAG_CONST) { - return MethodHandles.insertArguments(mh, 0, - recipe.getElements().get(0).getValue()); - } else if (recipe.getElements().get(1).getTag() == TAG_CONST && - recipe.getElements().get(0).getTag() != TAG_CONST) { - return MethodHandles.insertArguments(mh, 1, - recipe.getElements().get(1).getValue()); - } - // else... fall-through to slow-path - } - } - // Create filters and obtain filtered parameter types. Filters would be used in the beginning // to convert the incoming arguments into the arguments we can process (e.g. Objects -> Strings). // The filtered argument type list is used all over in the combinators below. @@ -1661,6 +1626,13 @@ return mh; } + @ForceInline + private static byte[] newArray(long indexCoder) { + byte coder = (byte)(indexCoder >> 32); + int index = (int)indexCoder; + return (byte[]) UNSAFE.allocateUninitializedArray(byte.class, index << coder); + } + private static MethodHandle prepender(Class cl) { return PREPENDERS.computeIfAbsent(cl, PREPEND); } @@ -1687,15 +1659,16 @@ } }; - private static final MethodHandle SIMPLE; private static final MethodHandle NEW_STRING; private static final MethodHandle NEW_ARRAY; private static final ConcurrentMap, MethodHandle> PREPENDERS; private static final ConcurrentMap, MethodHandle> MIXERS; private static final long INITIAL_CODER; + static final Class STRING_HELPER; static { try { + STRING_HELPER = Class.forName("java.lang.StringConcatHelper"); MethodHandle initCoder = lookupStatic(Lookup.IMPL_LOOKUP, STRING_HELPER, "initialCoder", long.class); INITIAL_CODER = (long) initCoder.invoke(); } catch (Throwable e) { @@ -1705,9 +1678,8 @@ PREPENDERS = new ConcurrentHashMap<>(); MIXERS = new ConcurrentHashMap<>(); - SIMPLE = lookupStatic(Lookup.IMPL_LOOKUP, STRING_HELPER, "simpleConcat", String.class, Object.class, Object.class); NEW_STRING = lookupStatic(Lookup.IMPL_LOOKUP, STRING_HELPER, "newString", String.class, byte[].class, long.class); - NEW_ARRAY = lookupStatic(Lookup.IMPL_LOOKUP, STRING_HELPER, "newArray", byte[].class, long.class); + NEW_ARRAY = lookupStatic(Lookup.IMPL_LOOKUP, MethodHandleInlineCopyStrategy.class, "newArray", byte[].class, long.class); } } @@ -1720,8 +1692,22 @@ // no instantiation } - private static final MethodHandle OBJECT_INSTANCE = - lookupStatic(Lookup.IMPL_LOOKUP, STRING_HELPER, "stringOf", String.class, Object.class); + private static class ObjectStringifier { + + // We need some additional conversion for Objects in general, because String.valueOf(Object) + // may return null. String conversion rules in Java state we need to produce "null" String + // in this case, so we provide a customized version that deals with this problematic corner case. + private static String valueOf(Object value) { + String s; + return (value == null || (s = value.toString()) == null) ? "null" : s; + } + + // Could have used MethodHandles.lookup() instead of Lookup.IMPL_LOOKUP, if not for the fact + // java.lang.invoke Lookups are explicitly forbidden to be retrieved using that API. + private static final MethodHandle INSTANCE = + lookupStatic(Lookup.IMPL_LOOKUP, ObjectStringifier.class, "valueOf", String.class, Object.class); + + } private static class FloatStringifiers { private static final MethodHandle FLOAT_INSTANCE = @@ -1765,7 +1751,7 @@ */ static MethodHandle forMost(Class t) { if (!t.isPrimitive()) { - return OBJECT_INSTANCE; + return ObjectStringifier.INSTANCE; } else if (t == float.class) { return FloatStringifiers.FLOAT_INSTANCE; } else if (t == double.class) { --- old/src/java.base/share/classes/java/lang/invoke/VarHandle.java 2019-05-21 01:01:43.373107299 +0200 +++ new/src/java.base/share/classes/java/lang/invoke/VarHandle.java 2019-05-21 01:01:43.221107571 +0200 @@ -45,6 +45,7 @@ import jdk.internal.vm.annotation.Stable; import static java.lang.invoke.MethodHandleStatics.UNSAFE; +import static java.lang.invoke.MethodHandleStatics.newInternalError; /** * A VarHandle is a dynamically strongly typed reference to a variable, or to a @@ -2281,6 +2282,11 @@ throw new InternalError("Cannot reach here"); } } + + @Override + public Optional describeConstable() { + return Optional.empty(); + } } } --- old/src/java.base/share/classes/java/lang/invoke/package-info.java 2019-05-21 01:01:43.589106911 +0200 +++ new/src/java.base/share/classes/java/lang/invoke/package-info.java 2019-05-21 01:01:43.433107191 +0200 @@ -96,23 +96,28 @@ * following items: *

    *
  • the bootstrap method, a {@code CONSTANT_MethodHandle}
  • - *
  • the {@code Class} or {@code MethodType} derived from + *
  • the {@code MethodType} or {@code Class} derived from * type component of the {@code CONSTANT_NameAndType} descriptor
  • *
  • static arguments, if any (note that static arguments can themselves be * dynamically-computed constants)
  • *
*

- * The bootstrap method is then invoked, as if by + * The bootstrap method is then invoked, in general, as if by * {@link java.lang.invoke.MethodHandle#invoke MethodHandle.invoke}, * with the following arguments: *

    *
  • a {@code MethodHandles.Lookup}, which is a lookup object on the caller class * in which dynamically-computed constant or call site occurs
  • *
  • a {@code String}, the name mentioned in the {@code CONSTANT_NameAndType}
  • - *
  • a {@code MethodType} or {@code Class}, the resolved type descriptor of the {@code CONSTANT_NameAndType}
  • - *
  • a {@code Class}, the resolved type descriptor of the constant, if it is a dynamic constant
  • + *
  • for a dynamically-computed call site a {@code MethodType} (the resolved + * type descriptor of the call site), or for a dynamically computed constant, + * a {@code Class} (the resolved type descriptor of the constant)
  • *
  • the additional resolved static arguments, if any
  • *
+ * For dynamically computed constant, if the bootstrap method has no parameters + * or the first parameter type is not assignable to {@code MethodHandles.Lookup} + * then the method is invoked as described above but with just the arguments + * that are the additional resolved static arguments, if any. *

* For a dynamically-computed call site, the returned result must be a non-null reference to a * {@link java.lang.invoke.CallSite CallSite}. @@ -122,11 +127,11 @@ * On success the call site then becomes permanently linked to the {@code invokedynamic} * instruction. *

- * For a dynamically-computed constant, the first parameter of the bootstrap - * method must be assignable to {@code MethodHandles.Lookup}. If this condition - * is not met, a {@code BootstrapMethodError} is thrown. - * On success the result of the bootstrap method is cached as the resolved - * constant value. + * For a dynamically-computed constant, the result of the bootstrap method is + * cached as the resolved constant value. The constant value must be + * convertible to the {@code Class} derived from type component of the + * {@code CONSTANT_NameAndType} descriptor, otherwise a + * {@code BootstrapMethodError} is thrown. *

* If an exception, {@code E} say, occurs during execution of the bootstrap method, then * resolution fails and terminates abnormally. {@code E} is rethrown if the type of @@ -176,21 +181,18 @@ * types {@code MethodHandles.Lookup}, {@code String}, {@code MethodType}, and the types * of any static arguments; the return type is {@code CallSite}. *

- * For a dynamically-computed constant, the bootstrap method is invoked with parameter types - * {@code MethodHandles.Lookup}, {@code String}, {@code Class}, and the types of any - * static arguments; the return type is the type represented by the {@code Class}. + * For a dynamically-computed constant, if the first parameter of the bootstrap + * method is assignable to {@code MethodHandles.Lookup} then the bootstrap + * method is invoked with parameter types {@code MethodHandles.Lookup}, + * {@code String}, {@code Class}, and the types of any static arguments. + * Otherwise, the bootstrap method is invoked with just the parameter types of + * any static arguments. In either case the return type is the type represented + * by the {@code Class} (regardless of whether the bootstrap is invoked with + * just the static arguments). *

* Because {@link java.lang.invoke.MethodHandle#invoke MethodHandle.invoke} allows for * adaptations between the invoked method type and the bootstrap method handle's method type, * there is flexibility in the declaration of the bootstrap method. - * For a dynamically-computed constant the first parameter type of the bootstrap method handle - * must be assignable to {@code MethodHandles.Lookup}, other than that constraint the same degree - * of flexibility applies to bootstrap methods of dynamically-computed call sites and - * dynamically-computed constants. - * Note: this constraint allows for the future possibility where the bootstrap method is - * invoked with just the parameter types of static arguments, thereby supporting a wider - * range of methods compatible with the static arguments (such as methods that don't declare - * or require the lookup, name, and type meta-data parameters). *

For example, for dynamically-computed call site, a the first argument * could be {@code Object} instead of {@code MethodHandles.Lookup}, and the return type * could also be {@code Object} instead of {@code CallSite}. @@ -205,13 +207,15 @@ * between {@code CONSTANT_MethodHandle} constants, the modifier bit for variable arity methods, * and the {@link java.lang.invoke.MethodHandle#asVarargsCollector asVarargsCollector} transformation.) *

- * Given these rules, here are examples of legal bootstrap method declarations for + * Given these rules the following examples and explanations are presented for + * legal bootstrap method declarations. + * Here are examples of legal bootstrap method declarations for * dynamically-computed call sites, given various numbers {@code N} of extra arguments. * The first row (marked {@code *}) will work for any number of extra arguments. * * * - * + * * * *
Static argument types
NSample bootstrap method
NSample bootstrap method for a dynamically-computed call site
* @@ -239,32 +243,73 @@ * {@code String} and {@code Integer} (or {@code int}), respectively. * The second-to-last example assumes that all extra arguments are of type * {@code String}. - * The other examples work with all types of extra arguments. Note that all - * the examples except the second and third also work with dynamically-computed - * constants if the return type is changed to be compatible with the - * constant's declared type (such as {@code Object}, which is always compatible). - *

- * Since dynamically-computed constants can be provided as static arguments to bootstrap - * methods, there are no limitations on the types of bootstrap arguments. - * However, arguments of type {@code boolean}, {@code byte}, {@code short}, or {@code char} - * cannot be directly supplied by {@code CONSTANT_Integer} - * constant pool entries, since the {@code asType} conversions do - * not perform the necessary narrowing primitive conversions. - *

- * In the above examples, the return type is always {@code CallSite}, - * but that is not a necessary feature of bootstrap methods. - * In the case of a dynamically-computed call site, the only requirement is that - * the return type of the bootstrap method must be convertible - * (using the {@code asType} conversions) to {@code CallSite}, which + * The other examples work with all types of extra arguments. + *

+ * Since dynamically-computed constants can be provided as static arguments to + * bootstrap methods for both dynamically-computed call sites and + * dynamically-computed constants, there are no limitations on the types of + * bootstrap arguments. However, arguments of type {@code boolean}, + * {@code byte}, {@code short}, or {@code char} cannot be directly + * supplied by {@code CONSTANT_Integer} constant pool entries, since the + * {@code asType} conversions do not perform the necessary narrowing primitive + * conversions. + *

+ * In the above examples, the return type is always {@code CallSite}, but that + * is not a necessary feature of call site bootstrap methods. The only + * requirement is that the return type of the bootstrap method must be + * convertible (using the {@code asType} conversions) to {@code CallSite}, which * means the bootstrap method return type might be {@code Object} or * {@code ConstantCallSite}. - * In the case of a dynamically-resolved constant, the return type of the bootstrap - * method must be convertible to the type of the constant, as - * represented by its field type descriptor. For example, if the - * dynamic constant has a field type descriptor of {@code "C"} - * ({@code char}) then the bootstrap method return type could be - * {@code Object}, {@code Character}, or {@code char}, but not - * {@code int} or {@code Integer}. + *

+ * Here are examples of legal bootstrap method declarations for + * dynamically-computed constants, given various numbers {@code N} of extra + * arguments. The first row (marked {@code *}) will work for any number of + * extra arguments. + * + * + * + * + * + * + * + * + * + * + * + *
Static argument types
NSample bootstrap method for a dynamically-computed constant
* + *
    + *
  • Object bootstrap(Lookup caller, String name, Class type, Object... args) + *
  • Object bootstrap(Object... args) + *
  • Object bootstrap(Object firstArg, Object... otherArgs) + *
0 + *
    + *
  • Object bootstrap(Lookup caller, String name, Class type) + *
  • Object bootstrap(Lookup caller, Object... nameAndType) + *
  • Object bootstrap() + *
  • Object bootstrap(Object... args) + *
1 + *
    + *
  • Object bootstrap(Lookup caller, String name, Class type, Object arg) + *
  • Object bootstrap(Object arg) + *
2 + *
    + *
  • Object bootstrap(Lookup caller, String name, Class type, Object... args) + *
  • Object bootstrap(Lookup caller, String name, Class type, String... args) + *
  • Object bootstrap(Lookup caller, String name, Class type, String x, int y) + *
  • Object bootstrap(Object... args) + *
  • Object bootstrap(String... args) + *
  • Object bootstrap(String x, int y) + *
+ * The example methods whose first parameter type, if any, is not {@code Lookup} + * will be invoked with just the static arguments. + *

+ * In the above examples, the return type is always {@code Object}, but that + * is not a necessary feature of dynamic constant bootstrap methods. The only + * requirement is that method must be convertible to the type of the constant, + * as represented by its field type descriptor. For example, if the dynamic + * constant has a field type descriptor of {@code "C"} ({@code char}) then the + * bootstrap method return type could be {@code Object}, {@code Character}, or + * {@code char}, but not {@code int} or {@code Integer}. * * @author John Rose, JSR 292 EG * @since 1.7 --- old/src/java.base/share/classes/java/lang/reflect/AccessibleObject.java 2019-05-21 01:01:43.801106532 +0200 +++ new/src/java.base/share/classes/java/lang/reflect/AccessibleObject.java 2019-05-21 01:01:43.645106812 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -56,10 +56,7 @@ * {@code Field}s, {@code Method}s, or {@code Constructor}s are used to get or * set fields, to invoke methods, or to create and initialize new instances of * classes, respectively. Every reflected object checks that the code using it - * is in an appropriate class, package, or module. The check when invoked by - * JNI code with no Java - * class on the stack only succeeds if the member and the declaring class are - * public, and the class is in a package that is exported to all modules.

+ * is in an appropriate class, package, or module.

* *

The one variation from Java language access control is that the checks * by reflected objects assume readability. That is, the module containing @@ -673,13 +670,6 @@ private boolean slowVerifyAccess(Class caller, Class memberClass, Class targetClass, int modifiers) { - - if (caller == null) { - // No caller frame when a native thread attaches to the VM - // only allow access to a public accessible member - return Reflection.verifyPublicMemberAccess(memberClass, modifiers); - } - if (!Reflection.verifyMemberAccess(caller, memberClass, targetClass, modifiers)) { // access denied return false; --- old/src/java.base/share/classes/java/math/BigDecimal.java 2019-05-21 01:01:44.005106165 +0200 +++ new/src/java.base/share/classes/java/math/BigDecimal.java 2019-05-21 01:01:43.849106445 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -3414,32 +3414,9 @@ */ @Override public long longValue(){ - if (intCompact != INFLATED && scale == 0) { - return intCompact; - } else { - // Fastpath zero and small values - if (this.signum() == 0 || fractionOnly() || - // Fastpath very large-scale values that will result - // in a truncated value of zero. If the scale is -64 - // or less, there are at least 64 powers of 10 in the - // value of the numerical result. Since 10 = 2*5, in - // that case there would also be 64 powers of 2 in the - // result, meaning all 64 bits of a long will be zero. - scale <= -64) { - return 0; - } else { - return toBigInteger().longValue(); - } - } - } - - /** - * Return true if a nonzero BigDecimal has an absolute value less - * than one; i.e. only has fraction digits. - */ - private boolean fractionOnly() { - assert this.signum() != 0; - return (this.precision() - this.scale) <= 0; + return (intCompact != INFLATED && scale == 0) ? + intCompact: + toBigInteger().longValue(); } /** @@ -3457,20 +3434,15 @@ public long longValueExact() { if (intCompact != INFLATED && scale == 0) return intCompact; - - // Fastpath zero - if (this.signum() == 0) - return 0; - - // Fastpath numbers less than 1.0 (the latter can be very slow - // to round if very small) - if (fractionOnly()) - throw new ArithmeticException("Rounding necessary"); - // If more than 19 digits in integer part it cannot possibly fit if ((precision() - scale) > 19) // [OK for negative scale too] throw new java.lang.ArithmeticException("Overflow"); - + // Fastpath zero and < 1.0 numbers (the latter can be very slow + // to round if very small) + if (this.signum() == 0) + return 0; + if ((this.precision() - this.scale) <= 0) + throw new ArithmeticException("Rounding necessary"); // round to an integer, with Exception if decimal part non-0 BigDecimal num = this.setScale(0, ROUND_UNNECESSARY); if (num.precision() >= 19) // need to check carefully @@ -3514,7 +3486,7 @@ public int intValue() { return (intCompact != INFLATED && scale == 0) ? (int)intCompact : - (int)longValue(); + toBigInteger().intValue(); } /** --- old/src/java.base/share/classes/java/nio/channels/FileChannel.java 2019-05-21 01:01:44.249105729 +0200 +++ new/src/java.base/share/classes/java/nio/channels/FileChannel.java 2019-05-21 01:01:44.089106014 +0200 @@ -791,7 +791,7 @@ // -- Memory-mapped buffers -- /** - * A file-mapping mode. + * A typesafe enumeration for file-mapping modes. * * @since 1.4 * @@ -819,12 +819,6 @@ private final String name; - /** - * Constructs an instance of this class. This constructor may be used - * by code in java.base to create file mapping modes beyond the file - * mapping modes defined here. - * @param name the name of the map mode - */ private MapMode(String name) { this.name = name; } @@ -843,8 +837,8 @@ /** * Maps a region of this channel's file directly into memory. * - *

The {@code mode} parameter specifies how the region of the file is - * mapped and may be one of the following modes: + *

A region of a file may be mapped into memory in one of three modes: + *

* *
    * @@ -865,8 +859,6 @@ * *
* - *

An implementation may support additional map modes. - * *

For a read-only mapping, this channel must have been opened for * reading; for a read/write or private mapping, this channel must have * been opened for both reading and writing. @@ -900,8 +892,7 @@ * MapMode#READ_WRITE READ_WRITE}, or {@link MapMode#PRIVATE * PRIVATE} defined in the {@link MapMode} class, according to * whether the file is to be mapped read-only, read/write, or - * privately (copy-on-write), respectively, or an implementation - * specific map mode + * privately (copy-on-write), respectively * * @param position * The position within the file at which the mapped region @@ -914,29 +905,25 @@ * @return The mapped byte buffer * * @throws NonReadableChannelException - * If the {@code mode} is {@link MapMode#READ_ONLY READ_ONLY} or - * an implementation specific map mode requiring read access - * but this channel was not opened for reading + * If the {@code mode} is {@link MapMode#READ_ONLY READ_ONLY} but + * this channel was not opened for reading * * @throws NonWritableChannelException - * If the {@code mode} is {@link MapMode#READ_WRITE READ_WRITE}. - * {@link MapMode#PRIVATE PRIVATE} or an implementation specific - * map mode requiring write access but this channel was not - * opened for both reading and writing + * If the {@code mode} is {@link MapMode#READ_WRITE READ_WRITE} or + * {@link MapMode#PRIVATE PRIVATE} but this channel was not opened + * for both reading and writing * * @throws IllegalArgumentException * If the preconditions on the parameters do not hold * - * @throws UnsupportedOperationException - * If an unsupported map mode is specified - * * @throws IOException * If some other I/O error occurs * * @see java.nio.channels.FileChannel.MapMode * @see java.nio.MappedByteBuffer */ - public abstract MappedByteBuffer map(MapMode mode, long position, long size) + public abstract MappedByteBuffer map(MapMode mode, + long position, long size) throws IOException; --- old/src/java.base/share/classes/java/security/Permissions.java 2019-05-21 01:01:44.457105354 +0200 +++ new/src/java.base/share/classes/java/security/Permissions.java 2019-05-21 01:01:44.297105642 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,20 +25,21 @@ package java.security; -import java.io.InvalidObjectException; -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.io.ObjectStreamField; -import java.io.Serializable; import java.util.Enumeration; -import java.util.HashMap; import java.util.Hashtable; -import java.util.Iterator; -import java.util.List; -import java.util.Map; import java.util.NoSuchElementException; +import java.util.Map; +import java.util.HashMap; +import java.util.List; +import java.util.Iterator; +import java.util.Collections; import java.util.concurrent.ConcurrentHashMap; +import java.io.Serializable; +import java.io.ObjectStreamField; +import java.io.ObjectOutputStream; +import java.io.ObjectInputStream; +import java.io.IOException; + /** * This class represents a heterogeneous collection of Permissions. That is, @@ -391,22 +392,6 @@ permsMap = new ConcurrentHashMap<>(perms.size()*2); permsMap.putAll(perms); - // Check that Class is mapped to PermissionCollection containing - // Permissions of the same class - for (Map.Entry, PermissionCollection> e : perms.entrySet()) { - Class k = e.getKey(); - PermissionCollection v = e.getValue(); - Enumeration en = v.elements(); - while (en.hasMoreElements()) { - Permission p = en.nextElement(); - if (!k.equals(p.getClass())) { - throw new InvalidObjectException("Permission with class " + - k + " incorrectly mapped to PermissionCollection " + - "containing Permission with " + p.getClass()); - } - } - } - // Set hasUnresolved UnresolvedPermissionCollection uc = (UnresolvedPermissionCollection) permsMap.get(UnresolvedPermission.class); @@ -599,15 +584,5 @@ (Hashtable)gfields.get("perms", null); permsMap = new ConcurrentHashMap<>(perms.size()*2); permsMap.putAll(perms); - - // check that the Permission key and value are the same object - for (Map.Entry e : perms.entrySet()) { - Permission k = e.getKey(); - Permission v = e.getValue(); - if (k != v) { - throw new InvalidObjectException("Permission (" + k + - ") incorrectly mapped to Permission (" + v + ")"); - } - } } } --- old/src/java.base/share/classes/java/security/Signature.java 2019-05-21 01:01:44.657104997 +0200 +++ new/src/java.base/share/classes/java/security/Signature.java 2019-05-21 01:01:44.501105275 +0200 @@ -40,8 +40,6 @@ import javax.crypto.IllegalBlockSizeException; import javax.crypto.BadPaddingException; import javax.crypto.NoSuchPaddingException; -import jdk.internal.access.JavaSecuritySignatureAccess; -import jdk.internal.access.SharedSecrets; import sun.security.util.Debug; import sun.security.jca.*; @@ -120,34 +118,6 @@ public abstract class Signature extends SignatureSpi { - static { - SharedSecrets.setJavaSecuritySignatureAccess( - new JavaSecuritySignatureAccess() { - @Override - public void initVerify(Signature s, PublicKey publicKey, - AlgorithmParameterSpec params) - throws InvalidKeyException, - InvalidAlgorithmParameterException { - s.initVerify(publicKey, params); - } - @Override - public void initVerify(Signature s, - java.security.cert.Certificate certificate, - AlgorithmParameterSpec params) - throws InvalidKeyException, - InvalidAlgorithmParameterException { - s.initVerify(certificate, params); - } - @Override - public void initSign(Signature s, PrivateKey privateKey, - AlgorithmParameterSpec params, SecureRandom random) - throws InvalidKeyException, - InvalidAlgorithmParameterException { - s.initSign(privateKey, params, random); - } - }); - } - private static final Debug debug = Debug.getInstance("jca", "Signature"); @@ -512,53 +482,6 @@ } /** - * Initialize this object for verification. If this method is called - * again with different arguments, it negates the effect - * of this call. - * - * @param publicKey the public key of the identity whose signature is - * going to be verified. - * @param params the parameters used for verifying this signature. - * - * @exception InvalidKeyException if the key is invalid. - * @exception InvalidAlgorithmParameterException if the params is invalid. - */ - final void initVerify(PublicKey publicKey, AlgorithmParameterSpec params) - throws InvalidKeyException, InvalidAlgorithmParameterException { - engineInitVerify(publicKey, params); - state = VERIFY; - - if (!skipDebug && pdebug != null) { - pdebug.println("Signature." + algorithm + - " verification algorithm from: " + getProviderName()); - } - } - - private static PublicKey getPublicKeyFromCert(Certificate cert) - throws InvalidKeyException { - // If the certificate is of type X509Certificate, - // we should check whether it has a Key Usage - // extension marked as critical. - //if (cert instanceof java.security.cert.X509Certificate) { - if (cert instanceof X509Certificate) { - // Check whether the cert has a key usage extension - // marked as a critical extension. - // The OID for KeyUsage extension is 2.5.29.15. - X509Certificate c = (X509Certificate)cert; - Set critSet = c.getCriticalExtensionOIDs(); - - if (critSet != null && !critSet.isEmpty() - && critSet.contains("2.5.29.15")) { - boolean[] keyUsageInfo = c.getKeyUsage(); - // keyUsageInfo[0] is for digitalSignature. - if ((keyUsageInfo != null) && (keyUsageInfo[0] == false)) - throw new InvalidKeyException("Wrong key usage"); - } - } - return cert.getPublicKey(); - } - - /** * Initializes this object for verification, using the public key from * the given certificate. *

If the certificate is of type X.509 and has a key usage @@ -578,40 +501,27 @@ */ public final void initVerify(Certificate certificate) throws InvalidKeyException { - engineInitVerify(getPublicKeyFromCert(certificate)); - state = VERIFY; + // If the certificate is of type X509Certificate, + // we should check whether it has a Key Usage + // extension marked as critical. + if (certificate instanceof java.security.cert.X509Certificate) { + // Check whether the cert has a key usage extension + // marked as a critical extension. + // The OID for KeyUsage extension is 2.5.29.15. + X509Certificate cert = (X509Certificate)certificate; + Set critSet = cert.getCriticalExtensionOIDs(); - if (!skipDebug && pdebug != null) { - pdebug.println("Signature." + algorithm + - " verification algorithm from: " + getProviderName()); + if (critSet != null && !critSet.isEmpty() + && critSet.contains("2.5.29.15")) { + boolean[] keyUsageInfo = cert.getKeyUsage(); + // keyUsageInfo[0] is for digitalSignature. + if ((keyUsageInfo != null) && (keyUsageInfo[0] == false)) + throw new InvalidKeyException("Wrong key usage"); + } } - } - /** - * Initializes this object for verification, using the public key from - * the given certificate. - *

If the certificate is of type X.509 and has a key usage - * extension field marked as critical, and the value of the key usage - * extension field implies that the public key in - * the certificate and its corresponding private key are not - * supposed to be used for digital signatures, an - * {@code InvalidKeyException} is thrown. - * - * @param certificate the certificate of the identity whose signature is - * going to be verified. - * @param params the parameters used for verifying this signature. - * - * @exception InvalidKeyException if the public key in the certificate - * is not encoded properly or does not include required parameter - * information or cannot be used for digital signature purposes. - * @exception InvalidAlgorithmParameterException if the params is invalid. - * - * @since 13 - */ - final void initVerify(Certificate certificate, - AlgorithmParameterSpec params) - throws InvalidKeyException, InvalidAlgorithmParameterException { - engineInitVerify(getPublicKeyFromCert(certificate), params); + PublicKey publicKey = certificate.getPublicKey(); + engineInitVerify(publicKey); state = VERIFY; if (!skipDebug && pdebug != null) { @@ -665,31 +575,6 @@ } /** - * Initialize this object for signing. If this method is called - * again with different arguments, it negates the effect - * of this call. - * - * @param privateKey the private key of the identity whose signature - * is going to be generated. - * @param params the parameters used for generating signature. - * @param random the source of randomness for this signature. - * - * @exception InvalidKeyException if the key is invalid. - * @exception InvalidAlgorithmParameterException if the params is invalid - */ - final void initSign(PrivateKey privateKey, - AlgorithmParameterSpec params, SecureRandom random) - throws InvalidKeyException, InvalidAlgorithmParameterException { - engineInitSign(privateKey, params, random); - state = SIGN; - - if (!skipDebug && pdebug != null) { - pdebug.println("Signature." + algorithm + - " signing algorithm from: " + getProviderName()); - } - } - - /** * Returns the signature bytes of all the data updated. * The format of the signature depends on the underlying * signature scheme. @@ -1225,13 +1110,11 @@ } } - // Used by engineSetParameter/engineInitSign/engineInitVerify() to - // find the right provider with the supplied key, parameters, random source - private void chooseProvider(int type, Key key, - AlgorithmParameterSpec params, SecureRandom random) - throws InvalidKeyException, InvalidAlgorithmParameterException { + private void chooseProvider(int type, Key key, SecureRandom random) + throws InvalidKeyException { synchronized (lock) { if (sigSpi != null) { + init(sigSpi, type, key, random); return; } Exception lastException = null; @@ -1244,7 +1127,7 @@ s = serviceIterator.next(); } // if provider says it does not support this key, ignore it - if (key != null && s.supportsParameter(key) == false) { + if (s.supportsParameter(key) == false) { continue; } // if instance is not a SignatureSpi, ignore it @@ -1253,7 +1136,7 @@ } try { SignatureSpi spi = newInstance(s); - tryOperation(spi, type, key, params, random); + init(spi, type, key, random); provider = s.getProvider(); sigSpi = spi; firstService = null; @@ -1275,10 +1158,6 @@ if (lastException instanceof RuntimeException) { throw (RuntimeException)lastException; } - if (lastException instanceof InvalidAlgorithmParameterException) { - throw (InvalidAlgorithmParameterException)lastException; - } - String k = (key != null) ? key.getClass().getName() : "(null)"; throw new InvalidKeyException ("No installed provider supports this key: " @@ -1286,35 +1165,22 @@ } } - private static final int I_PUB = 1; - private static final int I_PRIV = 2; - private static final int I_PRIV_SR = 3; - private static final int I_PUB_PARAM = 4; - private static final int I_PRIV_PARAM_SR = 5; - private static final int S_PARAM = 6; - - private void tryOperation(SignatureSpi spi, int type, Key key, - AlgorithmParameterSpec params, SecureRandom random) - throws InvalidKeyException, InvalidAlgorithmParameterException { + private static final int I_PUB = 1; + private static final int I_PRIV = 2; + private static final int I_PRIV_SR = 3; + + private void init(SignatureSpi spi, int type, Key key, + SecureRandom random) throws InvalidKeyException { switch (type) { case I_PUB: spi.engineInitVerify((PublicKey)key); break; - case I_PUB_PARAM: - spi.engineInitVerify((PublicKey)key, params); - break; case I_PRIV: spi.engineInitSign((PrivateKey)key); break; case I_PRIV_SR: spi.engineInitSign((PrivateKey)key, random); break; - case I_PRIV_PARAM_SR: - spi.engineInitSign((PrivateKey)key, params, random); - break; - case S_PARAM: - spi.engineSetParameter(params); - break; default: throw new AssertionError("Internal error: " + type); } @@ -1325,22 +1191,7 @@ if (sigSpi != null) { sigSpi.engineInitVerify(publicKey); } else { - try { - chooseProvider(I_PUB, publicKey, null, null); - } catch (InvalidAlgorithmParameterException iape) { - // should not happen, re-throw as IKE just in case - throw new InvalidKeyException(iape); - } - } - } - - void engineInitVerify(PublicKey publicKey, - AlgorithmParameterSpec params) - throws InvalidKeyException, InvalidAlgorithmParameterException { - if (sigSpi != null) { - sigSpi.engineInitVerify(publicKey, params); - } else { - chooseProvider(I_PUB_PARAM, publicKey, params, null); + chooseProvider(I_PUB, publicKey, null); } } @@ -1349,12 +1200,7 @@ if (sigSpi != null) { sigSpi.engineInitSign(privateKey); } else { - try { - chooseProvider(I_PRIV, privateKey, null, null); - } catch (InvalidAlgorithmParameterException iape) { - // should not happen, re-throw as IKE just in case - throw new InvalidKeyException(iape); - } + chooseProvider(I_PRIV, privateKey, null); } } @@ -1363,22 +1209,7 @@ if (sigSpi != null) { sigSpi.engineInitSign(privateKey, sr); } else { - try { - chooseProvider(I_PRIV_SR, privateKey, null, sr); - } catch (InvalidAlgorithmParameterException iape) { - // should not happen, re-throw as IKE just in case - throw new InvalidKeyException(iape); - } - } - } - - void engineInitSign(PrivateKey privateKey, - AlgorithmParameterSpec params, SecureRandom sr) - throws InvalidKeyException, InvalidAlgorithmParameterException { - if (sigSpi != null) { - sigSpi.engineInitSign(privateKey, params, sr); - } else { - chooseProvider(I_PRIV_PARAM_SR, privateKey, params, sr); + chooseProvider(I_PRIV_SR, privateKey, sr); } } @@ -1429,16 +1260,8 @@ protected void engineSetParameter(AlgorithmParameterSpec params) throws InvalidAlgorithmParameterException { - if (sigSpi != null) { - sigSpi.engineSetParameter(params); - } else { - try { - chooseProvider(S_PARAM, null, params, null); - } catch (InvalidKeyException ike) { - // should never happen, rethrow just in case - throw new InvalidAlgorithmParameterException(ike); - } - } + chooseFirstProvider(); + sigSpi.engineSetParameter(params); } protected Object engineGetParameter(String param) --- old/src/java.base/share/classes/java/security/SignatureSpi.java 2019-05-21 01:01:44.865104623 +0200 +++ new/src/java.base/share/classes/java/security/SignatureSpi.java 2019-05-21 01:01:44.713104896 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -72,33 +72,6 @@ /** * Initializes this signature object with the specified - * public key for verification operations. - * - * @param publicKey the public key of the identity whose signature is - * going to be verified. - * @param params the parameters for generating this signature - * - * @exception InvalidKeyException if the key is improperly - * encoded, does not work with the given parameters, and so on. - * @exception InvalidAlgorithmParameterException if the given parameters - * is invalid. - */ - void engineInitVerify(PublicKey publicKey, - AlgorithmParameterSpec params) - throws InvalidKeyException, InvalidAlgorithmParameterException { - if (params != null) { - try { - engineSetParameter(params); - } catch (UnsupportedOperationException usoe) { - // error out if not overrridden - throw new InvalidAlgorithmParameterException(usoe); - } - } - engineInitVerify(publicKey); - } - - /** - * Initializes this signature object with the specified * private key for signing operations. * * @param privateKey the private key of the identity whose signature @@ -125,41 +98,10 @@ * encoded, parameters are missing, and so on. */ protected void engineInitSign(PrivateKey privateKey, - SecureRandom random) - throws InvalidKeyException { - this.appRandom = random; - engineInitSign(privateKey); - } - - /** - * Initializes this signature object with the specified - * private key and source of randomness for signing operations. - * - *

This concrete method has been added to this previously-defined - * abstract class. (For backwards compatibility, it cannot be abstract.) - * - * @param privateKey the private key of the identity whose signature - * will be generated. - * @param params the parameters for generating this signature - * @param random the source of randomness - * - * @exception InvalidKeyException if the key is improperly - * encoded, parameters are missing, and so on. - * @exception InvalidAlgorithmParameterException if the parameters is - * invalid. - */ - void engineInitSign(PrivateKey privateKey, - AlgorithmParameterSpec params, SecureRandom random) - throws InvalidKeyException, InvalidAlgorithmParameterException { - if (params != null) { - try { - engineSetParameter(params); - } catch (UnsupportedOperationException usoe) { - // error out if not overrridden - throw new InvalidAlgorithmParameterException(usoe); - } - } - engineInitSign(privateKey, random); + SecureRandom random) + throws InvalidKeyException { + this.appRandom = random; + engineInitSign(privateKey); } /** @@ -185,7 +127,7 @@ * properly */ protected abstract void engineUpdate(byte[] b, int off, int len) - throws SignatureException; + throws SignatureException; /** * Updates the data to be signed or verified using the specified @@ -281,7 +223,7 @@ * @since 1.2 */ protected int engineSign(byte[] outbuf, int offset, int len) - throws SignatureException { + throws SignatureException { byte[] sig = engineSign(); if (len < sig.length) { throw new SignatureException @@ -309,7 +251,7 @@ * process the input data provided, etc. */ protected abstract boolean engineVerify(byte[] sigBytes) - throws SignatureException; + throws SignatureException; /** * Verifies the passed-in signature in the specified array @@ -331,7 +273,7 @@ * @since 1.4 */ protected boolean engineVerify(byte[] sigBytes, int offset, int length) - throws SignatureException { + throws SignatureException { byte[] sigBytesCopy = new byte[length]; System.arraycopy(sigBytes, offset, sigBytesCopy, 0, length); return engineVerify(sigBytesCopy); @@ -363,7 +305,7 @@ */ @Deprecated protected abstract void engineSetParameter(String param, Object value) - throws InvalidParameterException; + throws InvalidParameterException; /** *

This method is overridden by providers to initialize @@ -379,8 +321,8 @@ * are inappropriate for this signature engine */ protected void engineSetParameter(AlgorithmParameterSpec params) - throws InvalidAlgorithmParameterException { - throw new UnsupportedOperationException(); + throws InvalidAlgorithmParameterException { + throw new UnsupportedOperationException(); } /** --- old/src/java.base/share/classes/java/security/cert/X509CRL.java 2019-05-21 01:01:45.065104266 +0200 +++ new/src/java.base/share/classes/java/security/cert/X509CRL.java 2019-05-21 01:01:44.913104539 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -239,15 +239,16 @@ public void verify(PublicKey key, Provider sigProvider) throws CRLException, NoSuchAlgorithmException, InvalidKeyException, SignatureException { - String sigAlgName = getSigAlgName(); Signature sig = (sigProvider == null) - ? Signature.getInstance(sigAlgName) - : Signature.getInstance(sigAlgName, sigProvider); + ? Signature.getInstance(getSigAlgName()) + : Signature.getInstance(getSigAlgName(), sigProvider); + sig.initVerify(key); + + // set parameters after Signature.initSign/initVerify call, + // so the deferred provider selections occur when key is set try { - byte[] paramBytes = getSigAlgParams(); - SignatureUtil.initVerifyWithParam(sig, key, - SignatureUtil.getParamSpec(sigAlgName, paramBytes)); + SignatureUtil.specialSetParameter(sig, getSigAlgParams()); } catch (ProviderException e) { throw new CRLException(e.getMessage(), e.getCause()); } catch (InvalidAlgorithmParameterException e) { --- old/src/java.base/share/classes/java/security/cert/X509Certificate.java 2019-05-21 01:01:45.269103899 +0200 +++ new/src/java.base/share/classes/java/security/cert/X509Certificate.java 2019-05-21 01:01:45.113104179 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -676,14 +676,16 @@ public void verify(PublicKey key, Provider sigProvider) throws CertificateException, NoSuchAlgorithmException, InvalidKeyException, SignatureException { - String sigName = getSigAlgName(); Signature sig = (sigProvider == null) - ? Signature.getInstance(sigName) - : Signature.getInstance(sigName, sigProvider); + ? Signature.getInstance(getSigAlgName()) + : Signature.getInstance(getSigAlgName(), sigProvider); + sig.initVerify(key); + + // set parameters after Signature.initSign/initVerify call, + // so the deferred provider selections occur when key is set try { - SignatureUtil.initVerifyWithParam(sig, key, - SignatureUtil.getParamSpec(sigName, getSigAlgParams())); + SignatureUtil.specialSetParameter(sig, getSigAlgParams()); } catch (ProviderException e) { throw new CertificateException(e.getMessage(), e.getCause()); } catch (InvalidAlgorithmParameterException e) { --- old/src/java.base/share/classes/java/util/ImmutableCollections.java 2019-05-21 01:01:45.469103540 +0200 +++ new/src/java.base/share/classes/java/util/ImmutableCollections.java 2019-05-21 01:01:45.317103813 +0200 @@ -95,6 +95,11 @@ } } + @SuppressWarnings("unchecked") + static List emptyList() { + return (List) ListN.EMPTY_LIST; + } + static abstract class AbstractImmutableList extends AbstractImmutableCollection implements List, RandomAccess { @@ -404,11 +409,6 @@ } @Override - public boolean isEmpty() { - return false; - } - - @Override public E get(int index) { if (index == 0) { return e0; @@ -485,7 +485,7 @@ @Override public boolean isEmpty() { - return elements.length == 0; + return size() == 0; } @Override @@ -556,6 +556,11 @@ public abstract int hashCode(); } + @SuppressWarnings("unchecked") + static Set emptySet() { + return (Set) SetN.EMPTY_SET; + } + static final class Set12 extends AbstractImmutableSet implements Serializable { @@ -584,11 +589,6 @@ } @Override - public boolean isEmpty() { - return false; - } - - @Override public boolean contains(Object o) { return o.equals(e0) || o.equals(e1); // implicit nullcheck of o } @@ -716,11 +716,6 @@ } @Override - public boolean isEmpty() { - return size == 0; - } - - @Override public boolean contains(Object o) { Objects.requireNonNull(o); return size > 0 && probe(o) >= 0; @@ -849,6 +844,11 @@ // ---------- Map Implementations ---------- + @SuppressWarnings("unchecked") + static Map emptyMap() { + return (Map) MapN.EMPTY_MAP; + } + abstract static class AbstractImmutableMap extends AbstractMap implements Serializable { @Override public void clear() { throw uoe(); } @Override public V compute(K key, BiFunction rf) { throw uoe(); } @@ -882,11 +882,6 @@ } @Override - public V get(Object o) { - return o.equals(k0) ? v0 : null; // implicit nullcheck of o - } - - @Override public boolean containsKey(Object o) { return o.equals(k0); // implicit nullcheck of o } @@ -896,16 +891,6 @@ return o.equals(v0); // implicit nullcheck of o } - @Override - public int size() { - return 1; - } - - @Override - public boolean isEmpty() { - return false; - } - private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { throw new InvalidObjectException("not serial proxy"); } @@ -1023,11 +1008,6 @@ return size; } - @Override - public boolean isEmpty() { - return size == 0; - } - class MapNIterator implements Iterator> { private int remaining; @@ -1268,7 +1248,7 @@ return Set.of(array); case IMM_MAP: if (array.length == 0) { - return ImmutableCollections.MapN.EMPTY_MAP; + return ImmutableCollections.emptyMap(); } else if (array.length == 2) { return new ImmutableCollections.Map1<>(array[0], array[1]); } else { --- old/src/java.base/share/classes/java/util/List.java 2019-05-21 01:01:45.681103160 +0200 +++ new/src/java.base/share/classes/java/util/List.java 2019-05-21 01:01:45.525103440 +0200 @@ -787,9 +787,8 @@ * * @since 9 */ - @SuppressWarnings("unchecked") static List of() { - return (List) ImmutableCollections.ListN.EMPTY_LIST; + return ImmutableCollections.emptyList(); } /** @@ -1032,9 +1031,7 @@ static List of(E... elements) { switch (elements.length) { // implicit null check of elements case 0: - @SuppressWarnings("unchecked") - var list = (List) ImmutableCollections.ListN.EMPTY_LIST; - return list; + return ImmutableCollections.emptyList(); case 1: return new ImmutableCollections.List12<>(elements[0]); case 2: --- old/src/java.base/share/classes/java/util/Map.java 2019-05-21 01:01:45.885102796 +0200 +++ new/src/java.base/share/classes/java/util/Map.java 2019-05-21 01:01:45.733103068 +0200 @@ -1286,9 +1286,8 @@ * * @since 9 */ - @SuppressWarnings("unchecked") static Map of() { - return (Map) ImmutableCollections.MapN.EMPTY_MAP; + return ImmutableCollections.emptyMap(); } /** @@ -1605,9 +1604,7 @@ @SuppressWarnings("varargs") static Map ofEntries(Entry... entries) { if (entries.length == 0) { // implicit null check of entries array - @SuppressWarnings("unchecked") - var map = (Map) ImmutableCollections.MapN.EMPTY_MAP; - return map; + return ImmutableCollections.emptyMap(); } else if (entries.length == 1) { // implicit null check of the array slot return new ImmutableCollections.Map1<>(entries[0].getKey(), --- old/src/java.base/share/classes/java/util/Optional.java 2019-05-21 01:01:46.093102421 +0200 +++ new/src/java.base/share/classes/java/util/Optional.java 2019-05-21 01:01:45.937102702 +0200 @@ -61,7 +61,7 @@ /** * Common instance for {@code empty()}. */ - private static final Optional EMPTY = new Optional<>(null); + private static final Optional EMPTY = new Optional<>(); /** * If non-null, the value; if null, indicates no value is present @@ -69,6 +69,16 @@ private final T value; /** + * Constructs an empty instance. + * + * @implNote Generally only one empty instance, {@link Optional#EMPTY}, + * should exist per VM. + */ + private Optional() { + this.value = null; + } + + /** * Returns an empty {@code Optional} instance. No value is present for this * {@code Optional}. * @@ -90,12 +100,11 @@ /** * Constructs an instance with the described value. * - * @param value the value to describe; it's the caller's responsibility to - * ensure the value is non-{@code null} unless creating the singleton - * instance returned by {@code empty()}. + * @param value the non-{@code null} value to describe + * @throws NullPointerException if value is {@code null} */ private Optional(T value) { - this.value = value; + this.value = Objects.requireNonNull(value); } /** @@ -108,7 +117,7 @@ * @throws NullPointerException if value is {@code null} */ public static Optional of(T value) { - return new Optional<>(Objects.requireNonNull(value)); + return new Optional<>(value); } /** @@ -120,10 +129,8 @@ * @return an {@code Optional} with a present value if the specified value * is non-{@code null}, otherwise an empty {@code Optional} */ - @SuppressWarnings("unchecked") public static Optional ofNullable(T value) { - return value == null ? (Optional) EMPTY - : new Optional<>(value); + return value == null ? empty() : of(value); } /** --- old/src/java.base/share/classes/java/util/Set.java 2019-05-21 01:01:46.297102057 +0200 +++ new/src/java.base/share/classes/java/util/Set.java 2019-05-21 01:01:46.137102342 +0200 @@ -448,9 +448,8 @@ * * @since 9 */ - @SuppressWarnings("unchecked") static Set of() { - return (Set) ImmutableCollections.SetN.EMPTY_SET; + return ImmutableCollections.emptySet(); } /** @@ -693,9 +692,7 @@ static Set of(E... elements) { switch (elements.length) { // implicit null check of elements case 0: - @SuppressWarnings("unchecked") - var set = (Set) ImmutableCollections.SetN.EMPTY_SET; - return set; + return ImmutableCollections.emptySet(); case 1: return new ImmutableCollections.Set12<>(elements[0]); case 2: --- old/src/java.base/share/classes/javax/net/ssl/SSLContext.java 2019-05-21 01:01:46.509101677 +0200 +++ new/src/java.base/share/classes/javax/net/ssl/SSLContext.java 2019-05-21 01:01:46.341101978 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,9 +26,8 @@ package javax.net.ssl; import java.security.*; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.VarHandle; import java.util.Objects; + import sun.security.jca.GetInstance; /** @@ -59,20 +58,6 @@ private final String protocol; - private static volatile SSLContext defaultContext; - - private static final VarHandle VH_DEFAULT_CONTEXT; - - static { - try { - VH_DEFAULT_CONTEXT = MethodHandles.lookup() - .findStaticVarHandle( - SSLContext.class, "defaultContext", SSLContext.class); - } catch (Exception e) { - throw new ExceptionInInitializerError(e); - } - } - /** * Creates an SSLContext object. * @@ -87,6 +72,8 @@ this.protocol = protocol; } + private static SSLContext defaultContext; + /** * Returns the default SSL context. * @@ -104,16 +91,12 @@ * {@link SSLContext#getInstance SSLContext.getInstance()} call fails * @since 1.6 */ - public static SSLContext getDefault() throws NoSuchAlgorithmException { - SSLContext temporaryContext = defaultContext; - if (temporaryContext == null) { - temporaryContext = SSLContext.getInstance("Default"); - if (!VH_DEFAULT_CONTEXT.compareAndSet(null, temporaryContext)) { - temporaryContext = defaultContext; - } + public static synchronized SSLContext getDefault() + throws NoSuchAlgorithmException { + if (defaultContext == null) { + defaultContext = SSLContext.getInstance("Default"); } - - return temporaryContext; + return defaultContext; } /** @@ -128,7 +111,7 @@ * {@code SSLPermission("setDefaultSSLContext")} * @since 1.6 */ - public static void setDefault(SSLContext context) { + public static synchronized void setDefault(SSLContext context) { if (context == null) { throw new NullPointerException(); } @@ -136,7 +119,6 @@ if (sm != null) { sm.checkPermission(new SSLPermission("setDefaultSSLContext")); } - defaultContext = context; } --- old/src/java.base/share/classes/javax/net/ssl/SSLServerSocketFactory.java 2019-05-21 01:01:46.705101325 +0200 +++ new/src/java.base/share/classes/javax/net/ssl/SSLServerSocketFactory.java 2019-05-21 01:01:46.557101590 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -42,7 +42,17 @@ * @see SSLServerSocket * @author David Brownell */ -public abstract class SSLServerSocketFactory extends ServerSocketFactory { +public abstract class SSLServerSocketFactory extends ServerSocketFactory +{ + private static SSLServerSocketFactory theFactory; + + private static boolean propertyChecked; + + private static void log(String msg) { + if (SSLSocketFactory.DEBUG) { + System.out.println(msg); + } + } /** * Constructor is used only by subclasses. @@ -65,9 +75,39 @@ * @return the default ServerSocketFactory * @see SSLContext#getDefault */ - public static ServerSocketFactory getDefault() { - if (DefaultFactoryHolder.defaultFactory != null) { - return DefaultFactoryHolder.defaultFactory; + public static synchronized ServerSocketFactory getDefault() { + if (theFactory != null) { + return theFactory; + } + + if (propertyChecked == false) { + propertyChecked = true; + String clsName = SSLSocketFactory.getSecurityProperty + ("ssl.ServerSocketFactory.provider"); + if (clsName != null) { + log("setting up default SSLServerSocketFactory"); + try { + Class cls = null; + try { + cls = Class.forName(clsName); + } catch (ClassNotFoundException e) { + ClassLoader cl = ClassLoader.getSystemClassLoader(); + if (cl != null) { + cls = cl.loadClass(clsName); + } + } + log("class " + clsName + " is loaded"); + @SuppressWarnings("deprecation") + SSLServerSocketFactory fac = (SSLServerSocketFactory)cls.newInstance(); + log("instantiated an instance of class " + clsName); + theFactory = fac; + return fac; + } catch (Exception e) { + log("SSLServerSocketFactory instantiation failed: " + e); + theFactory = new DefaultSSLServerSocketFactory(e); + return theFactory; + } + } } try { @@ -116,51 +156,9 @@ * @see #getDefaultCipherSuites() */ public abstract String [] getSupportedCipherSuites(); - - // lazy initialization holder class idiom for static default factory - // - // See Effective Java Second Edition: Item 71. - private static final class DefaultFactoryHolder { - private static final SSLServerSocketFactory defaultFactory; - - static { - SSLServerSocketFactory mediator = null; - String clsName = SSLSocketFactory.getSecurityProperty( - "ssl.ServerSocketFactory.provider"); - if (clsName != null) { - log("setting up default SSLServerSocketFactory"); - try { - Class cls = null; - try { - cls = Class.forName(clsName); - } catch (ClassNotFoundException e) { - ClassLoader cl = ClassLoader.getSystemClassLoader(); - if (cl != null) { - cls = cl.loadClass(clsName); - } - } - log("class " + clsName + " is loaded"); - - mediator = (SSLServerSocketFactory)cls - .getDeclaredConstructor().newInstance(); - log("instantiated an instance of class " + clsName); - } catch (Exception e) { - log("SSLServerSocketFactory instantiation failed: " + e); - mediator = new DefaultSSLServerSocketFactory(e); - } - } - - defaultFactory = mediator; - } - - private static void log(String msg) { - if (SSLSocketFactory.DEBUG) { - System.out.println(msg); - } - } - } } + // // The default factory does NOTHING. // --- old/src/java.base/share/classes/javax/net/ssl/SSLSocketFactory.java 2019-05-21 01:01:46.909100958 +0200 +++ new/src/java.base/share/classes/javax/net/ssl/SSLSocketFactory.java 2019-05-21 01:01:46.753101239 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -42,20 +42,31 @@ * @see SSLSocket * @author David Brownell */ -public abstract class SSLSocketFactory extends SocketFactory { +public abstract class SSLSocketFactory extends SocketFactory +{ + private static SSLSocketFactory theFactory; + + private static boolean propertyChecked; + static final boolean DEBUG; static { - String s = GetPropertyAction.privilegedGetProperty( - "javax.net.debug", "").toLowerCase(Locale.ENGLISH); + String s = GetPropertyAction.privilegedGetProperty("javax.net.debug", "") + .toLowerCase(Locale.ENGLISH); + DEBUG = s.contains("all") || s.contains("ssl"); } + private static void log(String msg) { + if (DEBUG) { + System.out.println(msg); + } + } + /** * Constructor is used only by subclasses. */ public SSLSocketFactory() { - // blank } /** @@ -74,9 +85,38 @@ * @return the default SocketFactory * @see SSLContext#getDefault */ - public static SocketFactory getDefault() { - if (DefaultFactoryHolder.defaultFactory != null) { - return DefaultFactoryHolder.defaultFactory; + public static synchronized SocketFactory getDefault() { + if (theFactory != null) { + return theFactory; + } + + if (propertyChecked == false) { + propertyChecked = true; + String clsName = getSecurityProperty("ssl.SocketFactory.provider"); + if (clsName != null) { + log("setting up default SSLSocketFactory"); + try { + Class cls = null; + try { + cls = Class.forName(clsName); + } catch (ClassNotFoundException e) { + ClassLoader cl = ClassLoader.getSystemClassLoader(); + if (cl != null) { + cls = cl.loadClass(clsName); + } + } + log("class " + clsName + " is loaded"); + @SuppressWarnings("deprecation") + SSLSocketFactory fac = (SSLSocketFactory)cls.newInstance(); + log("instantiated an instance of class " + clsName); + theFactory = fac; + return fac; + } catch (Exception e) { + log("SSLSocketFactory instantiation failed: " + e.toString()); + theFactory = new DefaultSSLSocketFactory(e); + return theFactory; + } + } } try { @@ -206,49 +246,6 @@ boolean autoClose) throws IOException { throw new UnsupportedOperationException(); } - - // lazy initialization holder class idiom for static default factory - // - // See Effective Java Second Edition: Item 71. - private static final class DefaultFactoryHolder { - private static final SSLSocketFactory defaultFactory; - - static { - SSLSocketFactory mediator = null; - String clsName = getSecurityProperty("ssl.SocketFactory.provider"); - if (clsName != null) { - log("setting up default SSLSocketFactory"); - try { - Class cls = null; - try { - cls = Class.forName(clsName); - } catch (ClassNotFoundException e) { - ClassLoader cl = ClassLoader.getSystemClassLoader(); - if (cl != null) { - cls = cl.loadClass(clsName); - } - } - log("class " + clsName + " is loaded"); - - mediator = (SSLSocketFactory)cls - .getDeclaredConstructor().newInstance(); - - log("instantiated an instance of class " + clsName); - } catch (Exception e) { - log("SSLSocketFactory instantiation failed: " + e); - mediator = new DefaultSSLSocketFactory(e); - } - } - - defaultFactory = mediator; - } - - private static void log(String msg) { - if (DEBUG) { - System.out.println(msg); - } - } - } } --- old/src/java.base/share/classes/jdk/internal/access/JavaSecuritySignatureAccess.java 2019-05-21 01:01:47.109100601 +0200 +++ /dev/null 2019-04-27 15:49:57.376009302 +0200 @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2019, 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.access; - -import java.security.*; -import java.security.spec.AlgorithmParameterSpec; - -public interface JavaSecuritySignatureAccess { - - void initVerify(Signature s, PublicKey publicKey, AlgorithmParameterSpec params) - throws InvalidKeyException, InvalidAlgorithmParameterException; - - void initVerify(Signature s, java.security.cert.Certificate certificate, - AlgorithmParameterSpec params) - throws InvalidKeyException, InvalidAlgorithmParameterException; - - void initSign(Signature s, PrivateKey privateKey, - AlgorithmParameterSpec params, SecureRandom random) - throws InvalidKeyException, InvalidAlgorithmParameterException; -} --- old/src/java.base/share/classes/jdk/internal/access/SharedSecrets.java 2019-05-21 01:01:47.289100278 +0200 +++ new/src/java.base/share/classes/jdk/internal/access/SharedSecrets.java 2019-05-21 01:01:47.133100558 +0200 @@ -36,7 +36,6 @@ import java.io.ObjectInputStream; import java.io.RandomAccessFile; import java.security.ProtectionDomain; -import java.security.Signature; import jdk.internal.misc.Unsafe; /** A repository of "shared secrets", which are a mechanism for @@ -74,7 +73,6 @@ private static JavaObjectInputStreamAccess javaObjectInputStreamAccess; private static JavaObjectInputFilterAccess javaObjectInputFilterAccess; private static JavaIORandomAccessFileAccess javaIORandomAccessFileAccess; - private static JavaSecuritySignatureAccess javaSecuritySignatureAccess; private static JavaxCryptoSealedObjectAccess javaxCryptoSealedObjectAccess; public static JavaUtilJarAccess javaUtilJarAccess() { @@ -329,17 +327,6 @@ return javaIORandomAccessFileAccess; } - public static void setJavaSecuritySignatureAccess(JavaSecuritySignatureAccess jssa) { - javaSecuritySignatureAccess = jssa; - } - - public static JavaSecuritySignatureAccess getJavaSecuritySignatureAccess() { - if (javaSecuritySignatureAccess == null) { - unsafe.ensureClassInitialized(Signature.class); - } - return javaSecuritySignatureAccess; - } - public static void setJavaxCryptoSealedObjectAccess(JavaxCryptoSealedObjectAccess jcsoa) { javaxCryptoSealedObjectAccess = jcsoa; } --- /dev/null 2019-04-27 15:49:57.376009302 +0200 +++ new/src/java.base/share/classes/jdk/internal/lang/annotation/Foldable.java 2019-05-21 01:01:47.333100199 +0200 @@ -0,0 +1,53 @@ +/* + * 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. 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.lang.annotation; + +import java.lang.annotation.*; + +import java.lang.constant.Constable; +import java.lang.constant.ConstantDesc; +import java.lang.invoke.Intrinsics; + +/** + * Identifies a method that is a candidate for compile-time constant folding. + * Such a method must be a pure function of its inputs, all inputs + * (including the receiver, if applied to an instance method) must be value-based + * types, and the output must be a value-based type that is representable + * in the constant pool ({@link Constable} or {@link ConstantDesc}). + * + *

For accesses of fields annotated as {@linkplain Foldable}, and invocations + * of methods annotated as {@linkplain Foldable} whose arguments (and, for instance + * methods, the receiver) are all constant expressions, the compiler may evaluate + * the expression reflectively at compile time and replace it with a constant + * load of the result, or track the result as a constant expression for possible + * intrinsification via methods in {@link Intrinsics}. + * + * @see Constable + * @see ConstantDesc + * @see Intrinsics + */ +@Retention(RetentionPolicy.CLASS) +@Target({ ElementType.METHOD, ElementType.FIELD }) +public @interface Foldable { } --- old/src/java.base/share/classes/jdk/internal/loader/BuiltinClassLoader.java 2019-05-21 01:01:47.713099518 +0200 +++ new/src/java.base/share/classes/jdk/internal/loader/BuiltinClassLoader.java 2019-05-21 01:01:47.557099796 +0200 @@ -64,7 +64,6 @@ import jdk.internal.misc.VM; import jdk.internal.module.ModulePatcher.PatchedModuleReader; import jdk.internal.module.Resources; -import jdk.internal.vm.annotation.Stable; /** @@ -118,18 +117,14 @@ private static class LoadedModule { private final BuiltinClassLoader loader; private final ModuleReference mref; - private final URI uri; // may be null - private @Stable URL codeSourceURL; // may be null + private final URL codeSourceURL; // may be null LoadedModule(BuiltinClassLoader loader, ModuleReference mref) { URL url = null; - this.uri = mref.location().orElse(null); - - // for non-jrt schemes we need to resolve the codeSourceURL - // eagerly during bootstrap since the handler might be - // overridden - if (uri != null && !"jrt".equals(uri.getScheme())) { - url = createURL(uri); + if (mref.location().isPresent()) { + try { + url = mref.location().get().toURL(); + } catch (MalformedURLException | IllegalArgumentException e) { } } this.loader = loader; this.mref = mref; @@ -139,23 +134,7 @@ BuiltinClassLoader loader() { return loader; } ModuleReference mref() { return mref; } String name() { return mref.descriptor().name(); } - - URL codeSourceURL() { - URL url = codeSourceURL; - if (url == null && uri != null) { - codeSourceURL = url = createURL(uri); - } - return url; - } - - private URL createURL(URI uri) { - URL url = null; - try { - url = uri.toURL(); - } catch (MalformedURLException | IllegalArgumentException e) { - } - return url; - } + URL codeSourceURL() { return codeSourceURL; } } --- old/src/java.base/share/classes/jdk/internal/misc/Unsafe.java 2019-05-21 01:01:47.921099144 +0200 +++ new/src/java.base/share/classes/jdk/internal/misc/Unsafe.java 2019-05-21 01:01:47.761099432 +0200 @@ -33,7 +33,6 @@ import java.lang.reflect.Field; import java.security.ProtectionDomain; -import static jdk.internal.misc.UnsafeConstants.*; /** * A collection of methods for performing low-level, unsafe operations. @@ -1167,13 +1166,14 @@ } /** The value of {@code addressSize()} */ - public static final int ADDRESS_SIZE = ADDRESS_SIZE0; + public static final int ADDRESS_SIZE = theUnsafe.addressSize0(); /** * Reports the size in bytes of a native memory page (whatever that is). * This value will always be a power of two. */ - public int pageSize() { return PAGE_SIZE; } + public native int pageSize(); + /// random trusted operations from JNI: @@ -1417,7 +1417,7 @@ byte x) { long wordOffset = offset & ~3; int shift = (int) (offset & 3) << 3; - if (BIG_ENDIAN) { + if (BE) { shift = 24 - shift; } int mask = 0xFF << shift; @@ -1491,7 +1491,7 @@ } long wordOffset = offset & ~3; int shift = (int) (offset & 3) << 3; - if (BIG_ENDIAN) { + if (BE) { shift = 16 - shift; } int mask = 0xFFFF << shift; @@ -3354,14 +3354,14 @@ * @return Returns true if the native byte ordering of this * platform is big-endian, false if it is little-endian. */ - public final boolean isBigEndian() { return BIG_ENDIAN; } + public final boolean isBigEndian() { return BE; } /** * @return Returns true if this platform is capable of performing * accesses at addresses which are not aligned for the type of the * primitive type being accessed, false otherwise. */ - public final boolean unalignedAccess() { return UNALIGNED_ACCESS; } + public final boolean unalignedAccess() { return unalignedAccess; } /** * Fetches a value at some byte offset into a given Java object. @@ -3603,7 +3603,14 @@ putCharUnaligned(o, offset, convEndian(bigEndian, x)); } - private static int pickPos(int top, int pos) { return BIG_ENDIAN ? top - pos : pos; } + // JVM interface methods + // BE is true iff the native endianness of this platform is big. + private static final boolean BE = theUnsafe.isBigEndian0(); + + // unalignedAccess is true iff this platform can perform unaligned accesses. + private static final boolean unalignedAccess = theUnsafe.unalignedAccess0(); + + private static int pickPos(int top, int pos) { return BE ? top - pos : pos; } // These methods construct integers from bytes. The byte ordering // is the native endianness of this platform. @@ -3642,9 +3649,9 @@ | (toUnsignedInt(i1) << pickPos(8, 8))); } - private static byte pick(byte le, byte be) { return BIG_ENDIAN ? be : le; } - private static short pick(short le, short be) { return BIG_ENDIAN ? be : le; } - private static int pick(int le, int be) { return BIG_ENDIAN ? be : le; } + private static byte pick(byte le, byte be) { return BE ? be : le; } + private static short pick(short le, short be) { return BE ? be : le; } + private static int pick(int le, int be) { return BE ? be : le; } // These methods write integers to memory from smaller parts // provided by their caller. The ordering in which these parts @@ -3692,10 +3699,10 @@ private static long toUnsignedLong(int n) { return n & 0xffffffffl; } // Maybe byte-reverse an integer - private static char convEndian(boolean big, char n) { return big == BIG_ENDIAN ? n : Character.reverseBytes(n); } - private static short convEndian(boolean big, short n) { return big == BIG_ENDIAN ? n : Short.reverseBytes(n) ; } - private static int convEndian(boolean big, int n) { return big == BIG_ENDIAN ? n : Integer.reverseBytes(n) ; } - private static long convEndian(boolean big, long n) { return big == BIG_ENDIAN ? n : Long.reverseBytes(n) ; } + private static char convEndian(boolean big, char n) { return big == BE ? n : Character.reverseBytes(n); } + private static short convEndian(boolean big, short n) { return big == BE ? n : Short.reverseBytes(n) ; } + private static int convEndian(boolean big, int n) { return big == BE ? n : Integer.reverseBytes(n) ; } + private static long convEndian(boolean big, long n) { return big == BE ? n : Long.reverseBytes(n) ; } @@ -3714,8 +3721,11 @@ private native void ensureClassInitialized0(Class c); private native int arrayBaseOffset0(Class arrayClass); private native int arrayIndexScale0(Class arrayClass); + private native int addressSize0(); private native Class defineAnonymousClass0(Class hostClass, byte[] data, Object[] cpPatches); private native int getLoadAverage0(double[] loadavg, int nelems); + private native boolean unalignedAccess0(); + private native boolean isBigEndian0(); /** --- old/src/java.base/share/classes/jdk/internal/misc/UnsafeConstants.java 2019-05-21 01:01:48.141098751 +0200 +++ /dev/null 2019-04-27 15:49:57.376009302 +0200 @@ -1,103 +0,0 @@ -/* - * Copyright (c) 2019, Red Hat Inc. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. 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.misc; - -/** - * A class used to expose details of the underlying hardware that - * configure the operation of class Unsafe. This class is - * package-private as the only intended client is class Unsafe. - * All fields in this class must be static final constants. - * - * @since 13 - * - * @implNote - * - * The JVM injects hardware-specific values into all the static fields - * of this class during JVM initialization. The static initialization - * block is executed when the class is initialized then JVM injection - * updates the fields with the correct constants. The static block - * is required to prevent the fields from being considered constant - * variables, so the field values will be not be compiled directly into - * any class that uses them. - */ - -final class UnsafeConstants { - - /** - * This constructor is private because the class is not meant to - * be instantiated. - */ - private UnsafeConstants() {} - - /** - * The size in bytes of a native pointer, as stored via {@link - * #putAddress}. This value will be either 4 or 8. Note that the - * sizes of other primitive types (as stored in native memory - * blocks) is determined fully by their information content. - * - * @implNote - * The actual value for this field is injected by the JVM. - */ - - static final int ADDRESS_SIZE0; - - /** - * The size in bytes of a native memory page (whatever that is). - * This value will always be a power of two. - * - * @implNote - * The actual value for this field is injected by the JVM. - */ - - static final int PAGE_SIZE; - - /** - * Flag whose value is true if and only if the native endianness - * of this platform is big. - * - * @implNote - * The actual value for this field is injected by the JVM. - */ - - static final boolean BIG_ENDIAN; - - /** - * Flag whose value is true if and only if the platform can - * perform unaligned accesses - * - * @implNote - * The actual value for this field is injected by the JVM. - */ - - static final boolean UNALIGNED_ACCESS; - - static { - ADDRESS_SIZE0 = 0; - PAGE_SIZE = 0; - BIG_ENDIAN = false; - UNALIGNED_ACCESS = false; - } -} --- old/src/java.base/share/classes/jdk/internal/reflect/Reflection.java 2019-05-21 01:01:48.321098428 +0200 +++ new/src/java.base/share/classes/jdk/internal/reflect/Reflection.java 2019-05-21 01:01:48.165098708 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -122,9 +122,6 @@ Class targetClass, int modifiers) { - Objects.requireNonNull(currentClass); - Objects.requireNonNull(memberClass); - if (currentClass == memberClass) { // Always succeeds return true; @@ -204,22 +201,6 @@ return true; } - /* - * Verify if a member is public and memberClass is a public type - * in a package that is unconditionally exported and - * return {@code true}if it is granted. - * - * @param memberClass the declaring class of the member being accessed - * @param modifiers the member's access modifiers - * @return {@code true} if the member is public and in a publicly accessible type - */ - public static boolean verifyPublicMemberAccess(Class memberClass, int modifiers) { - Module m = memberClass.getModule(); - return Modifier.isPublic(modifiers) - && m.isExported(memberClass.getPackageName()) - && Modifier.isPublic(Reflection.getClassAccessFlags(memberClass)); - } - /** * Returns {@code true} if memberClass's module exports memberClass's * package to currentModule. @@ -344,10 +325,8 @@ Class memberClass, Class targetClass, int modifiers) + throws IllegalAccessException { - if (currentClass == null) - return newIllegalAccessException(memberClass, modifiers); - String currentSuffix = ""; String memberSuffix = ""; Module m1 = currentClass.getModule(); @@ -374,36 +353,6 @@ } return new IllegalAccessException(msg); - } - - /** - * Returns an IllegalAccessException with an exception message where - * there is no caller frame. - */ - private static IllegalAccessException newIllegalAccessException(Class memberClass, - int modifiers) - { - String memberSuffix = ""; - Module m2 = memberClass.getModule(); - if (m2.isNamed()) - memberSuffix = " (in " + m2 + ")"; - - String memberPackageName = memberClass.getPackageName(); - - String msg = "JNI attached native thread (null caller frame) cannot access "; - if (m2.isExported(memberPackageName)) { - - // module access okay so include the modifiers in the message - msg += "a member of " + memberClass + memberSuffix + - " with modifiers \"" + Modifier.toString(modifiers) + "\""; - - } else { - // module access failed - msg += memberClass + memberSuffix+ " because " - + m2 + " does not export " + memberPackageName; - } - - return new IllegalAccessException(msg); } /** --- old/src/java.base/share/classes/module-info.java 2019-05-21 01:01:48.525098061 +0200 +++ new/src/java.base/share/classes/module-info.java 2019-05-21 01:01:48.365098349 +0200 @@ -157,6 +157,8 @@ exports jdk.internal.jmod to jdk.compiler, jdk.jlink; + exports jdk.internal.lang.annotation to + jdk.compiler; exports jdk.internal.logger to java.logging; exports jdk.internal.org.objectweb.asm to --- old/src/java.base/share/classes/sun/net/www/protocol/https/HttpsURLConnectionImpl.java 2019-05-21 01:01:48.721097712 +0200 +++ new/src/java.base/share/classes/sun/net/www/protocol/https/HttpsURLConnectionImpl.java 2019-05-21 01:01:48.569097982 +0200 @@ -57,7 +57,8 @@ public class HttpsURLConnectionImpl extends javax.net.ssl.HttpsURLConnection { - private final DelegateHttpsURLConnection delegate; + // NOTE: made protected for plugin so that subclass can set it. + protected DelegateHttpsURLConnection delegate; HttpsURLConnectionImpl(URL u, Handler handler) throws IOException { this(u, null, handler); @@ -77,6 +78,13 @@ delegate = new DelegateHttpsURLConnection(url, p, handler, this); } + // NOTE: introduced for plugin + // subclass needs to overwrite this to set delegate to + // the appropriate delegatee + protected HttpsURLConnectionImpl(URL u) throws IOException { + super(u); + } + /** * Create a new HttpClient object, bypassing the cache of * HTTP client objects/connections. @@ -211,11 +219,11 @@ * - get input, [read input,] get output, [write output] */ - public OutputStream getOutputStream() throws IOException { + public synchronized OutputStream getOutputStream() throws IOException { return delegate.getOutputStream(); } - public InputStream getInputStream() throws IOException { + public synchronized InputStream getInputStream() throws IOException { return delegate.getInputStream(); } --- old/src/java.base/share/classes/sun/nio/ch/FileChannelImpl.java 2019-05-21 01:01:48.925097345 +0200 +++ new/src/java.base/share/classes/sun/nio/ch/FileChannelImpl.java 2019-05-21 01:01:48.765097633 +0200 @@ -940,15 +940,14 @@ if (size > Integer.MAX_VALUE) throw new IllegalArgumentException("Size exceeds Integer.MAX_VALUE"); - int imode; + int imode = -1; if (mode == MapMode.READ_ONLY) imode = MAP_RO; else if (mode == MapMode.READ_WRITE) imode = MAP_RW; else if (mode == MapMode.PRIVATE) imode = MAP_PV; - else - throw new UnsupportedOperationException(); + assert (imode >= 0); if ((mode != MapMode.READ_ONLY) && !writable) throw new NonWritableChannelException(); if (!readable) --- old/src/java.base/share/classes/sun/nio/cs/StreamDecoder.java 2019-05-21 01:01:49.125096986 +0200 +++ new/src/java.base/share/classes/sun/nio/cs/StreamDecoder.java 2019-05-21 01:01:48.973097258 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,20 +28,10 @@ package sun.nio.cs; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.UnsupportedEncodingException; -import java.io.Reader; -import java.nio.ByteBuffer; -import java.nio.CharBuffer; -import java.nio.channels.FileChannel; -import java.nio.channels.ReadableByteChannel; -import java.nio.charset.Charset; -import java.nio.charset.CharsetDecoder; -import java.nio.charset.CoderResult; -import java.nio.charset.CodingErrorAction; -import java.nio.charset.IllegalCharsetNameException; +import java.io.*; +import java.nio.*; +import java.nio.channels.*; +import java.nio.charset.*; public class StreamDecoder extends Reader { @@ -200,11 +190,8 @@ synchronized (lock) { if (closed) return; - try { - implClose(); - } finally { - closed = true; - } + implClose(); + closed = true; } } --- old/src/java.base/share/classes/sun/nio/cs/StreamEncoder.java 2019-05-21 01:01:49.321096634 +0200 +++ new/src/java.base/share/classes/sun/nio/cs/StreamEncoder.java 2019-05-21 01:01:49.169096907 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2005, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,21 +23,15 @@ * questions. */ +/* + */ + package sun.nio.cs; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.io.UnsupportedEncodingException; -import java.io.Writer; -import java.nio.ByteBuffer; -import java.nio.CharBuffer; -import java.nio.channels.WritableByteChannel; -import java.nio.charset.Charset; -import java.nio.charset.CharsetEncoder; -import java.nio.charset.CoderResult; -import java.nio.charset.CodingErrorAction; -import java.nio.charset.IllegalCharsetNameException; +import java.io.*; +import java.nio.*; +import java.nio.channels.*; +import java.nio.charset.*; public class StreamEncoder extends Writer { @@ -164,11 +158,8 @@ synchronized (lock) { if (closed) return; - try { - implClose(); - } finally { - closed = true; - } + implClose(); + closed = true; } } @@ -346,13 +337,8 @@ writeBytes(); if (ch != null) ch.close(); - else { - try { - out.flush(); - } finally { - out.close(); - } - } + else + out.close(); } catch (IOException x) { encoder.reset(); throw x; --- old/src/java.base/share/classes/sun/security/pkcs/SignerInfo.java 2019-05-21 01:01:49.525096269 +0200 +++ new/src/java.base/share/classes/sun/security/pkcs/SignerInfo.java 2019-05-21 01:01:49.369096550 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -447,13 +447,15 @@ Signature sig = Signature.getInstance(algname); + sig.initVerify(key); + + // set parameters after Signature.initSign/initVerify call, + // so the deferred provider selections occur when key is set AlgorithmParameters ap = digestEncryptionAlgorithmId.getParameters(); try { - SignatureUtil.initVerifyWithParam(sig, key, - SignatureUtil.getParamSpec(algname, ap)); - } catch (ProviderException | InvalidAlgorithmParameterException | - InvalidKeyException e) { + SignatureUtil.specialSetParameter(sig, ap); + } catch (ProviderException | InvalidAlgorithmParameterException e) { throw new SignatureException(e.getMessage(), e); } @@ -464,6 +466,8 @@ } catch (IOException e) { throw new SignatureException("IO error verifying signature:\n" + e.getMessage()); + } catch (InvalidKeyException e) { + throw new SignatureException("InvalidKey: " + e.getMessage()); } return null; } --- old/src/java.base/share/classes/sun/security/pkcs10/PKCS10.java 2019-05-21 01:01:49.729095903 +0200 +++ new/src/java.base/share/classes/sun/security/pkcs10/PKCS10.java 2019-05-21 01:01:49.573096183 +0200 @@ -167,8 +167,12 @@ try { sigAlg = id.getName(); sig = Signature.getInstance(sigAlg); - SignatureUtil.initVerifyWithParam(sig, subjectPublicKeyInfo, - SignatureUtil.getParamSpec(sigAlg, id.getParameters())); + + sig.initVerify(subjectPublicKeyInfo); + + // set parameters after Signature.initSign/initVerify call, + // so the deferred provider selections occur when key is set + SignatureUtil.specialSetParameter(sig, id.getParameters()); sig.update(data); if (!sig.verify(sigData)) { --- old/src/java.base/share/classes/sun/security/ssl/BaseSSLSocketImpl.java 2019-05-21 01:01:49.937095530 +0200 +++ new/src/java.base/share/classes/sun/security/ssl/BaseSSLSocketImpl.java 2019-05-21 01:01:49.777095818 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -632,7 +632,7 @@ } @Override - public void setSoTimeout(int timeout) throws SocketException { + public synchronized void setSoTimeout(int timeout) throws SocketException { if (self == this) { super.setSoTimeout(timeout); } else { --- old/src/java.base/share/classes/sun/security/ssl/CipherSuite.java 2019-05-21 01:01:50.153095143 +0200 +++ new/src/java.base/share/classes/sun/security/ssl/CipherSuite.java 2019-05-21 01:01:49.989095436 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -56,22 +56,20 @@ // the following criteria: // 1. Prefer Suite B compliant cipher suites, see RFC6460 (To be // changed later, see below). - // 2. Prefer forward secrecy cipher suites. - // 3. Prefer the stronger bulk cipher, in the order of AES_256(GCM), + // 2. Prefer the stronger bulk cipher, in the order of AES_256(GCM), // AES_128(GCM), AES_256, AES_128, 3DES-EDE. - // 4. Prefer the stronger MAC algorithm, in the order of SHA384, + // 3. Prefer the stronger MAC algorithm, in the order of SHA384, // SHA256, SHA, MD5. - // 5. Prefer the better performance of key exchange and digital + // 4. Prefer the better performance of key exchange and digital // signature algorithm, in the order of ECDHE-ECDSA, ECDHE-RSA, - // DHE-RSA, DHE-DSS, ECDH-ECDSA, ECDH-RSA, RSA. + // RSA, ECDH-ECDSA, ECDH-RSA, DHE-RSA, DHE-DSS. - // TLS 1.3 cipher suites. - TLS_AES_256_GCM_SHA384( - 0x1302, true, "TLS_AES_256_GCM_SHA384", - ProtocolVersion.PROTOCOLS_OF_13, B_AES_256_GCM_IV, H_SHA384), TLS_AES_128_GCM_SHA256( 0x1301, true, "TLS_AES_128_GCM_SHA256", ProtocolVersion.PROTOCOLS_OF_13, B_AES_128_GCM_IV, H_SHA256), + TLS_AES_256_GCM_SHA384( + 0x1302, true, "TLS_AES_256_GCM_SHA384", + ProtocolVersion.PROTOCOLS_OF_13, B_AES_256_GCM_IV, H_SHA384), TLS_CHACHA20_POLY1305_SHA256( 0x1303, true, "TLS_CHACHA20_POLY1305_SHA256", ProtocolVersion.PROTOCOLS_OF_13, B_CC20_P1305, H_SHA256), @@ -99,11 +97,7 @@ ProtocolVersion.PROTOCOLS_OF_12, K_ECDHE_ECDSA, B_CC20_P1305, M_NULL, H_SHA256), - // - // Forward screcy cipher suites. - // - - // AES_256(GCM) - ECDHE + // AES_256(GCM) TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384( 0xC030, true, "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", "", ProtocolVersion.PROTOCOLS_OF_12, @@ -112,14 +106,18 @@ 0xCCA8, true, "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256", "", ProtocolVersion.PROTOCOLS_OF_12, K_ECDHE_RSA, B_CC20_P1305, M_NULL, H_SHA256), - - // AES_128(GCM) - ECDHE - TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256( - 0xC02F, true, "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", "", + TLS_RSA_WITH_AES_256_GCM_SHA384( + 0x009D, true, "TLS_RSA_WITH_AES_256_GCM_SHA384", "", ProtocolVersion.PROTOCOLS_OF_12, - K_ECDHE_RSA, B_AES_128_GCM, M_NULL, H_SHA256), - - // AES_256(GCM) - DHE + K_RSA, B_AES_256_GCM, M_NULL, H_SHA384), + TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384( + 0xC02E, true, "TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384", "", + ProtocolVersion.PROTOCOLS_OF_12, + K_ECDH_ECDSA, B_AES_256_GCM, M_NULL, H_SHA384), + TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384( + 0xC032, true, "TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384", "", + ProtocolVersion.PROTOCOLS_OF_12, + K_ECDH_RSA, B_AES_256_GCM, M_NULL, H_SHA384), TLS_DHE_RSA_WITH_AES_256_GCM_SHA384( 0x009F, true, "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384", "", ProtocolVersion.PROTOCOLS_OF_12, @@ -133,7 +131,23 @@ ProtocolVersion.PROTOCOLS_OF_12, K_DHE_DSS, B_AES_256_GCM, M_NULL, H_SHA384), - // AES_128(GCM) - DHE + // AES_128(GCM) + TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256( + 0xC02F, true, "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", "", + ProtocolVersion.PROTOCOLS_OF_12, + K_ECDHE_RSA, B_AES_128_GCM, M_NULL, H_SHA256), + TLS_RSA_WITH_AES_128_GCM_SHA256( + 0x009C, true, "TLS_RSA_WITH_AES_128_GCM_SHA256", "", + ProtocolVersion.PROTOCOLS_OF_12, + K_RSA, B_AES_128_GCM, M_NULL, H_SHA256), + TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256( + 0xC02D, true, "TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256", "", + ProtocolVersion.PROTOCOLS_OF_12, + K_ECDH_ECDSA, B_AES_128_GCM, M_NULL, H_SHA256), + TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256( + 0xC031, true, "TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256", "", + ProtocolVersion.PROTOCOLS_OF_12, + K_ECDH_RSA, B_AES_128_GCM, M_NULL, H_SHA256), TLS_DHE_RSA_WITH_AES_128_GCM_SHA256( 0x009E, true, "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256", "", ProtocolVersion.PROTOCOLS_OF_12, @@ -143,7 +157,7 @@ ProtocolVersion.PROTOCOLS_OF_12, K_DHE_DSS, B_AES_128_GCM, M_NULL, H_SHA256), - // AES_256(CBC) - ECDHE + // AES_256(CBC) TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384( 0xC024, true, "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384", "", ProtocolVersion.PROTOCOLS_OF_12, @@ -152,62 +166,10 @@ 0xC028, true, "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384", "", ProtocolVersion.PROTOCOLS_OF_12, K_ECDHE_RSA, B_AES_256, M_SHA384, H_SHA384), - - // AES_128(CBC) - ECDHE - TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256( - 0xC023, true, "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", "", - ProtocolVersion.PROTOCOLS_OF_12, - K_ECDHE_ECDSA, B_AES_128, M_SHA256, H_SHA256), - TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256( - 0xC027, true, "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", "", - ProtocolVersion.PROTOCOLS_OF_12, - K_ECDHE_RSA, B_AES_128, M_SHA256, H_SHA256), - - // AES_256(CBC) - DHE - TLS_DHE_RSA_WITH_AES_256_CBC_SHA256( - 0x006B, true, "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256", "", - ProtocolVersion.PROTOCOLS_OF_12, - K_DHE_RSA, B_AES_256, M_SHA256, H_SHA256), - TLS_DHE_DSS_WITH_AES_256_CBC_SHA256( - 0x006A, true, "TLS_DHE_DSS_WITH_AES_256_CBC_SHA256", "", - ProtocolVersion.PROTOCOLS_OF_12, - K_DHE_DSS, B_AES_256, M_SHA256, H_SHA256), - - // AES_128(CBC) - DHE - TLS_DHE_RSA_WITH_AES_128_CBC_SHA256( - 0x0067, true, "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256", "", - ProtocolVersion.PROTOCOLS_OF_12, - K_DHE_RSA, B_AES_128, M_SHA256, H_SHA256), - TLS_DHE_DSS_WITH_AES_128_CBC_SHA256( - 0x0040, true, "TLS_DHE_DSS_WITH_AES_128_CBC_SHA256", "", - ProtocolVersion.PROTOCOLS_OF_12, - K_DHE_DSS, B_AES_128, M_SHA256, H_SHA256), - - // - // not forward screcy cipher suites. - // - - // AES_256(GCM) - TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384( - 0xC02E, true, "TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384", "", - ProtocolVersion.PROTOCOLS_OF_12, - K_ECDH_ECDSA, B_AES_256_GCM, M_NULL, H_SHA384), - TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384( - 0xC032, true, "TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384", "", - ProtocolVersion.PROTOCOLS_OF_12, - K_ECDH_RSA, B_AES_256_GCM, M_NULL, H_SHA384), - - // AES_128(GCM) - TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256( - 0xC02D, true, "TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256", "", - ProtocolVersion.PROTOCOLS_OF_12, - K_ECDH_ECDSA, B_AES_128_GCM, M_NULL, H_SHA256), - TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256( - 0xC031, true, "TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256", "", + TLS_RSA_WITH_AES_256_CBC_SHA256( + 0x003D, true, "TLS_RSA_WITH_AES_256_CBC_SHA256", "", ProtocolVersion.PROTOCOLS_OF_12, - K_ECDH_RSA, B_AES_128_GCM, M_NULL, H_SHA256), - - // AES_256(CBC) + K_RSA, B_AES_256, M_SHA256, H_SHA256), TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384( 0xC026, true, "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384", "", ProtocolVersion.PROTOCOLS_OF_12, @@ -216,22 +178,15 @@ 0xC02A, true, "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384", "", ProtocolVersion.PROTOCOLS_OF_12, K_ECDH_RSA, B_AES_256, M_SHA384, H_SHA384), - - // AES_128(CBC) - TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256( - 0xC025, true, "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256", "", + TLS_DHE_RSA_WITH_AES_256_CBC_SHA256( + 0x006B, true, "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256", "", ProtocolVersion.PROTOCOLS_OF_12, - K_ECDH_ECDSA, B_AES_128, M_SHA256, H_SHA256), - TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256( - 0xC029, true, "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256", "", + K_DHE_RSA, B_AES_256, M_SHA256, H_SHA256), + TLS_DHE_DSS_WITH_AES_256_CBC_SHA256( + 0x006A, true, "TLS_DHE_DSS_WITH_AES_256_CBC_SHA256", "", ProtocolVersion.PROTOCOLS_OF_12, - K_ECDH_RSA, B_AES_128, M_SHA256, H_SHA256), - - // - // Legacy, used for compatibility - // + K_DHE_DSS, B_AES_256, M_SHA256, H_SHA256), - // AES_256(CBC) - ECDHE - Using SHA TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA( 0xC00A, true, "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", "", ProtocolVersion.PROTOCOLS_TO_12, @@ -240,38 +195,10 @@ 0xC014, true, "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", "", ProtocolVersion.PROTOCOLS_TO_12, K_ECDHE_RSA, B_AES_256, M_SHA, H_SHA256), - - // AES_128(CBC) - ECDHE - using SHA - TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA( - 0xC009, true, "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", "", - ProtocolVersion.PROTOCOLS_TO_12, - K_ECDHE_ECDSA, B_AES_128, M_SHA, H_SHA256), - TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA( - 0xC013, true, "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", "", - ProtocolVersion.PROTOCOLS_TO_12, - K_ECDHE_RSA, B_AES_128, M_SHA, H_SHA256), - - // AES_256(CBC) - DHE - Using SHA - TLS_DHE_RSA_WITH_AES_256_CBC_SHA( - 0x0039, true, "TLS_DHE_RSA_WITH_AES_256_CBC_SHA", "", - ProtocolVersion.PROTOCOLS_TO_12, - K_DHE_RSA, B_AES_256, M_SHA, H_SHA256), - TLS_DHE_DSS_WITH_AES_256_CBC_SHA( - 0x0038, true, "TLS_DHE_DSS_WITH_AES_256_CBC_SHA", "", - ProtocolVersion.PROTOCOLS_TO_12, - K_DHE_DSS, B_AES_256, M_SHA, H_SHA256), - - // AES_128(CBC) - DHE - using SHA - TLS_DHE_RSA_WITH_AES_128_CBC_SHA( - 0x0033, true, "TLS_DHE_RSA_WITH_AES_128_CBC_SHA", "", - ProtocolVersion.PROTOCOLS_TO_12, - K_DHE_RSA, B_AES_128, M_SHA, H_SHA256), - TLS_DHE_DSS_WITH_AES_128_CBC_SHA( - 0x0032, true, "TLS_DHE_DSS_WITH_AES_128_CBC_SHA", "", + TLS_RSA_WITH_AES_256_CBC_SHA( + 0x0035, true, "TLS_RSA_WITH_AES_256_CBC_SHA", "", ProtocolVersion.PROTOCOLS_TO_12, - K_DHE_DSS, B_AES_128, M_SHA, H_SHA256), - - // AES_256(CBC) - using SHA, not forward screcy + K_RSA, B_AES_256, M_SHA, H_SHA256), TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA( 0xC005, true, "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA", "", ProtocolVersion.PROTOCOLS_TO_12, @@ -280,58 +207,75 @@ 0xC00F, true, "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA", "", ProtocolVersion.PROTOCOLS_TO_12, K_ECDH_RSA, B_AES_256, M_SHA, H_SHA256), - - // AES_128(CBC) - using SHA, not forward screcy - TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA( - 0xC004, true, "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA", "", + TLS_DHE_RSA_WITH_AES_256_CBC_SHA( + 0x0039, true, "TLS_DHE_RSA_WITH_AES_256_CBC_SHA", "", ProtocolVersion.PROTOCOLS_TO_12, - K_ECDH_ECDSA, B_AES_128, M_SHA, H_SHA256), - TLS_ECDH_RSA_WITH_AES_128_CBC_SHA( - 0xC00E, true, "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA", "", + K_DHE_RSA, B_AES_256, M_SHA, H_SHA256), + TLS_DHE_DSS_WITH_AES_256_CBC_SHA( + 0x0038, true, "TLS_DHE_DSS_WITH_AES_256_CBC_SHA", "", ProtocolVersion.PROTOCOLS_TO_12, - K_ECDH_RSA, B_AES_128, M_SHA, H_SHA256), - - // - // deprecated, used for compatibility - // - - // RSA, AES_256(GCM) - TLS_RSA_WITH_AES_256_GCM_SHA384( - 0x009D, true, "TLS_RSA_WITH_AES_256_GCM_SHA384", "", - ProtocolVersion.PROTOCOLS_OF_12, - K_RSA, B_AES_256_GCM, M_NULL, H_SHA384), + K_DHE_DSS, B_AES_256, M_SHA, H_SHA256), - // RSA, AES_128(GCM) - TLS_RSA_WITH_AES_128_GCM_SHA256( - 0x009C, true, "TLS_RSA_WITH_AES_128_GCM_SHA256", "", + // AES_128(CBC) + TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256( + 0xC023, true, "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", "", ProtocolVersion.PROTOCOLS_OF_12, - K_RSA, B_AES_128_GCM, M_NULL, H_SHA256), - - // RSA, AES_256(CBC) - TLS_RSA_WITH_AES_256_CBC_SHA256( - 0x003D, true, "TLS_RSA_WITH_AES_256_CBC_SHA256", "", + K_ECDHE_ECDSA, B_AES_128, M_SHA256, H_SHA256), + TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256( + 0xC027, true, "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", "", ProtocolVersion.PROTOCOLS_OF_12, - K_RSA, B_AES_256, M_SHA256, H_SHA256), - - // RSA, AES_128(CBC) + K_ECDHE_RSA, B_AES_128, M_SHA256, H_SHA256), TLS_RSA_WITH_AES_128_CBC_SHA256( 0x003C, true, "TLS_RSA_WITH_AES_128_CBC_SHA256", "", ProtocolVersion.PROTOCOLS_OF_12, K_RSA, B_AES_128, M_SHA256, H_SHA256), + TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256( + 0xC025, true, "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256", "", + ProtocolVersion.PROTOCOLS_OF_12, + K_ECDH_ECDSA, B_AES_128, M_SHA256, H_SHA256), + TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256( + 0xC029, true, "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256", "", + ProtocolVersion.PROTOCOLS_OF_12, + K_ECDH_RSA, B_AES_128, M_SHA256, H_SHA256), + TLS_DHE_RSA_WITH_AES_128_CBC_SHA256( + 0x0067, true, "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256", "", + ProtocolVersion.PROTOCOLS_OF_12, + K_DHE_RSA, B_AES_128, M_SHA256, H_SHA256), + TLS_DHE_DSS_WITH_AES_128_CBC_SHA256( + 0x0040, true, "TLS_DHE_DSS_WITH_AES_128_CBC_SHA256", "", + ProtocolVersion.PROTOCOLS_OF_12, + K_DHE_DSS, B_AES_128, M_SHA256, H_SHA256), - // RSA, AES_256(CBC) - using SHA, not forward screcy - TLS_RSA_WITH_AES_256_CBC_SHA( - 0x0035, true, "TLS_RSA_WITH_AES_256_CBC_SHA", "", + TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA( + 0xC009, true, "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", "", ProtocolVersion.PROTOCOLS_TO_12, - K_RSA, B_AES_256, M_SHA, H_SHA256), - - // RSA, AES_128(CBC) - using SHA, not forward screcy + K_ECDHE_ECDSA, B_AES_128, M_SHA, H_SHA256), + TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA( + 0xC013, true, "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", "", + ProtocolVersion.PROTOCOLS_TO_12, + K_ECDHE_RSA, B_AES_128, M_SHA, H_SHA256), TLS_RSA_WITH_AES_128_CBC_SHA( 0x002F, true, "TLS_RSA_WITH_AES_128_CBC_SHA", "", ProtocolVersion.PROTOCOLS_TO_12, K_RSA, B_AES_128, M_SHA, H_SHA256), + TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA( + 0xC004, true, "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA", "", + ProtocolVersion.PROTOCOLS_TO_12, + K_ECDH_ECDSA, B_AES_128, M_SHA, H_SHA256), + TLS_ECDH_RSA_WITH_AES_128_CBC_SHA( + 0xC00E, true, "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA", "", + ProtocolVersion.PROTOCOLS_TO_12, + K_ECDH_RSA, B_AES_128, M_SHA, H_SHA256), + TLS_DHE_RSA_WITH_AES_128_CBC_SHA( + 0x0033, true, "TLS_DHE_RSA_WITH_AES_128_CBC_SHA", "", + ProtocolVersion.PROTOCOLS_TO_12, + K_DHE_RSA, B_AES_128, M_SHA, H_SHA256), + TLS_DHE_DSS_WITH_AES_128_CBC_SHA( + 0x0032, true, "TLS_DHE_DSS_WITH_AES_128_CBC_SHA", "", + ProtocolVersion.PROTOCOLS_TO_12, + K_DHE_DSS, B_AES_128, M_SHA, H_SHA256), - // 3DES_EDE, forward secrecy. + // 3DES_EDE TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA( 0xC008, true, "TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA", "", ProtocolVersion.PROTOCOLS_TO_12, @@ -340,18 +284,11 @@ 0xC012, true, "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA", "", ProtocolVersion.PROTOCOLS_TO_12, K_ECDHE_RSA, B_3DES, M_SHA, H_SHA256), - SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA( - 0x0016, true, "SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA", - "TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA", - ProtocolVersion.PROTOCOLS_TO_12, - K_DHE_RSA, B_3DES, M_SHA, H_SHA256), - SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA( - 0x0013, true, "SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA", - "TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA", + SSL_RSA_WITH_3DES_EDE_CBC_SHA( + 0x000A, true, "SSL_RSA_WITH_3DES_EDE_CBC_SHA", + "TLS_RSA_WITH_3DES_EDE_CBC_SHA", ProtocolVersion.PROTOCOLS_TO_12, - K_DHE_DSS, B_3DES, M_SHA, H_SHA256), - - // 3DES_EDE, not forward secrecy. + K_RSA, B_3DES, M_SHA, H_SHA256), TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA( 0xC003, true, "TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA", "", ProtocolVersion.PROTOCOLS_TO_12, @@ -360,11 +297,16 @@ 0xC00D, true, "TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA", "", ProtocolVersion.PROTOCOLS_TO_12, K_ECDH_RSA, B_3DES, M_SHA, H_SHA256), - SSL_RSA_WITH_3DES_EDE_CBC_SHA( - 0x000A, true, "SSL_RSA_WITH_3DES_EDE_CBC_SHA", - "TLS_RSA_WITH_3DES_EDE_CBC_SHA", + SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA( + 0x0016, true, "SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA", + "TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA", ProtocolVersion.PROTOCOLS_TO_12, - K_RSA, B_3DES, M_SHA, H_SHA256), + K_DHE_RSA, B_3DES, M_SHA, H_SHA256), + SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA( + 0x0013, true, "SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA", + "TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA", + ProtocolVersion.PROTOCOLS_TO_12, + K_DHE_DSS, B_3DES, M_SHA, H_SHA256), // Renegotiation protection request Signalling Cipher Suite Value (SCSV). TLS_EMPTY_RENEGOTIATION_INFO_SCSV( // RFC 5746, TLS 1.2 and prior --- old/src/java.base/share/classes/sun/security/ssl/DTLSInputRecord.java 2019-05-21 01:01:50.373094748 +0200 +++ new/src/java.base/share/classes/sun/security/ssl/DTLSInputRecord.java 2019-05-21 01:01:50.209095043 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -58,7 +58,7 @@ } @Override - public void close() throws IOException { + public synchronized void close() throws IOException { if (!isClosed) { super.close(); } --- old/src/java.base/share/classes/sun/security/ssl/DTLSOutputRecord.java 2019-05-21 01:01:50.577094384 +0200 +++ new/src/java.base/share/classes/sun/security/ssl/DTLSOutputRecord.java 2019-05-21 01:01:50.421094664 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -58,18 +58,13 @@ } @Override - public void close() throws IOException { - recordLock.lock(); - try { - if (!isClosed) { - if (fragmenter != null && fragmenter.hasAlert()) { - isCloseWaiting = true; - } else { - super.close(); - } + public synchronized void close() throws IOException { + if (!isClosed) { + if (fragmenter != null && fragmenter.hasAlert()) { + isCloseWaiting = true; + } else { + super.close(); } - } finally { - recordLock.unlock(); } } --- old/src/java.base/share/classes/sun/security/ssl/EphemeralKeyManager.java 2019-05-21 01:01:50.785094009 +0200 +++ new/src/java.base/share/classes/sun/security/ssl/EphemeralKeyManager.java 2019-05-21 01:01:50.625094297 +0200 @@ -26,7 +26,6 @@ package sun.security.ssl; import java.security.*; -import java.util.concurrent.locks.ReentrantLock; /** * The "KeyManager" for ephemeral RSA keys. Ephemeral DH and ECDH keys @@ -49,8 +48,6 @@ new EphemeralKeyPair(null), }; - private final ReentrantLock cachedKeysLock = new ReentrantLock(); - EphemeralKeyManager() { // empty } @@ -68,32 +65,20 @@ index = INDEX_RSA1024; } - KeyPair kp = keys[index].getKeyPair(); - if (kp != null) { - return kp; - } - - cachedKeysLock.lock(); - try { - // double check - kp = keys[index].getKeyPair(); - if (kp != null) { - return kp; + synchronized (keys) { + KeyPair kp = keys[index].getKeyPair(); + if (kp == null) { + try { + KeyPairGenerator kgen = KeyPairGenerator.getInstance("RSA"); + kgen.initialize(length, random); + keys[index] = new EphemeralKeyPair(kgen.genKeyPair()); + kp = keys[index].getKeyPair(); + } catch (Exception e) { + // ignore + } } - - try { - KeyPairGenerator kgen = KeyPairGenerator.getInstance("RSA"); - kgen.initialize(length, random); - keys[index] = new EphemeralKeyPair(kgen.genKeyPair()); - kp = keys[index].getKeyPair(); - } catch (Exception e) { - // ignore - } - } finally { - cachedKeysLock.unlock(); + return kp; } - - return kp; } /** --- old/src/java.base/share/classes/sun/security/ssl/HelloCookieManager.java 2019-05-21 01:01:50.981093660 +0200 +++ new/src/java.base/share/classes/sun/security/ssl/HelloCookieManager.java 2019-05-21 01:01:50.825093938 +0200 @@ -30,7 +30,6 @@ import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.util.Arrays; -import java.util.concurrent.locks.ReentrantLock; import static sun.security.ssl.ClientHello.ClientHelloMessage; /** @@ -46,8 +45,6 @@ private volatile D13HelloCookieManager d13HelloCookieManager; private volatile T13HelloCookieManager t13HelloCookieManager; - private final ReentrantLock managerLock = new ReentrantLock(); - Builder(SecureRandom secureRandom) { this.secureRandom = secureRandom; } @@ -59,14 +56,11 @@ return d13HelloCookieManager; } - managerLock.lock(); - try { + synchronized (this) { if (d13HelloCookieManager == null) { d13HelloCookieManager = new D13HelloCookieManager(secureRandom); } - } finally { - managerLock.unlock(); } return d13HelloCookieManager; @@ -75,14 +69,11 @@ return d10HelloCookieManager; } - managerLock.lock(); - try { + synchronized (this) { if (d10HelloCookieManager == null) { d10HelloCookieManager = new D10HelloCookieManager(secureRandom); } - } finally { - managerLock.unlock(); } return d10HelloCookieManager; @@ -93,14 +84,11 @@ return t13HelloCookieManager; } - managerLock.lock(); - try { + synchronized (this) { if (t13HelloCookieManager == null) { t13HelloCookieManager = new T13HelloCookieManager(secureRandom); } - } finally { - managerLock.unlock(); } return t13HelloCookieManager; @@ -126,8 +114,6 @@ private byte[] cookieSecret; private byte[] legacySecret; - private final ReentrantLock d10ManagerLock = new ReentrantLock(); - D10HelloCookieManager(SecureRandom secureRandom) { this.secureRandom = secureRandom; @@ -145,8 +131,7 @@ int version; byte[] secret; - d10ManagerLock.lock(); - try { + synchronized (this) { version = cookieVersion; secret = cookieSecret; @@ -157,8 +142,6 @@ } cookieVersion++; - } finally { - d10ManagerLock.unlock(); } MessageDigest md; @@ -185,15 +168,12 @@ } byte[] secret; - d10ManagerLock.lock(); - try { + synchronized (this) { if (((cookieVersion >> 24) & 0xFF) == cookie[0]) { secret = cookieSecret; } else { secret = legacySecret; // including out of window cookies } - } finally { - d10ManagerLock.unlock(); } MessageDigest md; @@ -238,8 +218,6 @@ private final byte[] cookieSecret; private final byte[] legacySecret; - private final ReentrantLock t13ManagerLock = new ReentrantLock(); - T13HelloCookieManager(SecureRandom secureRandom) { this.secureRandom = secureRandom; this.cookieVersion = secureRandom.nextInt(); @@ -256,8 +234,7 @@ int version; byte[] secret; - t13ManagerLock.lock(); - try { + synchronized (this) { version = cookieVersion; secret = cookieSecret; @@ -268,8 +245,6 @@ } cookieVersion++; // allow wrapped version number - } finally { - t13ManagerLock.unlock(); } MessageDigest md; @@ -338,15 +313,12 @@ Arrays.copyOfRange(cookie, 3 + hashLen, cookie.length); byte[] secret; - t13ManagerLock.lock(); - try { + synchronized (this) { if ((byte)((cookieVersion >> 24) & 0xFF) == cookie[2]) { secret = cookieSecret; } else { secret = legacySecret; // including out of window cookies } - } finally { - t13ManagerLock.unlock(); } MessageDigest md; --- old/src/java.base/share/classes/sun/security/ssl/InputRecord.java 2019-05-21 01:01:51.185093293 +0200 +++ new/src/java.base/share/classes/sun/security/ssl/InputRecord.java 2019-05-21 01:01:51.021093586 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,7 +31,6 @@ import java.io.OutputStream; import java.nio.BufferUnderflowException; import java.nio.ByteBuffer; -import java.util.concurrent.locks.ReentrantLock; import javax.crypto.BadPaddingException; import sun.security.ssl.SSLCipher.SSLReadCipher; @@ -44,10 +43,10 @@ abstract class InputRecord implements Record, Closeable { SSLReadCipher readCipher; // Needed for KeyUpdate, used after Handshake.Finished - TransportContext tc; + TransportContext tc; final HandshakeHash handshakeHash; - volatile boolean isClosed; + boolean isClosed; // The ClientHello version to accept. If set to ProtocolVersion.SSL20Hello // and the first message we read is a ClientHello in V2 format, we convert @@ -57,8 +56,6 @@ // fragment size int fragmentSize; - final ReentrantLock recordLock = new ReentrantLock(); - InputRecord(HandshakeHash handshakeHash, SSLReadCipher readCipher) { this.readCipher = readCipher; this.helloVersion = ProtocolVersion.TLS10; @@ -95,19 +92,14 @@ * and flag the record as holding no data. */ @Override - public void close() throws IOException { - recordLock.lock(); - try { - if (!isClosed) { - isClosed = true; - readCipher.dispose(); - } - } finally { - recordLock.unlock(); + public synchronized void close() throws IOException { + if (!isClosed) { + isClosed = true; + readCipher.dispose(); } } - boolean isClosed() { + synchronized boolean isClosed() { return isClosed; } --- old/src/java.base/share/classes/sun/security/ssl/OutputRecord.java 2019-05-21 01:01:51.381092941 +0200 +++ new/src/java.base/share/classes/sun/security/ssl/OutputRecord.java 2019-05-21 01:01:51.229093214 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,7 +30,6 @@ import java.io.IOException; import java.io.OutputStream; import java.nio.ByteBuffer; -import java.util.concurrent.locks.ReentrantLock; import sun.security.ssl.SSLCipher.SSLWriteCipher; /** @@ -69,8 +68,6 @@ // closed or not? volatile boolean isClosed; - final ReentrantLock recordLock = new ReentrantLock(); - /* * Mappings from V3 cipher suite encodings to their pure V2 equivalents. * This is taken from the SSL V3 specification, Appendix E. @@ -92,25 +89,15 @@ // Please set packetSize and protocolVersion in the implementation. } - void setVersion(ProtocolVersion protocolVersion) { - recordLock.lock(); - try { - this.protocolVersion = protocolVersion; - } finally { - recordLock.unlock(); - } + synchronized void setVersion(ProtocolVersion protocolVersion) { + this.protocolVersion = protocolVersion; } /* * Updates helloVersion of this record. */ - void setHelloVersion(ProtocolVersion helloVersion) { - recordLock.lock(); - try { - this.helloVersion = helloVersion; - } finally { - recordLock.unlock(); - } + synchronized void setHelloVersion(ProtocolVersion helloVersion) { + this.helloVersion = helloVersion; } /* @@ -121,14 +108,9 @@ return false; } - boolean seqNumIsHuge() { - recordLock.lock(); - try { - return (writeCipher.authenticator != null) && + synchronized boolean seqNumIsHuge() { + return (writeCipher.authenticator != null) && writeCipher.authenticator.seqNumIsHuge(); - } finally { - recordLock.unlock(); - } } // SSLEngine and SSLSocket @@ -166,93 +148,68 @@ } // Change write ciphers, may use change_cipher_spec record. - void changeWriteCiphers(SSLWriteCipher writeCipher, + synchronized void changeWriteCiphers(SSLWriteCipher writeCipher, boolean useChangeCipherSpec) throws IOException { - recordLock.lock(); - try { - if (isClosed()) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { - SSLLogger.warning("outbound has closed, ignore outbound " + - "change_cipher_spec message"); - } - return; - } - - if (useChangeCipherSpec) { - encodeChangeCipherSpec(); + if (isClosed()) { + if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + SSLLogger.warning("outbound has closed, ignore outbound " + + "change_cipher_spec message"); } + return; + } - /* - * Dispose of any intermediate state in the underlying cipher. - * For PKCS11 ciphers, this will release any attached sessions, - * and thus make finalization faster. - * - * Since MAC's doFinal() is called for every SSL/TLS packet, it's - * not necessary to do the same with MAC's. - */ - writeCipher.dispose(); - - this.writeCipher = writeCipher; - this.isFirstAppOutputRecord = true; - } finally { - recordLock.unlock(); + if (useChangeCipherSpec) { + encodeChangeCipherSpec(); } + + /* + * Dispose of any intermediate state in the underlying cipher. + * For PKCS11 ciphers, this will release any attached sessions, + * and thus make finalization faster. + * + * Since MAC's doFinal() is called for every SSL/TLS packet, it's + * not necessary to do the same with MAC's. + */ + writeCipher.dispose(); + + this.writeCipher = writeCipher; + this.isFirstAppOutputRecord = true; } // Change write ciphers using key_update handshake message. - void changeWriteCiphers(SSLWriteCipher writeCipher, + synchronized void changeWriteCiphers(SSLWriteCipher writeCipher, byte keyUpdateRequest) throws IOException { - recordLock.lock(); - try { - if (isClosed()) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { - SSLLogger.warning("outbound has closed, ignore outbound " + - "key_update handshake message"); - } - return; + if (isClosed()) { + if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + SSLLogger.warning("outbound has closed, ignore outbound " + + "key_update handshake message"); } - - // encode the handshake message, KeyUpdate - byte[] hm = HANDSHAKE_MESSAGE_KEY_UPDATE.clone(); - hm[hm.length - 1] = keyUpdateRequest; - encodeHandshake(hm, 0, hm.length); - flush(); - - // Dispose of any intermediate state in the underlying cipher. - writeCipher.dispose(); - - this.writeCipher = writeCipher; - this.isFirstAppOutputRecord = true; - } finally { - recordLock.unlock(); + return; } + + // encode the handshake message, KeyUpdate + byte[] hm = HANDSHAKE_MESSAGE_KEY_UPDATE.clone(); + hm[hm.length - 1] = keyUpdateRequest; + encodeHandshake(hm, 0, hm.length); + flush(); + + // Dispose of any intermediate state in the underlying cipher. + writeCipher.dispose(); + + this.writeCipher = writeCipher; + this.isFirstAppOutputRecord = true; } - void changePacketSize(int packetSize) { - recordLock.lock(); - try { - this.packetSize = packetSize; - } finally { - recordLock.unlock(); - } + synchronized void changePacketSize(int packetSize) { + this.packetSize = packetSize; } - void changeFragmentSize(int fragmentSize) { - recordLock.lock(); - try { - this.fragmentSize = fragmentSize; - } finally { - recordLock.unlock(); - } + synchronized void changeFragmentSize(int fragmentSize) { + this.fragmentSize = fragmentSize; } - int getMaxPacketSize() { - recordLock.lock(); - try { - return packetSize; - } finally { - recordLock.unlock(); - } + synchronized int getMaxPacketSize() { + return packetSize; } // apply to DTLS SSLEngine @@ -271,18 +228,13 @@ } @Override - public void close() throws IOException { - recordLock.lock(); - try { - if (isClosed) { - return; - } - - isClosed = true; - writeCipher.dispose(); - } finally { - recordLock.unlock(); + public synchronized void close() throws IOException { + if (isClosed) { + return; } + + isClosed = true; + writeCipher.dispose(); } boolean isClosed() { --- old/src/java.base/share/classes/sun/security/ssl/SSLContextImpl.java 2019-05-21 01:01:51.593092562 +0200 +++ new/src/java.base/share/classes/sun/security/ssl/SSLContextImpl.java 2019-05-21 01:01:51.425092862 +0200 @@ -30,7 +30,6 @@ import java.security.*; import java.security.cert.*; import java.util.*; -import java.util.concurrent.locks.ReentrantLock; import javax.net.ssl.*; import sun.security.action.GetPropertyAction; import sun.security.provider.certpath.AlgorithmChecker; @@ -70,8 +69,6 @@ private volatile StatusResponseManager statusResponseManager; - private final ReentrantLock contextLock = new ReentrantLock(); - SSLContextImpl() { ephemeralKeyManager = new EphemeralKeyManager(); clientCache = new SSLSessionContextImpl(); @@ -233,14 +230,11 @@ // Used for DTLS in server mode only. HelloCookieManager getHelloCookieManager(ProtocolVersion protocolVersion) { if (helloCookieManagerBuilder == null) { - contextLock.lock(); - try { + synchronized (this) { if (helloCookieManagerBuilder == null) { helloCookieManagerBuilder = new HelloCookieManager.Builder(secureRandom); } - } finally { - contextLock.unlock(); } } @@ -249,8 +243,7 @@ StatusResponseManager getStatusResponseManager() { if (serverEnableStapling && statusResponseManager == null) { - contextLock.lock(); - try { + synchronized (this) { if (statusResponseManager == null) { if (SSLLogger.isOn && SSLLogger.isOn("ssl,sslctx")) { SSLLogger.finest( @@ -258,8 +251,6 @@ } statusResponseManager = new StatusResponseManager(); } - } finally { - contextLock.unlock(); } } --- old/src/java.base/share/classes/sun/security/ssl/SSLEngineImpl.java 2019-05-21 01:01:51.809092174 +0200 +++ new/src/java.base/share/classes/sun/security/ssl/SSLEngineImpl.java 2019-05-21 01:01:51.653092454 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,7 +33,6 @@ import java.security.PrivilegedExceptionAction; import java.util.List; import java.util.Map; -import java.util.concurrent.locks.ReentrantLock; import java.util.function.BiFunction; import javax.net.ssl.SSLEngine; import javax.net.ssl.SSLEngineResult; @@ -55,7 +54,6 @@ final class SSLEngineImpl extends SSLEngine implements SSLTransport { private final SSLContextImpl sslContext; final TransportContext conContext; - private final ReentrantLock engineLock = new ReentrantLock(); /** * Constructor for an SSLEngine from SSLContext, without @@ -95,68 +93,57 @@ } @Override - public void beginHandshake() throws SSLException { - engineLock.lock(); - try { - if (conContext.isUnsureMode) { - throw new IllegalStateException( - "Client/Server mode has not yet been set."); - } + public synchronized void beginHandshake() throws SSLException { + if (conContext.isUnsureMode) { + throw new IllegalStateException( + "Client/Server mode has not yet been set."); + } - try { - conContext.kickstart(); - } catch (IOException ioe) { - throw conContext.fatal(Alert.HANDSHAKE_FAILURE, - "Couldn't kickstart handshaking", ioe); - } catch (Exception ex) { // including RuntimeException - throw conContext.fatal(Alert.INTERNAL_ERROR, - "Fail to begin handshake", ex); - } - } finally { - engineLock.unlock(); + try { + conContext.kickstart(); + } catch (IOException ioe) { + throw conContext.fatal(Alert.HANDSHAKE_FAILURE, + "Couldn't kickstart handshaking", ioe); + } catch (Exception ex) { // including RuntimeException + throw conContext.fatal(Alert.INTERNAL_ERROR, + "Fail to begin handshake", ex); } } @Override - public SSLEngineResult wrap(ByteBuffer[] appData, + public synchronized SSLEngineResult wrap(ByteBuffer[] appData, int offset, int length, ByteBuffer netData) throws SSLException { return wrap(appData, offset, length, new ByteBuffer[]{ netData }, 0, 1); } // @Override - public SSLEngineResult wrap( + public synchronized SSLEngineResult wrap( ByteBuffer[] srcs, int srcsOffset, int srcsLength, ByteBuffer[] dsts, int dstsOffset, int dstsLength) throws SSLException { - engineLock.lock(); - try { - if (conContext.isUnsureMode) { - throw new IllegalStateException( - "Client/Server mode has not yet been set."); - } + if (conContext.isUnsureMode) { + throw new IllegalStateException( + "Client/Server mode has not yet been set."); + } - // See if the handshaker needs to report back some SSLException. - checkTaskThrown(); + // See if the handshaker needs to report back some SSLException. + checkTaskThrown(); - // check parameters - checkParams(srcs, srcsOffset, srcsLength, - dsts, dstsOffset, dstsLength); + // check parameters + checkParams(srcs, srcsOffset, srcsLength, dsts, dstsOffset, dstsLength); - try { - return writeRecord( - srcs, srcsOffset, srcsLength, dsts, dstsOffset, dstsLength); - } catch (SSLProtocolException spe) { - // may be an unexpected handshake message - throw conContext.fatal(Alert.UNEXPECTED_MESSAGE, spe); - } catch (IOException ioe) { - throw conContext.fatal(Alert.INTERNAL_ERROR, - "problem wrapping app data", ioe); - } catch (Exception ex) { // including RuntimeException - throw conContext.fatal(Alert.INTERNAL_ERROR, - "Fail to wrap application data", ex); - } - } finally { - engineLock.unlock(); + try { + return writeRecord( + srcs, srcsOffset, srcsLength, dsts, dstsOffset, dstsLength); + } catch (SSLProtocolException spe) { + // may be an unexpected handshake message + throw conContext.fatal(Alert.UNEXPECTED_MESSAGE, spe); + } catch (IOException ioe) { + throw conContext.fatal(Alert.INTERNAL_ERROR, + "problem wrapping app data", ioe); + } catch (Exception ex) { // including RuntimeException + throw conContext.fatal(Alert.INTERNAL_ERROR, + "Fail to wrap application data", ex); } } @@ -441,53 +428,47 @@ } @Override - public SSLEngineResult unwrap(ByteBuffer src, + public synchronized SSLEngineResult unwrap(ByteBuffer src, ByteBuffer[] dsts, int offset, int length) throws SSLException { return unwrap( new ByteBuffer[]{src}, 0, 1, dsts, offset, length); } // @Override - public SSLEngineResult unwrap( + public synchronized SSLEngineResult unwrap( ByteBuffer[] srcs, int srcsOffset, int srcsLength, ByteBuffer[] dsts, int dstsOffset, int dstsLength) throws SSLException { - engineLock.lock(); - try { - if (conContext.isUnsureMode) { - throw new IllegalStateException( - "Client/Server mode has not yet been set."); - } + if (conContext.isUnsureMode) { + throw new IllegalStateException( + "Client/Server mode has not yet been set."); + } - // See if the handshaker needs to report back some SSLException. - checkTaskThrown(); + // See if the handshaker needs to report back some SSLException. + checkTaskThrown(); - // check parameters - checkParams(srcs, srcsOffset, srcsLength, - dsts, dstsOffset, dstsLength); + // check parameters + checkParams(srcs, srcsOffset, srcsLength, dsts, dstsOffset, dstsLength); - try { - return readRecord( - srcs, srcsOffset, srcsLength, dsts, dstsOffset, dstsLength); - } catch (SSLProtocolException spe) { - // may be an unexpected handshake message - throw conContext.fatal(Alert.UNEXPECTED_MESSAGE, - spe.getMessage(), spe); - } catch (IOException ioe) { - /* - * Don't reset position so it looks like we didn't - * consume anything. We did consume something, and it - * got us into this situation, so report that much back. - * Our days of consuming are now over anyway. - */ - throw conContext.fatal(Alert.INTERNAL_ERROR, - "problem unwrapping net record", ioe); - } catch (Exception ex) { // including RuntimeException - throw conContext.fatal(Alert.INTERNAL_ERROR, - "Fail to unwrap network record", ex); - } - } finally { - engineLock.unlock(); + try { + return readRecord( + srcs, srcsOffset, srcsLength, dsts, dstsOffset, dstsLength); + } catch (SSLProtocolException spe) { + // may be an unexpected handshake message + throw conContext.fatal(Alert.UNEXPECTED_MESSAGE, + spe.getMessage(), spe); + } catch (IOException ioe) { + /* + * Don't reset position so it looks like we didn't + * consume anything. We did consume something, and it + * got us into this situation, so report that much back. + * Our days of consuming are now over anyway. + */ + throw conContext.fatal(Alert.INTERNAL_ERROR, + "problem unwrapping net record", ioe); + } catch (Exception ex) { // including RuntimeException + throw conContext.fatal(Alert.INTERNAL_ERROR, + "Fail to unwrap network record", ex); } } @@ -722,87 +703,61 @@ } @Override - public Runnable getDelegatedTask() { - engineLock.lock(); - try { - if (conContext.handshakeContext != null && // PRE or POST handshake - !conContext.handshakeContext.taskDelegated && - !conContext.handshakeContext.delegatedActions.isEmpty()) { - conContext.handshakeContext.taskDelegated = true; - return new DelegatedTask(this); - } - } finally { - engineLock.unlock(); + public synchronized Runnable getDelegatedTask() { + if (conContext.handshakeContext != null && // PRE or POST handshake + !conContext.handshakeContext.taskDelegated && + !conContext.handshakeContext.delegatedActions.isEmpty()) { + conContext.handshakeContext.taskDelegated = true; + return new DelegatedTask(this); } return null; } @Override - public void closeInbound() throws SSLException { - engineLock.lock(); - try { - if (isInboundDone()) { - return; - } - - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { - SSLLogger.finest("Closing inbound of SSLEngine"); - } + public synchronized void closeInbound() throws SSLException { + if (isInboundDone()) { + return; + } - // Is it ready to close inbound? - // - // No exception if the initial handshake is not started. - if (!conContext.isInputCloseNotified && - (conContext.isNegotiated || - conContext.handshakeContext != null)) { + if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + SSLLogger.finest("Closing inbound of SSLEngine"); + } - throw conContext.fatal(Alert.INTERNAL_ERROR, - "closing inbound before receiving peer's close_notify"); - } + // Is it ready to close inbound? + // + // No need to throw exception if the initial handshake is not started. + if (!conContext.isInputCloseNotified && + (conContext.isNegotiated || conContext.handshakeContext != null)) { - conContext.closeInbound(); - } finally { - engineLock.unlock(); + throw conContext.fatal(Alert.INTERNAL_ERROR, + "closing inbound before receiving peer's close_notify"); } + + conContext.closeInbound(); } @Override - public boolean isInboundDone() { - engineLock.lock(); - try { - return conContext.isInboundClosed(); - } finally { - engineLock.unlock(); - } + public synchronized boolean isInboundDone() { + return conContext.isInboundClosed(); } @Override - public void closeOutbound() { - engineLock.lock(); - try { - if (conContext.isOutboundClosed()) { - return; - } - - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { - SSLLogger.finest("Closing outbound of SSLEngine"); - } + public synchronized void closeOutbound() { + if (conContext.isOutboundClosed()) { + return; + } - conContext.closeOutbound(); - } finally { - engineLock.unlock(); + if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + SSLLogger.finest("Closing outbound of SSLEngine"); } + + conContext.closeOutbound(); } @Override - public boolean isOutboundDone() { - engineLock.lock(); - try { - return conContext.isOutboundDone(); - } finally { - engineLock.unlock(); - } + public synchronized boolean isOutboundDone() { + return conContext.isOutboundDone(); } @Override @@ -811,24 +766,14 @@ } @Override - public String[] getEnabledCipherSuites() { - engineLock.lock(); - try { - return CipherSuite.namesOf(conContext.sslConfig.enabledCipherSuites); - } finally { - engineLock.unlock(); - } + public synchronized String[] getEnabledCipherSuites() { + return CipherSuite.namesOf(conContext.sslConfig.enabledCipherSuites); } @Override - public void setEnabledCipherSuites(String[] suites) { - engineLock.lock(); - try { - conContext.sslConfig.enabledCipherSuites = - CipherSuite.validValuesOf(suites); - } finally { - engineLock.unlock(); - } + public synchronized void setEnabledCipherSuites(String[] suites) { + conContext.sslConfig.enabledCipherSuites = + CipherSuite.validValuesOf(suites); } @Override @@ -838,214 +783,119 @@ } @Override - public String[] getEnabledProtocols() { - engineLock.lock(); - try { - return ProtocolVersion.toStringArray( - conContext.sslConfig.enabledProtocols); - } finally { - engineLock.unlock(); - } + public synchronized String[] getEnabledProtocols() { + return ProtocolVersion.toStringArray( + conContext.sslConfig.enabledProtocols); } @Override - public void setEnabledProtocols(String[] protocols) { - engineLock.lock(); - try { - if (protocols == null) { - throw new IllegalArgumentException("Protocols cannot be null"); - } - - conContext.sslConfig.enabledProtocols = - ProtocolVersion.namesOf(protocols); - } finally { - engineLock.unlock(); + public synchronized void setEnabledProtocols(String[] protocols) { + if (protocols == null) { + throw new IllegalArgumentException("Protocols cannot be null"); } + + conContext.sslConfig.enabledProtocols = + ProtocolVersion.namesOf(protocols); } @Override - public SSLSession getSession() { - engineLock.lock(); - try { - return conContext.conSession; - } finally { - engineLock.unlock(); - } + public synchronized SSLSession getSession() { + return conContext.conSession; } @Override - public SSLSession getHandshakeSession() { - engineLock.lock(); - try { - return conContext.handshakeContext == null ? - null : conContext.handshakeContext.handshakeSession; - } finally { - engineLock.unlock(); - } + public synchronized SSLSession getHandshakeSession() { + return conContext.handshakeContext == null ? + null : conContext.handshakeContext.handshakeSession; } @Override - public SSLEngineResult.HandshakeStatus getHandshakeStatus() { - engineLock.lock(); - try { - return conContext.getHandshakeStatus(); - } finally { - engineLock.unlock(); - } + public synchronized SSLEngineResult.HandshakeStatus getHandshakeStatus() { + return conContext.getHandshakeStatus(); } @Override - public void setUseClientMode(boolean mode) { - engineLock.lock(); - try { - conContext.setUseClientMode(mode); - } finally { - engineLock.unlock(); - } + public synchronized void setUseClientMode(boolean mode) { + conContext.setUseClientMode(mode); } @Override - public boolean getUseClientMode() { - engineLock.lock(); - try { - return conContext.sslConfig.isClientMode; - } finally { - engineLock.unlock(); - } + public synchronized boolean getUseClientMode() { + return conContext.sslConfig.isClientMode; } @Override - public void setNeedClientAuth(boolean need) { - engineLock.lock(); - try { - conContext.sslConfig.clientAuthType = - (need ? ClientAuthType.CLIENT_AUTH_REQUIRED : - ClientAuthType.CLIENT_AUTH_NONE); - } finally { - engineLock.unlock(); - } + public synchronized void setNeedClientAuth(boolean need) { + conContext.sslConfig.clientAuthType = + (need ? ClientAuthType.CLIENT_AUTH_REQUIRED : + ClientAuthType.CLIENT_AUTH_NONE); } @Override - public boolean getNeedClientAuth() { - engineLock.lock(); - try { - return (conContext.sslConfig.clientAuthType == - ClientAuthType.CLIENT_AUTH_REQUIRED); - } finally { - engineLock.unlock(); - } + public synchronized boolean getNeedClientAuth() { + return (conContext.sslConfig.clientAuthType == + ClientAuthType.CLIENT_AUTH_REQUIRED); } @Override - public void setWantClientAuth(boolean want) { - engineLock.lock(); - try { - conContext.sslConfig.clientAuthType = - (want ? ClientAuthType.CLIENT_AUTH_REQUESTED : - ClientAuthType.CLIENT_AUTH_NONE); - } finally { - engineLock.unlock(); - } + public synchronized void setWantClientAuth(boolean want) { + conContext.sslConfig.clientAuthType = + (want ? ClientAuthType.CLIENT_AUTH_REQUESTED : + ClientAuthType.CLIENT_AUTH_NONE); } @Override - public boolean getWantClientAuth() { - engineLock.lock(); - try { - return (conContext.sslConfig.clientAuthType == - ClientAuthType.CLIENT_AUTH_REQUESTED); - } finally { - engineLock.unlock(); - } + public synchronized boolean getWantClientAuth() { + return (conContext.sslConfig.clientAuthType == + ClientAuthType.CLIENT_AUTH_REQUESTED); } @Override - public void setEnableSessionCreation(boolean flag) { - engineLock.lock(); - try { - conContext.sslConfig.enableSessionCreation = flag; - } finally { - engineLock.unlock(); - } + public synchronized void setEnableSessionCreation(boolean flag) { + conContext.sslConfig.enableSessionCreation = flag; } @Override - public boolean getEnableSessionCreation() { - engineLock.lock(); - try { - return conContext.sslConfig.enableSessionCreation; - } finally { - engineLock.unlock(); - } + public synchronized boolean getEnableSessionCreation() { + return conContext.sslConfig.enableSessionCreation; } @Override - public SSLParameters getSSLParameters() { - engineLock.lock(); - try { - return conContext.sslConfig.getSSLParameters(); - } finally { - engineLock.unlock(); - } - } + public synchronized SSLParameters getSSLParameters() { + return conContext.sslConfig.getSSLParameters(); + } @Override - public void setSSLParameters(SSLParameters params) { - engineLock.lock(); - try { - conContext.sslConfig.setSSLParameters(params); + public synchronized void setSSLParameters(SSLParameters params) { + conContext.sslConfig.setSSLParameters(params); - if (conContext.sslConfig.maximumPacketSize != 0) { - conContext.outputRecord.changePacketSize( - conContext.sslConfig.maximumPacketSize); - } - } finally { - engineLock.unlock(); + if (conContext.sslConfig.maximumPacketSize != 0) { + conContext.outputRecord.changePacketSize( + conContext.sslConfig.maximumPacketSize); } - } + } @Override - public String getApplicationProtocol() { - engineLock.lock(); - try { - return conContext.applicationProtocol; - } finally { - engineLock.unlock(); - } + public synchronized String getApplicationProtocol() { + return conContext.applicationProtocol; } @Override - public String getHandshakeApplicationProtocol() { - engineLock.lock(); - try { - return conContext.handshakeContext == null ? - null : conContext.handshakeContext.applicationProtocol; - } finally { - engineLock.unlock(); - } + public synchronized String getHandshakeApplicationProtocol() { + return conContext.handshakeContext == null ? + null : conContext.handshakeContext.applicationProtocol; } @Override - public void setHandshakeApplicationProtocolSelector( + public synchronized void setHandshakeApplicationProtocolSelector( BiFunction, String> selector) { - engineLock.lock(); - try { - conContext.sslConfig.engineAPSelector = selector; - } finally { - engineLock.unlock(); - } + conContext.sslConfig.engineAPSelector = selector; } @Override - public BiFunction, String> + public synchronized BiFunction, String> getHandshakeApplicationProtocolSelector() { - engineLock.lock(); - try { - return conContext.sslConfig.engineAPSelector; - } finally { - engineLock.unlock(); - } + return conContext.sslConfig.engineAPSelector; } @Override @@ -1059,42 +909,38 @@ * null, report back the Exception that happened in the delegated * task(s). */ - private void checkTaskThrown() throws SSLException { + private synchronized void checkTaskThrown() throws SSLException { Exception exc = null; - engineLock.lock(); - try { - // First check the handshake context. - HandshakeContext hc = conContext.handshakeContext; - if ((hc != null) && (hc.delegatedThrown != null)) { - exc = hc.delegatedThrown; - hc.delegatedThrown = null; - } - /* - * hc.delegatedThrown and conContext.delegatedThrown are most - * likely the same, but it's possible we could have had a non-fatal - * exception and thus the new HandshakeContext is still valid - * (alert warning). If so, then we may have a secondary exception - * waiting to be reported from the TransportContext, so we will - * need to clear that on a successive call. Otherwise, clear it now. - */ - if (conContext.delegatedThrown != null) { - if (exc != null) { - // hc object comparison - if (conContext.delegatedThrown == exc) { - // clear if/only if both are the same - conContext.delegatedThrown = null; - } // otherwise report the hc delegatedThrown - } else { - // Nothing waiting in HandshakeContext, but one is in the - // TransportContext. - exc = conContext.delegatedThrown; + // First check the handshake context. + HandshakeContext hc = conContext.handshakeContext; + if ((hc != null) && (hc.delegatedThrown != null)) { + exc = hc.delegatedThrown; + hc.delegatedThrown = null; + } + + /* + * hc.delegatedThrown and conContext.delegatedThrown are most likely + * the same, but it's possible we could have had a non-fatal + * exception and thus the new HandshakeContext is still valid + * (alert warning). If so, then we may have a secondary exception + * waiting to be reported from the TransportContext, so we will + * need to clear that on a successive call. Otherwise, clear it now. + */ + if (conContext.delegatedThrown != null) { + if (exc != null) { + // hc object comparison + if (conContext.delegatedThrown == exc) { + // clear if/only if both are the same conContext.delegatedThrown = null; - } + } // otherwise report the hc delegatedThrown + } else { + // Nothing waiting in HandshakeContext, but one is in the + // TransportContext. + exc = conContext.delegatedThrown; + conContext.delegatedThrown = null; } - } finally { - engineLock.unlock(); } // Anything to report? @@ -1152,8 +998,7 @@ @Override public void run() { - engine.engineLock.lock(); - try { + synchronized (engine) { HandshakeContext hc = engine.conContext.handshakeContext; if (hc == null || hc.delegatedActions.isEmpty()) { return; @@ -1210,8 +1055,6 @@ if (hc != null) { hc.taskDelegated = false; } - } finally { - engine.engineLock.unlock(); } } --- old/src/java.base/share/classes/sun/security/ssl/SSLEngineOutputRecord.java 2019-05-21 01:01:52.025091787 +0200 +++ new/src/java.base/share/classes/sun/security/ssl/SSLEngineOutputRecord.java 2019-05-21 01:01:51.869092067 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -51,18 +51,13 @@ } @Override - public void close() throws IOException { - recordLock.lock(); - try { - if (!isClosed) { - if (fragmenter != null && fragmenter.hasAlert()) { - isCloseWaiting = true; - } else { - super.close(); - } + public synchronized void close() throws IOException { + if (!isClosed) { + if (fragmenter != null && fragmenter.hasAlert()) { + isCloseWaiting = true; + } else { + super.close(); } - } finally { - recordLock.unlock(); } } --- old/src/java.base/share/classes/sun/security/ssl/SSLServerSocketImpl.java 2019-05-21 01:01:52.241091400 +0200 +++ new/src/java.base/share/classes/sun/security/ssl/SSLServerSocketImpl.java 2019-05-21 01:01:52.069091708 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,7 +28,6 @@ import java.io.IOException; import java.net.InetAddress; import java.net.Socket; -import java.util.concurrent.locks.ReentrantLock; import javax.net.ssl.SSLParameters; import javax.net.ssl.SSLServerSocket; @@ -57,7 +56,6 @@ final class SSLServerSocketImpl extends SSLServerSocket { private final SSLContextImpl sslContext; private final SSLConfiguration sslConfig; - private final ReentrantLock serverSocketLock = new ReentrantLock(); SSLServerSocketImpl(SSLContextImpl sslContext) throws IOException { @@ -86,24 +84,14 @@ } @Override - public String[] getEnabledCipherSuites() { - serverSocketLock.lock(); - try { - return CipherSuite.namesOf(sslConfig.enabledCipherSuites); - } finally { - serverSocketLock.unlock(); - } + public synchronized String[] getEnabledCipherSuites() { + return CipherSuite.namesOf(sslConfig.enabledCipherSuites); } @Override - public void setEnabledCipherSuites(String[] suites) { - serverSocketLock.lock(); - try { - sslConfig.enabledCipherSuites = - CipherSuite.validValuesOf(suites); - } finally { - serverSocketLock.unlock(); - } + public synchronized void setEnabledCipherSuites(String[] suites) { + sslConfig.enabledCipherSuites = + CipherSuite.validValuesOf(suites); } @Override @@ -118,153 +106,93 @@ } @Override - public String[] getEnabledProtocols() { - serverSocketLock.lock(); - try { - return ProtocolVersion.toStringArray(sslConfig.enabledProtocols); - } finally { - serverSocketLock.unlock(); - } + public synchronized String[] getEnabledProtocols() { + return ProtocolVersion.toStringArray(sslConfig.enabledProtocols); } @Override - public void setEnabledProtocols(String[] protocols) { - serverSocketLock.lock(); - try { - if (protocols == null) { - throw new IllegalArgumentException("Protocols cannot be null"); - } - - sslConfig.enabledProtocols = ProtocolVersion.namesOf(protocols); - } finally { - serverSocketLock.unlock(); + public synchronized void setEnabledProtocols(String[] protocols) { + if (protocols == null) { + throw new IllegalArgumentException("Protocols cannot be null"); } + + sslConfig.enabledProtocols = ProtocolVersion.namesOf(protocols); } @Override - public void setNeedClientAuth(boolean need) { - serverSocketLock.lock(); - try { - sslConfig.clientAuthType = - (need ? ClientAuthType.CLIENT_AUTH_REQUIRED : - ClientAuthType.CLIENT_AUTH_NONE); - } finally { - serverSocketLock.unlock(); - } + public synchronized void setNeedClientAuth(boolean need) { + sslConfig.clientAuthType = + (need ? ClientAuthType.CLIENT_AUTH_REQUIRED : + ClientAuthType.CLIENT_AUTH_NONE); } @Override - public boolean getNeedClientAuth() { - serverSocketLock.lock(); - try { - return (sslConfig.clientAuthType == + public synchronized boolean getNeedClientAuth() { + return (sslConfig.clientAuthType == ClientAuthType.CLIENT_AUTH_REQUIRED); - } finally { - serverSocketLock.unlock(); - } } @Override - public void setWantClientAuth(boolean want) { - serverSocketLock.lock(); - try { - sslConfig.clientAuthType = - (want ? ClientAuthType.CLIENT_AUTH_REQUESTED : - ClientAuthType.CLIENT_AUTH_NONE); - } finally { - serverSocketLock.unlock(); - } + public synchronized void setWantClientAuth(boolean want) { + sslConfig.clientAuthType = + (want ? ClientAuthType.CLIENT_AUTH_REQUESTED : + ClientAuthType.CLIENT_AUTH_NONE); } @Override - public boolean getWantClientAuth() { - serverSocketLock.lock(); - try { - return (sslConfig.clientAuthType == + public synchronized boolean getWantClientAuth() { + return (sslConfig.clientAuthType == ClientAuthType.CLIENT_AUTH_REQUESTED); - } finally { - serverSocketLock.unlock(); - } } @Override - public void setUseClientMode(boolean useClientMode) { - serverSocketLock.lock(); - try { - /* - * If we need to change the client mode and the enabled - * protocols and cipher suites haven't specifically been - * set by the user, change them to the corresponding - * default ones. - */ - if (sslConfig.isClientMode != useClientMode) { - if (sslContext.isDefaultProtocolVesions( - sslConfig.enabledProtocols)) { - sslConfig.enabledProtocols = + public synchronized void setUseClientMode(boolean useClientMode) { + /* + * If we need to change the client mode and the enabled + * protocols and cipher suites haven't specifically been + * set by the user, change them to the corresponding + * default ones. + */ + if (sslConfig.isClientMode != useClientMode) { + if (sslContext.isDefaultProtocolVesions( + sslConfig.enabledProtocols)) { + sslConfig.enabledProtocols = sslContext.getDefaultProtocolVersions(!useClientMode); - } + } - if (sslContext.isDefaultCipherSuiteList( - sslConfig.enabledCipherSuites)) { - sslConfig.enabledCipherSuites = + if (sslContext.isDefaultCipherSuiteList( + sslConfig.enabledCipherSuites)) { + sslConfig.enabledCipherSuites = sslContext.getDefaultCipherSuites(!useClientMode); - } - - sslConfig.isClientMode = useClientMode; } - } finally { - serverSocketLock.unlock(); + + sslConfig.isClientMode = useClientMode; } } @Override - public boolean getUseClientMode() { - serverSocketLock.lock(); - try { - return sslConfig.isClientMode; - } finally { - serverSocketLock.unlock(); - } + public synchronized boolean getUseClientMode() { + return sslConfig.isClientMode; } @Override - public void setEnableSessionCreation(boolean flag) { - serverSocketLock.lock(); - try { - sslConfig.enableSessionCreation = flag; - } finally { - serverSocketLock.unlock(); - } + public synchronized void setEnableSessionCreation(boolean flag) { + sslConfig.enableSessionCreation = flag; } @Override - public boolean getEnableSessionCreation() { - serverSocketLock.lock(); - try { - return sslConfig.enableSessionCreation; - } finally { - serverSocketLock.unlock(); - } + public synchronized boolean getEnableSessionCreation() { + return sslConfig.enableSessionCreation; } @Override - public SSLParameters getSSLParameters() { - serverSocketLock.lock(); - try { - return sslConfig.getSSLParameters(); - } finally { - serverSocketLock.unlock(); - } + public synchronized SSLParameters getSSLParameters() { + return sslConfig.getSSLParameters(); } @Override - public void setSSLParameters(SSLParameters params) { - serverSocketLock.lock(); - try { - sslConfig.setSSLParameters(params); - } finally { - serverSocketLock.unlock(); - } + public synchronized void setSSLParameters(SSLParameters params) { + sslConfig.setSSLParameters(params); } @Override --- old/src/java.base/share/classes/sun/security/ssl/SSLSessionImpl.java 2019-05-21 01:01:52.489090956 +0200 +++ new/src/java.base/share/classes/sun/security/ssl/SSLSessionImpl.java 2019-05-21 01:01:52.309091277 +0200 @@ -38,7 +38,6 @@ import java.util.List; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedQueue; -import java.util.concurrent.locks.ReentrantLock; import javax.crypto.SecretKey; import javax.net.ssl.ExtendedSSLSession; import javax.net.ssl.SNIServerName; @@ -134,9 +133,7 @@ // The endpoint identification algorithm used to check certificates // in this session. - private final String identificationProtocol; - - private final ReentrantLock sessionLock = new ReentrantLock(); + private final String identificationProtocol; /* * Create a new non-rejoinable session, using the default (null) @@ -292,22 +289,15 @@ return resumptionMasterSecret; } - SecretKey getPreSharedKey() { - sessionLock.lock(); - try { - return preSharedKey; - } finally { - sessionLock.unlock(); - } + synchronized SecretKey getPreSharedKey() { + return preSharedKey; } - SecretKey consumePreSharedKey() { - sessionLock.lock(); + synchronized SecretKey consumePreSharedKey() { try { return preSharedKey; } finally { preSharedKey = null; - sessionLock.unlock(); } } @@ -323,13 +313,11 @@ * be used once. This method will return the identity and then clear it * so it cannot be used again. */ - byte[] consumePskIdentity() { - sessionLock.lock(); + synchronized byte[] consumePskIdentity() { try { return pskIdentity; } finally { pskIdentity = null; - sessionLock.unlock(); } } @@ -405,13 +393,8 @@ } @Override - public boolean isValid() { - sessionLock.lock(); - try { - return isRejoinable(); - } finally { - sessionLock.unlock(); - } + public synchronized boolean isValid() { + return isRejoinable(); } /** @@ -794,35 +777,29 @@ * no connections will be able to rejoin this session. */ @Override - public void invalidate() { - sessionLock.lock(); - try { - // - // Can't invalidate the NULL session -- this would be - // attempted when we get a handshaking error on a brand - // new connection, with no "real" session yet. - // - if (this == nullSession) { - return; - } - - if (context != null) { - context.remove(sessionId); - context = null; - } + public synchronized void invalidate() { + // + // Can't invalidate the NULL session -- this would be + // attempted when we get a handshaking error on a brand + // new connection, with no "real" session yet. + // + if (this == nullSession) { + return; + } - if (invalidated) { - return; - } - invalidated = true; - if (SSLLogger.isOn && SSLLogger.isOn("session")) { - SSLLogger.finest("Invalidated session: " + this); - } - for (SSLSessionImpl child : childSessions) { - child.invalidate(); - } - } finally { - sessionLock.unlock(); + if (context != null) { + context.remove(sessionId); + context = null; + } + if (invalidated) { + return; + } + invalidated = true; + if (SSLLogger.isOn && SSLLogger.isOn("session")) { + SSLLogger.finest("Invalidated session: " + this); + } + for (SSLSessionImpl child : childSessions) { + child.invalidate(); } } @@ -935,13 +912,8 @@ * Expand the buffer size of both SSL/TLS network packet and * application data. */ - protected void expandBufferSizes() { - sessionLock.lock(); - try { - acceptLargeFragments = true; - } finally { - sessionLock.unlock(); - } + protected synchronized void expandBufferSizes() { + acceptLargeFragments = true; } /** @@ -949,35 +921,30 @@ * when using this session. */ @Override - public int getPacketBufferSize() { - sessionLock.lock(); - try { - // Use the bigger packet size calculated from maximumPacketSize - // and negotiatedMaxFragLen. - int packetSize = 0; - if (negotiatedMaxFragLen > 0) { - packetSize = cipherSuite.calculatePacketSize( - negotiatedMaxFragLen, protocolVersion, - protocolVersion.isDTLS); - } + public synchronized int getPacketBufferSize() { + // Use the bigger packet size calculated from maximumPacketSize + // and negotiatedMaxFragLen. + int packetSize = 0; + if (negotiatedMaxFragLen > 0) { + packetSize = cipherSuite.calculatePacketSize( + negotiatedMaxFragLen, protocolVersion, + protocolVersion.isDTLS); + } - if (maximumPacketSize > 0) { - return (maximumPacketSize > packetSize) ? - maximumPacketSize : packetSize; - } + if (maximumPacketSize > 0) { + return (maximumPacketSize > packetSize) ? + maximumPacketSize : packetSize; + } - if (packetSize != 0) { - return packetSize; - } + if (packetSize != 0) { + return packetSize; + } - if (protocolVersion.isDTLS) { - return DTLSRecord.maxRecordSize; - } else { - return acceptLargeFragments ? - SSLRecord.maxLargeRecordSize : SSLRecord.maxRecordSize; - } - } finally { - sessionLock.unlock(); + if (protocolVersion.isDTLS) { + return DTLSRecord.maxRecordSize; + } else { + return acceptLargeFragments ? + SSLRecord.maxLargeRecordSize : SSLRecord.maxRecordSize; } } @@ -986,36 +953,31 @@ * expected when using this session. */ @Override - public int getApplicationBufferSize() { - sessionLock.lock(); - try { - // Use the bigger fragment size calculated from maximumPacketSize - // and negotiatedMaxFragLen. - int fragmentSize = 0; - if (maximumPacketSize > 0) { - fragmentSize = cipherSuite.calculateFragSize( - maximumPacketSize, protocolVersion, - protocolVersion.isDTLS); - } + public synchronized int getApplicationBufferSize() { + // Use the bigger fragment size calculated from maximumPacketSize + // and negotiatedMaxFragLen. + int fragmentSize = 0; + if (maximumPacketSize > 0) { + fragmentSize = cipherSuite.calculateFragSize( + maximumPacketSize, protocolVersion, + protocolVersion.isDTLS); + } - if (negotiatedMaxFragLen > 0) { - return (negotiatedMaxFragLen > fragmentSize) ? - negotiatedMaxFragLen : fragmentSize; - } + if (negotiatedMaxFragLen > 0) { + return (negotiatedMaxFragLen > fragmentSize) ? + negotiatedMaxFragLen : fragmentSize; + } - if (fragmentSize != 0) { - return fragmentSize; - } + if (fragmentSize != 0) { + return fragmentSize; + } - if (protocolVersion.isDTLS) { - return Record.maxDataSize; - } else { - int maxPacketSize = acceptLargeFragments ? - SSLRecord.maxLargeRecordSize : SSLRecord.maxRecordSize; - return (maxPacketSize - SSLRecord.headerSize); - } - } finally { - sessionLock.unlock(); + if (protocolVersion.isDTLS) { + return Record.maxDataSize; + } else { + int maxPacketSize = acceptLargeFragments ? + SSLRecord.maxLargeRecordSize : SSLRecord.maxRecordSize; + return (maxPacketSize - SSLRecord.headerSize); } } @@ -1027,14 +989,10 @@ * the negotiated maximum fragment length, or {@code -1} if * no such length has been negotiated. */ - void setNegotiatedMaxFragSize( + synchronized void setNegotiatedMaxFragSize( int negotiatedMaxFragLen) { - sessionLock.lock(); - try { - this.negotiatedMaxFragLen = negotiatedMaxFragLen; - } finally { - sessionLock.unlock(); - } + + this.negotiatedMaxFragLen = negotiatedMaxFragLen; } /** @@ -1044,31 +1002,16 @@ * @return the negotiated maximum fragment length, or {@code -1} if * no such length has been negotiated. */ - int getNegotiatedMaxFragSize() { - sessionLock.lock(); - try { - return negotiatedMaxFragLen; - } finally { - sessionLock.unlock(); - } + synchronized int getNegotiatedMaxFragSize() { + return negotiatedMaxFragLen; } - void setMaximumPacketSize(int maximumPacketSize) { - sessionLock.lock(); - try { - this.maximumPacketSize = maximumPacketSize; - } finally { - sessionLock.unlock(); - } + synchronized void setMaximumPacketSize(int maximumPacketSize) { + this.maximumPacketSize = maximumPacketSize; } - int getMaximumPacketSize() { - sessionLock.lock(); - try { - return maximumPacketSize; - } finally { - sessionLock.unlock(); - } + synchronized int getMaximumPacketSize() { + return maximumPacketSize; } /** --- old/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java 2019-05-21 01:01:52.697090582 +0200 +++ new/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java 2019-05-21 01:01:52.545090854 +0200 @@ -38,7 +38,6 @@ import java.net.UnknownHostException; import java.nio.ByteBuffer; import java.util.List; -import java.util.concurrent.locks.ReentrantLock; import java.util.function.BiFunction; import javax.net.ssl.HandshakeCompletedListener; import javax.net.ssl.SSLException; @@ -85,9 +84,6 @@ private boolean isConnected = false; private volatile boolean tlsIsClosed = false; - private final ReentrantLock socketLock = new ReentrantLock(); - private final ReentrantLock handshakeLock = new ReentrantLock(); - /* * Is the local name service trustworthy? * @@ -296,25 +292,14 @@ } @Override - public String[] getEnabledCipherSuites() { - socketLock.lock(); - try { - return CipherSuite.namesOf( - conContext.sslConfig.enabledCipherSuites); - } finally { - socketLock.unlock(); - } + public synchronized String[] getEnabledCipherSuites() { + return CipherSuite.namesOf(conContext.sslConfig.enabledCipherSuites); } @Override - public void setEnabledCipherSuites(String[] suites) { - socketLock.lock(); - try { - conContext.sslConfig.enabledCipherSuites = - CipherSuite.validValuesOf(suites); - } finally { - socketLock.unlock(); - } + public synchronized void setEnabledCipherSuites(String[] suites) { + conContext.sslConfig.enabledCipherSuites = + CipherSuite.validValuesOf(suites); } @Override @@ -324,29 +309,19 @@ } @Override - public String[] getEnabledProtocols() { - socketLock.lock(); - try { - return ProtocolVersion.toStringArray( - conContext.sslConfig.enabledProtocols); - } finally { - socketLock.unlock(); - } + public synchronized String[] getEnabledProtocols() { + return ProtocolVersion.toStringArray( + conContext.sslConfig.enabledProtocols); } @Override - public void setEnabledProtocols(String[] protocols) { + public synchronized void setEnabledProtocols(String[] protocols) { if (protocols == null) { throw new IllegalArgumentException("Protocols cannot be null"); } - socketLock.lock(); - try { - conContext.sslConfig.enabledProtocols = - ProtocolVersion.namesOf(protocols); - } finally { - socketLock.unlock(); - } + conContext.sslConfig.enabledProtocols = + ProtocolVersion.namesOf(protocols); } @Override @@ -366,44 +341,29 @@ } @Override - public SSLSession getHandshakeSession() { - socketLock.lock(); - try { - return conContext.handshakeContext == null ? - null : conContext.handshakeContext.handshakeSession; - } finally { - socketLock.unlock(); - } + public synchronized SSLSession getHandshakeSession() { + return conContext.handshakeContext == null ? + null : conContext.handshakeContext.handshakeSession; } @Override - public void addHandshakeCompletedListener( + public synchronized void addHandshakeCompletedListener( HandshakeCompletedListener listener) { if (listener == null) { throw new IllegalArgumentException("listener is null"); } - socketLock.lock(); - try { - conContext.sslConfig.addHandshakeCompletedListener(listener); - } finally { - socketLock.unlock(); - } + conContext.sslConfig.addHandshakeCompletedListener(listener); } @Override - public void removeHandshakeCompletedListener( + public synchronized void removeHandshakeCompletedListener( HandshakeCompletedListener listener) { if (listener == null) { throw new IllegalArgumentException("listener is null"); } - socketLock.lock(); - try { - conContext.sslConfig.removeHandshakeCompletedListener(listener); - } finally { - socketLock.unlock(); - } + conContext.sslConfig.removeHandshakeCompletedListener(listener); } @Override @@ -417,8 +377,7 @@ throw new SocketException("Socket has been closed or broken"); } - handshakeLock.lock(); - try { + synchronized (conContext) { // handshake lock // double check the context status if (conContext.isBroken || conContext.isInboundClosed() || conContext.isOutboundClosed()) { @@ -441,95 +400,53 @@ } catch (Exception oe) { // including RuntimeException handleException(oe); } - } finally { - handshakeLock.unlock(); } } @Override - public void setUseClientMode(boolean mode) { - socketLock.lock(); - try { - conContext.setUseClientMode(mode); - } finally { - socketLock.unlock(); - } + public synchronized void setUseClientMode(boolean mode) { + conContext.setUseClientMode(mode); } @Override - public boolean getUseClientMode() { - socketLock.lock(); - try { - return conContext.sslConfig.isClientMode; - } finally { - socketLock.unlock(); - } + public synchronized boolean getUseClientMode() { + return conContext.sslConfig.isClientMode; } @Override - public void setNeedClientAuth(boolean need) { - socketLock.lock(); - try { - conContext.sslConfig.clientAuthType = - (need ? ClientAuthType.CLIENT_AUTH_REQUIRED : - ClientAuthType.CLIENT_AUTH_NONE); - } finally { - socketLock.unlock(); - } + public synchronized void setNeedClientAuth(boolean need) { + conContext.sslConfig.clientAuthType = + (need ? ClientAuthType.CLIENT_AUTH_REQUIRED : + ClientAuthType.CLIENT_AUTH_NONE); } @Override - public boolean getNeedClientAuth() { - socketLock.lock(); - try { - return (conContext.sslConfig.clientAuthType == + public synchronized boolean getNeedClientAuth() { + return (conContext.sslConfig.clientAuthType == ClientAuthType.CLIENT_AUTH_REQUIRED); - } finally { - socketLock.unlock(); - } } @Override - public void setWantClientAuth(boolean want) { - socketLock.lock(); - try { - conContext.sslConfig.clientAuthType = - (want ? ClientAuthType.CLIENT_AUTH_REQUESTED : - ClientAuthType.CLIENT_AUTH_NONE); - } finally { - socketLock.unlock(); - } + public synchronized void setWantClientAuth(boolean want) { + conContext.sslConfig.clientAuthType = + (want ? ClientAuthType.CLIENT_AUTH_REQUESTED : + ClientAuthType.CLIENT_AUTH_NONE); } @Override - public boolean getWantClientAuth() { - socketLock.lock(); - try { - return (conContext.sslConfig.clientAuthType == + public synchronized boolean getWantClientAuth() { + return (conContext.sslConfig.clientAuthType == ClientAuthType.CLIENT_AUTH_REQUESTED); - } finally { - socketLock.unlock(); - } } @Override - public void setEnableSessionCreation(boolean flag) { - socketLock.lock(); - try { - conContext.sslConfig.enableSessionCreation = flag; - } finally { - socketLock.unlock(); - } + public synchronized void setEnableSessionCreation(boolean flag) { + conContext.sslConfig.enableSessionCreation = flag; } @Override - public boolean getEnableSessionCreation() { - socketLock.lock(); - try { - return conContext.sslConfig.enableSessionCreation; - } finally { - socketLock.unlock(); - } + public synchronized boolean getEnableSessionCreation() { + return conContext.sslConfig.enableSessionCreation; } @Override @@ -618,9 +535,8 @@ // Need a lock here so that the user_canceled alert and the // close_notify alert can be delivered together. - conContext.outputRecord.recordLock.lock(); try { - try { + synchronized (conContext.outputRecord) { // send a user_canceled alert if needed. if (useUserCanceled) { conContext.warning(Alert.USER_CANCELED); @@ -628,17 +544,15 @@ // send a close_notify alert conContext.warning(Alert.CLOSE_NOTIFY); - } finally { - if (!conContext.isOutboundClosed()) { - conContext.outputRecord.close(); - } - - if ((autoClose || !isLayered()) && !super.isOutputShutdown()) { - super.shutdownOutput(); - } } } finally { - conContext.outputRecord.recordLock.unlock(); + if (!conContext.isOutboundClosed()) { + conContext.outputRecord.close(); + } + + if ((autoClose || !isLayered()) && !super.isOutputShutdown()) { + super.shutdownOutput(); + } } if (!isInputShutdown()) { @@ -767,25 +681,20 @@ } @Override - public InputStream getInputStream() throws IOException { - socketLock.lock(); - try { - if (isClosed()) { - throw new SocketException("Socket is closed"); - } - - if (!isConnected) { - throw new SocketException("Socket is not connected"); - } + public synchronized InputStream getInputStream() throws IOException { + if (isClosed()) { + throw new SocketException("Socket is closed"); + } - if (conContext.isInboundClosed() || isInputShutdown()) { - throw new SocketException("Socket input is already shutdown"); - } + if (!isConnected) { + throw new SocketException("Socket is not connected"); + } - return appInput; - } finally { - socketLock.unlock(); + if (conContext.isInboundClosed() || isInputShutdown()) { + throw new SocketException("Socket input is already shutdown"); } + + return appInput; } private void ensureNegotiated() throws IOException { @@ -794,8 +703,7 @@ return; } - handshakeLock.lock(); - try { + synchronized (conContext) { // handshake lock // double check the context status if (conContext.isNegotiated || conContext.isBroken || conContext.isInboundClosed() || @@ -804,8 +712,6 @@ } startHandshake(); - } finally { - handshakeLock.unlock(); } } @@ -823,9 +729,6 @@ // Is application data available in the stream? private volatile boolean appDataIsAvailable; - // reading lock - private final ReentrantLock readLock = new ReentrantLock(); - AppInputStream() { this.appDataIsAvailable = false; this.buffer = ByteBuffer.allocate(4096); @@ -904,8 +807,7 @@ // // Note that the receiving and processing of post-handshake message // are also synchronized with the read lock. - readLock.lock(); - try { + synchronized (this) { int remains = available(); if (remains > 0) { int howmany = Math.min(remains, len); @@ -937,8 +839,6 @@ // dummy for compiler return -1; } - } finally { - readLock.unlock(); } } @@ -950,24 +850,19 @@ * things simpler. */ @Override - public long skip(long n) throws IOException { + public synchronized long skip(long n) throws IOException { // dummy array used to implement skip() byte[] skipArray = new byte[256]; - long skipped = 0; - readLock.lock(); - try { - while (n > 0) { - int len = (int)Math.min(n, skipArray.length); - int r = read(skipArray, 0, len); - if (r <= 0) { - break; - } - n -= r; - skipped += r; + long skipped = 0; + while (n > 0) { + int len = (int)Math.min(n, skipArray.length); + int r = read(skipArray, 0, len); + if (r <= 0) { + break; } - } finally { - readLock.unlock(); + n -= r; + skipped += r; } return skipped; @@ -980,7 +875,7 @@ } try { - SSLSocketImpl.this.close(); + shutdownInput(false); } catch (IOException ioe) { // ignore the exception if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { @@ -1015,18 +910,8 @@ * Try the best to use up the input records so as to close the * socket gracefully, without impact the performance too much. */ - private void deplete() { - if (conContext.isInboundClosed()) { - return; - } - - readLock.lock(); - try { - // double check - if (conContext.isInboundClosed()) { - return; - } - + private synchronized void deplete() { + if (!conContext.isInboundClosed()) { if (!(conContext.inputRecord instanceof SSLSocketInputRecord)) { return; } @@ -1042,32 +927,25 @@ "input stream close depletion failed", ioe); } } - } finally { - readLock.unlock(); } } } @Override - public OutputStream getOutputStream() throws IOException { - socketLock.lock(); - try { - if (isClosed()) { - throw new SocketException("Socket is closed"); - } - - if (!isConnected) { - throw new SocketException("Socket is not connected"); - } + public synchronized OutputStream getOutputStream() throws IOException { + if (isClosed()) { + throw new SocketException("Socket is closed"); + } - if (conContext.isOutboundDone() || isOutputShutdown()) { - throw new SocketException("Socket output is already shutdown"); - } + if (!isConnected) { + throw new SocketException("Socket is not connected"); + } - return appOutput; - } finally { - socketLock.unlock(); + if (conContext.isOutboundDone() || isOutputShutdown()) { + throw new SocketException("Socket output is already shutdown"); } + + return appOutput; } @@ -1146,7 +1024,7 @@ } try { - SSLSocketImpl.this.close(); + shutdownOutput(); } catch (IOException ioe) { // ignore the exception if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { @@ -1157,74 +1035,44 @@ } @Override - public SSLParameters getSSLParameters() { - socketLock.lock(); - try { - return conContext.sslConfig.getSSLParameters(); - } finally { - socketLock.unlock(); - } + public synchronized SSLParameters getSSLParameters() { + return conContext.sslConfig.getSSLParameters(); } @Override - public void setSSLParameters(SSLParameters params) { - socketLock.lock(); - try { - conContext.sslConfig.setSSLParameters(params); + public synchronized void setSSLParameters(SSLParameters params) { + conContext.sslConfig.setSSLParameters(params); - if (conContext.sslConfig.maximumPacketSize != 0) { - conContext.outputRecord.changePacketSize( - conContext.sslConfig.maximumPacketSize); - } - } finally { - socketLock.unlock(); + if (conContext.sslConfig.maximumPacketSize != 0) { + conContext.outputRecord.changePacketSize( + conContext.sslConfig.maximumPacketSize); } } @Override - public String getApplicationProtocol() { - socketLock.lock(); - try { - return conContext.applicationProtocol; - } finally { - socketLock.unlock(); - } + public synchronized String getApplicationProtocol() { + return conContext.applicationProtocol; } @Override - public String getHandshakeApplicationProtocol() { - socketLock.lock(); - try { - if (conContext.handshakeContext != null) { - return conContext.handshakeContext.applicationProtocol; - } - } finally { - socketLock.unlock(); + public synchronized String getHandshakeApplicationProtocol() { + if (conContext.handshakeContext != null) { + return conContext.handshakeContext.applicationProtocol; } return null; } @Override - public void setHandshakeApplicationProtocolSelector( + public synchronized void setHandshakeApplicationProtocolSelector( BiFunction, String> selector) { - socketLock.lock(); - try { - conContext.sslConfig.socketAPSelector = selector; - } finally { - socketLock.unlock(); - } + conContext.sslConfig.socketAPSelector = selector; } @Override - public BiFunction, String> + public synchronized BiFunction, String> getHandshakeApplicationProtocolSelector() { - socketLock.lock(); - try { - return conContext.sslConfig.socketAPSelector; - } finally { - socketLock.unlock(); - } + return conContext.sslConfig.socketAPSelector; } /** @@ -1294,11 +1142,8 @@ try { Plaintext plainText; - socketLock.lock(); - try { + synchronized (this) { plainText = decode(buffer); - } finally { - socketLock.unlock(); } if (plainText.contentType == ContentType.APPLICATION_DATA.id && buffer.position() > 0) { @@ -1377,33 +1222,27 @@ * * Called by connect, the layered constructor, and SSLServerSocket. */ - void doneConnect() throws IOException { - socketLock.lock(); - try { - // In server mode, it is not necessary to set host and serverNames. - // Otherwise, would require a reverse DNS lookup to get - // the hostname. - if (peerHost == null || peerHost.isEmpty()) { - boolean useNameService = - trustNameService && conContext.sslConfig.isClientMode; - useImplicitHost(useNameService); - } else { - conContext.sslConfig.serverNames = - Utilities.addToSNIServerNameList( - conContext.sslConfig.serverNames, peerHost); - } + synchronized void doneConnect() throws IOException { + // In server mode, it is not necessary to set host and serverNames. + // Otherwise, would require a reverse DNS lookup to get the hostname. + if (peerHost == null || peerHost.isEmpty()) { + boolean useNameService = + trustNameService && conContext.sslConfig.isClientMode; + useImplicitHost(useNameService); + } else { + conContext.sslConfig.serverNames = + Utilities.addToSNIServerNameList( + conContext.sslConfig.serverNames, peerHost); + } - InputStream sockInput = super.getInputStream(); - conContext.inputRecord.setReceiverStream(sockInput); + InputStream sockInput = super.getInputStream(); + conContext.inputRecord.setReceiverStream(sockInput); - OutputStream sockOutput = super.getOutputStream(); - conContext.inputRecord.setDeliverStream(sockOutput); - conContext.outputRecord.setDeliverStream(sockOutput); + OutputStream sockOutput = super.getOutputStream(); + conContext.inputRecord.setDeliverStream(sockOutput); + conContext.outputRecord.setDeliverStream(sockOutput); - this.isConnected = true; - } finally { - socketLock.unlock(); - } + this.isConnected = true; } private void useImplicitHost(boolean useNameService) { @@ -1449,16 +1288,11 @@ // Please NOTE that this method MUST be called before calling to // SSLSocket.setSSLParameters(). Otherwise, the {@code host} parameter // may override SNIHostName in the customized server name indication. - public void setHost(String host) { - socketLock.lock(); - try { - this.peerHost = host; - this.conContext.sslConfig.serverNames = - Utilities.addToSNIServerNameList( - conContext.sslConfig.serverNames, host); - } finally { - socketLock.unlock(); - } + public synchronized void setHost(String host) { + this.peerHost = host; + this.conContext.sslConfig.serverNames = + Utilities.addToSNIServerNameList( + conContext.sslConfig.serverNames, host); } /** --- old/src/java.base/share/classes/sun/security/ssl/SSLSocketOutputRecord.java 2019-05-21 01:01:52.925090174 +0200 +++ new/src/java.base/share/classes/sun/security/ssl/SSLSocketOutputRecord.java 2019-05-21 01:01:52.769090454 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -51,206 +51,123 @@ } @Override - void encodeAlert(byte level, byte description) throws IOException { - recordLock.lock(); - try { - if (isClosed()) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { - SSLLogger.warning("outbound has closed, ignore outbound " + - "alert message: " + Alert.nameOf(description)); - } - return; - } - - // use the buf of ByteArrayOutputStream - int position = headerSize + writeCipher.getExplicitNonceSize(); - count = position; - - write(level); - write(description); - if (SSLLogger.isOn && SSLLogger.isOn("record")) { - SSLLogger.fine("WRITE: " + protocolVersion + - " " + ContentType.ALERT.name + - "(" + Alert.nameOf(description) + ")" + - ", length = " + (count - headerSize)); + synchronized void encodeAlert( + byte level, byte description) throws IOException { + if (isClosed()) { + if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + SSLLogger.warning("outbound has closed, ignore outbound " + + "alert message: " + Alert.nameOf(description)); } + return; + } - // Encrypt the fragment and wrap up a record. - encrypt(writeCipher, ContentType.ALERT.id, headerSize); - - // deliver this message - deliverStream.write(buf, 0, count); // may throw IOException - deliverStream.flush(); // may throw IOException + // use the buf of ByteArrayOutputStream + int position = headerSize + writeCipher.getExplicitNonceSize(); + count = position; + + write(level); + write(description); + if (SSLLogger.isOn && SSLLogger.isOn("record")) { + SSLLogger.fine("WRITE: " + protocolVersion + + " " + ContentType.ALERT.name + + "(" + Alert.nameOf(description) + ")" + + ", length = " + (count - headerSize)); + } - if (SSLLogger.isOn && SSLLogger.isOn("packet")) { - SSLLogger.fine("Raw write", - (new ByteArrayInputStream(buf, 0, count))); - } + // Encrypt the fragment and wrap up a record. + encrypt(writeCipher, ContentType.ALERT.id, headerSize); - // reset the internal buffer - count = 0; - } finally { - recordLock.unlock(); + // deliver this message + deliverStream.write(buf, 0, count); // may throw IOException + deliverStream.flush(); // may throw IOException + + if (SSLLogger.isOn && SSLLogger.isOn("packet")) { + SSLLogger.fine("Raw write", + (new ByteArrayInputStream(buf, 0, count))); } + + // reset the internal buffer + count = 0; } @Override - void encodeHandshake(byte[] source, + synchronized void encodeHandshake(byte[] source, int offset, int length) throws IOException { - recordLock.lock(); - try { - if (isClosed()) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { - SSLLogger.warning("outbound has closed, ignore outbound " + - "handshake message", - ByteBuffer.wrap(source, offset, length)); - } - return; + if (isClosed()) { + if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + SSLLogger.warning("outbound has closed, ignore outbound " + + "handshake message", + ByteBuffer.wrap(source, offset, length)); } + return; + } - if (firstMessage) { - firstMessage = false; + if (firstMessage) { + firstMessage = false; - if ((helloVersion == ProtocolVersion.SSL20Hello) && - (source[offset] == SSLHandshake.CLIENT_HELLO.id) && + if ((helloVersion == ProtocolVersion.SSL20Hello) && + (source[offset] == SSLHandshake.CLIENT_HELLO.id) && // 5: recode header size - (source[offset + 4 + 2 + 32] == 0)) { + (source[offset + 4 + 2 + 32] == 0)) { // V3 session ID is empty // 4: handshake header size // 2: client_version in ClientHello // 32: random in ClientHello - ByteBuffer v2ClientHello = encodeV2ClientHello( - source, (offset + 4), (length - 4)); - - // array offset is zero - byte[] record = v2ClientHello.array(); - int limit = v2ClientHello.limit(); - handshakeHash.deliver(record, 2, (limit - 2)); - - if (SSLLogger.isOn && SSLLogger.isOn("record")) { - SSLLogger.fine( - "WRITE: SSLv2 ClientHello message" + - ", length = " + limit); - } - - // deliver this message - // - // Version 2 ClientHello message should be plaintext. - // - // No max fragment length negotiation. - deliverStream.write(record, 0, limit); - deliverStream.flush(); - - if (SSLLogger.isOn && SSLLogger.isOn("packet")) { - SSLLogger.fine("Raw write", - (new ByteArrayInputStream(record, 0, limit))); - } - - return; - } - } - - byte handshakeType = source[0]; - if (handshakeHash.isHashable(handshakeType)) { - handshakeHash.deliver(source, offset, length); - } - - int fragLimit = getFragLimit(); - int position = headerSize + writeCipher.getExplicitNonceSize(); - if (count == 0) { - count = position; - } - - if ((count - position) < (fragLimit - length)) { - write(source, offset, length); - return; - } - - for (int limit = (offset + length); offset < limit;) { - - int remains = (limit - offset) + (count - position); - int fragLen = Math.min(fragLimit, remains); + ByteBuffer v2ClientHello = encodeV2ClientHello( + source, (offset + 4), (length - 4)); - // use the buf of ByteArrayOutputStream - write(source, offset, fragLen); - if (remains < fragLimit) { - return; - } + byte[] record = v2ClientHello.array(); // array offset is zero + int limit = v2ClientHello.limit(); + handshakeHash.deliver(record, 2, (limit - 2)); if (SSLLogger.isOn && SSLLogger.isOn("record")) { SSLLogger.fine( - "WRITE: " + protocolVersion + - " " + ContentType.HANDSHAKE.name + - ", length = " + (count - headerSize)); + "WRITE: SSLv2 ClientHello message" + + ", length = " + limit); } - // Encrypt the fragment and wrap up a record. - encrypt(writeCipher, ContentType.HANDSHAKE.id, headerSize); - // deliver this message - deliverStream.write(buf, 0, count); // may throw IOException - deliverStream.flush(); // may throw IOException + // + // Version 2 ClientHello message should be plaintext. + // + // No max fragment length negotiation. + deliverStream.write(record, 0, limit); + deliverStream.flush(); if (SSLLogger.isOn && SSLLogger.isOn("packet")) { SSLLogger.fine("Raw write", - (new ByteArrayInputStream(buf, 0, count))); + (new ByteArrayInputStream(record, 0, limit))); } - // reset the offset - offset += fragLen; - - // reset the internal buffer - count = position; + return; } - } finally { - recordLock.unlock(); } - } - @Override - void encodeChangeCipherSpec() throws IOException { - recordLock.lock(); - try { - if (isClosed()) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { - SSLLogger.warning("outbound has closed, ignore outbound " + - "change_cipher_spec message"); - } - return; - } + byte handshakeType = source[0]; + if (handshakeHash.isHashable(handshakeType)) { + handshakeHash.deliver(source, offset, length); + } - // use the buf of ByteArrayOutputStream - int position = headerSize + writeCipher.getExplicitNonceSize(); + int fragLimit = getFragLimit(); + int position = headerSize + writeCipher.getExplicitNonceSize(); + if (count == 0) { count = position; + } - write((byte)1); // byte 1: change_cipher_spec( - - // Encrypt the fragment and wrap up a record. - encrypt(writeCipher, ContentType.CHANGE_CIPHER_SPEC.id, headerSize); - - // deliver this message - deliverStream.write(buf, 0, count); // may throw IOException - // deliverStream.flush(); // flush in Finished + if ((count - position) < (fragLimit - length)) { + write(source, offset, length); + return; + } - if (SSLLogger.isOn && SSLLogger.isOn("packet")) { - SSLLogger.fine("Raw write", - (new ByteArrayInputStream(buf, 0, count))); - } + for (int limit = (offset + length); offset < limit;) { - // reset the internal buffer - count = 0; - } finally { - recordLock.unlock(); - } - } + int remains = (limit - offset) + (count - position); + int fragLen = Math.min(fragLimit, remains); - @Override - public void flush() throws IOException { - recordLock.lock(); - try { - int position = headerSize + writeCipher.getExplicitNonceSize(); - if (count <= position) { + // use the buf of ByteArrayOutputStream + write(source, offset, fragLen); + if (remains < fragLimit) { return; } @@ -273,103 +190,155 @@ (new ByteArrayInputStream(buf, 0, count))); } + // reset the offset + offset += fragLen; + // reset the internal buffer - count = 0; // DON'T use position - } finally { - recordLock.unlock(); + count = position; } } @Override - void deliver(byte[] source, int offset, int length) throws IOException { - recordLock.lock(); - try { - if (isClosed()) { - throw new SocketException( - "Connection or outbound has been closed"); + synchronized void encodeChangeCipherSpec() throws IOException { + if (isClosed()) { + if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + SSLLogger.warning("outbound has closed, ignore outbound " + + "change_cipher_spec message"); } + return; + } - if (writeCipher.authenticator.seqNumOverflow()) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { - SSLLogger.fine( - "sequence number extremely close to overflow " + - "(2^64-1 packets). Closing connection."); - } + // use the buf of ByteArrayOutputStream + int position = headerSize + writeCipher.getExplicitNonceSize(); + count = position; + + write((byte)1); // byte 1: change_cipher_spec( + + // Encrypt the fragment and wrap up a record. + encrypt(writeCipher, ContentType.CHANGE_CIPHER_SPEC.id, headerSize); + + // deliver this message + deliverStream.write(buf, 0, count); // may throw IOException + // deliverStream.flush(); // flush in Finished + + if (SSLLogger.isOn && SSLLogger.isOn("packet")) { + SSLLogger.fine("Raw write", + (new ByteArrayInputStream(buf, 0, count))); + } - throw new SSLHandshakeException("sequence number overflow"); - } + // reset the internal buffer + count = 0; + } - boolean isFirstRecordOfThePayload = true; - for (int limit = (offset + length); offset < limit;) { - int fragLen; - if (packetSize > 0) { - fragLen = Math.min(maxRecordSize, packetSize); - fragLen = writeCipher.calculateFragmentSize( - fragLen, headerSize); - - fragLen = Math.min(fragLen, Record.maxDataSize); - } else { - fragLen = Record.maxDataSize; - } + @Override + public synchronized void flush() throws IOException { + int position = headerSize + writeCipher.getExplicitNonceSize(); + if (count <= position) { + return; + } - if (fragmentSize > 0) { - fragLen = Math.min(fragLen, fragmentSize); - } + if (SSLLogger.isOn && SSLLogger.isOn("record")) { + SSLLogger.fine( + "WRITE: " + protocolVersion + + " " + ContentType.HANDSHAKE.name + + ", length = " + (count - headerSize)); + } - if (isFirstRecordOfThePayload && needToSplitPayload()) { - fragLen = 1; - isFirstRecordOfThePayload = false; - } else { - fragLen = Math.min(fragLen, (limit - offset)); - } + // Encrypt the fragment and wrap up a record. + encrypt(writeCipher, ContentType.HANDSHAKE.id, headerSize); - // use the buf of ByteArrayOutputStream - int position = headerSize + writeCipher.getExplicitNonceSize(); - count = position; - write(source, offset, fragLen); + // deliver this message + deliverStream.write(buf, 0, count); // may throw IOException + deliverStream.flush(); // may throw IOException + + if (SSLLogger.isOn && SSLLogger.isOn("packet")) { + SSLLogger.fine("Raw write", + (new ByteArrayInputStream(buf, 0, count))); + } - if (SSLLogger.isOn && SSLLogger.isOn("record")) { - SSLLogger.fine( - "WRITE: " + protocolVersion + - " " + ContentType.APPLICATION_DATA.name + - ", length = " + (count - position)); - } + // reset the internal buffer + count = 0; // DON'T use position + } - // Encrypt the fragment and wrap up a record. - encrypt(writeCipher, - ContentType.APPLICATION_DATA.id, headerSize); + @Override + synchronized void deliver( + byte[] source, int offset, int length) throws IOException { + if (isClosed()) { + throw new SocketException("Connection or outbound has been closed"); + } - // deliver this message - deliverStream.write(buf, 0, count); // may throw IOException - deliverStream.flush(); // may throw IOException + if (writeCipher.authenticator.seqNumOverflow()) { + if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { + SSLLogger.fine( + "sequence number extremely close to overflow " + + "(2^64-1 packets). Closing connection."); + } - if (SSLLogger.isOn && SSLLogger.isOn("packet")) { - SSLLogger.fine("Raw write", - (new ByteArrayInputStream(buf, 0, count))); - } + throw new SSLHandshakeException("sequence number overflow"); + } - // reset the internal buffer - count = 0; + boolean isFirstRecordOfThePayload = true; + for (int limit = (offset + length); offset < limit;) { + int fragLen; + if (packetSize > 0) { + fragLen = Math.min(maxRecordSize, packetSize); + fragLen = + writeCipher.calculateFragmentSize(fragLen, headerSize); + + fragLen = Math.min(fragLen, Record.maxDataSize); + } else { + fragLen = Record.maxDataSize; + } + + if (fragmentSize > 0) { + fragLen = Math.min(fragLen, fragmentSize); + } + + if (isFirstRecordOfThePayload && needToSplitPayload()) { + fragLen = 1; + isFirstRecordOfThePayload = false; + } else { + fragLen = Math.min(fragLen, (limit - offset)); + } - if (isFirstAppOutputRecord) { - isFirstAppOutputRecord = false; - } + // use the buf of ByteArrayOutputStream + int position = headerSize + writeCipher.getExplicitNonceSize(); + count = position; + write(source, offset, fragLen); - offset += fragLen; + if (SSLLogger.isOn && SSLLogger.isOn("record")) { + SSLLogger.fine( + "WRITE: " + protocolVersion + + " " + ContentType.APPLICATION_DATA.name + + ", length = " + (count - position)); } - } finally { - recordLock.unlock(); + + // Encrypt the fragment and wrap up a record. + encrypt(writeCipher, ContentType.APPLICATION_DATA.id, headerSize); + + // deliver this message + deliverStream.write(buf, 0, count); // may throw IOException + deliverStream.flush(); // may throw IOException + + if (SSLLogger.isOn && SSLLogger.isOn("packet")) { + SSLLogger.fine("Raw write", + (new ByteArrayInputStream(buf, 0, count))); + } + + // reset the internal buffer + count = 0; + + if (isFirstAppOutputRecord) { + isFirstAppOutputRecord = false; + } + + offset += fragLen; } } @Override - void setDeliverStream(OutputStream outputStream) { - recordLock.lock(); - try { - this.deliverStream = outputStream; - } finally { - recordLock.unlock(); - } + synchronized void setDeliverStream(OutputStream outputStream) { + this.deliverStream = outputStream; } /* --- old/src/java.base/share/classes/sun/security/ssl/SignatureScheme.java 2019-05-21 01:01:53.145089779 +0200 +++ new/src/java.base/share/classes/sun/security/ssl/SignatureScheme.java 2019-05-21 01:01:52.997090044 +0200 @@ -43,7 +43,6 @@ import sun.security.ssl.SupportedGroupsExtension.NamedGroupType; import sun.security.ssl.X509Authentication.X509Possession; import sun.security.util.KeyUtil; -import sun.security.util.SignatureUtil; enum SignatureScheme { // EdDSA algorithms @@ -472,11 +471,16 @@ Signature signer = Signature.getInstance(algorithm); if (key instanceof PublicKey) { - SignatureUtil.initVerifyWithParam(signer, (PublicKey)key, - signAlgParameter); + signer.initVerify((PublicKey)(key)); } else { - SignatureUtil.initSignWithParam(signer, (PrivateKey)key, - signAlgParameter, null); + signer.initSign((PrivateKey)key); + } + + // Important note: Please don't set the parameters before signature + // or verification initialization, so that the crypto provider can + // be selected properly. + if (signAlgParameter != null) { + signer.setParameter(signAlgParameter); } return signer; --- old/src/java.base/share/classes/sun/security/ssl/SunX509KeyManagerImpl.java 2019-05-21 01:01:53.345089420 +0200 +++ new/src/java.base/share/classes/sun/security/ssl/SunX509KeyManagerImpl.java 2019-05-21 01:01:53.189089700 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -102,21 +102,25 @@ * Basic container for credentials implemented as an inner class. */ private static class X509Credentials { - final PrivateKey privateKey; - final X509Certificate[] certificates; - private final Set issuerX500Principals; + PrivateKey privateKey; + X509Certificate[] certificates; + private Set issuerX500Principals; X509Credentials(PrivateKey privateKey, X509Certificate[] certificates) { // assert privateKey and certificates != null this.privateKey = privateKey; this.certificates = certificates; - this.issuerX500Principals = new HashSet<>(certificates.length); - for (X509Certificate certificate : certificates) { - issuerX500Principals.add(certificate.getIssuerX500Principal()); - } } - Set getIssuerX500Principals() { + synchronized Set getIssuerX500Principals() { + // lazy initialization + if (issuerX500Principals == null) { + issuerX500Principals = new HashSet(); + for (int i = 0; i < certificates.length; i++) { + issuerX500Principals.add( + certificates[i].getIssuerX500Principal()); + } + } return issuerX500Principals; } } --- old/src/java.base/share/classes/sun/security/ssl/TransportContext.java 2019-05-21 01:01:53.549089055 +0200 +++ new/src/java.base/share/classes/sun/security/ssl/TransportContext.java 2019-05-21 01:01:53.393089335 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -496,16 +496,13 @@ } if (needCloseNotify) { - outputRecord.recordLock.lock(); - try { + synchronized (outputRecord) { try { // send a close_notify alert warning(Alert.CLOSE_NOTIFY); } finally { outputRecord.close(); } - } finally { - outputRecord.recordLock.unlock(); } } } @@ -544,8 +541,7 @@ // Need a lock here so that the user_canceled alert and the // close_notify alert can be delivered together. - outputRecord.recordLock.lock(); - try { + synchronized (outputRecord) { try { // send a user_canceled alert if needed. if (useUserCanceled) { @@ -557,8 +553,6 @@ } finally { outputRecord.close(); } - } finally { - outputRecord.recordLock.unlock(); } } --- old/src/java.base/share/classes/sun/security/ssl/TrustStoreManager.java 2019-05-21 01:01:53.745088703 +0200 +++ new/src/java.base/share/classes/sun/security/ssl/TrustStoreManager.java 2019-05-21 01:01:53.593088976 +0200 @@ -30,7 +30,6 @@ import java.security.*; import java.security.cert.*; import java.util.*; -import java.util.concurrent.locks.ReentrantLock; import sun.security.action.*; import sun.security.validator.TrustStoreUtil; @@ -245,8 +244,6 @@ // objects can be atomically cleared, and reloaded if needed. private WeakReference> csRef; - private final ReentrantLock tamLock = new ReentrantLock(); - private TrustAnchorManager() { this.descriptor = null; this.ksRef = new WeakReference<>(null); @@ -258,7 +255,7 @@ * * @return null if the underlying KeyStore is not available. */ - KeyStore getKeyStore( + synchronized KeyStore getKeyStore( TrustStoreDescriptor descriptor) throws Exception { TrustStoreDescriptor temporaryDesc = this.descriptor; @@ -267,26 +264,15 @@ return ks; } - tamLock.lock(); - try { - // double check - ks = ksRef.get(); - if ((ks != null) && descriptor.equals(temporaryDesc)) { - return ks; - } - - // Reload a new key store. - if (SSLLogger.isOn && SSLLogger.isOn("trustmanager")) { - SSLLogger.fine("Reload the trust store"); - } - - ks = loadKeyStore(descriptor); - this.descriptor = descriptor; - this.ksRef = new WeakReference<>(ks); - } finally { - tamLock.unlock(); + // Reload a new key store. + if (SSLLogger.isOn && SSLLogger.isOn("trustmanager")) { + SSLLogger.fine("Reload the trust store"); } + ks = loadKeyStore(descriptor); + this.descriptor = descriptor; + this.ksRef = new WeakReference<>(ks); + return ks; } @@ -296,62 +282,51 @@ * * @return empty collection if the underlying KeyStore is not available. */ - Set getTrustedCerts( + synchronized Set getTrustedCerts( TrustStoreDescriptor descriptor) throws Exception { KeyStore ks = null; TrustStoreDescriptor temporaryDesc = this.descriptor; Set certs = csRef.get(); - if ((certs != null) && descriptor.equals(temporaryDesc)) { - return certs; - } - - tamLock.lock(); - try { - // double check - temporaryDesc = this.descriptor; - certs = csRef.get(); - if (certs != null) { - if (descriptor.equals(temporaryDesc)) { - return certs; - } else { - // Use the new descriptor. - this.descriptor = descriptor; - } + if (certs != null) { + if (descriptor.equals(temporaryDesc)) { + return certs; } else { - // Try to use the cached store at first. - if (descriptor.equals(temporaryDesc)) { - ks = ksRef.get(); - } else { - // Use the new descriptor. - this.descriptor = descriptor; - } + // Use the new descriptor. + this.descriptor = descriptor; } - - // Reload the trust store if needed. - if (ks == null) { - if (SSLLogger.isOn && SSLLogger.isOn("trustmanager")) { - SSLLogger.fine("Reload the trust store"); - } - ks = loadKeyStore(descriptor); - this.ksRef = new WeakReference<>(ks); + } else { + // Try to use the cached store at first. + if (descriptor.equals(temporaryDesc)) { + ks = ksRef.get(); + } else { + // Use the new descriptor. + this.descriptor = descriptor; } + } - // Reload trust certs from the key store. + // Reload the trust store if needed. + if (ks == null) { if (SSLLogger.isOn && SSLLogger.isOn("trustmanager")) { - SSLLogger.fine("Reload trust certs"); + SSLLogger.fine("Reload the trust store"); } + ks = loadKeyStore(descriptor); + } - certs = loadTrustedCerts(ks); - if (SSLLogger.isOn && SSLLogger.isOn("trustmanager")) { - SSLLogger.fine("Reloaded " + certs.size() + " trust certs"); - } + // Reload trust certs from the key store. + if (SSLLogger.isOn && SSLLogger.isOn("trustmanager")) { + SSLLogger.fine("Reload trust certs"); + } - this.csRef = new WeakReference<>(certs); - } finally { - tamLock.unlock(); + certs = loadTrustedCerts(ks); + if (SSLLogger.isOn && SSLLogger.isOn("trustmanager")) { + SSLLogger.fine("Reloaded " + certs.size() + " trust certs"); } + // Note that as ks is a local variable, it is not + // necessary to add it to the ksRef weak reference. + this.csRef = new WeakReference<>(certs); + return certs; } --- old/src/java.base/share/classes/sun/security/ssl/X509TrustManagerImpl.java 2019-05-21 01:01:53.957088324 +0200 +++ new/src/java.base/share/classes/sun/security/ssl/X509TrustManagerImpl.java 2019-05-21 01:01:53.789088624 +0200 @@ -29,7 +29,6 @@ import java.security.*; import java.security.cert.*; import java.util.*; -import java.util.concurrent.locks.ReentrantLock; import javax.net.ssl.*; import sun.security.util.AnchorCertificates; import sun.security.util.HostnameChecker; @@ -64,8 +63,6 @@ // the different extension checks. They are initialized lazily on demand. private volatile Validator clientValidator, serverValidator; - private final ReentrantLock validatorLock = new ReentrantLock(); - X509TrustManagerImpl(String validatorType, Collection trustedCerts) { @@ -160,15 +157,12 @@ if (isClient) { v = clientValidator; if (v == null) { - validatorLock.lock(); - try { + synchronized (this) { v = clientValidator; if (v == null) { v = getValidator(Validator.VAR_TLS_CLIENT); clientValidator = v; } - } finally { - validatorLock.unlock(); } } } else { @@ -176,15 +170,12 @@ // (guaranteed under the new Tiger memory model) v = serverValidator; if (v == null) { - validatorLock.lock(); - try { + synchronized (this) { v = serverValidator; if (v == null) { v = getValidator(Validator.VAR_TLS_SERVER); serverValidator = v; } - } finally { - validatorLock.unlock(); } } } --- old/src/java.base/share/classes/sun/security/tools/keytool/Main.java 2019-05-21 01:01:54.161087957 +0200 +++ new/src/java.base/share/classes/sun/security/tools/keytool/Main.java 2019-05-21 01:01:54.005088237 +0200 @@ -84,7 +84,6 @@ import sun.security.util.Password; import sun.security.util.SecurityProperties; import sun.security.util.SecurityProviderConstants; -import sun.security.util.SignatureUtil; import javax.crypto.KeyGenerator; import javax.crypto.SecretKey; import javax.crypto.SecretKeyFactory; @@ -1442,12 +1441,11 @@ sigAlgName = getCompatibleSigAlgName(privateKey); } Signature signature = Signature.getInstance(sigAlgName); - AlgorithmParameterSpec params = AlgorithmId - .getDefaultAlgorithmParameterSpec(sigAlgName, privateKey); - - SignatureUtil.initSignWithParam(signature, privateKey, params, null); + signature.initSign(privateKey); X509CertInfo info = new X509CertInfo(); + AlgorithmParameterSpec params = AlgorithmId + .getDefaultAlgorithmParameterSpec(sigAlgName, privateKey); AlgorithmId algID = AlgorithmId.getWithParameterSpec(sigAlgName, params); info.set(X509CertInfo.VALIDITY, interval); info.set(X509CertInfo.SERIAL_NUMBER, @@ -1601,9 +1599,12 @@ } Signature signature = Signature.getInstance(sigAlgName); + signature.initSign(privKey); AlgorithmParameterSpec params = AlgorithmId .getDefaultAlgorithmParameterSpec(sigAlgName, privKey); - SignatureUtil.initSignWithParam(signature, privKey, params, null); + if (params != null) { + signature.setParameter(params); + } X500Name subject = dname == null? new X500Name(((X509Certificate)cert).getSubjectDN().toString()): --- old/src/java.base/share/classes/sun/security/util/SignatureUtil.java 2019-05-21 01:01:54.389087549 +0200 +++ new/src/java.base/share/classes/sun/security/util/SignatureUtil.java 2019-05-21 01:01:54.237087822 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,7 +29,6 @@ import java.security.*; import java.security.spec.*; import sun.security.rsa.RSAUtil; -import jdk.internal.access.SharedSecrets; /** * Utility class for Signature related operations. Currently used by various @@ -40,25 +39,12 @@ */ public class SignatureUtil { - private static String checkName(String algName) throws ProviderException { - if (algName.indexOf(".") == -1) { - return algName; - } - // convert oid to String - try { - return Signature.getInstance(algName).getAlgorithm(); - } catch (Exception e) { - throw new ProviderException("Error mapping algorithm name", e); - } - } - // Utility method of creating an AlgorithmParameters object with // the specified algorithm name and encoding private static AlgorithmParameters createAlgorithmParameters(String algName, byte[] paramBytes) throws ProviderException { try { - algName = checkName(algName); AlgorithmParameters result = AlgorithmParameters.getInstance(algName); result.init(paramBytes); @@ -68,81 +54,52 @@ } } - // Utility method for converting the specified AlgorithmParameters object - // into an AlgorithmParameterSpec object. - public static AlgorithmParameterSpec getParamSpec(String sigName, + private static AlgorithmParameterSpec getParamSpec(String sigName, AlgorithmParameters params) - throws ProviderException { + throws InvalidAlgorithmParameterException, ProviderException { - sigName = checkName(sigName); - AlgorithmParameterSpec paramSpec = null; - if (params != null) { - if (sigName.toUpperCase().indexOf("RSA") == -1) { - throw new ProviderException - ("Unrecognized algorithm for signature parameters " + - sigName); - } - // AlgorithmParameters.getAlgorithm() may returns oid if it's - // created during DER decoding. Convert to use the standard name - // before passing it to RSAUtil - if (params.getAlgorithm().indexOf(".") != -1) { - try { - params = createAlgorithmParameters(sigName, - params.getEncoded()); - } catch (IOException e) { - throw new ProviderException(e); - } + if (params == null) return null; + + if (sigName.toUpperCase().indexOf("RSA") == -1) { + throw new ProviderException + ("Unrecognized algorithm for signature parameters " + + sigName); + } + // AlgorithmParameters.getAlgorithm() may returns oid if it's + // created during DER decoding. Convert to use the standard name + // before passing it to RSAUtil + String alg = params.getAlgorithm(); + if (alg.equalsIgnoreCase(sigName) || alg.indexOf(".") != -1) { + try { + params = createAlgorithmParameters(sigName, + params.getEncoded()); + } catch (IOException e) { + throw new ProviderException(e); } - paramSpec = RSAUtil.getParamSpec(params); } - return paramSpec; + return RSAUtil.getParamSpec(params); } - // Utility method for converting the specified parameter bytes into an - // AlgorithmParameterSpec object. - public static AlgorithmParameterSpec getParamSpec(String sigName, - byte[] paramBytes) - throws ProviderException { - sigName = checkName(sigName); - AlgorithmParameterSpec paramSpec = null; + // Special method for setting the specified parameter bytes into the + // specified Signature object as signature parameters. + public static void specialSetParameter(Signature sig, byte[] paramBytes) + throws InvalidAlgorithmParameterException, ProviderException { if (paramBytes != null) { - if (sigName.toUpperCase().indexOf("RSA") == -1) { - throw new ProviderException - ("Unrecognized algorithm for signature parameters " + - sigName); - } + String sigName = sig.getAlgorithm(); AlgorithmParameters params = createAlgorithmParameters(sigName, paramBytes); - paramSpec = RSAUtil.getParamSpec(params); + specialSetParameter(sig, params); } - return paramSpec; - } - - // Utility method for initializing the specified Signature object - // for verification with the specified key and params (may be null) - public static void initVerifyWithParam(Signature s, PublicKey key, - AlgorithmParameterSpec params) - throws ProviderException, InvalidAlgorithmParameterException, - InvalidKeyException { - SharedSecrets.getJavaSecuritySignatureAccess().initVerify(s, key, params); - } - - // Utility method for initializing the specified Signature object - // for verification with the specified Certificate and params (may be null) - public static void initVerifyWithParam(Signature s, - java.security.cert.Certificate cert, - AlgorithmParameterSpec params) - throws ProviderException, InvalidAlgorithmParameterException, - InvalidKeyException { - SharedSecrets.getJavaSecuritySignatureAccess().initVerify(s, cert, params); } - // Utility method for initializing the specified Signature object - // for signing with the specified key and params (may be null) - public static void initSignWithParam(Signature s, PrivateKey key, - AlgorithmParameterSpec params, SecureRandom sr) - throws ProviderException, InvalidAlgorithmParameterException, - InvalidKeyException { - SharedSecrets.getJavaSecuritySignatureAccess().initSign(s, key, params, sr); + // Special method for setting the specified AlgorithmParameter object + // into the specified Signature object as signature parameters. + public static void specialSetParameter(Signature sig, + AlgorithmParameters params) + throws InvalidAlgorithmParameterException, ProviderException { + if (params != null) { + String sigName = sig.getAlgorithm(); + sig.setParameter(getParamSpec(sigName, params)); + } } } --- old/src/java.base/share/classes/sun/security/x509/X509CRLImpl.java 2019-05-21 01:01:54.589087190 +0200 +++ new/src/java.base/share/classes/sun/security/x509/X509CRLImpl.java 2019-05-21 01:01:54.433087470 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -370,16 +370,18 @@ throw new CRLException("Uninitialized CRL"); } Signature sigVerf = null; - String sigName = sigAlgId.getName(); if (sigProvider.isEmpty()) { - sigVerf = Signature.getInstance(sigName); + sigVerf = Signature.getInstance(sigAlgId.getName()); } else { - sigVerf = Signature.getInstance(sigName, sigProvider); + sigVerf = Signature.getInstance(sigAlgId.getName(), sigProvider); } + sigVerf.initVerify(key); + + // set parameters after Signature.initSign/initVerify call, + // so the deferred provider selection happens when key is set try { - SignatureUtil.initVerifyWithParam(sigVerf, key, - SignatureUtil.getParamSpec(sigName, getSigAlgParams())); + SignatureUtil.specialSetParameter(sigVerf, getSigAlgParams()); } catch (ProviderException e) { throw new CRLException(e.getMessage(), e.getCause()); } catch (InvalidAlgorithmParameterException e) { @@ -423,16 +425,18 @@ throw new CRLException("Uninitialized CRL"); } Signature sigVerf = null; - String sigName = sigAlgId.getName(); if (sigProvider == null) { - sigVerf = Signature.getInstance(sigName); + sigVerf = Signature.getInstance(sigAlgId.getName()); } else { - sigVerf = Signature.getInstance(sigName, sigProvider); + sigVerf = Signature.getInstance(sigAlgId.getName(), sigProvider); } + sigVerf.initVerify(key); + + // set parameters after Signature.initSign/initVerify call, + // so the deferred provider selection happens when key is set try { - SignatureUtil.initVerifyWithParam(sigVerf, key, - SignatureUtil.getParamSpec(sigName, getSigAlgParams())); + SignatureUtil.specialSetParameter(sigVerf, getSigAlgParams()); } catch (ProviderException e) { throw new CRLException(e.getMessage(), e.getCause()); } catch (InvalidAlgorithmParameterException e) { @@ -498,7 +502,7 @@ sigEngine.initSign(key); - // in case the name is reset + // in case the name is reset sigAlgId = AlgorithmId.get(sigEngine.getAlgorithm()); infoSigAlgId = sigAlgId; --- old/src/java.base/share/classes/sun/security/x509/X509CertImpl.java 2019-05-21 01:01:54.793086825 +0200 +++ new/src/java.base/share/classes/sun/security/x509/X509CertImpl.java 2019-05-21 01:01:54.641087098 +0200 @@ -422,16 +422,18 @@ } // Verify the signature ... Signature sigVerf = null; - String sigName = algId.getName(); if (sigProvider.isEmpty()) { - sigVerf = Signature.getInstance(sigName); + sigVerf = Signature.getInstance(algId.getName()); } else { - sigVerf = Signature.getInstance(sigName, sigProvider); + sigVerf = Signature.getInstance(algId.getName(), sigProvider); } + sigVerf.initVerify(key); + + // set parameters after Signature.initSign/initVerify call, + // so the deferred provider selection happens when key is set try { - SignatureUtil.initVerifyWithParam(sigVerf, key, - SignatureUtil.getParamSpec(sigName, getSigAlgParams())); + SignatureUtil.specialSetParameter(sigVerf, getSigAlgParams()); } catch (ProviderException e) { throw new CertificateException(e.getMessage(), e.getCause()); } catch (InvalidAlgorithmParameterException e) { @@ -476,16 +478,18 @@ } // Verify the signature ... Signature sigVerf = null; - String sigName = algId.getName(); if (sigProvider == null) { - sigVerf = Signature.getInstance(sigName); + sigVerf = Signature.getInstance(algId.getName()); } else { - sigVerf = Signature.getInstance(sigName, sigProvider); + sigVerf = Signature.getInstance(algId.getName(), sigProvider); } + sigVerf.initVerify(key); + + // set parameters after Signature.initSign/initVerify call, + // so the deferred provider selection happens when key is set try { - SignatureUtil.initVerifyWithParam(sigVerf, key, - SignatureUtil.getParamSpec(sigName, getSigAlgParams())); + SignatureUtil.specialSetParameter(sigVerf, getSigAlgParams()); } catch (ProviderException e) { throw new CertificateException(e.getMessage(), e.getCause()); } catch (InvalidAlgorithmParameterException e) { @@ -583,19 +587,22 @@ InvalidKeyException, InvalidAlgorithmParameterException, NoSuchProviderException, SignatureException { try { - if (readOnly) { + if (readOnly) throw new CertificateEncodingException( - "cannot over-write existing certificate"); - } + "cannot over-write existing certificate"); Signature sigEngine = null; - if (provider == null || provider.isEmpty()) { + if (provider == null || provider.isEmpty()) sigEngine = Signature.getInstance(algorithm); - } else { + else sigEngine = Signature.getInstance(algorithm, provider); - } - SignatureUtil.initSignWithParam(sigEngine, key, signingParams, - null); + sigEngine.initSign(key); + + if (signingParams != null) { + // set parameters after Signature.initSign/initVerify call, so + // the deferred provider selection happens when the key is set + sigEngine.setParameter(signingParams); + } // in case the name is reset if (signingParams != null) { --- old/src/java.base/share/native/libjli/java.c 2019-05-21 01:01:55.001086451 +0200 +++ new/src/java.base/share/native/libjli/java.c 2019-05-21 01:01:54.849086724 +0200 @@ -204,14 +204,11 @@ */ static jlong threadStackSize = 0; /* stack size of the new thread */ static jlong maxHeapSize = 0; /* max heap size */ -static jlong initialHeapSize = 0; /* initial heap size */ +static jlong initialHeapSize = 0; /* inital heap size */ /* - * A minimum initial-thread stack size suitable for most platforms. - * This is the minimum amount of stack needed to load the JVM such - * that it can reject a too small -Xss value. If this is too small - * JVM initialization would cause a StackOverflowError. - */ + * A minimum -Xss stack size suitable for all platforms. + */ #ifndef STACK_SIZE_MINIMUM #define STACK_SIZE_MINIMUM (64 * KB) #endif @@ -937,18 +934,16 @@ options[numOptions].optionString = str; options[numOptions++].extraInfo = info; - /* - * -Xss is used both by the JVM and here to establish the stack size of the thread - * created to launch the JVM. In the latter case we need to ensure we don't go - * below the minimum stack size allowed. If -Xss is zero that tells the JVM to use - * 'default' sizes (either from JVM or system configuration, e.g. 'ulimit -s' on linux), - * and is not itself a small stack size that will be rejected. So we ignore -Xss0 here. - */ if (JLI_StrCCmp(str, "-Xss") == 0) { jlong tmp; if (parse_size(str + 4, &tmp)) { threadStackSize = tmp; - if (threadStackSize > 0 && threadStackSize < (jlong)STACK_SIZE_MINIMUM) { + /* + * Make sure the thread stack size is big enough that we won't get a stack + * overflow before the JVM startup code can check to make sure the stack + * is big enough. + */ + if (threadStackSize < (jlong)STACK_SIZE_MINIMUM) { threadStackSize = STACK_SIZE_MINIMUM; } } @@ -2327,38 +2322,38 @@ int argc, char **argv, int mode, char *what, int ret) { + + /* + * If user doesn't specify stack size, check if VM has a preference. + * Note that HotSpot no longer supports JNI_VERSION_1_1 but it will + * return its default stack size through the init args structure. + */ if (threadStackSize == 0) { - /* - * If the user hasn't specified a non-zero stack size ask the JVM for its default. - * A returned 0 means 'use the system default' for a platform, e.g., Windows. - * Note that HotSpot no longer supports JNI_VERSION_1_1 but it will - * return its default stack size through the init args structure. - */ - struct JDK1_1InitArgs args1_1; - memset((void*)&args1_1, 0, sizeof(args1_1)); - args1_1.version = JNI_VERSION_1_1; - ifn->GetDefaultJavaVMInitArgs(&args1_1); /* ignore return value */ - if (args1_1.javaStackSize > 0) { - threadStackSize = args1_1.javaStackSize; - } + struct JDK1_1InitArgs args1_1; + memset((void*)&args1_1, 0, sizeof(args1_1)); + args1_1.version = JNI_VERSION_1_1; + ifn->GetDefaultJavaVMInitArgs(&args1_1); /* ignore return value */ + if (args1_1.javaStackSize > 0) { + threadStackSize = args1_1.javaStackSize; + } } { /* Create a new thread to create JVM and invoke main method */ - JavaMainArgs args; - int rslt; + JavaMainArgs args; + int rslt; - args.argc = argc; - args.argv = argv; - args.mode = mode; - args.what = what; - args.ifn = *ifn; - - rslt = CallJavaMainInNewThread(threadStackSize, (void*)&args); - /* If the caller has deemed there is an error we - * simply return that, otherwise we return the value of - * the callee - */ - return (ret != 0) ? ret : rslt; + args.argc = argc; + args.argv = argv; + args.mode = mode; + args.what = what; + args.ifn = *ifn; + + rslt = CallJavaMainInNewThread(threadStackSize, (void*)&args); + /* If the caller has deemed there is an error we + * simply return that, otherwise we return the value of + * the callee + */ + return (ret != 0) ? ret : rslt; } } --- old/src/java.base/windows/classes/sun/nio/fs/WindowsConstants.java 2019-05-21 01:01:55.217086063 +0200 +++ new/src/java.base/windows/classes/sun/nio/fs/WindowsConstants.java 2019-05-21 01:01:55.061086344 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -75,7 +75,6 @@ public static final int IO_REPARSE_TAG_SYMLINK = 0xA000000C; public static final int MAXIMUM_REPARSE_DATA_BUFFER_SIZE = 16 * 1024; public static final int SYMBOLIC_LINK_FLAG_DIRECTORY = 0x1; - public static final int SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE = 0x2; // volume flags public static final int FILE_CASE_SENSITIVE_SEARCH = 0x00000001; @@ -105,7 +104,6 @@ public static final int ERROR_MORE_DATA = 234; public static final int ERROR_DIRECTORY = 267; public static final int ERROR_NOTIFY_ENUM_DIR = 1022; - public static final int ERROR_PRIVILEGE_NOT_HELD = 1314; public static final int ERROR_NONE_MAPPED = 1332; public static final int ERROR_NOT_A_REPARSE_POINT = 4390; public static final int ERROR_INVALID_REPARSE_DATA = 4392; --- old/src/java.base/windows/classes/sun/nio/fs/WindowsNativeDispatcher.java 2019-05-21 01:01:55.413085714 +0200 +++ new/src/java.base/windows/classes/sun/nio/fs/WindowsNativeDispatcher.java 2019-05-21 01:01:55.257085992 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 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,8 +29,6 @@ import java.security.PrivilegedAction; import jdk.internal.misc.Unsafe; -import static sun.nio.fs.WindowsConstants.*; - /** * Win32 and library calls. */ @@ -922,12 +920,6 @@ * LPCWSTR lpTargetFileName, * DWORD dwFlags * ) - * - * Creates a symbolic link, conditionally retrying with the addition of - * the flag SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE if the initial - * attempt fails with ERROR_PRIVILEGE_NOT_HELD. If the retry fails, throw - * the original exception due to ERROR_PRIVILEGE_NOT_HELD. The retry will - * succeed only on Windows build 14972 or later if Developer Mode is on. */ static void CreateSymbolicLink(String link, String target, int flags) throws WindowsException @@ -937,19 +929,6 @@ try { CreateSymbolicLink0(linkBuffer.address(), targetBuffer.address(), flags); - } catch (WindowsException x) { - if (x.lastError() == ERROR_PRIVILEGE_NOT_HELD) { - flags |= SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE; - try { - CreateSymbolicLink0(linkBuffer.address(), - targetBuffer.address(), flags); - return; - } catch (WindowsException ignored) { - // Will fail with ERROR_INVALID_PARAMETER for Windows - // builds older than 14972. - } - } - throw x; } finally { targetBuffer.release(); linkBuffer.release(); --- old/src/java.base/windows/native/common/version.rc 2019-05-21 01:01:55.609085362 +0200 +++ new/src/java.base/windows/native/common/version.rc 2019-05-21 01:01:55.457085635 +0200 @@ -1,5 +1,5 @@ // -// Copyright (c) 2004, 2019, Oracle and/or its affiliates. All rights reserved. +// Copyright (c) 2004, 2015, Oracle and/or its affiliates. All rights reserved. // DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. // // This code is free software; you can redistribute it and/or modify it @@ -55,15 +55,15 @@ BEGIN BLOCK "000004b0" BEGIN - VALUE "CompanyName", XSTR(JDK_COMPANY) "\0" - VALUE "FileDescription", XSTR(JDK_FILEDESC) "\0" - VALUE "FileVersion", XSTR(JDK_VER) "\0" + VALUE "CompanyName", XSTR(JDK_COMPANY) "\0" + VALUE "FileDescription", XSTR(JDK_COMPONENT) "\0" + VALUE "FileVersion", XSTR(JDK_VER) "\0" VALUE "Full Version", XSTR(JDK_VERSION_STRING) "\0" - VALUE "InternalName", XSTR(JDK_INTERNAL_NAME) "\0" - VALUE "LegalCopyright", XSTR(JDK_COPYRIGHT) "\0" - VALUE "OriginalFilename", XSTR(JDK_FNAME) "\0" - VALUE "ProductName", XSTR(JDK_NAME) "\0" - VALUE "ProductVersion", XSTR(JDK_VER) "\0" + VALUE "InternalName", XSTR(JDK_INTERNAL_NAME) "\0" + VALUE "LegalCopyright", XSTR(JDK_COPYRIGHT) "\0" + VALUE "OriginalFilename", XSTR(JDK_FNAME) "\0" + VALUE "ProductName", XSTR(JDK_NAME) "\0" + VALUE "ProductVersion", XSTR(JDK_VER) "\0" END END BLOCK "VarFileInfo" --- old/src/java.base/windows/native/libjli/java_md.c 2019-05-21 01:01:55.805085011 +0200 +++ new/src/java.base/windows/native/libjli/java_md.c 2019-05-21 01:01:55.649085289 +0200 @@ -41,6 +41,8 @@ #define JVM_DLL "jvm.dll" #define JAVA_DLL "java.dll" +#define ELP_PREFIX L"\\\\?\\" + /* * Prototypes. */ @@ -495,67 +497,57 @@ return rc; } -/* taken from hotspot and slightly adjusted for jli lib; - * creates a UNC/ELP path from input 'path' - * the return buffer is allocated in C heap and needs to be freed using - * JLI_MemFree by the caller. - */ -static wchar_t* create_unc_path(const char* path, errno_t* err) { - wchar_t* wpath = NULL; - size_t converted_chars = 0; - size_t path_len = strlen(path) + 1; /* includes the terminating NULL */ - if (path[0] == '\\' && path[1] == '\\') { - if (path[2] == '?' && path[3] == '\\') { - /* if it already has a \\?\ don't do the prefix */ - wpath = (wchar_t*) JLI_MemAlloc(path_len * sizeof(wchar_t)); - if (wpath != NULL) { - *err = mbstowcs_s(&converted_chars, wpath, path_len, path, path_len); - } else { - *err = ENOMEM; - } - } else { - /* only UNC pathname includes double slashes here */ - wpath = (wchar_t*) JLI_MemAlloc((path_len + 7) * sizeof(wchar_t)); - if (wpath != NULL) { - wcscpy(wpath, L"\\\\?\\UNC\0"); - *err = mbstowcs_s(&converted_chars, &wpath[7], path_len, path, path_len); - } else { - *err = ENOMEM; - } - } - } else { - wpath = (wchar_t*) JLI_MemAlloc((path_len + 4) * sizeof(wchar_t)); - if (wpath != NULL) { - wcscpy(wpath, L"\\\\?\\\0"); - *err = mbstowcs_s(&converted_chars, &wpath[4], path_len, path, path_len); - } else { - *err = ENOMEM; - } - } - return wpath; -} - +/* On Windows, if _open fails, retry again with CreateFileW and + * "\\?\" prefix ( extended-length paths) - this allows to open paths with larger file names; + * otherwise we run into the MAX_PATH limitation */ int JLI_Open(const char* name, int flags) { - int fd; - if (strlen(name) < MAX_PATH) { - fd = _open(name, flags); - } else { - errno_t err = ERROR_SUCCESS; - wchar_t* wpath = create_unc_path(name, &err); - if (err != ERROR_SUCCESS) { - if (wpath != NULL) JLI_MemFree(wpath); - errno = err; - return -1; - } - fd = _wopen(wpath, flags); - if (fd == -1) { - errno = GetLastError(); + int fd = _open(name, flags); + if (fd == -1 && errno == ENOENT) { + wchar_t* wname = NULL; + wchar_t* wfullname = NULL; + wchar_t* wfullname_w_prefix = NULL; + size_t wnamelen, wfullnamelen, elplen; + HANDLE h; + + wnamelen = strlen(name) + 1; + wname = (wchar_t*) malloc(wnamelen*sizeof(wchar_t)); + if (wname == NULL) { + goto end; + } + if (mbstowcs(wname, name, wnamelen - 1) == -1) { + goto end; + } + wname[wnamelen - 1] = L'\0'; + wfullname = _wfullpath(wfullname, wname, 0); + if (wfullname == NULL) { + goto end; + } + + wfullnamelen = wcslen(wfullname); + if (wfullnamelen > 247) { + elplen = wcslen(ELP_PREFIX); + wfullname_w_prefix = (wchar_t*) malloc((elplen+wfullnamelen+1)*sizeof(wchar_t)); + wcscpy(wfullname_w_prefix, ELP_PREFIX); + wcscpy(wfullname_w_prefix+elplen, wfullname); + + h = CreateFileW(wfullname_w_prefix, GENERIC_READ, FILE_SHARE_READ, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (h == INVALID_HANDLE_VALUE) { + goto end; + } + /* associates fd with handle */ + fd = _open_osfhandle((intptr_t)h, _O_RDONLY); } - JLI_MemFree(wpath); +end: + free(wname); + free(wfullname); + free(wfullname_w_prefix); } return fd; } + + JNIEXPORT void JNICALL JLI_ReportErrorMessage(const char* fmt, ...) { va_list vl; --- old/src/java.base/windows/native/libnio/fs/WindowsNativeDispatcher.c 2019-05-21 01:01:56.009084644 +0200 +++ new/src/java.base/windows/native/libnio/fs/WindowsNativeDispatcher.c 2019-05-21 01:01:55.853084924 +0200 @@ -1063,7 +1063,17 @@ LPCWSTR link = jlong_to_ptr(linkAddress); LPCWSTR target = jlong_to_ptr(targetAddress); - if (CreateSymbolicLinkW(link, target, (DWORD)flags) == 0) + // Allow creation of symbolic links when the process is not elevated. + // Developer Mode must be enabled for this option to function, otherwise + // it will be ignored. Check that symbol is available in current build SDK. + DWORD dwFlags = (DWORD)flags; +#ifdef SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE + dwFlags |= SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE; +#endif + + // On Windows 64-bit this appears to succeed even when there are + // insufficient privileges + if (CreateSymbolicLinkW(link, target, dwFlags) == 0) throwWindowsException(env, GetLastError()); } --- old/src/java.compiler/share/classes/javax/annotation/processing/ProcessingEnvironment.java 2019-05-21 01:01:56.209084287 +0200 +++ new/src/java.compiler/share/classes/javax/annotation/processing/ProcessingEnvironment.java 2019-05-21 01:01:56.057084557 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2012, 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 @@ -131,18 +131,4 @@ * effect */ Locale getLocale(); - - /** - * Returns {@code true} if preview features are enabled - * and {@code false} otherwise. - * @return whether or not preview features are enabled - * - * @implSpec The default implementation of this method returns - * {@code false}. - * - * @since 13 - */ - default boolean isPreviewEnabled() { - return false; - } } --- old/src/java.desktop/share/classes/com/sun/media/sound/FastSysexMessage.java 2019-05-21 01:01:56.401083941 +0200 +++ new/src/java.desktop/share/classes/com/sun/media/sound/FastSysexMessage.java 2019-05-21 01:01:56.249084213 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,7 +37,9 @@ FastSysexMessage(byte[] data) throws InvalidMidiDataException { super(data); - MidiUtils.checkSysexStatus(data, data.length); + if (data.length==0 || (((data[0] & 0xFF) != 0xF0) && ((data[0] & 0xFF) != 0xF7))) { + super.setMessage(data, data.length); // will throw Exception + } } /** @@ -52,7 +54,9 @@ // which is shared among all transmitters, cannot be modified @Override public void setMessage(byte[] data, int length) throws InvalidMidiDataException { - MidiUtils.checkSysexStatus(data, length); + if ((data.length == 0) || (((data[0] & 0xFF) != 0xF0) && ((data[0] & 0xFF) != 0xF7))) { + super.setMessage(data, data.length); // will throw Exception + } this.length = length; this.data = new byte[this.length]; System.arraycopy(data, 0, this.data, 0, length); --- old/src/java.desktop/share/classes/com/sun/media/sound/MidiUtils.java 2019-05-21 01:01:56.597083591 +0200 +++ new/src/java.desktop/share/classes/com/sun/media/sound/MidiUtils.java 2019-05-21 01:01:56.445083862 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -27,7 +27,6 @@ import java.util.ArrayList; -import javax.sound.midi.InvalidMidiDataException; import javax.sound.midi.MetaMessage; import javax.sound.midi.MidiDevice; import javax.sound.midi.MidiEvent; @@ -35,9 +34,6 @@ import javax.sound.midi.Sequence; import javax.sound.midi.Track; -import static javax.sound.midi.SysexMessage.SPECIAL_SYSTEM_EXCLUSIVE; -import static javax.sound.midi.SysexMessage.SYSTEM_EXCLUSIVE; - // TODO: // - define and use a global symbolic constant for 60000000 (see convertTempo) @@ -69,37 +65,6 @@ "MidiDevice %s not supported by this provider", info)); } - /** - * Checks the status byte for the system exclusive message. - * - * @param data the system exclusive message data - * @param length the length of the valid message data in the array - * @throws InvalidMidiDataException if the status byte is invalid for a - * system exclusive message - */ - public static void checkSysexStatus(final byte[] data, final int length) - throws InvalidMidiDataException { - if (data.length == 0 || length == 0) { - throw new InvalidMidiDataException("Status byte is missing"); - } - checkSysexStatus(data[0] & 0xFF); - } - - /** - * Checks the status byte for the system exclusive message. - * - * @param status the status byte for the message (0xF0 or 0xF7) - * @throws InvalidMidiDataException if the status byte is invalid for a - * system exclusive message - */ - public static void checkSysexStatus(final int status) - throws InvalidMidiDataException { - if (status != SYSTEM_EXCLUSIVE && status != SPECIAL_SYSTEM_EXCLUSIVE) { - throw new InvalidMidiDataException(String.format( - "Invalid status byte for sysex message: 0x%X", status)); - } - } - /** return true if the passed message is Meta End Of Track */ public static boolean isMetaEndOfTrack(MidiMessage midiMsg) { // first check if it is a META message at all --- old/src/java.desktop/share/classes/javax/sound/midi/SysexMessage.java 2019-05-21 01:01:56.809083209 +0200 +++ new/src/java.desktop/share/classes/javax/sound/midi/SysexMessage.java 2019-05-21 01:01:56.653083490 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,8 +25,6 @@ package javax.sound.midi; -import com.sun.media.sound.MidiUtils; - /** * A {@code SysexMessage} object represents a MIDI system exclusive message. *

@@ -185,7 +183,10 @@ */ @Override public void setMessage(byte[] data, int length) throws InvalidMidiDataException { - MidiUtils.checkSysexStatus(data, length); + int status = (data[0] & 0xFF); + if ((status != 0xF0) && (status != 0xF7)) { + throw new InvalidMidiDataException("Invalid status byte for sysex message: 0x" + Integer.toHexString(status)); + } super.setMessage(data, length); } @@ -199,7 +200,9 @@ * system exclusive message */ public void setMessage(int status, byte[] data, int length) throws InvalidMidiDataException { - MidiUtils.checkSysexStatus(status); + if ( (status != 0xF0) && (status != 0xF7) ) { + throw new InvalidMidiDataException("Invalid status byte for sysex message: 0x" + Integer.toHexString(status)); + } if (length < 0 || length > data.length) { throw new IndexOutOfBoundsException("length out of bounds: "+length); } --- old/src/java.desktop/share/classes/javax/swing/text/ElementIterator.java 2019-05-21 01:01:57.001082865 +0200 +++ new/src/java.desktop/share/classes/javax/swing/text/ElementIterator.java 2019-05-21 01:01:56.849083138 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,58 +25,65 @@ package javax.swing.text; -import java.util.Enumeration; import java.util.Stack; +import java.util.Enumeration; /** - * {@code ElementIterator}, as the name suggests, iterates over the - * {@code Element} tree. The constructor can be invoked with either - * {@code Document} or an {@code Element} as an argument. If the constructor is - * invoked with a {@code Document} as an argument then the root of the iteration - * is the return value of {@code document.getDefaultRootElement()}. - *

- * The iteration happens in a depth-first manner. In terms of how boundary - * conditions are handled: - *

    - *
  • if {@link #next} is called before {@link #first} or {@link #current}, - * the root will be returned - *
  • {@link #next} returns {@code null} to indicate the end of the list - *
  • {@link #previous} returns {@code null} when the current element is the - * root or {@link #next} has returned {@code null} - *
*

- * The {@code ElementIterator} does no locking of the {@code Element} tree. This - * means that it does not track any changes. It is the responsibility of the + * ElementIterator, as the name suggests, iterates over the Element + * tree. The constructor can be invoked with either Document or an Element + * as an argument. If the constructor is invoked with a Document as an + * argument then the root of the iteration is the return value of + * document.getDefaultRootElement(). + * + * The iteration happens in a depth-first manner. In terms of how + * boundary conditions are handled: + * a) if next() is called before first() or current(), the + * root will be returned. + * b) next() returns null to indicate the end of the list. + * c) previous() returns null when the current element is the root + * or next() has returned null. + * + * The ElementIterator does no locking of the Element tree. This means + * that it does not track any changes. It is the responsibility of the * user of this class, to ensure that no changes happen during element * iteration. - *

+ * * Simple usage example: - *

{@code public void iterate() {
- *      ElementIterator it = new ElementIterator(root);
- *      Element elem;
- *      while (true) {
- *          if ((elem = it.next()) != null) {
- *              // process element
- *              System.out.println("elem: " + elem.getName());
- *          } else {
- *              break;
- *          }
- *      }
- * }}
+ * + * public void iterate() { + * ElementIterator it = new ElementIterator(root); + * Element elem; + * while (true) { + * if ((elem = next()) != null) { + * // process element + * System.out.println("elem: " + elem.getName()); + * } else { + * break; + * } + * } + * } * * @author Sunita Mani + * */ + public class ElementIterator implements Cloneable { + private Element root; private Stack elementStack = null; /** - * The {@code StackItem} class stores the element as well as a child index. - * If the index is -1, then the element represented on the stack is the - * element itself. Otherwise, the index functions as an index into the - * vector of children of the element. In this case, the item on the stack - * represents the "index"th child of the element. + * The StackItem class stores the element + * as well as a child index. If the + * index is -1, then the element represented + * on the stack is the element itself. + * Otherwise, the index functions as an index + * into the vector of children of the element. + * In this case, the item on the stack + * represents the "index"th child of the element + * */ private class StackItem implements Cloneable { Element item; @@ -110,28 +117,31 @@ } /** - * Creates a new {@code ElementIterator}. The root element is taken to get - * the default root element of the document. + * Creates a new ElementIterator. The + * root element is taken to get the + * default root element of the document. * - * @param document a {@code Document} + * @param document a Document. */ public ElementIterator(Document document) { root = document.getDefaultRootElement(); } + /** - * Creates a new {@code ElementIterator}. + * Creates a new ElementIterator. * - * @param root the root {@code Element} + * @param root the root Element. */ public ElementIterator(Element root) { this.root = root; } + /** - * Clones the {@code ElementIterator}. + * Clones the ElementIterator. * - * @return a cloned {@code ElementIterator} Object + * @return a cloned ElementIterator Object. */ public synchronized Object clone() { @@ -151,10 +161,11 @@ } } + /** * Fetches the first element. * - * @return an {@code Element} + * @return an Element. */ public Element first() { // just in case... @@ -172,7 +183,7 @@ /** * Fetches the current depth of element tree. * - * @return the depth + * @return the depth. */ public int depth() { if (elementStack == null) { @@ -181,11 +192,12 @@ return elementStack.size(); } + /** - * Fetches the current {@code Element}. + * Fetches the current Element. * - * @return element on top of the stack or {@code null} if the root element - * is {@code null} + * @return element on top of the stack or + * null if the root element is null */ public Element current() { @@ -210,11 +222,14 @@ return null; } + /** - * Fetches the next {@code Element}. The strategy used to locate the next - * element is a depth-first search. + * Fetches the next Element. The strategy + * used to locate the next element is + * a depth-first search. * - * @return the next element or {@code null} at the end of the list + * @return the next element or null + * at the end of the list. */ public Element next() { @@ -267,12 +282,14 @@ return null; } + /** - * Fetches the previous {@code Element}. If however the current element is - * the last element, or the current element is {@code null}, then - * {@code null} is returned. + * Fetches the previous Element. If however the current + * element is the last element, or the current element + * is null, then null is returned. + * + * @return previous Element if available * - * @return previous {@code Element} if available */ public Element previous() { @@ -318,8 +335,8 @@ } /** - * Returns the last child of {@code parent} that is a leaf. If the last - * child is a not a leaf, this method is called with the last child. + * Returns the last child of parent that is a leaf. If the + * last child is a not a leaf, this method is called with the last child. */ private Element getDeepestLeaf(Element parent) { if (parent.isLeaf()) { @@ -332,10 +349,10 @@ return getDeepestLeaf(parent.getElement(childCount - 1)); } - /** - * Iterates through the element tree and prints out each element and its - * attributes. - */ + /* + Iterates through the element tree and prints + out each element and its attributes. + */ private void dumpTree() { Element elem; --- old/src/java.desktop/share/classes/javax/swing/text/View.java 2019-05-21 01:01:57.201082508 +0200 +++ new/src/java.desktop/share/classes/javax/swing/text/View.java 2019-05-21 01:01:57.045082786 +0200 @@ -229,6 +229,7 @@ * Typically the view is told to render into the span * that is returned, although there is no guarantee. * The parent may choose to resize or break the view + * @see View#getPreferredSpan */ public abstract float getPreferredSpan(int axis); --- old/src/java.desktop/unix/native/libawt_xawt/awt/gtk3_interface.c 2019-05-21 01:01:57.401082149 +0200 +++ new/src/java.desktop/unix/native/libawt_xawt/awt/gtk3_interface.c 2019-05-21 01:01:57.249082422 +0200 @@ -1777,18 +1777,9 @@ (widget_type == CHECK_BOX || widget_type == RADIO_BUTTON)) { return; } - - GtkStyleContext* context = NULL; + GtkStyleContext* context = get_style(widget_type, detail); if (widget_type == TOOL_TIP) { - context = get_style(widget_type, detail); fp_gtk_style_context_add_class(context, "background"); - } else { - gtk3_widget = gtk3_get_widget(widget_type); - context = fp_gtk_widget_get_style_context (gtk3_widget); - fp_gtk_style_context_save (context); - if (detail != 0) { - transform_detail_string(detail, context); - } } GtkStateFlags flags = get_gtk_flags(state_type); @@ -1804,11 +1795,8 @@ } fp_gtk_render_background (context, cr, x, y, width, height); - if (widget_type == TOOL_TIP) { - disposeOrRestoreContext(context); - } else { - fp_gtk_style_context_restore (context); - } + + disposeOrRestoreContext(context); } static void gtk3_paint_focus(WidgetType widget_type, GtkStateType state_type, --- old/src/java.desktop/windows/native/libawt/windows/awt.rc 2019-05-21 01:01:57.609081777 +0200 +++ new/src/java.desktop/windows/native/libawt/windows/awt.rc 2019-05-21 01:01:57.457082049 +0200 @@ -1,5 +1,5 @@ // -// Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. +// Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. // DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. // // This code is free software; you can redistribute it and/or modify it @@ -65,15 +65,15 @@ BEGIN BLOCK "040904b0" BEGIN - VALUE "CompanyName", XSTR(JDK_COMPANY) "\0" - VALUE "FileDescription", XSTR(JDK_FILEDESC) "\0" - VALUE "FileVersion", XSTR(JDK_VER) "\0" + VALUE "CompanyName", XSTR(JDK_COMPANY) "\0" + VALUE "FileDescription", XSTR(JDK_COMPONENT) "\0" + VALUE "FileVersion", XSTR(JDK_VER) "\0" VALUE "Full Version", XSTR(JDK_VERSION_STRING) "\0" - VALUE "InternalName", XSTR(JDK_INTERNAL_NAME) "\0" - VALUE "LegalCopyright", XSTR(JDK_COPYRIGHT) "\0" - VALUE "OriginalFilename", XSTR(JDK_FNAME) "\0" - VALUE "ProductName", XSTR(JDK_NAME) "\0" - VALUE "ProductVersion", XSTR(JDK_VER) "\0" + VALUE "InternalName", XSTR(JDK_INTERNAL_NAME) "\0" + VALUE "LegalCopyright", XSTR(JDK_COPYRIGHT) "\0" + VALUE "OriginalFilename", XSTR(JDK_FNAME) "\0" + VALUE "ProductName", XSTR(JDK_NAME) "\0" + VALUE "ProductVersion", XSTR(JDK_VER) "\0" END END BLOCK "VarFileInfo" --- old/src/java.rmi/share/classes/sun/rmi/registry/RegistryImpl_Skel.java 2019-05-21 01:01:57.809081418 +0200 +++ new/src/java.rmi/share/classes/sun/rmi/registry/RegistryImpl_Skel.java 2019-05-21 01:01:57.657081690 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -58,24 +58,8 @@ public void dispatch(java.rmi.Remote obj, java.rmi.server.RemoteCall call, int opnum, long hash) throws java.lang.Exception { - if (opnum < 0) { - if (hash == 7583982177005850366L) { - opnum = 0; - } else if (hash == 2571371476350237748L) { - opnum = 1; - } else if (hash == -7538657168040752697L) { - opnum = 2; - } else if (hash == -8381844669958460146L) { - opnum = 3; - } else if (hash == 7305022919901907578L) { - opnum = 4; - } else { - throw new java.rmi.UnmarshalException("invalid method hash"); - } - } else { - if (hash != interfaceHash) - throw new java.rmi.server.SkeletonMismatchException("interface hash mismatch"); - } + if (hash != interfaceHash) + throw new java.rmi.server.SkeletonMismatchException("interface hash mismatch"); sun.rmi.registry.RegistryImpl server = (sun.rmi.registry.RegistryImpl) obj; switch (opnum) { --- old/src/java.rmi/share/classes/sun/rmi/server/UnicastServerRef.java 2019-05-21 01:01:58.009081058 +0200 +++ new/src/java.rmi/share/classes/sun/rmi/server/UnicastServerRef.java 2019-05-21 01:01:57.853081339 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2019, 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 @@ -40,7 +40,6 @@ import java.rmi.ServerException; import java.rmi.UnmarshalException; import java.rmi.server.ExportException; -import java.rmi.server.Operation; import java.rmi.server.RemoteCall; import java.rmi.server.RemoteRef; import java.rmi.server.RemoteStub; @@ -293,14 +292,15 @@ throw new UnmarshalException("error unmarshalling call header", readEx); } - if (skel != null) { - // If there is a skeleton, use it + if (num >= 0) { + if (skel != null) { oldDispatch(obj, call, num); return; - - } else if (num >= 0){ - throw new UnmarshalException( - "skeleton class not found but required for client version"); + } else { + throw new UnmarshalException( + "skeleton class not found but required " + + "for client version"); + } } try { op = in.readLong(); @@ -428,8 +428,8 @@ /** * Handle server-side dispatch using the RMI 1.1 stub/skeleton - * protocol, given a non-negative operation number or negative method hash - * that has already been read from the call stream. + * protocol, given a non-negative operation number that has + * already been read from the call stream. * Exceptions are handled by the caller to be sent to the remote client. * * @param obj the target remote object for the call @@ -461,8 +461,7 @@ } // if calls are being logged, write out object id and operation - Operation[] operations = skel.getOperations(); - logCall(obj, op >= 0 && op < operations.length ? operations[op] : "op: " + op); + logCall(obj, skel.getOperations()[op]); unmarshalCustomCallData(in); // dispatch to skeleton for remote object skel.dispatch(obj, call, op, hash); --- old/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLEntityManager.java 2019-05-21 01:01:58.213080694 +0200 +++ new/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLEntityManager.java 2019-05-21 01:01:58.057080972 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2018, Oracle and/or its affiliates. All rights reserved. */ /* * Licensed to the Apache Software Foundation (ASF) under one or more @@ -22,7 +22,6 @@ import com.sun.org.apache.xerces.internal.impl.io.ASCIIReader; import com.sun.org.apache.xerces.internal.impl.io.UCSReader; -import com.sun.org.apache.xerces.internal.impl.io.UTF16Reader; import com.sun.org.apache.xerces.internal.impl.io.UTF8Reader; import com.sun.org.apache.xerces.internal.impl.msg.XMLMessageFormatter; import com.sun.org.apache.xerces.internal.impl.validation.ValidationManager; @@ -90,7 +89,7 @@ * @author K.Venugopal SUN Microsystems * @author Neeraj Bajaj SUN Microsystems * @author Sunitha Reddy SUN Microsystems - * @LastModified: Apr 2019 + * @LastModified: Nov 2018 */ public class XMLEntityManager implements XMLComponent, XMLEntityResolver { @@ -413,6 +412,9 @@ /** Augmentations for entities. */ private final Augmentations fEntityAugs = new AugmentationsImpl(); + /** Pool of character buffers. */ + private CharacterBufferPool fBufferPool = new CharacterBufferPool(fBufferSize, DEFAULT_INTERNAL_BUFFER_SIZE); + /** indicate whether Catalog should be used for resolving external resources */ private boolean fUseCatalog = true; CatalogFeatures fCatalogFeatures; @@ -692,8 +694,7 @@ } // wrap this stream in RewindableInputStream - RewindableInputStream rewindableStream = new RewindableInputStream(stream); - stream = rewindableStream; + stream = new RewindableInputStream(stream); // perform auto-detect of encoding if necessary if (encoding == null) { @@ -701,30 +702,27 @@ final byte[] b4 = new byte[4]; int count = 0; for (; count<4; count++ ) { - b4[count] = (byte)rewindableStream.readAndBuffer(); + b4[count] = (byte)stream.read(); } if (count == 4) { - final EncodingInfo info = getEncodingInfo(b4, count); - encoding = info.autoDetectedEncoding; - final String readerEncoding = info.readerEncoding; - isBigEndian = info.isBigEndian; + Object [] encodingDesc = getEncodingName(b4, count); + encoding = (String)(encodingDesc[0]); + isBigEndian = (Boolean)(encodingDesc[1]); + stream.reset(); - if (info.hasBOM) { - // Special case UTF-8 files with BOM created by Microsoft - // tools. It's more efficient to consume the BOM than make - // the reader perform extra checks. -Ac - if (EncodingInfo.STR_UTF8.equals(readerEncoding)) { - // UTF-8 BOM: 0xEF 0xBB 0xBF + // Special case UTF-8 files with BOM created by Microsoft + // tools. It's more efficient to consume the BOM than make + // the reader perform extra checks. -Ac + if (count > 2 && encoding.equals("UTF-8")) { + int b0 = b4[0] & 0xFF; + int b1 = b4[1] & 0xFF; + int b2 = b4[2] & 0xFF; + if (b0 == 0xEF && b1 == 0xBB && b2 == 0xBF) { + // ignore first three bytes... stream.skip(3); } - // It's also more efficient to consume the UTF-16 BOM. - else if (EncodingInfo.STR_UTF16.equals(readerEncoding)) { - // UTF-16 BE BOM: 0xFE 0xFF - // UTF-16 LE BOM: 0xFF 0xFE - stream.skip(2); - } } - reader = createReader(stream, readerEncoding, isBigEndian); + reader = createReader(stream, encoding, isBigEndian); } else { reader = createReader(stream, encoding, isBigEndian); } @@ -735,11 +733,11 @@ encoding = encoding.toUpperCase(Locale.ENGLISH); // If encoding is UTF-8, consume BOM if one is present. - if (EncodingInfo.STR_UTF8.equals(encoding)) { + if (encoding.equals("UTF-8")) { final int[] b3 = new int[3]; int count = 0; for (; count < 3; ++count) { - b3[count] = rewindableStream.readAndBuffer(); + b3[count] = stream.read(); if (b3[count] == -1) break; } @@ -752,51 +750,56 @@ stream.reset(); } } - // If encoding is UTF-16, we still need to read the first - // four bytes, in order to discover the byte order. - else if (EncodingInfo.STR_UTF16.equals(encoding)) { + // If encoding is UTF-16, we still need to read the first four bytes + // in order to discover the byte order. + else if (encoding.equals("UTF-16")) { final int[] b4 = new int[4]; int count = 0; for (; count < 4; ++count) { - b4[count] = rewindableStream.readAndBuffer(); + b4[count] = stream.read(); if (b4[count] == -1) break; } stream.reset(); + + String utf16Encoding = "UTF-16"; if (count >= 2) { final int b0 = b4[0]; final int b1 = b4[1]; if (b0 == 0xFE && b1 == 0xFF) { // UTF-16, big-endian + utf16Encoding = "UTF-16BE"; isBigEndian = Boolean.TRUE; - stream.skip(2); } else if (b0 == 0xFF && b1 == 0xFE) { // UTF-16, little-endian + utf16Encoding = "UTF-16LE"; isBigEndian = Boolean.FALSE; - stream.skip(2); } else if (count == 4) { final int b2 = b4[2]; final int b3 = b4[3]; if (b0 == 0x00 && b1 == 0x3C && b2 == 0x00 && b3 == 0x3F) { // UTF-16, big-endian, no BOM + utf16Encoding = "UTF-16BE"; isBigEndian = Boolean.TRUE; } if (b0 == 0x3C && b1 == 0x00 && b2 == 0x3F && b3 == 0x00) { // UTF-16, little-endian, no BOM + utf16Encoding = "UTF-16LE"; isBigEndian = Boolean.FALSE; } } } + reader = createReader(stream, utf16Encoding, isBigEndian); } // If encoding is UCS-4, we still need to read the first four bytes // in order to discover the byte order. - else if (EncodingInfo.STR_UCS4.equals(encoding)) { + else if (encoding.equals("ISO-10646-UCS-4")) { final int[] b4 = new int[4]; int count = 0; for (; count < 4; ++count) { - b4[count] = rewindableStream.readAndBuffer(); + b4[count] = stream.read(); if (b4[count] == -1) break; } @@ -816,11 +819,11 @@ } // If encoding is UCS-2, we still need to read the first four bytes // in order to discover the byte order. - else if (EncodingInfo.STR_UCS2.equals(encoding)) { + else if (encoding.equals("ISO-10646-UCS-2")) { final int[] b4 = new int[4]; int count = 0; for (; count < 4; ++count) { - b4[count] = rewindableStream.readAndBuffer(); + b4[count] = stream.read(); if (b4[count] == -1) break; } @@ -1795,6 +1798,7 @@ bufferSize.intValue() > DEFAULT_XMLDECL_BUFFER_SIZE) { fBufferSize = bufferSize.intValue(); fEntityScanner.setBufferSize(fBufferSize); + fBufferPool.setExternalBufferSize(fBufferSize); } } if (suffixLength == Constants.SECURITY_MANAGER_PROPERTY.length() && @@ -2421,12 +2425,14 @@ * * @param b4 The first four bytes of the input. * @param count The number of bytes actually read. - * @return an instance of EncodingInfo which represents the auto-detected encoding. + * @return a 2-element array: the first element, an IANA-encoding string, + * the second element a Boolean which is true iff the document is big endian, false + * if it's little-endian, and null if the distinction isn't relevant. */ - protected EncodingInfo getEncodingInfo(byte[] b4, int count) { + protected Object[] getEncodingName(byte[] b4, int count) { if (count < 2) { - return EncodingInfo.UTF_8; + return defaultEncoding; } // UTF-16, with BOM @@ -2434,70 +2440,69 @@ int b1 = b4[1] & 0xFF; if (b0 == 0xFE && b1 == 0xFF) { // UTF-16, big-endian - return EncodingInfo.UTF_16_BIG_ENDIAN_WITH_BOM; + return new Object [] {"UTF-16BE", true}; } if (b0 == 0xFF && b1 == 0xFE) { // UTF-16, little-endian - return EncodingInfo.UTF_16_LITTLE_ENDIAN_WITH_BOM; + return new Object [] {"UTF-16LE", false}; } // default to UTF-8 if we don't have enough bytes to make a // good determination of the encoding if (count < 3) { - return EncodingInfo.UTF_8; + return defaultEncoding; } // UTF-8 with a BOM int b2 = b4[2] & 0xFF; if (b0 == 0xEF && b1 == 0xBB && b2 == 0xBF) { - return EncodingInfo.UTF_8_WITH_BOM; + return defaultEncoding; } // default to UTF-8 if we don't have enough bytes to make a // good determination of the encoding if (count < 4) { - return EncodingInfo.UTF_8; + return defaultEncoding; } // other encodings int b3 = b4[3] & 0xFF; if (b0 == 0x00 && b1 == 0x00 && b2 == 0x00 && b3 == 0x3C) { // UCS-4, big endian (1234) - return EncodingInfo.UCS_4_BIG_ENDIAN; + return new Object [] {"ISO-10646-UCS-4", true}; } if (b0 == 0x3C && b1 == 0x00 && b2 == 0x00 && b3 == 0x00) { // UCS-4, little endian (4321) - return EncodingInfo.UCS_4_LITTLE_ENDIAN; + return new Object [] {"ISO-10646-UCS-4", false}; } if (b0 == 0x00 && b1 == 0x00 && b2 == 0x3C && b3 == 0x00) { // UCS-4, unusual octet order (2143) // REVISIT: What should this be? - return EncodingInfo.UCS_4_UNUSUAL_BYTE_ORDER; + return new Object [] {"ISO-10646-UCS-4", null}; } if (b0 == 0x00 && b1 == 0x3C && b2 == 0x00 && b3 == 0x00) { // UCS-4, unusual octect order (3412) // REVISIT: What should this be? - return EncodingInfo.UCS_4_UNUSUAL_BYTE_ORDER; + return new Object [] {"ISO-10646-UCS-4", null}; } if (b0 == 0x00 && b1 == 0x3C && b2 == 0x00 && b3 == 0x3F) { // UTF-16, big-endian, no BOM // (or could turn out to be UCS-2... // REVISIT: What should this be? - return EncodingInfo.UTF_16_BIG_ENDIAN; + return new Object [] {"UTF-16BE", true}; } if (b0 == 0x3C && b1 == 0x00 && b2 == 0x3F && b3 == 0x00) { // UTF-16, little-endian, no BOM // (or could turn out to be UCS-2... - return EncodingInfo.UTF_16_LITTLE_ENDIAN; + return new Object [] {"UTF-16LE", false}; } if (b0 == 0x4C && b1 == 0x6F && b2 == 0xA7 && b3 == 0x94) { // EBCDIC // a la xerces1, return CP037 instead of EBCDIC here - return EncodingInfo.EBCDIC; + return new Object [] {"CP037", null}; } - // default encoding - return EncodingInfo.UTF_8; + return defaultEncoding; } // getEncodingName(byte[],int):Object[] @@ -2512,95 +2517,95 @@ * encoding name may be a Java encoding name; * otherwise, it is an ianaEncoding name. * @param isBigEndian For encodings (like uCS-4), whose names cannot - * specify a byte order, this tells whether the order - * is bigEndian. null if unknown or irrelevant. + * specify a byte order, this tells whether the order is bigEndian. null menas + * unknown or not relevant. * * @return Returns a reader. */ protected Reader createReader(InputStream inputStream, String encoding, Boolean isBigEndian) - throws IOException { + throws IOException { - String enc = (encoding != null) ? encoding : EncodingInfo.STR_UTF8; - enc = enc.toUpperCase(Locale.ENGLISH); - MessageFormatter f = fErrorReporter.getMessageFormatter(XMLMessageFormatter.XML_DOMAIN); - Locale l = fErrorReporter.getLocale(); - switch (enc) { - case EncodingInfo.STR_UTF8: - return new UTF8Reader(inputStream, fBufferSize, f, l); - case EncodingInfo.STR_UTF16: - if (isBigEndian != null) { - return new UTF16Reader(inputStream, fBufferSize, isBigEndian, f, l); - } - break; - case EncodingInfo.STR_UTF16BE: - return new UTF16Reader(inputStream, fBufferSize, true, f, l); - case EncodingInfo.STR_UTF16LE: - return new UTF16Reader(inputStream, fBufferSize, false, f, l); - case EncodingInfo.STR_UCS4: - if(isBigEndian != null) { - if(isBigEndian) { - return new UCSReader(inputStream, UCSReader.UCS4BE); - } else { - return new UCSReader(inputStream, UCSReader.UCS4LE); - } + // normalize encoding name + if (encoding == null) { + encoding = "UTF-8"; + } + + // try to use an optimized reader + String ENCODING = encoding.toUpperCase(Locale.ENGLISH); + if (ENCODING.equals("UTF-8")) { + if (DEBUG_ENCODINGS) { + System.out.println("$$$ creating UTF8Reader"); + } + return new UTF8Reader(inputStream, fBufferSize, fErrorReporter.getMessageFormatter(XMLMessageFormatter.XML_DOMAIN), fErrorReporter.getLocale() ); + } + if (ENCODING.equals("US-ASCII")) { + if (DEBUG_ENCODINGS) { + System.out.println("$$$ creating ASCIIReader"); + } + return new ASCIIReader(inputStream, fBufferSize, fErrorReporter.getMessageFormatter(XMLMessageFormatter.XML_DOMAIN), fErrorReporter.getLocale()); + } + if(ENCODING.equals("ISO-10646-UCS-4")) { + if(isBigEndian != null) { + boolean isBE = isBigEndian.booleanValue(); + if(isBE) { + return new UCSReader(inputStream, UCSReader.UCS4BE); } else { - fErrorReporter.reportError(this.getEntityScanner(), - XMLMessageFormatter.XML_DOMAIN, - "EncodingByteOrderUnsupported", - new Object[] { encoding }, - XMLErrorReporter.SEVERITY_FATAL_ERROR); + return new UCSReader(inputStream, UCSReader.UCS4LE); } - break; - case EncodingInfo.STR_UCS2: - if(isBigEndian != null) { - if(isBigEndian) { - return new UCSReader(inputStream, UCSReader.UCS2BE); - } else { - return new UCSReader(inputStream, UCSReader.UCS2LE); - } + } else { + fErrorReporter.reportError(this.getEntityScanner(),XMLMessageFormatter.XML_DOMAIN, + "EncodingByteOrderUnsupported", + new Object[] { encoding }, + XMLErrorReporter.SEVERITY_FATAL_ERROR); + } + } + if(ENCODING.equals("ISO-10646-UCS-2")) { + if(isBigEndian != null) { // sould never happen with this encoding... + boolean isBE = isBigEndian.booleanValue(); + if(isBE) { + return new UCSReader(inputStream, UCSReader.UCS2BE); } else { - fErrorReporter.reportError(this.getEntityScanner(), - XMLMessageFormatter.XML_DOMAIN, - "EncodingByteOrderUnsupported", - new Object[] { encoding }, - XMLErrorReporter.SEVERITY_FATAL_ERROR); + return new UCSReader(inputStream, UCSReader.UCS2LE); } - break; + } else { + fErrorReporter.reportError(this.getEntityScanner(),XMLMessageFormatter.XML_DOMAIN, + "EncodingByteOrderUnsupported", + new Object[] { encoding }, + XMLErrorReporter.SEVERITY_FATAL_ERROR); + } } // check for valid name boolean validIANA = XMLChar.isValidIANAEncoding(encoding); boolean validJava = XMLChar.isValidJavaEncoding(encoding); if (!validIANA || (fAllowJavaEncodings && !validJava)) { - fErrorReporter.reportError(this.getEntityScanner(), - XMLMessageFormatter.XML_DOMAIN, + fErrorReporter.reportError(this.getEntityScanner(),XMLMessageFormatter.XML_DOMAIN, "EncodingDeclInvalid", new Object[] { encoding }, XMLErrorReporter.SEVERITY_FATAL_ERROR); - // NOTE: AndyH suggested that, on failure, we use ISO Latin 1 - // because every byte is a valid ISO Latin 1 character. - // It may not translate correctly but if we failed on - // the encoding anyway, then we're expecting the content - // of the document to be bad. This will just prevent an - // invalid UTF-8 sequence to be detected. This is only - // important when continue-after-fatal-error is turned - // on. -Ac + // NOTE: AndyH suggested that, on failure, we use ISO Latin 1 + // because every byte is a valid ISO Latin 1 character. + // It may not translate correctly but if we failed on + // the encoding anyway, then we're expecting the content + // of the document to be bad. This will just prevent an + // invalid UTF-8 sequence to be detected. This is only + // important when continue-after-fatal-error is turned + // on. -Ac encoding = "ISO-8859-1"; } // try to use a Java reader - String javaEncoding = EncodingMap.getIANA2JavaMapping(enc); + String javaEncoding = EncodingMap.getIANA2JavaMapping(ENCODING); if (javaEncoding == null) { - if (fAllowJavaEncodings) { + if(fAllowJavaEncodings) { javaEncoding = encoding; } else { - fErrorReporter.reportError(this.getEntityScanner(), - XMLMessageFormatter.XML_DOMAIN, + fErrorReporter.reportError(this.getEntityScanner(),XMLMessageFormatter.XML_DOMAIN, "EncodingDeclInvalid", new Object[] { encoding }, XMLErrorReporter.SEVERITY_FATAL_ERROR); - // see comment above. - javaEncoding = "ISO8859_1"; + // see comment above. + javaEncoding = "ISO8859_1"; } } if (DEBUG_ENCODINGS) { @@ -2893,78 +2898,108 @@ } // print() /** - * Information about auto-detectable encodings. + * Buffer used in entity manager to reuse character arrays instead + * of creating new ones every time. + * + * @xerces.internal + * + * @author Ankit Pasricha, IBM + */ + private static class CharacterBuffer { + + /** character buffer */ + private char[] ch; + + /** whether the buffer is for an external or internal scanned entity */ + private boolean isExternal; + + public CharacterBuffer(boolean isExternal, int size) { + this.isExternal = isExternal; + ch = new char[size]; + } + } + + + /** + * Stores a number of character buffers and provides it to the entity + * manager to use when an entity is seen. * * @xerces.internal * - * @author Michael Glavassevich, IBM + * @author Ankit Pasricha, IBM */ - private static class EncodingInfo { - public static final String STR_UTF8 = "UTF-8"; - public static final String STR_UTF16 = "UTF-16"; - public static final String STR_UTF16BE = "UTF-16BE"; - public static final String STR_UTF16LE = "UTF-16LE"; - public static final String STR_UCS4 = "ISO-10646-UCS-4"; - public static final String STR_UCS2 = "ISO-10646-UCS-2"; - public static final String STR_CP037 = "CP037"; - - /** UTF-8 **/ - public static final EncodingInfo UTF_8 = - new EncodingInfo(STR_UTF8, null, false); - - /** UTF-8, with BOM **/ - public static final EncodingInfo UTF_8_WITH_BOM = - new EncodingInfo(STR_UTF8, null, true); - - /** UTF-16, big-endian **/ - public static final EncodingInfo UTF_16_BIG_ENDIAN = - new EncodingInfo(STR_UTF16BE, STR_UTF16, Boolean.TRUE, false); - - /** UTF-16, big-endian with BOM **/ - public static final EncodingInfo UTF_16_BIG_ENDIAN_WITH_BOM = - new EncodingInfo(STR_UTF16BE, STR_UTF16, Boolean.TRUE, true); - - /** UTF-16, little-endian **/ - public static final EncodingInfo UTF_16_LITTLE_ENDIAN = - new EncodingInfo(STR_UTF16LE, STR_UTF16, Boolean.FALSE, false); - - /** UTF-16, little-endian with BOM **/ - public static final EncodingInfo UTF_16_LITTLE_ENDIAN_WITH_BOM = - new EncodingInfo(STR_UTF16LE, STR_UTF16, Boolean.FALSE, true); - - /** UCS-4, big-endian **/ - public static final EncodingInfo UCS_4_BIG_ENDIAN = - new EncodingInfo(STR_UCS4, Boolean.TRUE, false); - - /** UCS-4, little-endian **/ - public static final EncodingInfo UCS_4_LITTLE_ENDIAN = - new EncodingInfo(STR_UCS4, Boolean.FALSE, false); - - /** UCS-4, unusual byte-order (2143) or (3412) **/ - public static final EncodingInfo UCS_4_UNUSUAL_BYTE_ORDER = - new EncodingInfo(STR_UCS4, null, false); - - /** EBCDIC **/ - public static final EncodingInfo EBCDIC = new EncodingInfo(STR_CP037, null, false); - - public final String autoDetectedEncoding; - public final String readerEncoding; - public final Boolean isBigEndian; - public final boolean hasBOM; - - private EncodingInfo(String autoDetectedEncoding, Boolean isBigEndian, boolean hasBOM) { - this(autoDetectedEncoding, autoDetectedEncoding, isBigEndian, hasBOM); - } // (String,Boolean,boolean) - - private EncodingInfo(String autoDetectedEncoding, String readerEncoding, - Boolean isBigEndian, boolean hasBOM) { - this.autoDetectedEncoding = autoDetectedEncoding; - this.readerEncoding = readerEncoding; - this.isBigEndian = isBigEndian; - this.hasBOM = hasBOM; - } // (String,String,Boolean,boolean) + private static class CharacterBufferPool { + + private static final int DEFAULT_POOL_SIZE = 3; + + private CharacterBuffer[] fInternalBufferPool; + private CharacterBuffer[] fExternalBufferPool; - } // class EncodingInfo + private int fExternalBufferSize; + private int fInternalBufferSize; + private int poolSize; + + private int fInternalTop; + private int fExternalTop; + + public CharacterBufferPool(int externalBufferSize, int internalBufferSize) { + this(DEFAULT_POOL_SIZE, externalBufferSize, internalBufferSize); + } + + public CharacterBufferPool(int poolSize, int externalBufferSize, int internalBufferSize) { + fExternalBufferSize = externalBufferSize; + fInternalBufferSize = internalBufferSize; + this.poolSize = poolSize; + init(); + } + + /** Initializes buffer pool. **/ + private void init() { + fInternalBufferPool = new CharacterBuffer[poolSize]; + fExternalBufferPool = new CharacterBuffer[poolSize]; + fInternalTop = -1; + fExternalTop = -1; + } + + /** Retrieves buffer from pool. **/ + public CharacterBuffer getBuffer(boolean external) { + if (external) { + if (fExternalTop > -1) { + return fExternalBufferPool[fExternalTop--]; + } + else { + return new CharacterBuffer(true, fExternalBufferSize); + } + } + else { + if (fInternalTop > -1) { + return fInternalBufferPool[fInternalTop--]; + } + else { + return new CharacterBuffer(false, fInternalBufferSize); + } + } + } + + /** Returns buffer to pool. **/ + public void returnToPool(CharacterBuffer buffer) { + if (buffer.isExternal) { + if (fExternalTop < fExternalBufferPool.length - 1) { + fExternalBufferPool[++fExternalTop] = buffer; + } + } + else if (fInternalTop < fInternalBufferPool.length - 1) { + fInternalBufferPool[++fInternalTop] = buffer; + } + } + + /** Sets the size of external buffers and dumps the old pool. **/ + public void setExternalBufferSize(int bufferSize) { + fExternalBufferSize = bufferSize; + fExternalBufferPool = new CharacterBuffer[poolSize]; + fExternalTop = -1; + } + } /** * This class wraps the byte inputstreams we're presented with. @@ -3017,13 +3052,20 @@ fOffset = fStartOffset; } - public int readAndBuffer() throws IOException { + public int read() throws IOException { + int b = 0; + if (fOffset < fLength) { + return fData[fOffset++] & 0xff; + } + if (fOffset == fEndOffset) { + return -1; + } if (fOffset == fData.length) { byte[] newData = new byte[fOffset << 1]; System.arraycopy(fData, 0, newData, 0, fOffset); fData = newData; } - final int b = fInputStream.read(); + b = fInputStream.read(); if (b == -1) { fEndOffset = fOffset; return -1; @@ -3033,27 +3075,18 @@ return b & 0xff; } - public int read() throws IOException { - if (fOffset < fLength) { - return fData[fOffset++] & 0xff; - } - if (fOffset == fEndOffset) { - return -1; - } - if (fCurrentEntity.mayReadChunks) { - return fInputStream.read(); - } - return readAndBuffer(); - } - public int read(byte[] b, int off, int len) throws IOException { - final int bytesLeft = fLength - fOffset; + int bytesLeft = fLength - fOffset; if (bytesLeft == 0) { if (fOffset == fEndOffset) { return -1; } - // read a block of data as requested + /** + * //System.out.println("fCurrentEntitty = " + fCurrentEntity ); + * //System.out.println("fInputStream = " + fInputStream ); + * // better get some more for the voracious reader... */ + if(fCurrentEntity.mayReadChunks || !fCurrentEntity.xmlDeclChunkRead) { if (!fCurrentEntity.xmlDeclChunkRead) @@ -3063,13 +3096,15 @@ } return fInputStream.read(b, off, len); } - int returnedVal = readAndBuffer(); - if (returnedVal == -1) { - fEndOffset = fOffset; - return -1; + + int returnedVal = read(); + if(returnedVal == -1) { + fEndOffset = fOffset; + return -1; } b[off] = (byte)returnedVal; return 1; + } if (len < bytesLeft) { if (len <= 0) { @@ -3085,7 +3120,8 @@ return len; } - public long skip(long n) throws IOException { + public long skip(long n) + throws IOException { int bytesLeft; if (n <= 0) { return 0; @@ -3106,7 +3142,7 @@ return bytesLeft; } n -= bytesLeft; - /* + /* * In a manner of speaking, when this class isn't permitting more * than one byte at a time to be read, it is "blocking". The * available() method should indicate how much can be read without @@ -3118,13 +3154,13 @@ } public int available() throws IOException { - final int bytesLeft = fLength - fOffset; + int bytesLeft = fLength - fOffset; if (bytesLeft == 0) { if (fOffset == fEndOffset) { return -1; } return fCurrentEntity.mayReadChunks ? fInputStream.available() - : 0; + : 0; } return bytesLeft; } @@ -3135,6 +3171,7 @@ public void reset() { fOffset = fMark; + //test(); } public boolean markSupported() { --- /dev/null 2019-04-27 15:49:57.376009302 +0200 +++ new/src/jdk.accessibility/windows/native/common/AccessBridgeStatusWindow.RC 2019-05-21 01:01:58.301080536 +0200 @@ -0,0 +1,174 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" +#include "accessBridgeResource.h" + +#define XSTR(x) STR(x) +#define STR(x) #x + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#define APSTUDIO_HIDDEN_SYMBOLS +#include "windows.h" +#undef APSTUDIO_HIDDEN_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +ACCESSBRIDGESTATUSWINDOW DIALOGEX 160, 78, 209, 163 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +EXSTYLE WS_EX_CLIENTEDGE +CAPTION "Access Bridge status" +FONT 8, "MS Sans Serif", 0, 0, 0x1 +BEGIN + EDITTEXT cVMID,67,23,121,13,ES_READONLY + EDITTEXT cStatusText,40,147,162,13,ES_READONLY + LTEXT "Java VM ID:",IDC_STATIC,23,25,40,8 + LTEXT "Status:",IDC_STATIC,11,149,23,8 + EDITTEXT cWindowsID,67,39,121,13,ES_READONLY + LTEXT "Windows ID:",IDC_STATIC,21,41,42,8 + EDITTEXT cCallInfo,12,65,184,75,ES_MULTILINE | ES_AUTOVSCROLL | + ES_AUTOHSCROLL | ES_READONLY | WS_VSCROLL + GROUPBOX "Call info",IDC_STATIC,4,55,197,90 + EDITTEXT cInvokedByText,67,1,121,13,ES_READONLY + LTEXT "Invoked by:",IDC_STATIC,25,3,38,8 +END + +IDD_DIALOG1 DIALOG DISCARDABLE 0, 0, 186, 95 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Dialog" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,129,7,50,14 + PUSHBUTTON "Cancel",IDCANCEL,129,24,50,14 +END + + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "#define APSTUDIO_HIDDEN_SYMBOLS\r\n" + "#include ""windows.h""\r\n" + "#undef APSTUDIO_HIDDEN_SYMBOLS\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO DISCARDABLE +BEGIN + "ACCESSBRIDGESTATUSWINDOW", DIALOG + BEGIN + LEFTMARGIN, 4 + RIGHTMARGIN, 202 + BOTTOMMARGIN, 160 + END + + "IDD_DIALOG1", DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 179 + TOPMARGIN, 7 + BOTTOMMARGIN, 88 + END +END +#endif // APSTUDIO_INVOKED + + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION JDK_FVER + PRODUCTVERSION JDK_FVER + FILEFLAGSMASK 0x3fL +#ifdef DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE JDK_FTYPE + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "Comments", "Java Access Bridge\0" + VALUE "CompanyName", XSTR(JDK_COMPANY) "\0" + VALUE "FileDescription", XSTR(JDK_COMPONENT) "\0" + VALUE "FileVersion", XSTR(JDK_VER) "\0" + VALUE "Full Version", XSTR(JDK_VERSION_STRING) "\0" + VALUE "InternalName", XSTR(JDK_INTERNAL_NAME) "\0" + VALUE "LegalCopyright", XSTR(JDK_COPYRIGHT) "\0" + VALUE "OriginalFilename", XSTR(JDK_FNAME) "\0" + VALUE "ProductName", XSTR(JDK_NAME) "\0" + VALUE "ProductVersion", XSTR(JDK_VER) "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + +#endif // !_MAC + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED --- old/src/jdk.accessibility/windows/native/common/AccessBridgeStatusWindow.rc 2019-05-21 01:01:58.689079840 +0200 +++ /dev/null 2019-04-27 15:49:57.376009302 +0200 @@ -1,174 +0,0 @@ -//Microsoft Developer Studio generated resource script. -// -#include "resource.h" -#include "accessBridgeResource.h" - -#define XSTR(x) STR(x) -#define STR(x) #x - -#define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -#define APSTUDIO_HIDDEN_SYMBOLS -#include "windows.h" -#undef APSTUDIO_HIDDEN_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -// English (U.S.) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) -#ifdef _WIN32 -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US -#pragma code_page(1252) -#endif //_WIN32 - -///////////////////////////////////////////////////////////////////////////// -// -// Dialog -// - -ACCESSBRIDGESTATUSWINDOW DIALOGEX 160, 78, 209, 163 -STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU -EXSTYLE WS_EX_CLIENTEDGE -CAPTION "Access Bridge status" -FONT 8, "MS Sans Serif", 0, 0, 0x1 -BEGIN - EDITTEXT cVMID,67,23,121,13,ES_READONLY - EDITTEXT cStatusText,40,147,162,13,ES_READONLY - LTEXT "Java VM ID:",IDC_STATIC,23,25,40,8 - LTEXT "Status:",IDC_STATIC,11,149,23,8 - EDITTEXT cWindowsID,67,39,121,13,ES_READONLY - LTEXT "Windows ID:",IDC_STATIC,21,41,42,8 - EDITTEXT cCallInfo,12,65,184,75,ES_MULTILINE | ES_AUTOVSCROLL | - ES_AUTOHSCROLL | ES_READONLY | WS_VSCROLL - GROUPBOX "Call info",IDC_STATIC,4,55,197,90 - EDITTEXT cInvokedByText,67,1,121,13,ES_READONLY - LTEXT "Invoked by:",IDC_STATIC,25,3,38,8 -END - -IDD_DIALOG1 DIALOG DISCARDABLE 0, 0, 186, 95 -STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Dialog" -FONT 8, "MS Sans Serif" -BEGIN - DEFPUSHBUTTON "OK",IDOK,129,7,50,14 - PUSHBUTTON "Cancel",IDCANCEL,129,24,50,14 -END - - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -1 TEXTINCLUDE DISCARDABLE -BEGIN - "resource.h\0" -END - -2 TEXTINCLUDE DISCARDABLE -BEGIN - "#define APSTUDIO_HIDDEN_SYMBOLS\r\n" - "#include ""windows.h""\r\n" - "#undef APSTUDIO_HIDDEN_SYMBOLS\r\n" - "\0" -END - -3 TEXTINCLUDE DISCARDABLE -BEGIN - "\r\n" - "\0" -END - -#endif // APSTUDIO_INVOKED - - -///////////////////////////////////////////////////////////////////////////// -// -// DESIGNINFO -// - -#ifdef APSTUDIO_INVOKED -GUIDELINES DESIGNINFO DISCARDABLE -BEGIN - "ACCESSBRIDGESTATUSWINDOW", DIALOG - BEGIN - LEFTMARGIN, 4 - RIGHTMARGIN, 202 - BOTTOMMARGIN, 160 - END - - "IDD_DIALOG1", DIALOG - BEGIN - LEFTMARGIN, 7 - RIGHTMARGIN, 179 - TOPMARGIN, 7 - BOTTOMMARGIN, 88 - END -END -#endif // APSTUDIO_INVOKED - - -#ifndef _MAC -///////////////////////////////////////////////////////////////////////////// -// -// Version -// - -VS_VERSION_INFO VERSIONINFO - FILEVERSION JDK_FVER - PRODUCTVERSION JDK_FVER - FILEFLAGSMASK 0x3fL -#ifdef DEBUG - FILEFLAGS 0x1L -#else - FILEFLAGS 0x0L -#endif - FILEOS 0x40004L - FILETYPE JDK_FTYPE - FILESUBTYPE 0x0L -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "040904b0" - BEGIN - VALUE "Comments", "Java Access Bridge" "\0" - VALUE "CompanyName", XSTR(JDK_COMPANY) "\0" - VALUE "FileDescription", XSTR(JDK_FILEDESC) "\0" - VALUE "FileVersion", XSTR(JDK_VER) "\0" - VALUE "Full Version", XSTR(JDK_VERSION_STRING) "\0" - VALUE "InternalName", XSTR(JDK_INTERNAL_NAME) "\0" - VALUE "LegalCopyright", XSTR(JDK_COPYRIGHT) "\0" - VALUE "OriginalFilename", XSTR(JDK_FNAME) "\0" - VALUE "ProductName", XSTR(JDK_NAME) "\0" - VALUE "ProductVersion", XSTR(JDK_VER) "\0" - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x409, 1200 - END -END - -#endif // !_MAC - -#endif // English (U.S.) resources -///////////////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// - - -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED --- old/src/jdk.accessibility/windows/native/common/resource.h 2019-05-21 01:01:58.869079517 +0200 +++ new/src/jdk.accessibility/windows/native/common/resource.h 2019-05-21 01:01:58.709079804 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,7 @@ //{{NO_DEPENDENCIES}} // Microsoft Developer Studio generated include file. -// Used by AccessBridgeStatusWindow.rc +// Used by AccessBridgeStatusWindow.RC // //#define IDB_BITMAP1 102 --- old/src/jdk.accessibility/windows/native/jaccessinspector/jaccessinspectorWindow.rc 2019-05-21 01:01:59.065079165 +0200 +++ new/src/jdk.accessibility/windows/native/jaccessinspector/jaccessinspectorWindow.rc 2019-05-21 01:01:58.909079445 +0200 @@ -199,15 +199,15 @@ BEGIN BLOCK "000004b0" BEGIN - VALUE "CompanyName", XSTR(JDK_COMPANY) "\0" - VALUE "FileDescription", XSTR(JDK_FILEDESC) "\0" - VALUE "FileVersion", XSTR(JDK_VER) "\0" + VALUE "CompanyName", XSTR(JDK_COMPANY) "\0" + VALUE "FileDescription", XSTR(JDK_COMPONENT) "\0" + VALUE "FileVersion", XSTR(JDK_VER) "\0" VALUE "Full Version", XSTR(JDK_VERSION_STRING) "\0" - VALUE "InternalName", XSTR(JDK_INTERNAL_NAME) "\0" - VALUE "LegalCopyright", XSTR(JDK_COPYRIGHT) "\0" - VALUE "OriginalFilename", XSTR(JDK_FNAME) "\0" - VALUE "ProductName", XSTR(JDK_NAME) "\0" - VALUE "ProductVersion", XSTR(JDK_VER) "\0" + VALUE "InternalName", XSTR(JDK_INTERNAL_NAME) "\0" + VALUE "LegalCopyright", XSTR(JDK_COPYRIGHT) "\0" + VALUE "OriginalFilename", XSTR(JDK_FNAME) "\0" + VALUE "ProductName", XSTR(JDK_NAME) "\0" + VALUE "ProductVersion", XSTR(JDK_VER) "\0" END END BLOCK "VarFileInfo" --- old/src/jdk.accessibility/windows/native/jaccesswalker/jaccesswalkerWindow.rc 2019-05-21 01:01:59.269078800 +0200 +++ new/src/jdk.accessibility/windows/native/jaccesswalker/jaccesswalkerWindow.rc 2019-05-21 01:01:59.109079086 +0200 @@ -164,15 +164,15 @@ BEGIN BLOCK "000004b0" BEGIN - VALUE "CompanyName", XSTR(JDK_COMPANY) "\0" - VALUE "FileDescription", XSTR(JDK_FILEDESC) "\0" - VALUE "FileVersion", XSTR(JDK_VER) "\0" + VALUE "CompanyName", XSTR(JDK_COMPANY) "\0" + VALUE "FileDescription", XSTR(JDK_COMPONENT) "\0" + VALUE "FileVersion", XSTR(JDK_VER) "\0" VALUE "Full Version", XSTR(JDK_VERSION_STRING) "\0" - VALUE "InternalName", XSTR(JDK_INTERNAL_NAME) "\0" - VALUE "LegalCopyright", XSTR(JDK_COPYRIGHT) "\0" - VALUE "OriginalFilename", XSTR(JDK_FNAME) "\0" - VALUE "ProductName", XSTR(JDK_NAME) "\0" - VALUE "ProductVersion", XSTR(JDK_VER) "\0" + VALUE "InternalName", XSTR(JDK_INTERNAL_NAME) "\0" + VALUE "LegalCopyright", XSTR(JDK_COPYRIGHT) "\0" + VALUE "OriginalFilename", XSTR(JDK_FNAME) "\0" + VALUE "ProductName", XSTR(JDK_NAME) "\0" + VALUE "ProductVersion", XSTR(JDK_VER) "\0" END END BLOCK "VarFileInfo" --- old/src/jdk.compiler/share/classes/com/sun/source/util/JavacTask.java 2019-05-21 01:01:59.473078434 +0200 +++ new/src/jdk.compiler/share/classes/com/sun/source/util/JavacTask.java 2019-05-21 01:01:59.313078721 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,7 +29,6 @@ import javax.annotation.processing.ProcessingEnvironment; import javax.lang.model.element.Element; -import javax.lang.model.element.VariableElement; import javax.lang.model.type.TypeMirror; import javax.lang.model.util.Elements; import javax.lang.model.util.Types; @@ -138,27 +137,6 @@ public abstract void removeTaskListener(TaskListener taskListener); /** - * Sets the specified {@link ParameterNameProvider}. It may be used when - * {@link VariableElement#getSimpleName()} is called for a method parameter - * for which an authoritative name is not found. The given - * {@code ParameterNameProvider} may infer a user-friendly name - * for the method parameter. - * - * Setting a new {@code ParameterNameProvider} will clear any previously set - * {@code ParameterNameProvider}, which won't be queried any more. - * - * When no {@code ParameterNameProvider} is set, or when it returns null from - * {@link ParameterNameProvider#getParameterName(javax.lang.model.element.VariableElement)}, - * an automatically synthesized name is returned from {@code VariableElement.getSimpleName()}. - * - * @implSpec The default implementation of this method does nothing. - * - * @param provider the provider. - * @since 13 - */ - public void setParameterNameProvider(ParameterNameProvider provider) {} - - /** * Returns a type mirror of the tree node determined by the specified path. * This method has been superceded by methods on * {@link com.sun.source.util.Trees Trees}. --- old/src/jdk.compiler/share/classes/com/sun/source/util/ParameterNameProvider.java 2019-05-21 01:01:59.669078082 +0200 +++ /dev/null 2019-04-27 15:49:57.376009302 +0200 @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2019, 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 com.sun.source.util; - -import javax.lang.model.element.VariableElement; - -/** - * A provider for parameter names when the parameter names are not determined from - * a reliable source, like a classfile. - * - * @since 13 - */ -public interface ParameterNameProvider { - - /** - * Infer a parameter name for the given parameter. The implementations of this method - * should infer parameter names in such a way that the parameter names are distinct - * for any given owning method. - * - * If the implementation of this method returns null, an automatically synthesized name is used. - * - * @param parameter the parameter for which the name should be inferred. - * @return a user-friendly name for the parameter, or null if unknown - */ - public CharSequence getParameterName(VariableElement parameter); - -} --- old/src/jdk.compiler/share/classes/com/sun/tools/javac/api/BasicJavacTask.java 2019-05-21 01:01:59.837077781 +0200 +++ new/src/jdk.compiler/share/classes/com/sun/tools/javac/api/BasicJavacTask.java 2019-05-21 01:01:59.685078054 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2019, 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 @@ -43,11 +43,9 @@ import com.sun.source.tree.CompilationUnitTree; import com.sun.source.tree.Tree; import com.sun.source.util.JavacTask; -import com.sun.source.util.ParameterNameProvider; import com.sun.source.util.Plugin; import com.sun.source.util.TaskListener; import com.sun.tools.doclint.DocLint; -import com.sun.tools.javac.code.MissingInfoHandler; import com.sun.tools.javac.main.JavaCompiler; import com.sun.tools.javac.model.JavacElements; import com.sun.tools.javac.model.JavacTypes; @@ -125,11 +123,6 @@ mtl.remove(taskListener); } - @Override - public void setParameterNameProvider(ParameterNameProvider handler) { - MissingInfoHandler.instance(context).setDelegate(handler); - } - public Collection getTaskListeners() { MultiTaskListener mtl = MultiTaskListener.instance(context); return mtl.getTaskListeners(); --- old/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Flags.java 2019-05-21 01:02:00.029077437 +0200 +++ new/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Flags.java 2019-05-21 01:01:59.877077710 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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 @@ -319,11 +319,6 @@ */ public static final long BODY_ONLY_FINALIZE = 1L<<17; //blocks only - /** - * Flag to indicate the given ParamSymbol has a user-friendly name filled. - */ - public static final long NAME_FILLED = 1L<<58; //ParamSymbols only - /** Modifier masks. */ public static final int @@ -440,8 +435,7 @@ DEPRECATED_REMOVAL(Flags.DEPRECATED_REMOVAL), HAS_RESOURCE(Flags.HAS_RESOURCE), POTENTIALLY_AMBIGUOUS(Flags.POTENTIALLY_AMBIGUOUS), - ANONCONSTR_BASED(Flags.ANONCONSTR_BASED), - NAME_FILLED(Flags.NAME_FILLED); + ANONCONSTR_BASED(Flags.ANONCONSTR_BASED); Flag(long flag) { this.value = flag; --- old/src/jdk.compiler/share/classes/com/sun/tools/javac/code/MissingInfoHandler.java 2019-05-21 01:02:00.221077093 +0200 +++ /dev/null 2019-04-27 15:49:57.376009302 +0200 @@ -1,75 +0,0 @@ -/* - * Copyright (c) 2019, 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 com.sun.tools.javac.code; - -import com.sun.source.util.ParameterNameProvider; -import com.sun.tools.javac.code.Symbol.ParamSymbol; -import com.sun.tools.javac.util.Context; -import com.sun.tools.javac.util.Name; -import com.sun.tools.javac.util.Names; - -/** - * A Context class, that can return additional useful information for Symbols, currently - * parameter names. It does so by calling user-supplied {@link ParameterNameProvider}. - * - *

This is NOT part of any supported API. - * If you write code that depends on this, you do so at your own risk. - * This code and its internal interfaces are subject to change or - * deletion without notice. - */ -public class MissingInfoHandler { - protected static final Context.Key missingInfoHandlerWrapperKey = new Context.Key<>(); - - public static MissingInfoHandler instance(Context context) { - MissingInfoHandler instance = context.get(missingInfoHandlerWrapperKey); - if (instance == null) - instance = new MissingInfoHandler(context); - return instance; - } - - private final Names names; - private ParameterNameProvider parameterNameProvider; - - protected MissingInfoHandler(Context context) { - context.put(missingInfoHandlerWrapperKey, this); - names = Names.instance(context); - } - - public Name getParameterName(ParamSymbol parameter) { - if (parameterNameProvider != null) { - CharSequence name = parameterNameProvider.getParameterName(parameter); - if (name != null) { - return names.fromString(name.toString()); - } - } - - return null; - } - - public void setDelegate(ParameterNameProvider delegate) { - this.parameterNameProvider = delegate; - } -} --- old/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Source.java 2019-05-21 01:02:00.389076792 +0200 +++ new/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Source.java 2019-05-21 01:02:00.241077057 +0200 @@ -188,7 +188,9 @@ IMPORT_ON_DEMAND_OBSERVABLE_PACKAGES(JDK1_2, JDK8), SWITCH_MULTIPLE_CASE_LABELS(JDK13, Fragments.FeatureMultipleCaseLabels, DiagKind.PLURAL), SWITCH_RULE(JDK13, Fragments.FeatureSwitchRules, DiagKind.PLURAL), - SWITCH_EXPRESSION(JDK13, Fragments.FeatureSwitchExpressions, DiagKind.PLURAL); + SWITCH_EXPRESSION(JDK13, Fragments.FeatureSwitchExpressions, DiagKind.PLURAL), + CONDY_FOR_LAMBDA(JDK13), + CONSTABLES(JDK13); enum DiagKind { NORMAL, --- old/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java 2019-05-21 01:02:00.581076448 +0200 +++ new/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symbol.java 2019-05-21 01:02:00.433076713 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -48,14 +48,16 @@ import javax.tools.JavaFileManager; import javax.tools.JavaFileObject; +import com.sun.tools.javac.code.ClassFinder.BadEnclosingMethodAttr; +import com.sun.tools.javac.code.Directive.RequiresFlag; import com.sun.tools.javac.code.Kinds.Kind; import com.sun.tools.javac.comp.Annotate.AnnotationTypeMetadata; +import com.sun.tools.javac.code.Scope.WriteableScope; import com.sun.tools.javac.code.Type.*; import com.sun.tools.javac.comp.Attr; import com.sun.tools.javac.comp.AttrContext; import com.sun.tools.javac.comp.Env; import com.sun.tools.javac.jvm.*; -import com.sun.tools.javac.jvm.PoolConstant; import com.sun.tools.javac.tree.JCTree.JCFieldAccess; import com.sun.tools.javac.tree.JCTree.JCVariableDecl; import com.sun.tools.javac.tree.JCTree.Tag; @@ -66,12 +68,8 @@ import static com.sun.tools.javac.code.Flags.*; import static com.sun.tools.javac.code.Kinds.*; import static com.sun.tools.javac.code.Kinds.Kind.*; -import com.sun.tools.javac.code.MissingInfoHandler; import static com.sun.tools.javac.code.Scope.LookupKind.NON_RECURSIVE; -import com.sun.tools.javac.code.Scope.WriteableScope; -import com.sun.tools.javac.code.Symbol; import static com.sun.tools.javac.code.Symbol.OperatorSymbol.AccessCode.FIRSTASGOP; -import com.sun.tools.javac.code.Type; import static com.sun.tools.javac.code.TypeTag.CLASS; import static com.sun.tools.javac.code.TypeTag.FORALL; import static com.sun.tools.javac.code.TypeTag.TYPEVAR; @@ -80,7 +78,6 @@ import static com.sun.tools.javac.jvm.ByteCodes.lushrl; import static com.sun.tools.javac.jvm.ByteCodes.lxor; import static com.sun.tools.javac.jvm.ByteCodes.string_add; -import com.sun.tools.javac.util.Name; /** Root class for Java symbols. It contains subclasses * for specific sorts of symbols, such as variables, methods and operators, @@ -92,7 +89,7 @@ * This code and its internal interfaces are subject to change or * deletion without notice. */ -public abstract class Symbol extends AnnoConstruct implements PoolConstant, Element { +public abstract class Symbol extends AnnoConstruct implements Element { /** The kind of this symbol. * @see Kinds @@ -287,11 +284,6 @@ this.name = name; } - @Override - public int poolTag() { - throw new AssertionError("Invalid pool entry"); - } - /** Clone this symbol with new owner. * Legal only for fields and methods. */ @@ -410,6 +402,14 @@ return (flags() & ENUM) != 0; } + public boolean isFinal() { + return (flags() & FINAL) != 0; + } + + public boolean isEffectivelyFinal() { + return (flags() & EFFECTIVELY_FINAL) != 0; + } + /** Is this symbol declared (directly or indirectly) local * to a method or variable initializer? * Also includes fields of inner classes which are in @@ -829,7 +829,7 @@ for (Symbol sym : members().getSymbols(NON_RECURSIVE)) { sym.apiComplete(); if ((sym.flags() & SYNTHETIC) == 0 && sym.owner == this && sym.kind != ERR) { - list = list.prepend(sym); + list = list.prepend(sym); } } return list; @@ -977,11 +977,6 @@ this.type = new ModuleType(this); } - @Override - public int poolTag() { - return ClassFile.CONSTANT_Module; - } - @Override @DefinedBy(Api.LANGUAGE_MODEL) public Name getSimpleName() { return Convert.shortName(name); @@ -1148,11 +1143,6 @@ return members_field; } - @Override - public int poolTag() { - return ClassFile.CONSTANT_Package; - } - public long flags() { complete(); return flags_field; @@ -1209,16 +1199,6 @@ } - public static class RootPackageSymbol extends PackageSymbol { - public final MissingInfoHandler missingInfoHandler; - - public RootPackageSymbol(Name name, Symbol owner, MissingInfoHandler missingInfoHandler) { - super(name, owner); - this.missingInfoHandler = missingInfoHandler; - } - - } - /** A class for class symbols */ public static class ClassSymbol extends TypeSymbol implements TypeElement { @@ -1253,6 +1233,10 @@ */ public List trans_local; + /** the constant pool of the class + */ + public Pool pool; + /** the annotation metadata attached to this class */ private AnnotationTypeMetadata annotationTypeMetadata; @@ -1263,6 +1247,7 @@ this.flatname = formFlatName(name, owner); this.sourcefile = null; this.classfile = null; + this.pool = null; this.annotationTypeMetadata = AnnotationTypeMetadata.notAnAnnotationType(); } @@ -1554,11 +1539,6 @@ super(VAR, flags, name, type, owner); } - @Override - public int poolTag() { - return ClassFile.CONSTANT_Fieldref; - } - /** Clone this symbol with new owner. */ public VarSymbol clone(Symbol newOwner) { @@ -1567,11 +1547,6 @@ public Symbol baseSymbol() { return VarSymbol.this; } - - @Override - public Object poolKey(Types types) { - return new Pair<>(newOwner, baseSymbol()); - } }; v.pos = pos; v.adr = adr; @@ -1584,6 +1559,10 @@ return name.toString(); } + public boolean isDynamic() { + return false; + } + public Symbol asMemberOf(Type site, Types types) { return new VarSymbol(flags_field, name, types.memberType(site, this), owner); } @@ -1669,32 +1648,6 @@ } } - public static class ParamSymbol extends VarSymbol { - public ParamSymbol(long flags, Name name, Type type, Symbol owner) { - super(flags, name, type, owner); - } - - @Override - public Name getSimpleName() { - if ((flags_field & NAME_FILLED) == 0) { - flags_field |= NAME_FILLED; - Symbol rootPack = this; - while (rootPack != null && !(rootPack instanceof RootPackageSymbol)) { - rootPack = rootPack.owner; - } - if (rootPack != null) { - Name inferredName = - ((RootPackageSymbol) rootPack).missingInfoHandler.getParameterName(this); - if (inferredName != null) { - this.name = inferredName; - } - } - } - return super.getSimpleName(); - } - - } - /** A class for method symbols. */ public static class MethodSymbol extends Symbol implements ExecutableElement { @@ -1732,11 +1685,6 @@ public Symbol baseSymbol() { return MethodSymbol.this; } - - @Override - public Object poolKey(Types types) { - return new Pair<>(newOwner, baseSymbol()); - } }; m.code = code; return m; @@ -1766,23 +1714,12 @@ } } - @Override - public int poolTag() { - return owner.isInterface() ? - ClassFile.CONSTANT_InterfaceMethodref : ClassFile.CONSTANT_Methodref; - } - public boolean isDynamic() { return false; } - public boolean isHandle() { - return false; - } - - - public MethodHandleSymbol asHandle() { - return new MethodHandleSymbol(this); + public boolean isOwnerAnInterface() { + return (owner.flags_field & INTERFACE) != 0; } /** find a symbol that this (proxy method) symbol implements. @@ -2064,18 +2001,36 @@ public List getThrownTypes() { return asType().getThrownTypes(); } + + public boolean isIntrinsicsLDC() { return false; } + } + + public static class IntrinsicsLDCMethodSymbol extends MethodSymbol { + private Object constant; + + public IntrinsicsLDCMethodSymbol(long flags, Name name, Type type, Symbol owner, Object constant) { + super(flags, name, type, owner); + this.constant = constant; + } + + public Object getConstant() { return constant; } + + @Override + public boolean isIntrinsicsLDC() { return true; } } /** A class for invokedynamic method calls. */ - public static class DynamicMethodSymbol extends MethodSymbol implements Dynamic { + public static class DynamicMethodSymbol extends MethodSymbol { - public LoadableConstant[] staticArgs; - public MethodHandleSymbol bsm; + public Object[] staticArgs; + public MethodSymbol bsm; + public int bsmKind; - public DynamicMethodSymbol(Name name, Symbol owner, MethodHandleSymbol bsm, Type type, LoadableConstant[] staticArgs) { + public DynamicMethodSymbol(Name name, Symbol owner, int bsmKind, MethodSymbol bsm, Type type, Object[] staticArgs) { super(0, name, type, owner); this.bsm = bsm; + this.bsmKind = bsmKind; this.staticArgs = staticArgs; } @@ -2083,81 +2038,24 @@ public boolean isDynamic() { return true; } - - @Override - public LoadableConstant[] staticArgs() { - return staticArgs; - } - - @Override - public MethodHandleSymbol bootstrapMethod() { - return bsm; - } - - @Override - public int poolTag() { - return ClassFile.CONSTANT_InvokeDynamic; - } - - @Override - public Type dynamicType() { - return type; - } } - /** A class for method handles. + /** A class for condy. */ - public static class MethodHandleSymbol extends MethodSymbol implements LoadableConstant { - - private Symbol refSym; + public static class DynamicVarSymbol extends VarSymbol { + public Object[] staticArgs; + public MethodSymbol bsm; + public int bsmKind; - public MethodHandleSymbol(Symbol msym) { - super(msym.flags_field, msym.name, msym.type, msym.owner); - this.refSym = msym; - } - - /** - * Returns the kind associated with this method handle. - */ - public int referenceKind() { - if (refSym.isConstructor()) { - return ClassFile.REF_newInvokeSpecial; - } else { - if (refSym.isStatic()) { - return ClassFile.REF_invokeStatic; - } else if ((refSym.flags() & PRIVATE) != 0) { - return ClassFile.REF_invokeSpecial; - } else if (refSym.enclClass().isInterface()) { - return ClassFile.REF_invokeInterface; - } else { - return ClassFile.REF_invokeVirtual; - } - } - } - - @Override - public int poolTag() { - return ClassFile.CONSTANT_MethodHandle; - } - - @Override - public Object poolKey(Types types) { - return new Pair<>(baseSymbol(), referenceKind()); - } - - @Override - public MethodHandleSymbol asHandle() { - return this; + public DynamicVarSymbol(Name name, Symbol owner, int bsmKind, MethodSymbol bsm, Type type, Object[] staticArgs) { + super(0, name, type, owner); + this.bsm = bsm; + this.bsmKind = bsmKind; + this.staticArgs = staticArgs; } @Override - public Symbol baseSymbol() { - return refSym; - } - - - @Override - public boolean isHandle() { + public boolean isDynamic() { return true; } } @@ -2187,6 +2085,18 @@ return accessCode; } + public OperatorSymbol pre(Types types) { + Assert.check(opcode > ByteCodes.preMask); + return new OperatorSymbol(types.names.empty, type, opcode >> ByteCodes.preShift, owner); + } + + public OperatorSymbol post(Types types) { + Assert.check(opcode > ByteCodes.preMask); + return new OperatorSymbol(types.names.empty, + types.createMethodTypeWithParameters(type, List.of(type.getParameterTypes().head)), + opcode & ByteCodes.preMask, owner); + } + /** Access codes for dereferencing, assignment, * and pre/post increment/decrement. --- old/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symtab.java 2019-05-21 01:02:00.789076074 +0200 +++ new/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Symtab.java 2019-05-21 01:02:00.641076339 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -42,7 +42,6 @@ import com.sun.tools.javac.code.Symbol.MethodSymbol; import com.sun.tools.javac.code.Symbol.ModuleSymbol; import com.sun.tools.javac.code.Symbol.PackageSymbol; -import com.sun.tools.javac.code.Symbol.RootPackageSymbol; import com.sun.tools.javac.code.Symbol.TypeSymbol; import com.sun.tools.javac.code.Symbol.VarSymbol; import com.sun.tools.javac.code.Type.BottomType; @@ -172,8 +171,10 @@ public final Type serializedLambdaType; public final Type varHandleType; public final Type methodHandleType; - public final Type methodHandleLookupType; + public final Type methodHandlesLookupType; + public final Type intrinsicsType; public final Type methodTypeType; + public final Type foldableType; public final Type nativeHeaderType; public final Type throwableType; public final Type errorType; @@ -383,9 +384,7 @@ messages = JavacMessages.instance(context); - MissingInfoHandler missingInfoHandler = MissingInfoHandler.instance(context); - - rootPackage = new RootPackageSymbol(names.empty, null, missingInfoHandler); + rootPackage = new PackageSymbol(names.empty, null); // create the basic builtin symbols unnamedModule = new ModuleSymbol(names.empty, null) { @@ -519,8 +518,10 @@ serializedLambdaType = enterClass("java.lang.invoke.SerializedLambda"); varHandleType = enterClass("java.lang.invoke.VarHandle"); methodHandleType = enterClass("java.lang.invoke.MethodHandle"); - methodHandleLookupType = enterClass("java.lang.invoke.MethodHandles$Lookup"); + methodHandlesLookupType = enterClass("java.lang.invoke.MethodHandles$Lookup"); + intrinsicsType = enterClass("java.lang.invoke.Intrinsics"); methodTypeType = enterClass("java.lang.invoke.MethodType"); + foldableType = enterClass("jdk.internal.lang.annotation.Foldable"); errorType = enterClass("java.lang.Error"); illegalArgumentExceptionType = enterClass("java.lang.IllegalArgumentException"); interruptedExceptionType = enterClass("java.lang.InterruptedException"); --- old/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Type.java 2019-05-21 01:02:00.989075717 +0200 +++ new/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Type.java 2019-05-21 01:02:00.837075989 +0200 @@ -36,10 +36,7 @@ import com.sun.tools.javac.code.Symbol.*; import com.sun.tools.javac.code.TypeMetadata.Entry; import com.sun.tools.javac.code.Types.TypeMapping; -import com.sun.tools.javac.code.Types.UniqueType; import com.sun.tools.javac.comp.Infer.IncorporationAction; -import com.sun.tools.javac.jvm.ClassFile; -import com.sun.tools.javac.jvm.PoolConstant; import com.sun.tools.javac.util.*; import com.sun.tools.javac.util.DefinedBy.Api; @@ -76,7 +73,7 @@ * * @see TypeTag */ -public abstract class Type extends AnnoConstruct implements TypeMirror, PoolConstant { +public abstract class Type extends AnnoConstruct implements TypeMirror { /** * Type metadata, Should be {@code null} for the default value. @@ -128,16 +125,6 @@ */ public TypeSymbol tsym; - @Override - public int poolTag() { - throw new AssertionError("Invalid pool entry"); - } - - @Override - public Object poolKey(Types types) { - return new UniqueType(this, types); - } - /** * Checks if the current type tag is equal to the given tag. * @return true if tag is equal to the current type tag. @@ -190,18 +177,6 @@ return null; } - /** Is this a constant type whose value is false? - */ - public boolean isFalse() { - return false; - } - - /** Is this a constant type whose value is true? - */ - public boolean isTrue() { - return false; - } - /** * Get the representation of this type used for modelling purposes. * By default, this is itself. For ErrorType, a different value @@ -493,14 +468,6 @@ } /** - * The constant value of this type, converted to String - */ - public String stringValue() { - Object cv = Assert.checkNonNull(constValue()); - return cv.toString(); - } - - /** * Override this method with care. For most Type instances this should behave as ==. */ @Override @DefinedBy(Api.LANGUAGE_MODEL) @@ -756,43 +723,6 @@ }; } - /** - * The constant value of this type, converted to String - */ - @Override - public String stringValue() { - Object cv = Assert.checkNonNull(constValue()); - if (tag == BOOLEAN) { - return ((Integer) cv).intValue() == 0 ? "false" : "true"; - } - else if (tag == CHAR) { - return String.valueOf((char) ((Integer) cv).intValue()); - } - else { - return cv.toString(); - } - } - - /** Is this a constant type whose value is false? - */ - @Override - public boolean isFalse() { - return - tag == BOOLEAN && - constValue() != null && - ((Integer)constValue()).intValue() == 0; - } - - /** Is this a constant type whose value is true? - */ - @Override - public boolean isTrue() { - return - tag == BOOLEAN && - constValue() != null && - ((Integer)constValue()).intValue() != 0; - } - @Override @DefinedBy(Api.LANGUAGE_MODEL) public R accept(TypeVisitor v, P p) { return v.visitPrimitive(this, p); @@ -943,7 +873,7 @@ } } - public static class ClassType extends Type implements DeclaredType, LoadableConstant, + public static class ClassType extends Type implements DeclaredType, javax.lang.model.type.ErrorType { /** The enclosing type of this type. If this is the type of an inner @@ -988,10 +918,6 @@ this.interfaces_field = null; } - public int poolTag() { - return ClassFile.CONSTANT_Class; - } - @Override public ClassType cloneWithMetadata(TypeMetadata md) { return new ClassType(outer_field, typarams_field, tsym, md) { @@ -1294,7 +1220,7 @@ } public static class ArrayType extends Type - implements LoadableConstant, javax.lang.model.type.ArrayType { + implements javax.lang.model.type.ArrayType { public Type elemtype; @@ -1314,10 +1240,6 @@ this(that.elemtype, that.tsym, that.getMetadata()); } - public int poolTag() { - return ClassFile.CONSTANT_Class; - } - @Override public ArrayType cloneWithMetadata(TypeMetadata md) { return new ArrayType(elemtype, tsym, md) { @@ -1433,7 +1355,7 @@ } } - public static class MethodType extends Type implements ExecutableType, LoadableConstant { + public static class MethodType extends Type implements ExecutableType { public List argtypes; public Type restype; @@ -1500,11 +1422,6 @@ restype != null && restype.isErroneous(); } - @Override - public int poolTag() { - return ClassFile.CONSTANT_MethodType; - } - public boolean contains(Type elem) { return elem.equalsIgnoreMetadata(this) || contains(argtypes, elem) || restype.contains(elem) || contains(thrown, elem); } @@ -2318,11 +2235,6 @@ } @Override - public String stringValue() { - return "null"; - } - - @Override public boolean isNullOrReference() { return true; } --- old/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeTag.java 2019-05-21 01:02:01.193075350 +0200 +++ new/src/jdk.compiler/share/classes/com/sun/tools/javac/code/TypeTag.java 2019-05-21 01:02:01.045075615 +0200 @@ -42,36 +42,36 @@ public enum TypeTag { /** The tag of the basic type `byte'. */ - BYTE(BYTE_CLASS, BYTE_SUPERCLASSES, true), + BYTE(BYTE_CLASS, BYTE_SUPERCLASSES, true, byte.class), /** The tag of the basic type `char'. */ - CHAR(CHAR_CLASS, CHAR_SUPERCLASSES, true), + CHAR(CHAR_CLASS, CHAR_SUPERCLASSES, true, char.class), /** The tag of the basic type `short'. */ - SHORT(SHORT_CLASS, SHORT_SUPERCLASSES, true), + SHORT(SHORT_CLASS, SHORT_SUPERCLASSES, true, short.class), /** The tag of the basic type `long'. */ - LONG(LONG_CLASS, LONG_SUPERCLASSES, true), + LONG(LONG_CLASS, LONG_SUPERCLASSES, true, long.class), /** The tag of the basic type `float'. */ - FLOAT(FLOAT_CLASS, FLOAT_SUPERCLASSES, true), + FLOAT(FLOAT_CLASS, FLOAT_SUPERCLASSES, true, float.class), /** The tag of the basic type `int'. */ - INT(INT_CLASS, INT_SUPERCLASSES, true), + INT(INT_CLASS, INT_SUPERCLASSES, true, int.class), /** The tag of the basic type `double'. */ - DOUBLE(DOUBLE_CLASS, DOUBLE_CLASS, true), + DOUBLE(DOUBLE_CLASS, DOUBLE_CLASS, true, double.class), /** The tag of the basic type `boolean'. */ - BOOLEAN(0, 0, true), + BOOLEAN(0, 0, true, boolean.class), /** The tag of the type `void'. */ - VOID, + VOID(0, 0, false, void.class), /** The tag of all class and interface types. */ @@ -138,15 +138,17 @@ final int superClasses; final int numericClass; final boolean isPrimitive; + public final Class theClass; private TypeTag() { - this(0, 0, false); + this(0, 0, false, null); } - private TypeTag(int numericClass, int superClasses, boolean isPrimitive) { + private TypeTag(int numericClass, int superClasses, boolean isPrimitive, Class theClass) { this.superClasses = superClasses; this.numericClass = numericClass; this.isPrimitive = isPrimitive; + this.theClass = theClass; } public static class NumericClasses { --- old/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java 2019-05-21 01:02:01.389074999 +0200 +++ new/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java 2019-05-21 01:02:01.237075271 +0200 @@ -48,8 +48,6 @@ import com.sun.tools.javac.comp.Check; import com.sun.tools.javac.comp.Enter; import com.sun.tools.javac.comp.Env; -import com.sun.tools.javac.comp.LambdaToMethod; -import com.sun.tools.javac.jvm.ClassFile; import com.sun.tools.javac.util.*; import static com.sun.tools.javac.code.BoundKind.*; @@ -100,6 +98,8 @@ final Name capturedName; public final Warner noWarnings; + private final boolean doConstantFold; + private final Constables constables; // public static Types instance(Context context) { @@ -122,6 +122,12 @@ messages = JavacMessages.instance(context); diags = JCDiagnostic.Factory.instance(context); noWarnings = new Warner(null); + Options options = Options.instance(context); + String foldingOp = options.get("folding"); + doConstantFold = foldingOp != null ? + foldingOp.equals("true") : + Feature.CONSTABLES.allowedInSource(source); + constables = Constables.instance(context); } // @@ -1321,6 +1327,9 @@ * (v) is native. */ public boolean isSignaturePolymorphic(MethodSymbol msym) { + if (doConstantFold && constables.isIntrinsicsIndy(msym)) { + return true; + } List argtypes = msym.type.getParameterTypes(); return (msym.flags_field & NATIVE) != 0 && (msym.owner == syms.methodHandleType.tsym || msym.owner == syms.varHandleType.tsym) && @@ -5183,29 +5192,6 @@ } } } - - public Type constantType(LoadableConstant c) { - switch (c.poolTag()) { - case ClassFile.CONSTANT_Class: - return syms.classType; - case ClassFile.CONSTANT_String: - return syms.stringType; - case ClassFile.CONSTANT_Integer: - return syms.intType; - case ClassFile.CONSTANT_Float: - return syms.floatType; - case ClassFile.CONSTANT_Long: - return syms.longType; - case ClassFile.CONSTANT_Double: - return syms.doubleType; - case ClassFile.CONSTANT_MethodHandle: - return syms.methodHandleType; - case ClassFile.CONSTANT_MethodType: - return syms.methodTypeType; - default: - throw new AssertionError("Not a loadable constant: " + c.poolTag()); - } - } // public void newRound() { --- old/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java 2019-05-21 01:02:01.609074604 +0200 +++ new/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java 2019-05-21 01:02:01.457074876 +0200 @@ -1701,7 +1701,7 @@ falsetype.constValue() != null && !owntype.hasTag(NONE)) { //constant folding - owntype = cfolder.coerce(condtype.isTrue() ? truetype : falsetype, owntype); + owntype = cfolder.coerce(ConstFold.isTrue(condtype.getTag(), condtype.constValue()) ? truetype : falsetype, owntype); } result = check(tree, owntype, KindSelector.VAL, resultInfo); } @@ -3572,7 +3572,7 @@ // If the argument is constant, fold it. if (argtype.constValue() != null) { - Type ctype = cfolder.fold1(opc, argtype); + Type ctype = cfolder.fold1((OperatorSymbol)operator, argtype); if (ctype != null) { owntype = cfolder.coerce(ctype, owntype); } @@ -3595,7 +3595,7 @@ int opc = ((OperatorSymbol)operator).opcode; // If both arguments are constants, fold them. if (left.constValue() != null && right.constValue() != null) { - Type ctype = cfolder.fold2(opc, left, right); + Type ctype = cfolder.fold2((OperatorSymbol)operator, left, right); if (ctype != null) { owntype = cfolder.coerce(ctype, owntype); } --- old/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/ConstFold.java 2019-05-21 01:02:01.845074180 +0200 +++ new/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/ConstFold.java 2019-05-21 01:02:01.681074476 +0200 @@ -26,11 +26,14 @@ package com.sun.tools.javac.comp; import com.sun.tools.javac.code.*; +import com.sun.tools.javac.code.Symbol.OperatorSymbol; import com.sun.tools.javac.jvm.*; import com.sun.tools.javac.util.*; import static com.sun.tools.javac.code.TypeTag.BOOLEAN; +import static com.sun.tools.javac.code.TypeTag.BOT; +import static com.sun.tools.javac.code.TypeTag.CHAR; import static com.sun.tools.javac.jvm.ByteCodes.*; /** Helper class for constant folding, used by the attribution phase. @@ -41,10 +44,11 @@ * This code and its internal interfaces are subject to change or * deletion without notice. */ -strictfp class ConstFold { +strictfp public class ConstFold { protected static final Context.Key constFoldKey = new Context.Key<>(); private Symtab syms; + private Types types; public static ConstFold instance(Context context) { ConstFold instance = context.get(constFoldKey); @@ -57,6 +61,7 @@ context.put(constFoldKey, this); syms = Symtab.instance(context); + types = Types.instance(context); } static final Integer minusOne = -1; @@ -72,229 +77,231 @@ private static long longValue(Object x) { return ((Number)x).longValue(); } private static float floatValue(Object x) { return ((Number)x).floatValue(); } private static double doubleValue(Object x) { return ((Number)x).doubleValue(); } + public static String stringValue(TypeTag tag, Object x) { + if (tag == BOT) { + return "null"; + } else if (tag == BOOLEAN) { + return ((Integer)x).intValue() == 0 ? "false" : "true"; + } else if (tag == CHAR) { + return String.valueOf((char) ((Integer)x).intValue()); + } else { + return x.toString(); + } + } + public static boolean isTrue(TypeTag tag, Object x) { + return tag == BOOLEAN && + x != null && + ((Integer)x).intValue() != 0; + } + public static boolean isFalse(TypeTag tag, Object x) { + return tag == BOOLEAN && + x != null && + ((Integer)x).intValue() == 0; + } + + Type fold1(OperatorSymbol op, Type od) { + if (op.opcode == nop) { + return od; + } else { + Object v = fold1(op, od.constValue()); + Type foldType = foldType(op); + return (foldType != null && v != null) ? + foldType(op).constType(v) : + null; + } + } /** Fold unary operation. - * @param opcode The operation's opcode instruction (usually a byte code), - * as entered by class Symtab. + * @param op The operator symbol. * opcode's ifeq to ifge are for postprocessing * xcmp; ifxx pairs of instructions. - * @param operand The operation's operand type. - * Argument types are assumed to have non-null constValue's. + * @param od The operation's operand. Assumed to be non-null. */ - Type fold1(int opcode, Type operand) { + Object fold1(OperatorSymbol op, Object od) { + int opcode = op.opcode; try { - Object od = operand.constValue(); switch (opcode) { - case nop: - return operand; - case ineg: // unary - - return syms.intType.constType(-intValue(od)); - case ixor: // ~ - return syms.intType.constType(~intValue(od)); - case bool_not: // ! - return syms.booleanType.constType(b2i(intValue(od) == 0)); - case ifeq: - return syms.booleanType.constType(b2i(intValue(od) == 0)); - case ifne: - return syms.booleanType.constType(b2i(intValue(od) != 0)); - case iflt: - return syms.booleanType.constType(b2i(intValue(od) < 0)); - case ifgt: - return syms.booleanType.constType(b2i(intValue(od) > 0)); - case ifle: - return syms.booleanType.constType(b2i(intValue(od) <= 0)); - case ifge: - return syms.booleanType.constType(b2i(intValue(od) >= 0)); - - case lneg: // unary - - return syms.longType.constType(Long.valueOf(-longValue(od))); - case lxor: // ~ - return syms.longType.constType(Long.valueOf(~longValue(od))); + case ineg: // unary - + return -intValue(od); + case ixor: // ~ + return ~intValue(od); + case bool_not: // ! + return b2i(intValue(od) == 0); + case ifeq: + return b2i(intValue(od) == 0); + case ifne: + return b2i(intValue(od) != 0); + case iflt: + return b2i(intValue(od) < 0); + case ifgt: + return b2i(intValue(od) > 0); + case ifle: + return b2i(intValue(od) <= 0); + case ifge: + return b2i(intValue(od) >= 0); + + case lneg: // unary - + return Long.valueOf(-longValue(od)); + case lxor: // ~ + return Long.valueOf(~longValue(od)); - case fneg: // unary - - return syms.floatType.constType(Float.valueOf(-floatValue(od))); + case fneg: // unary - + return Float.valueOf(-floatValue(od)); - case dneg: // ~ - return syms.doubleType.constType(Double.valueOf(-doubleValue(od))); + case dneg: // ~ + return Double.valueOf(-doubleValue(od)); - default: - return null; + default: + return null; } } catch (ArithmeticException e) { return null; } } + Type fold2(OperatorSymbol op, Type left, Type right) { + Object v = fold2(op, left.constValue(), right.constValue()); + Type foldType = foldType(op); + return (foldType != null && v != null) ? + foldType(op).constType(v) : + null; + } + /** Fold binary operation. - * @param opcode The operation's opcode instruction (usually a byte code), - * as entered by class Symtab. - * opcode's ifeq to ifge are for postprocessing - * xcmp; ifxx pairs of instructions. - * @param left The type of the operation's left operand. - * @param right The type of the operation's right operand. + * @param op The operator symbol. + * @param l The operation's left operand. + * @param r The operation's right operand. */ - Type fold2(int opcode, Type left, Type right) { + Object fold2(OperatorSymbol op, Object l, Object r) { + int opcode = op.opcode; try { if (opcode > ByteCodes.preMask) { // we are seeing a composite instruction of the form xcmp; ifxx. // In this case fold both instructions separately. - Type t1 = fold2(opcode >> ByteCodes.preShift, left, right); - return (t1.constValue() == null) ? t1 - : fold1(opcode & ByteCodes.preMask, t1); + Object t1 = fold2(op.pre(types), l, r); + return (t1 == null) ? t1 + : fold1(op.post(types), t1); } else { - Object l = left.constValue(); - Object r = right.constValue(); switch (opcode) { case iadd: - return syms.intType.constType(intValue(l) + intValue(r)); + return intValue(l) + intValue(r); case isub: - return syms.intType.constType(intValue(l) - intValue(r)); + return intValue(l) - intValue(r); case imul: - return syms.intType.constType(intValue(l) * intValue(r)); + return intValue(l) * intValue(r); case idiv: - return syms.intType.constType(intValue(l) / intValue(r)); + return intValue(l) / intValue(r); case imod: - return syms.intType.constType(intValue(l) % intValue(r)); + return intValue(l) % intValue(r); case iand: - return (left.hasTag(BOOLEAN) - ? syms.booleanType : syms.intType) - .constType(intValue(l) & intValue(r)); + return intValue(l) & intValue(r); case bool_and: - return syms.booleanType.constType(b2i((intValue(l) & intValue(r)) != 0)); + return b2i((intValue(l) & intValue(r)) != 0); case ior: - return (left.hasTag(BOOLEAN) - ? syms.booleanType : syms.intType) - .constType(intValue(l) | intValue(r)); + return intValue(l) | intValue(r); case bool_or: - return syms.booleanType.constType(b2i((intValue(l) | intValue(r)) != 0)); + return b2i((intValue(l) | intValue(r)) != 0); case ixor: - return (left.hasTag(BOOLEAN) - ? syms.booleanType : syms.intType) - .constType(intValue(l) ^ intValue(r)); + return intValue(l) ^ intValue(r); case ishl: case ishll: - return syms.intType.constType(intValue(l) << intValue(r)); + return intValue(l) << intValue(r); case ishr: case ishrl: - return syms.intType.constType(intValue(l) >> intValue(r)); + return intValue(l) >> intValue(r); case iushr: case iushrl: - return syms.intType.constType(intValue(l) >>> intValue(r)); + return intValue(l) >>> intValue(r); case if_icmpeq: - return syms.booleanType.constType( - b2i(intValue(l) == intValue(r))); + return b2i(intValue(l) == intValue(r)); case if_icmpne: - return syms.booleanType.constType( - b2i(intValue(l) != intValue(r))); + return b2i(intValue(l) != intValue(r)); case if_icmplt: - return syms.booleanType.constType( - b2i(intValue(l) < intValue(r))); + return b2i(intValue(l) < intValue(r)); case if_icmpgt: - return syms.booleanType.constType( - b2i(intValue(l) > intValue(r))); + return b2i(intValue(l) > intValue(r)); case if_icmple: - return syms.booleanType.constType( - b2i(intValue(l) <= intValue(r))); + return b2i(intValue(l) <= intValue(r)); case if_icmpge: - return syms.booleanType.constType( - b2i(intValue(l) >= intValue(r))); + return b2i(intValue(l) >= intValue(r)); case ladd: - return syms.longType.constType( - Long.valueOf(longValue(l) + longValue(r))); + return Long.valueOf(longValue(l) + longValue(r)); case lsub: - return syms.longType.constType( - Long.valueOf(longValue(l) - longValue(r))); + return Long.valueOf(longValue(l) - longValue(r)); case lmul: - return syms.longType.constType( - Long.valueOf(longValue(l) * longValue(r))); + return Long.valueOf(longValue(l) * longValue(r)); case ldiv: - return syms.longType.constType( - Long.valueOf(longValue(l) / longValue(r))); + return Long.valueOf(longValue(l) / longValue(r)); case lmod: - return syms.longType.constType( - Long.valueOf(longValue(l) % longValue(r))); + return Long.valueOf(longValue(l) % longValue(r)); case land: - return syms.longType.constType( - Long.valueOf(longValue(l) & longValue(r))); + return Long.valueOf(longValue(l) & longValue(r)); case lor: - return syms.longType.constType( - Long.valueOf(longValue(l) | longValue(r))); + return Long.valueOf(longValue(l) | longValue(r)); case lxor: - return syms.longType.constType( - Long.valueOf(longValue(l) ^ longValue(r))); + return Long.valueOf(longValue(l) ^ longValue(r)); case lshl: case lshll: - return syms.longType.constType( - Long.valueOf(longValue(l) << intValue(r))); + return Long.valueOf(longValue(l) << intValue(r)); case lshr: case lshrl: - return syms.longType.constType( - Long.valueOf(longValue(l) >> intValue(r))); + return Long.valueOf(longValue(l) >> intValue(r)); case lushr: - return syms.longType.constType( - Long.valueOf(longValue(l) >>> intValue(r))); + return Long.valueOf(longValue(l) >>> intValue(r)); case lcmp: if (longValue(l) < longValue(r)) - return syms.intType.constType(minusOne); + return minusOne; else if (longValue(l) > longValue(r)) - return syms.intType.constType(one); + return one; else - return syms.intType.constType(zero); + return zero; case fadd: - return syms.floatType.constType( - Float.valueOf(floatValue(l) + floatValue(r))); + return Float.valueOf(floatValue(l) + floatValue(r)); case fsub: - return syms.floatType.constType( - Float.valueOf(floatValue(l) - floatValue(r))); + return Float.valueOf(floatValue(l) - floatValue(r)); case fmul: - return syms.floatType.constType( - Float.valueOf(floatValue(l) * floatValue(r))); + return Float.valueOf(floatValue(l) * floatValue(r)); case fdiv: - return syms.floatType.constType( - Float.valueOf(floatValue(l) / floatValue(r))); + return Float.valueOf(floatValue(l) / floatValue(r)); case fmod: - return syms.floatType.constType( - Float.valueOf(floatValue(l) % floatValue(r))); + return Float.valueOf(floatValue(l) % floatValue(r)); case fcmpg: case fcmpl: if (floatValue(l) < floatValue(r)) - return syms.intType.constType(minusOne); + return minusOne; else if (floatValue(l) > floatValue(r)) - return syms.intType.constType(one); + return one; else if (floatValue(l) == floatValue(r)) - return syms.intType.constType(zero); + return zero; else if (opcode == fcmpg) - return syms.intType.constType(one); + return one; else - return syms.intType.constType(minusOne); + return minusOne; case dadd: - return syms.doubleType.constType( - Double.valueOf(doubleValue(l) + doubleValue(r))); + return Double.valueOf(doubleValue(l) + doubleValue(r)); case dsub: - return syms.doubleType.constType( - Double.valueOf(doubleValue(l) - doubleValue(r))); + return Double.valueOf(doubleValue(l) - doubleValue(r)); case dmul: - return syms.doubleType.constType( - Double.valueOf(doubleValue(l) * doubleValue(r))); + return Double.valueOf(doubleValue(l) * doubleValue(r)); case ddiv: - return syms.doubleType.constType( - Double.valueOf(doubleValue(l) / doubleValue(r))); + return Double.valueOf(doubleValue(l) / doubleValue(r)); case dmod: return syms.doubleType.constType( Double.valueOf(doubleValue(l) % doubleValue(r))); case dcmpg: case dcmpl: if (doubleValue(l) < doubleValue(r)) - return syms.intType.constType(minusOne); + return minusOne; else if (doubleValue(l) > doubleValue(r)) - return syms.intType.constType(one); + return one; else if (doubleValue(l) == doubleValue(r)) - return syms.intType.constType(zero); + return zero; else if (opcode == dcmpg) - return syms.intType.constType(one); + return one; else - return syms.intType.constType(minusOne); + return minusOne; case if_acmpeq: - return syms.booleanType.constType(b2i(l.equals(r))); + return b2i(l.equals(r)); case if_acmpne: - return syms.booleanType.constType(b2i(!l.equals(r))); - case string_add: - return syms.stringType.constType( - left.stringValue() + right.stringValue()); + return b2i(!l.equals(r)); + case string_add: { + List params = op.type.getParameterTypes(); + return stringValue(params.head.getTag(), l) + stringValue(params.tail.head.getTag(), r); + } default: return null; } @@ -304,35 +311,78 @@ } } + /** Fold binary operation. + * @param opcode The operation's opcode instruction (usually a byte code), + * as entered by class Symtab. + * opcode's ifeq to ifge are for postprocessing + * xcmp; ifxx pairs of instructions. + * @param left The type of the operation's left operand. + * @param right The type of the operation's right operand. + */ + Type foldType(OperatorSymbol op) { + int opcode = op.opcode; + if (opcode > ByteCodes.preMask) { + // we are seeing a composite instruction of the form xcmp; ifxx. + // In this case fold both instructions separately. + return syms.booleanType; + } else { + switch (opcode) { + case iadd: case isub: case imul: case idiv: case imod: + case ishl: case ishll: case ishr: case ishrl: case iushr: case iushrl: + case ineg: case lcmp: case fcmpg: case fcmpl: case dcmpg: case dcmpl: + return syms.intType; + case bool_and: case bool_or: case if_icmpeq: case if_icmpne: case if_icmplt: case if_icmpgt: + case if_icmple: case if_icmpge: case if_acmpeq: case if_acmpne: case bool_not: case ifeq: + case ifne: case iflt: case ifgt: case ifle: case ifge: + return syms.booleanType; + case ior: case iand: case ixor: + return (op.type.getParameterTypes().head.hasTag(BOOLEAN) + ? syms.booleanType : syms.intType); + case ladd: case lsub: case lmul: case ldiv: case lmod: case land: + case lor: case lxor: case lshl: case lshll: case lshr: case lshrl: case lneg: + case lushr: + return syms.longType; + case fadd: case fsub: case fmul: case fdiv: case fmod: case fneg: + return syms.floatType; + case dadd: case dsub: case dmul: case ddiv: case dmod: case dneg: + return syms.doubleType; + case string_add: + return syms.stringType; + default: + return null; + } + } + } + /** Coerce constant type to target type. * @param etype The source type of the coercion, * which is assumed to be a constant type compatible with * ttype. * @param ttype The target type of the coercion. */ - Type coerce(Type etype, Type ttype) { - // WAS if (etype.baseType() == ttype.baseType()) - if (etype.tsym.type == ttype.tsym.type) - return etype; - if (etype.isNumeric()) { - Object n = etype.constValue(); - switch (ttype.getTag()) { - case BYTE: - return syms.byteType.constType(0 + (byte)intValue(n)); - case CHAR: - return syms.charType.constType(0 + (char)intValue(n)); - case SHORT: - return syms.shortType.constType(0 + (short)intValue(n)); - case INT: - return syms.intType.constType(intValue(n)); - case LONG: - return syms.longType.constType(longValue(n)); - case FLOAT: - return syms.floatType.constType(floatValue(n)); - case DOUBLE: - return syms.doubleType.constType(doubleValue(n)); - } - } - return ttype; - } + Type coerce(Type etype, Type ttype) { + // WAS if (etype.baseType() == ttype.baseType()) + if (etype.tsym.type == ttype.tsym.type) + return etype; + if (etype.isNumeric()) { + Object n = etype.constValue(); + switch (ttype.getTag()) { + case BYTE: + return syms.byteType.constType(0 + (byte)intValue(n)); + case CHAR: + return syms.charType.constType(0 + (char)intValue(n)); + case SHORT: + return syms.shortType.constType(0 + (short)intValue(n)); + case INT: + return syms.intType.constType(intValue(n)); + case LONG: + return syms.longType.constType(longValue(n)); + case FLOAT: + return syms.floatType.constType(floatValue(n)); + case DOUBLE: + return syms.doubleType.constType(doubleValue(n)); + } + } + return ttype; + } } --- /dev/null 2019-04-27 15:49:57.376009302 +0200 +++ new/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/ConstablesVisitor.java 2019-05-21 01:02:01.893074096 +0200 @@ -0,0 +1,458 @@ +/* + * 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. 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 com.sun.tools.javac.comp; + +import java.util.EnumSet; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import java.util.Set; + +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.DynamicVarSymbol; +import com.sun.tools.javac.code.Symbol.DynamicMethodSymbol; +import com.sun.tools.javac.code.Symbol.IntrinsicsLDCMethodSymbol; +import com.sun.tools.javac.code.Symbol.MethodSymbol; +import com.sun.tools.javac.code.Symbol.VarSymbol; +import com.sun.tools.javac.code.Symtab; +import com.sun.tools.javac.code.Type; +import com.sun.tools.javac.code.Type.MethodType; +import com.sun.tools.javac.code.Types; +import com.sun.tools.javac.jvm.Pool; +import com.sun.tools.javac.jvm.Target; +import com.sun.tools.javac.resources.CompilerProperties.Errors; +import com.sun.tools.javac.tree.JCTree; +import com.sun.tools.javac.tree.JCTree.JCBinary; +import com.sun.tools.javac.tree.JCTree.JCConditional; +import com.sun.tools.javac.tree.JCTree.JCFieldAccess; +import com.sun.tools.javac.tree.JCTree.JCIdent; +import com.sun.tools.javac.tree.JCTree.JCMethodInvocation; +import com.sun.tools.javac.tree.JCTree.JCTypeCast; +import com.sun.tools.javac.tree.JCTree.JCUnary; +import com.sun.tools.javac.tree.JCTree.JCVariableDecl; +import com.sun.tools.javac.tree.TreeInfo; +import com.sun.tools.javac.tree.TreeMaker; +import com.sun.tools.javac.tree.TreeScanner; +import com.sun.tools.javac.tree.TreeTranslator; +import com.sun.tools.javac.util.Constables; +import com.sun.tools.javac.util.Context; +import com.sun.tools.javac.util.List; +import com.sun.tools.javac.util.ListBuffer; +import com.sun.tools.javac.util.Log; +import com.sun.tools.javac.util.Name; +import com.sun.tools.javac.util.Names; +import com.sun.tools.javac.util.Options; + +import static com.sun.tools.javac.code.Kinds.Kind.VAR; +import static com.sun.tools.javac.code.TypeTag.NONE; +import static com.sun.tools.javac.main.Option.G; +import static com.sun.tools.javac.main.Option.G_CUSTOM; + +/** + *

This is NOT part of any supported API. + * If you write code that depends on this, you do so at your own risk. + * This code and its internal interfaces are subject to change or + * deletion without notice. + */ +public class ConstablesVisitor extends TreeScanner { + protected static final Context.Key constablesVisitorKey = new Context.Key<>(); + + public static ConstablesVisitor instance(Context context) { + ConstablesVisitor instance = context.get(constablesVisitorKey); + if (instance == null) + instance = new ConstablesVisitor(context); + return instance; + } + + private final Symtab syms; + private final Names names; + private final Types types; + private final Log log; + private final ConstFold cfolder; + private final Constables constables; + private final boolean varDebugInfo; + private final TreeMaker make; + + protected ConstablesVisitor(Context context) { + context.put(constablesVisitorKey, this); + Options options = Options.instance(context); + // format: -XDfolding=true, which is the default, or -XDfolding=false + String foldingOp = options.get("folding"); + Source source = Source.instance(context); + doConstantFold = foldingOp != null ? + foldingOp.equals("true") : + Feature.CONSTABLES.allowedInSource(source); + syms = Symtab.instance(context); + names = Names.instance(context); + types = Types.instance(context); + log = Log.instance(context); + cfolder = ConstFold.instance(context); + make = TreeMaker.instance(context); + constables = Constables.instance(context); + varDebugInfo = + options.isUnset(G_CUSTOM) + ? options.isSet(G) + : options.isSet(G_CUSTOM, "vars"); + elementToConstantMap = new HashMap<>(); + } + + /** + * Switch: fold special constants + */ + private final boolean doConstantFold; + + private Env attrEnv; + + public Map elementToConstantMap; + + public JCTree analyzeTree(JCTree tree, Env attrEnv) { + try { + if (!doConstantFold) { + return tree; + } + this.attrEnv = attrEnv; + errorForLDCAndIndy = false; + scan(tree); + errorForLDCAndIndy = true; + scan(tree); + if (!varDebugInfo) { + tree = constablesSetter.translate(tree); + } + return tree; + } finally { + elementToConstantMap.clear(); + } + } + + boolean errorForLDCAndIndy = false; + + @Override + public void visitVarDef(JCVariableDecl tree) { + super.visitVarDef(tree); + if (tree.init != null) { + VarSymbol v = tree.sym; + if (elementToConstantMap.get(v) != null) { + return; + } + Object constant = getConstant(tree.init, v.type); + if (constant != null && + (v.isFinal() || v.isEffectivelyFinal())) { + elementToConstantMap.remove(tree.init); + elementToConstantMap.put(v, constant); + } + } + } + + Object getConstant(JCTree tree) { + Symbol sym = TreeInfo.symbol(tree); + Object result = tree.type.constValue() != null ? + tree.type.constValue() : + elementToConstantMap.get(tree); + return result == null ? elementToConstantMap.get(sym) : result; + } + + // this one coerces + Object getConstant(JCTree tree, Type targetType) { + Symbol sym = TreeInfo.symbol(tree); + Object result; + if (tree.type.constValue() != null) { + if (tree.type.isNumeric() && targetType.isNumeric()) { + result = cfolder.coerce(tree.type, targetType).constValue(); + } else { + result = tree.type.constValue(); + } + } else { + result = elementToConstantMap.get(tree); + } + return result == null ? elementToConstantMap.get(sym) : result; + } + + @Override + public void visitBinary(JCBinary tree) { + super.visitBinary(tree); + if (elementToConstantMap.get(tree) == null && + tree.type.constValue() == null && + getConstant(tree.lhs) != null && + getConstant(tree.rhs) != null) { + Object constant = cfolder.fold2(tree.operator, getConstant(tree.lhs), getConstant(tree.rhs)); + if (constant != null) { + elementToConstantMap.put(tree, constant); + } + } + } + + @Override + public void visitUnary(JCUnary tree) { + super.visitUnary(tree); + Object constant; + if (elementToConstantMap.get(tree) == null && + tree.type.constValue() == null && + (constant = getConstant(tree.arg)) != null && + constant instanceof Number) { + constant = cfolder.fold1(tree.operator, constant); + if (constant != null) { + elementToConstantMap.put(tree, constant); + } + } + } + + @Override + public void visitConditional(JCConditional tree) { + super.visitConditional(tree); + if (elementToConstantMap.get(tree) != null) { + return; + } + Object condConstant = getConstant(tree.cond); + Object truePartConstant = getConstant(tree.truepart); + Object falsePartConstant = getConstant(tree.falsepart); + if (tree.type.constValue() == null && + condConstant != null && + truePartConstant != null && + falsePartConstant != null && + !tree.type.hasTag(NONE)) { + Object constant = ConstFold.isTrue(tree.cond.type.getTag(), condConstant) ? + getConstant(tree.truepart, tree.type) : + getConstant(tree.falsepart, tree.type); + elementToConstantMap.put(tree, constant); + } + if (condConstant != null) { + elementToConstantMap.put(tree.cond, condConstant); + } + } + + @Override + public void visitTypeCast(JCTypeCast tree) { + super.visitTypeCast(tree); + if (elementToConstantMap.get(tree) == null && + tree.type.constValue() == null && + getConstant(tree.expr) != null) { + elementToConstantMap.put(tree, getConstant(tree.expr, tree.type)); + } + } + + @Override + public void visitIdent(JCIdent tree) { + super.visitIdent(tree); + checkForSymbolConstant(tree); + } + + void checkForSymbolConstant(JCTree tree) { + if (elementToConstantMap.get(tree) != null) { + return; + } + Symbol sym = TreeInfo.symbol(tree); + if (sym != null && sym.kind == VAR) { + VarSymbol v = (VarSymbol)sym; + Object constant = v.getConstValue(); + if (constant != null && tree.type.constValue() == null) { + // we are seeing an effectively final variable which has just being assigned a + // legacy constant, we should update the type of the tree if we want Gen to generate + // the right code for us + tree.type = tree.type.constType(constant); + } else { + constant = elementToConstantMap.get(v); + constant = constant != null ? + constant : + constables.foldTrackableField(tree, attrEnv); + if (constant != null) { + elementToConstantMap.put(tree, constant); + } + } + } + } + + @Override + public void visitSelect(JCFieldAccess tree) { + super.visitSelect(tree); + checkForSymbolConstant(tree); + } + + @Override + public void visitApply(JCMethodInvocation tree) { + super.visitApply(tree); + if (elementToConstantMap.get(tree) != null) { + return; + } + Name methName = TreeInfo.name(tree.meth); + boolean isConstructorCall = methName == names._this || methName == names._super; + if (!isConstructorCall) { + Object constant = constables.foldMethodInvocation(tree, attrEnv); + Symbol msym = TreeInfo.symbol(tree.meth); + boolean isLDC = constables.isIntrinsicsLDCInvocation(msym); + if (constant == null && isLDC) { + if (errorForLDCAndIndy) { + log.error(tree.pos(), Errors.IntrinsicsLdcMustHaveConstantArg); + } else { + return; + } + } + if (constant != null) { + if (!isLDC) { + elementToConstantMap.put(tree, constant); + } + if (isLDC) { + Symbol sym = TreeInfo.symbol(tree.meth); + if (sym instanceof IntrinsicsLDCMethodSymbol) { + return; + } + Type newType; + // if condy + if (constables.dynamicConstantClass.isInstance(constant)) { + constant = constables.convertConstant(tree, attrEnv, + constant, attrEnv.enclClass.sym.packge().modle); + newType = ((Pool.DynamicVariable)constant).type; + } else { + newType = tree.meth.type.asMethodType().restype; + Type unboxed = types.unboxedType(newType); + newType = unboxed != Type.noType ? unboxed : newType; + constant = constables.convertConstant(tree, attrEnv, + constant, attrEnv.enclClass.sym.packge().modle); + } + MethodType oldMT = tree.meth.type.asMethodType(); + MethodType newMT = new MethodType(oldMT.argtypes, newType, oldMT.thrown, syms.methodClass); + IntrinsicsLDCMethodSymbol ldcSymbol = new IntrinsicsLDCMethodSymbol( + msym.flags_field, msym.name, newMT, msym.owner, constant); + TreeInfo.setSymbol(tree.meth, ldcSymbol); + tree.meth.type = newMT; + tree.type = newMT.restype; + } + } else if (constables.isIntrinsicsIndy(tree.meth)) { + List constants = constables.extractAllConstansOrNone(List.of(tree.args.head)); + if (constants.isEmpty()) { + if (errorForLDCAndIndy) { + log.error(tree.args.head.pos(), Errors.IntrinsicsIndyMustHaveConstantArg); + } + } else { + Symbol sym = TreeInfo.symbol(tree.meth); + if (sym instanceof DynamicMethodSymbol) { + return; + } + Object indyRef = constants.head; + String invocationName = (String)constables.invokeMethodReflectively(constables.dynamicCallsiteRefClass, + indyRef, "invocationName"); + if (invocationName.isEmpty()) { + log.error(tree.args.tail.head.pos(), Errors.InvocationNameCannotBeEmpty); + } + Object mh = constables.invokeMethodReflectively(constables.dynamicCallsiteRefClass, + indyRef, "bootstrapMethod"); + Pool.MethodHandle mHandle = (Pool.MethodHandle)constables + .convertConstant(tree, attrEnv, mh, attrEnv.enclClass.sym.packge().modle); + boolean correct = false; + if (mHandle.refKind == 6 || mHandle.refKind == 8) { + MethodSymbol ms = (MethodSymbol)mHandle.refSym; + MethodType mt = (MethodType)ms.type; + correct = (mt.argtypes.size() >= 3 && + mt.argtypes.head.tsym == syms.methodHandlesLookupType.tsym && + mt.argtypes.tail.head.tsym == syms.stringType.tsym && + mt.argtypes.tail.tail.head.tsym == syms.methodTypeType.tsym); + } + if (!correct) { + log.error(tree.args.head.pos(), Errors.MethodHandleNotSuitableIndy(mHandle.refSym.type)); + } + + ListBuffer arguments = new ListBuffer<>(); + tree.args = tree.args.tail; + tree.args.forEach(arg -> arguments.add(arg.type)); + Object[] bsmArgs = (Object[])constables.invokeMethodReflectively(constables.dynamicCallsiteRefClass, indyRef, "bootstrapArgs"); + Object[] convertedBsmArgs = constables.convertConstants(tree, attrEnv, bsmArgs, attrEnv.enclClass.sym.packge().modle, true); + Object mt = constables.invokeMethodReflectively(constables.dynamicCallsiteRefClass, indyRef, "invocationType"); + String methodTypeDesc = (String)constables.invokeMethodReflectively( + constables.methodTypeRefClass, mt, "descriptorString"); + MethodType mType = (MethodType)constables.descriptorToType(methodTypeDesc, + attrEnv.enclClass.sym.packge().modle, true); + DynamicMethodSymbol dynSym = new DynamicMethodSymbol( + names.fromString(invocationName), + syms.noSymbol, + mHandle.refKind, + (MethodSymbol)mHandle.refSym, + mType, + convertedBsmArgs); + TreeInfo.setSymbol(tree.meth, dynSym); + tree.meth.type = mType; + // we need to issue a warning if the type of the indy is not assignable to the type of the + // tree, same for condy + tree.type = mType.restype; + tree.varargsElement = null; + } + } + } + } + + ConstablesSetter constablesSetter = new ConstablesSetter(); + class ConstablesSetter extends TreeTranslator { + @Override + public void visitVarDef(JCVariableDecl tree) { + super.visitVarDef(tree); + tree = (JCVariableDecl)result; + if (tree.init != null) { + VarSymbol v = tree.sym; + Object constant = elementToConstantMap.get(v); + if (constant != null) { + v.setData(constant); + } + } + result = tree; + } + + Set treesToCheck = EnumSet.of( + JCTree.Tag.SELECT, + JCTree.Tag.APPLY, + JCTree.Tag.IDENT, + JCTree.Tag.CONDEXPR, + JCTree.Tag.TYPECAST + ); + + @SuppressWarnings("unchecked") + @Override + public T translate(T tree) { + tree = super.translate(tree); + Object constant = elementToConstantMap.get(tree); + if (tree != null && + treesToCheck.contains(tree.getTag()) && + constant != null) { + Optional opDynSym = constables.getDynamicFieldSymbol(tree, constant, attrEnv); + if (opDynSym.isPresent()) { + DynamicVarSymbol dynSym = opDynSym.get(); + JCTree ident = make.at(tree.pos()).Ident(dynSym); + ident.type = dynSym.type.constType(constant); + return (T)ident; + } else { + if (constables.canMakeItToConstantValue(tree.type)) { + tree.type = tree.type.constType(constant); + } + } + } + return tree; + } + + @Override + public void visitTree(JCTree tree) { + result = tree; + } + } +} --- old/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java 2019-05-21 01:02:02.261073436 +0200 +++ new/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Flow.java 2019-05-21 01:02:02.113073701 +0200 @@ -546,7 +546,7 @@ scanStat(tree.body); alive = alive.or(resolveContinues(tree)); scan(tree.cond); - alive = alive.and(!tree.cond.type.isTrue()); + alive = alive.and(!ConstFold.isTrue(tree.cond.type.getTag(), tree.cond.type.constValue())); alive = alive.or(resolveBreaks(tree, prevPendingExits)); } @@ -554,11 +554,11 @@ ListBuffer prevPendingExits = pendingExits; pendingExits = new ListBuffer<>(); scan(tree.cond); - alive = Liveness.from(!tree.cond.type.isFalse()); + alive = Liveness.from(!ConstFold.isFalse(tree.cond.type.getTag(), tree.cond.type.constValue())); scanStat(tree.body); alive = alive.or(resolveContinues(tree)); alive = resolveBreaks(tree, prevPendingExits).or( - !tree.cond.type.isTrue()); + !ConstFold.isTrue(tree.cond.type.getTag(), tree.cond.type.constValue())); } public void visitForLoop(JCForLoop tree) { @@ -567,7 +567,7 @@ pendingExits = new ListBuffer<>(); if (tree.cond != null) { scan(tree.cond); - alive = Liveness.from(!tree.cond.type.isFalse()); + alive = Liveness.from(!ConstFold.isFalse(tree.cond.type.getTag(), tree.cond.type.constValue())); } else { alive = Liveness.ALIVE; } @@ -575,7 +575,7 @@ alive = alive.or(resolveContinues(tree)); scan(tree.step); alive = resolveBreaks(tree, prevPendingExits).or( - tree.cond != null && !tree.cond.type.isTrue()); + tree.cond != null && !ConstFold.isTrue(tree.cond.type.getTag(), tree.cond.type.constValue())); } public void visitForeachLoop(JCEnhancedForLoop tree) { @@ -1794,7 +1794,7 @@ * rather than (un)inits on exit. */ void scanCond(JCTree tree) { - if (tree.type.isFalse()) { + if (ConstFold.isFalse(tree.type.getTag(), tree.type.constValue())) { if (inits.isReset()) merge(); initsWhenTrue.assign(inits); initsWhenTrue.inclRange(firstadr, nextadr); @@ -1802,7 +1802,7 @@ uninitsWhenTrue.inclRange(firstadr, nextadr); initsWhenFalse.assign(inits); uninitsWhenFalse.assign(uninits); - } else if (tree.type.isTrue()) { + } else if (ConstFold.isTrue(tree.type.getTag(), tree.type.constValue())) { if (inits.isReset()) merge(); initsWhenFalse.assign(inits); initsWhenFalse.inclRange(firstadr, nextadr); --- old/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/InferenceContext.java 2019-05-21 01:02:02.465073069 +0200 +++ new/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/InferenceContext.java 2019-05-21 01:02:02.317073335 +0200 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2019, 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 @@ -30,7 +30,6 @@ import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; -import java.util.LinkedHashSet; import java.util.Map; import java.util.Set; @@ -367,11 +366,9 @@ for (Type t : minContext.inferencevars) { //add listener that forwards notifications to original context minContext.addFreeTypeListener(List.of(t), (inferenceContext) -> { - Type instType = inferenceContext.asInstType(t); - for (Type eq : rv.minMap.get(t)) { - ((UndetVar)asUndetVar(eq)).setInst(instType); - } - infer.doIncorporation(this, warn); + ((UndetVar)asUndetVar(t)).setInst(inferenceContext.asInstType(t)); + infer.doIncorporation(inferenceContext, warn); + solve(List.from(rv.minMap.get(t)), warn); notifyChange(); }); } @@ -388,9 +385,9 @@ class ReachabilityVisitor extends Types.UnaryVisitor { - Set equiv = new LinkedHashSet<>(); - Set min = new LinkedHashSet<>(); - Map> minMap = new LinkedHashMap<>(); + Set equiv = new HashSet<>(); + Set min = new HashSet<>(); + Map> minMap = new HashMap<>(); void scan(List roots) { roots.stream().forEach(this::visit); @@ -404,7 +401,7 @@ @Override public Void visitUndetVar(UndetVar t, Void _unused) { if (min.add(t.qtype)) { - Set deps = minMap.getOrDefault(t.qtype, new LinkedHashSet<>(Collections.singleton(t.qtype))); + Set deps = minMap.getOrDefault(t.qtype, new HashSet<>(Collections.singleton(t.qtype))); for (InferenceBound boundKind : InferenceBound.values()) { for (Type b : t.getBounds(boundKind)) { Type undet = asUndetVar(b); --- old/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java 2019-05-21 01:02:02.657072725 +0200 +++ new/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/LambdaToMethod.java 2019-05-21 01:02:02.505072998 +0200 @@ -25,11 +25,10 @@ package com.sun.tools.javac.comp; -import com.sun.tools.javac.code.Symbol.MethodHandleSymbol; import com.sun.tools.javac.code.Types.SignatureGenerator.InvalidSignatureException; -import com.sun.tools.javac.jvm.PoolConstant.LoadableConstant; import com.sun.tools.javac.resources.CompilerProperties.Errors; import com.sun.tools.javac.resources.CompilerProperties.Fragments; +import com.sun.tools.javac.code.Source.Feature; import com.sun.tools.javac.tree.*; import com.sun.tools.javac.tree.JCTree.*; import com.sun.tools.javac.tree.JCTree.JCMemberReference.ReferenceKind; @@ -61,6 +60,7 @@ import java.util.HashSet; import java.util.LinkedHashMap; import java.util.Map; +import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.function.Consumer; @@ -71,11 +71,16 @@ import static com.sun.tools.javac.code.Kinds.Kind.*; import static com.sun.tools.javac.code.TypeTag.*; import static com.sun.tools.javac.tree.JCTree.Tag.*; +import static com.sun.tools.javac.jvm.Pool.DynamicMethod; import javax.lang.model.element.ElementKind; import javax.lang.model.type.TypeKind; +import com.sun.tools.javac.code.Type.IntersectionClassType; +import com.sun.tools.javac.code.Types.FunctionDescriptorLookupError; import com.sun.tools.javac.main.Option; +import com.sun.tools.javac.code.Source; +import com.sun.tools.javac.code.Symbol.DynamicVarSymbol; /** * This pass desugars lambda expressions into static methods @@ -168,6 +173,12 @@ || options.isSet(Option.G_CUSTOM, "vars"); verboseDeduplication = options.isSet("debug.dumpLambdaToMethodDeduplication"); deduplicateLambdas = options.getBoolean("deduplicateLambdas", true); + Source source = Source.instance(context); + // format: -XDforNonCapturingLambda=generateCondy, which is the default, or -XDforNonCapturingLambda=generateIndy + String condyOp = options.get("forNonCapturingLambda"); + condyForLambda = condyOp != null ? + condyOp.equals("generateCondy") : + Feature.CONDY_FOR_LAMBDA.allowedInSource(source); } // @@ -212,7 +223,7 @@ private Map dedupedLambdas; - private Map dynMethSyms = new HashMap<>(); + private Map dynMethSyms = new HashMap<>(); /** * list of deserialization cases @@ -437,8 +448,11 @@ //then, determine the arguments to the indy call List indy_args = translate(syntheticInits.toList(), localContext.prev); + //build a sam instance using an indy call to the meta-factory + int refKind = referenceKind(sym); + //convert to an invokedynamic call - result = makeMetafactoryIndyCall(context, sym.asHandle(), indy_args); + result = makeMetafactoryIndyCall(context, refKind, sym, indy_args); } // where @@ -483,7 +497,7 @@ //first determine the method symbol to be used to generate the sam instance //this is either the method reference symbol, or the bridged reference symbol - MethodSymbol refSym = (MethodSymbol)tree.sym; + Symbol refSym = tree.sym; //the qualifying expression is treated as a special captured arg JCExpression init; @@ -517,7 +531,7 @@ //build a sam instance using an indy call to the meta-factory - result = makeMetafactoryIndyCall(localContext, refSym.asHandle(), indy_args); + result = makeMetafactoryIndyCall(localContext, localContext.referenceKind(), refSym, indy_args); } /** @@ -760,8 +774,8 @@ rs.resolveConstructor(null, attrEnv, ctype, TreeInfo.types(args), List.nil())); } - private void addDeserializationCase(MethodHandleSymbol refSym, Type targetType, MethodSymbol samSym, - DiagnosticPosition pos, List staticArgs, MethodType indyType) { + private void addDeserializationCase(int implMethodKind, Symbol refSym, Type targetType, MethodSymbol samSym, + DiagnosticPosition pos, List staticArgs, MethodType indyType) { String functionalInterfaceClass = classSig(targetType); String functionalInterfaceMethodName = samSym.getSimpleName().toString(); String functionalInterfaceMethodSignature = typeSig(types.erasure(samSym.type)); @@ -769,8 +783,7 @@ String implMethodName = refSym.getQualifiedName().toString(); String implMethodSignature = typeSig(types.erasure(refSym.type)); - JCExpression kindTest = eqTest(syms.intType, deserGetter("getImplMethodKind", syms.intType), - make.Literal(refSym.referenceKind())); + JCExpression kindTest = eqTest(syms.intType, deserGetter("getImplMethodKind", syms.intType), make.Literal(implMethodKind)); ListBuffer serArgs = new ListBuffer<>(); int i = 0; for (Type t : indyType.getParameterTypes()) { @@ -787,11 +800,11 @@ "getFunctionalInterfaceMethodSignature", functionalInterfaceMethodSignature), "getImplClass", implClass), "getImplMethodSignature", implMethodSignature), - make.Return(makeIndyCall( + make.Return(makeDynamicCall( pos, syms.lambdaMetafactory, names.altMetafactory, - staticArgs, indyType, serArgs.toList(), samSym.name)), + staticArgs, targetType, indyType, serArgs.toList(), samSym.name)), null); ListBuffer stmts = kInfo.deserializeCases.get(implMethodName); if (stmts == null) { @@ -1102,13 +1115,13 @@ * Generate an indy method call to the meta factory */ private JCExpression makeMetafactoryIndyCall(TranslationContext context, - MethodHandleSymbol refSym, List indy_args) { + int refKind, Symbol refSym, List indy_args) { JCFunctionalExpression tree = context.tree; //determine the static bsm args MethodSymbol samSym = (MethodSymbol) types.findDescriptorSymbol(tree.target.tsym); - List staticArgs = List.of( + List staticArgs = List.of( typeToMethodType(samSym.type), - ((MethodSymbol)refSym).asHandle(), + new Pool.MethodHandle(refKind, refSym, types), typeToMethodType(tree.getDescriptorType(types))); //computed indy arg types @@ -1127,7 +1140,7 @@ names.altMetafactory : names.metafactory; if (context.needsAltMetafactory()) { - ListBuffer markers = new ListBuffer<>(); + ListBuffer markers = new ListBuffer<>(); List targets = tree.target.isIntersection() ? types.directSupertypes(tree.target) : List.nil(); @@ -1136,7 +1149,7 @@ if (t.tsym != syms.serializableType.tsym && t.tsym != tree.type.tsym && t.tsym != syms.objectType.tsym) { - markers.append(t); + markers.append(t.tsym); } } int flags = context.isSerializable() ? FLAG_SERIALIZABLE : 0; @@ -1148,17 +1161,17 @@ if (hasBridges) { flags |= FLAG_BRIDGES; } - staticArgs = staticArgs.append(LoadableConstant.Int(flags)); + staticArgs = staticArgs.append(flags); if (hasMarkers) { - staticArgs = staticArgs.append(LoadableConstant.Int(markers.length())); - staticArgs = staticArgs.appendList(List.convert(LoadableConstant.class, markers.toList())); + staticArgs = staticArgs.append(markers.length()); + staticArgs = staticArgs.appendList(markers.toList()); } if (hasBridges) { - staticArgs = staticArgs.append(LoadableConstant.Int(context.bridges.length() - 1)); + staticArgs = staticArgs.append(context.bridges.length() - 1); for (Symbol s : context.bridges) { Type s_erasure = s.erasure(types); if (!types.isSameType(s_erasure, samSym.erasure(types))) { - staticArgs = staticArgs.append(((MethodType)s.erasure(types))); + staticArgs = staticArgs.append(s.erasure(types)); } } } @@ -1166,7 +1179,7 @@ int prevPos = make.pos; try { make.at(kInfo.clazz); - addDeserializationCase(refSym, tree.type, samSym, + addDeserializationCase(refKind, refSym, tree.type, samSym, tree, staticArgs, indyType); } finally { make.at(prevPos); @@ -1174,7 +1187,53 @@ } } - return makeIndyCall(tree, syms.lambdaMetafactory, metafactoryName, staticArgs, indyType, indy_args, samSym.name); + return makeDynamicCall(tree, syms.lambdaMetafactory, + metafactoryName, staticArgs, tree.type, indyType, indy_args, samSym.name); + } + + private JCExpression makeDynamicCall(DiagnosticPosition pos, Type site, Name bsmName, + List staticArgs, Type interfaceType, MethodType indyType, List indyArgs, + Name methName) { + return condyForLambda && + !context.needsAltMetafactory() && + indyArgs.isEmpty() ? + makeCondy(pos, site, bsmName, staticArgs, interfaceType, methName) : + makeIndyCall(pos, site, bsmName, staticArgs, indyType, indyArgs, methName); + } + + /* this extra flag should be temporary and used as long as it's not possible to do the build + * due to the lack of support for condy in the current version of ASM present in the build + */ + private final boolean condyForLambda; + + private JCExpression makeCondy(DiagnosticPosition pos, Type site, Name bsmName, + List staticArgs, Type interfaceType, Name methName) { + int prevPos = make.pos; + try { + make.at(pos); + List bsm_staticArgs = List.of(syms.methodHandlesLookupType, + syms.stringType, + syms.classType).appendList(bsmStaticArgToTypes(staticArgs)); + + Symbol bsm = rs.resolveInternalMethod(pos, attrEnv, site, + bsmName, bsm_staticArgs, List.nil()); + + DynamicVarSymbol dynSym = new DynamicVarSymbol(methName, + syms.noSymbol, + bsm.isStatic() ? + ClassFile.REF_invokeStatic : + ClassFile.REF_invokeVirtual, + (MethodSymbol)bsm, + interfaceType, + staticArgs.toArray()); + + JCIdent ident = make.Ident(dynSym); + ident.type = interfaceType; + + return ident; + } finally { + make.at(prevPos); + } } /** @@ -1182,14 +1241,14 @@ * arguments types */ private JCExpression makeIndyCall(DiagnosticPosition pos, Type site, Name bsmName, - List staticArgs, MethodType indyType, List indyArgs, - Name methName) { + List staticArgs, MethodType indyType, List indyArgs, + Name methName) { int prevPos = make.pos; try { make.at(pos); - List bsm_staticArgs = List.of(syms.methodHandleLookupType, - syms.stringType, - syms.methodTypeType).appendList(staticArgs.map(types::constantType)); + List bsm_staticArgs = List.of(syms.methodHandlesLookupType, + syms.stringType, + syms.methodTypeType).appendList(bsmStaticArgToTypes(staticArgs)); Symbol bsm = rs.resolveInternalMethod(pos, attrEnv, site, bsmName, bsm_staticArgs, List.nil()); @@ -1197,12 +1256,15 @@ DynamicMethodSymbol dynSym = new DynamicMethodSymbol(methName, syms.noSymbol, - ((MethodSymbol)bsm).asHandle(), + bsm.isStatic() ? + ClassFile.REF_invokeStatic : + ClassFile.REF_invokeVirtual, + (MethodSymbol)bsm, indyType, - staticArgs.toArray(new LoadableConstant[staticArgs.length()])); + staticArgs.toArray()); JCFieldAccess qualifier = make.Select(make.QualIdent(site.tsym), bsmName); DynamicMethodSymbol existing = kInfo.dynMethSyms.putIfAbsent( - dynSym.poolKey(types), dynSym); + new DynamicMethod(dynSym, types), dynSym); qualifier.sym = existing != null ? existing : dynSym; qualifier.type = indyType.getReturnType(); @@ -1213,6 +1275,57 @@ make.at(prevPos); } } + //where + private List bsmStaticArgToTypes(List args) { + ListBuffer argtypes = new ListBuffer<>(); + for (Object arg : args) { + argtypes.append(bsmStaticArgToType(arg)); + } + return argtypes.toList(); + } + + private Type bsmStaticArgToType(Object arg) { + Assert.checkNonNull(arg); + if (arg instanceof ClassSymbol) { + return syms.classType; + } else if (arg instanceof Integer) { + return syms.intType; + } else if (arg instanceof Long) { + return syms.longType; + } else if (arg instanceof Float) { + return syms.floatType; + } else if (arg instanceof Double) { + return syms.doubleType; + } else if (arg instanceof String) { + return syms.stringType; + } else if (arg instanceof Pool.MethodHandle) { + return syms.methodHandleType; + } else if (arg instanceof MethodType) { + return syms.methodTypeType; + } else { + Assert.error("bad static arg " + arg.getClass()); + return null; + } + } + + /** + * Get the opcode associated with this method reference + */ + private int referenceKind(Symbol refSym) { + if (refSym.isConstructor()) { + return ClassFile.REF_newInvokeSpecial; + } else { + if (refSym.isStatic()) { + return ClassFile.REF_invokeStatic; + } else if ((refSym.flags() & PRIVATE) != 0) { + return ClassFile.REF_invokeSpecial; + } else if (refSym.enclClass().isInterface()) { + return ClassFile.REF_invokeInterface; + } else { + return ClassFile.REF_invokeVirtual; + } + } + } // /** @@ -2254,6 +2367,13 @@ this.isSuper = tree.hasKind(ReferenceKind.SUPER); } + /** + * Get the opcode associated with this method reference + */ + int referenceKind() { + return LambdaToMethod.this.referenceKind(tree.sym); + } + boolean needsVarArgsConversion() { return tree.varargsElement != null; } --- old/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java 2019-05-21 01:02:02.881072325 +0200 +++ new/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java 2019-05-21 01:02:02.725072603 +0200 @@ -93,6 +93,7 @@ private final Attr attr; private TreeMaker make; private DiagnosticPosition make_pos; + private final ClassWriter writer; private final ConstFold cfolder; private final Target target; private final Source source; @@ -115,6 +116,7 @@ chk = Check.instance(context); attr = Attr.instance(context); make = TreeMaker.instance(context); + writer = ClassWriter.instance(context); cfolder = ConstFold.instance(context); target = Target.instance(context); source = Source.instance(context); @@ -473,7 +475,7 @@ .fromString(target.syntheticNameChar() + "SwitchMap" + target.syntheticNameChar() + - names.fromUtf(ClassWriter.externalize(forEnum.type.tsym.flatName())).toString() + writer.xClassName(forEnum.type).toString() .replace('/', '.') .replace('.', target.syntheticNameChar())); ClassSymbol outerCacheClass = outerCacheClass(); @@ -2635,13 +2637,13 @@ // are safe to simplify as no side-effects can occur. private boolean isTrue(JCTree exp) { - if (exp.type.isTrue()) + if (ConstFold.isTrue(exp.type.getTag(), exp.type.constValue())) return true; Boolean b = expValue(exp); return b == null ? false : b; } private boolean isFalse(JCTree exp) { - if (exp.type.isFalse()) + if (ConstFold.isFalse(exp.type.getTag(), exp.type.constValue())) return true; Boolean b = expValue(exp); return b == null ? false : !b; @@ -2730,11 +2732,11 @@ */ public void visitAssert(JCAssert tree) { tree.cond = translate(tree.cond, syms.booleanType); - if (!tree.cond.type.isTrue()) { + if (!ConstFold.isTrue(tree.cond.type.getTag(), tree.cond.type.constValue())) { JCExpression cond = assertFlagTest(tree.pos()); List exnArgs = (tree.detail == null) ? List.nil() : List.of(translate(tree.detail)); - if (!tree.cond.type.isFalse()) { + if (!ConstFold.isFalse(tree.cond.type.getTag(), tree.cond.type.constValue())) { cond = makeBinary (AND, cond, @@ -3098,7 +3100,7 @@ tree.arg = boxIfNeeded(translate(tree.arg, tree), tree.type); if (tree.hasTag(NOT) && tree.arg.type.constValue() != null) { - tree.type = cfolder.fold1(bool_not, tree.arg.type); + tree.type = cfolder.fold1(tree.operator, tree.arg.type); } // If translated left hand side is an Apply, we are --- old/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Operators.java 2019-05-21 01:02:03.093071943 +0200 +++ new/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Operators.java 2019-05-21 01:02:02.941072216 +0200 @@ -546,16 +546,16 @@ /** * This routine applies following mappings: - * - if input type is primitive, apply numeric promotion - * - if input type is either 'void', 'null' or 'String' leave it untouched + * - if input type is either 'char', 'void', 'null' or 'String' leave it untouched + * - otherwise, if input type is primitive, apply numeric promotion * - otherwise return 'Object' */ private Type stringPromotion(Type t) { - if (t.isPrimitive()) { - return unaryPromotion(t); - } else if (t.hasTag(TypeTag.VOID) || t.hasTag(TypeTag.BOT) || + if (t.hasTag(TypeTag.CHAR) || t.hasTag(TypeTag.VOID) || t.hasTag(TypeTag.BOT) || types.isSameType(t, syms.stringType)) { return t; + } else if (t.isPrimitive()) { + return unaryPromotion(t); } else if (t.hasTag(TypeTag.TYPEVAR)) { return stringPromotion(t.getUpperBound()); } else { @@ -696,12 +696,14 @@ .addBinaryOperator(STRING, OBJECT, STRING, string_add) .addBinaryOperator(OBJECT, STRING, STRING, string_add) .addBinaryOperator(STRING, STRING, STRING, string_add) + .addBinaryOperator(STRING, CHAR, STRING, string_add) .addBinaryOperator(STRING, INT, STRING, string_add) .addBinaryOperator(STRING, LONG, STRING, string_add) .addBinaryOperator(STRING, FLOAT, STRING, string_add) .addBinaryOperator(STRING, DOUBLE, STRING, string_add) .addBinaryOperator(STRING, BOOLEAN, STRING, string_add) .addBinaryOperator(STRING, BOT, STRING, string_add) + .addBinaryOperator(CHAR, STRING, STRING, string_add) .addBinaryOperator(INT, STRING, STRING, string_add) .addBinaryOperator(LONG, STRING, STRING, string_add) .addBinaryOperator(FLOAT, STRING, STRING, string_add) --- old/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java 2019-05-21 01:02:03.289071591 +0200 +++ new/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java 2019-05-21 01:02:03.141071859 +0200 @@ -2642,7 +2642,7 @@ List typeargtypes) { return resolveQualifiedMethod(new MethodResolutionContext(), pos, env, location, site, name, argtypes, typeargtypes); } - private Symbol resolveQualifiedMethod(MethodResolutionContext resolveContext, + public Symbol resolveQualifiedMethod(MethodResolutionContext resolveContext, DiagnosticPosition pos, Env env, Symbol location, Type site, Name name, List argtypes, List typeargtypes) { @@ -2656,7 +2656,7 @@ @Override Symbol access(Env env, DiagnosticPosition pos, Symbol location, Symbol sym) { if (sym.kind.isResolutionError()) { - sym = super.access(env, pos, location, sym); + sym = resolveContext.silentFail ? sym : super.access(env, pos, location, sym); } else { MethodSymbol msym = (MethodSymbol)sym; if ((msym.flags() & SIGNATURE_POLYMORPHIC) != 0) { @@ -4769,7 +4769,7 @@ * can be nested - this means that when each overload resolution routine should * work within the resolution context it created. */ - class MethodResolutionContext { + public class MethodResolutionContext { private List candidates = List.nil(); @@ -4777,7 +4777,9 @@ MethodCheck methodCheck = resolveMethodCheck; - private boolean internalResolution = false; + public boolean internalResolution = false; + // in case of failure, don't report the error + public boolean silentFail = false; private DeferredAttr.AttrMode attrMode = DeferredAttr.AttrMode.SPECULATIVE; void addInapplicableCandidate(Symbol sym, JCDiagnostic details) { --- old/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransTypes.java 2019-05-21 01:02:03.501071212 +0200 +++ new/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransTypes.java 2019-05-21 01:02:03.357071471 +0200 @@ -661,8 +661,12 @@ tree.args = translateArgs(tree.args, argtypes, tree.varargsElement); tree.type = types.erasure(tree.type); + Object constant = tree.type.constValue(); // Insert casts of method invocation results as needed. result = retype(tree, mt.getReturnType(), pt); + if (constant != null) { + tree.type = tree.type.constType(constant); + } } public void visitNewClass(JCNewClass tree) { --- old/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassFile.java 2019-05-21 01:02:03.697070860 +0200 +++ new/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassFile.java 2019-05-21 01:02:03.549071127 +0200 @@ -25,6 +25,9 @@ package com.sun.tools.javac.jvm; +import com.sun.tools.javac.code.Type; +import com.sun.tools.javac.code.Types; +import com.sun.tools.javac.code.Types.UniqueType; import com.sun.tools.javac.util.Name; @@ -186,4 +189,38 @@ public static byte[] externalize(Name name) { return externalize(name.getByteArray(), name.getByteOffset(), name.getByteLength()); } + +/************************************************************************ + * Name-and-type + ***********************************************************************/ + + /** A class for the name-and-type signature of a method or field. + */ + public static class NameAndType { + Name name; + UniqueType uniqueType; + Types types; + + NameAndType(Name name, Type type, Types types) { + this.name = name; + this.uniqueType = new UniqueType(type, types); + this.types = types; + } + + void setType(Type type) { + this.uniqueType = new UniqueType(type, types); + } + + @Override + public boolean equals(Object other) { + return (other instanceof NameAndType && + name == ((NameAndType) other).name && + uniqueType.equals(((NameAndType) other).uniqueType)); + } + + @Override + public int hashCode() { + return name.hashCode() * uniqueType.hashCode(); + } + } } --- old/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java 2019-05-21 01:02:03.881070531 +0200 +++ new/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java 2019-05-21 01:02:03.733070796 +0200 @@ -36,7 +36,6 @@ import java.util.HashSet; import java.util.Map; import java.util.Set; -import java.util.function.IntFunction; import javax.lang.model.element.Modifier; import javax.lang.model.element.NestingKind; @@ -56,8 +55,8 @@ import com.sun.tools.javac.comp.Annotate.AnnotationTypeMetadata; import com.sun.tools.javac.file.BaseFileManager; import com.sun.tools.javac.file.PathFileObject; +import com.sun.tools.javac.jvm.ClassFile.NameAndType; import com.sun.tools.javac.jvm.ClassFile.Version; -import com.sun.tools.javac.jvm.PoolConstant.NameAndType; import com.sun.tools.javac.main.Option; import com.sun.tools.javac.resources.CompilerProperties.Fragments; import com.sun.tools.javac.resources.CompilerProperties.Warnings; @@ -101,6 +100,11 @@ */ boolean verbose; + /** Switch: read constant pool and code sections. This switch is initially + * set to false but can be turned on from outside. + */ + public boolean readAllOfClassFile = false; + /** Switch: allow modules. */ boolean allowModules; @@ -166,15 +170,20 @@ /** The buffer containing the currently read class file. */ - ByteBuffer buf = new ByteBuffer(INITIAL_BUFFER_SIZE); + byte[] buf = new byte[INITIAL_BUFFER_SIZE]; /** The current input pointer. */ protected int bp; - /** The pool reader. + /** The objects of the constant pool. + */ + Object[] poolObj; + + /** For every constant pool entry, an index into buf where the + * defining section of the entry is found. */ - PoolReader poolReader; + int[] poolIdx; /** The major version number of the class file being read. */ int majorVersion; @@ -314,29 +323,294 @@ /** Read a character. */ char nextChar() { - char res = buf.getChar(bp); - bp += 2; - return res; + return (char)(((buf[bp++] & 0xFF) << 8) + (buf[bp++] & 0xFF)); } /** Read a byte. */ int nextByte() { - return buf.getByte(bp++) & 0xFF; + return buf[bp++] & 0xFF; } /** Read an integer. */ int nextInt() { - int res = buf.getInt(bp); - bp += 4; - return res; + return + ((buf[bp++] & 0xFF) << 24) + + ((buf[bp++] & 0xFF) << 16) + + ((buf[bp++] & 0xFF) << 8) + + (buf[bp++] & 0xFF); + } + + /** Extract a character at position bp from buf. + */ + char getChar(int bp) { + return + (char)(((buf[bp] & 0xFF) << 8) + (buf[bp+1] & 0xFF)); + } + + /** Extract an integer at position bp from buf. + */ + int getInt(int bp) { + return + ((buf[bp] & 0xFF) << 24) + + ((buf[bp+1] & 0xFF) << 16) + + ((buf[bp+2] & 0xFF) << 8) + + (buf[bp+3] & 0xFF); + } + + + /** Extract a long integer at position bp from buf. + */ + long getLong(int bp) { + DataInputStream bufin = + new DataInputStream(new ByteArrayInputStream(buf, bp, 8)); + try { + return bufin.readLong(); + } catch (IOException e) { + throw new AssertionError(e); + } + } + + /** Extract a float at position bp from buf. + */ + float getFloat(int bp) { + DataInputStream bufin = +