diff --git a/.github/workflows/submit.yml b/.github/workflows/submit.yml index 4db164f1a73..0a719f8fa37 100644 --- a/.github/workflows/submit.yml +++ b/.github/workflows/submit.yml @@ -9,7 +9,7 @@ on: platforms: description: "Platform(s) to execute on" required: true - default: "Linux x64, Windows x64, macOS x64" + default: "Linux x64, Linux x86, Windows x64, macOS x64" jobs: prerequisites: @@ -18,7 +18,7 @@ jobs: outputs: should_run: ${{ steps.check_submit.outputs.should_run }} bundle_id: ${{ steps.check_bundle_id.outputs.bundle_id }} - platform_linux_x32: ${{ steps.check_platforms.outputs.platform_linux_x32 }} + platform_linux_x86: ${{ steps.check_platforms.outputs.platform_linux_x86 }} platform_linux_x64: ${{ steps.check_platforms.outputs.platform_linux_x64 }} platform_windows_x64: ${{ steps.check_platforms.outputs.platform_windows_x64 }} platform_macos_x64: ${{ steps.check_platforms.outputs.platform_macos_x64 }} @@ -33,12 +33,13 @@ jobs: id: check_platforms run: | echo "::set-output name=platform_linux_x64::${{ contains(github.event.inputs.platforms, 'linux x64') || (github.event.inputs.platforms == '' && (secrets.JDK_SUBMIT_PLATFORMS == '' || contains(secrets.JDK_SUBMIT_PLATFORMS, 'linux x64'))) }}" - echo "::set-output name=platform_linux_x32::${{ contains(github.event.inputs.platforms, 'linux x32') || (github.event.inputs.platforms == '' && (secrets.JDK_SUBMIT_PLATFORMS == '' || contains(secrets.JDK_SUBMIT_PLATFORMS, 'linux x32'))) }}" + echo "::set-output name=platform_linux_x86::${{ contains(github.event.inputs.platforms, 'linux x86') || (github.event.inputs.platforms == '' && (secrets.JDK_SUBMIT_PLATFORMS == '' || contains(secrets.JDK_SUBMIT_PLATFORMS, 'linux x86'))) }}" echo "::set-output name=platform_windows_x64::${{ contains(github.event.inputs.platforms, 'windows x64') || (github.event.inputs.platforms == '' && (secrets.JDK_SUBMIT_PLATFORMS == '' || contains(secrets.JDK_SUBMIT_PLATFORMS, 'windows x64'))) }}" echo "::set-output name=platform_macos_x64::${{ contains(github.event.inputs.platforms, 'macos x64') || (github.event.inputs.platforms == '' && (secrets.JDK_SUBMIT_PLATFORMS == '' || contains(secrets.JDK_SUBMIT_PLATFORMS, 'macos x64'))) }}" if: steps.check_submit.outputs.should_run != 'false' - name: Determine unique bundle identifier + id: check_bundle_id run: echo "::set-output name=bundle_id::${GITHUB_ACTOR}_${GITHUB_SHA:0:8}" if: steps.check_submit.outputs.should_run != 'false' @@ -350,24 +351,52 @@ jobs: if: always() run: echo "logsuffix=`echo ${{ matrix.test }} | sed -e 's!/!_!'g -e 's! !_!'g`" >> $GITHUB_ENV - - name: Persist test logs + - name: Package test results + if: always() + working-directory: build/run-test-prebuilt/test-results/ + run: > + zip -r9 + "$HOME/linux-x64${{ matrix.artifact }}_testresults_${{ env.logsuffix }}.zip" + . + continue-on-error: true + + - name: Package test support + if: always() + working-directory: build/run-test-prebuilt/test-support/ + run: > + zip -r9 + "$HOME/linux-x64${{ matrix.artifact }}_testsupport_${{ env.logsuffix }}.zip" + . + -i *.jtr + -i hs_err* + -i replay* + continue-on-error: true + + - name: Persist test results + if: always() + uses: actions/upload-artifact@v2 + with: + path: ~/linux-x64${{ matrix.artifact }}_testresults_${{ env.logsuffix }}.zip + continue-on-error: true + + - name: Persist test outputs if: always() uses: actions/upload-artifact@v2 with: - name: linux-x64${{ matrix.artifact }}_testlogs_${{ env.logsuffix }} - path: build/*/test-results + path: ~/linux-x64${{ matrix.artifact }}_testsupport_${{ env.logsuffix }}.zip continue-on-error: true - linux_x32_build: - name: Linux x32 + linux_x86_build: + name: Linux x86 runs-on: "ubuntu-latest" needs: prerequisites - if: needs.prerequisites.outputs.should_run != 'false' && needs.prerequisites.outputs.platform_linux_x32 != 'false' + if: needs.prerequisites.outputs.should_run != 'false' && needs.prerequisites.outputs.platform_linux_x86 != 'false' strategy: fail-fast: false matrix: flavor: + - build release - build debug include: - flavor: build debug @@ -438,7 +467,7 @@ jobs: - name: Configure run: > bash configure - --with-conf-name=linux-x32 + --with-conf-name=linux-x86 --with-target-bits=32 ${{ matrix.flags }} --with-version-opt=${GITHUB_ACTOR}-${GITHUB_SHA} @@ -452,9 +481,198 @@ jobs: working-directory: jdk - name: Build - run: make CONF_NAME=linux-x32 ${{ matrix.build-target }} + run: make CONF_NAME=linux-x86 ${{ matrix.build-target }} working-directory: jdk + - name: Persist test bundles + uses: actions/upload-artifact@v2 + with: + name: transient_jdk-linux-x86${{ matrix.artifact }}_${{ needs.prerequisites.outputs.bundle_id }} + path: | + jdk/build/linux-x86/bundles/jdk-${{ env.JDK_VERSION }}-internal+0_linux-x86_bin${{ matrix.artifact }}.tar.gz + jdk/build/linux-x86/bundles/jdk-${{ env.JDK_VERSION }}-internal+0_linux-x86_bin-tests${{ matrix.artifact }}.tar.gz + if: matrix.build-target == false + + linux_x86_test: + name: Linux x86 + runs-on: "ubuntu-latest" + needs: + - prerequisites + - linux_x86_build + + strategy: + fail-fast: false + matrix: + test: + - jdk/tier1 part 1 + - jdk/tier1 part 2 + - jdk/tier1 part 3 + - langtools/tier1 + - hs/tier1 common + - hs/tier1 compiler + - hs/tier1 gc + - hs/tier1 runtime + - hs/tier1 serviceability + include: + - test: jdk/tier1 part 1 + suites: test/jdk/:tier1_part1 + - test: jdk/tier1 part 2 + suites: test/jdk/:tier1_part2 + - test: jdk/tier1 part 3 + suites: test/jdk/:tier1_part3 + - test: langtools/tier1 + suites: test/langtools/:tier1 + - test: hs/tier1 common + suites: test/hotspot/jtreg/:tier1_common + artifact: -debug + - test: hs/tier1 compiler + suites: test/hotspot/jtreg/:tier1_compiler + artifact: -debug + - test: hs/tier1 gc + suites: test/hotspot/jtreg/:tier1_gc + artifact: -debug + - test: hs/tier1 runtime + suites: test/hotspot/jtreg/:tier1_runtime + artifact: -debug + - test: hs/tier1 serviceability + suites: test/hotspot/jtreg/:tier1_serviceability + artifact: -debug + + # Reduced 32-bit build uses the same boot JDK as 64-bit build + env: + JDK_VERSION: "${{ fromJson(needs.prerequisites.outputs.dependencies).DEFAULT_VERSION_FEATURE }}" + BOOT_JDK_VERSION: "${{ fromJson(needs.prerequisites.outputs.dependencies).BOOT_JDK_VERSION }}" + BOOT_JDK_FILENAME: "${{ fromJson(needs.prerequisites.outputs.dependencies).LINUX_X64_BOOT_JDK_FILENAME }}" + BOOT_JDK_URL: "${{ fromJson(needs.prerequisites.outputs.dependencies).LINUX_X64_BOOT_JDK_URL }}" + BOOT_JDK_SHA256: "${{ fromJson(needs.prerequisites.outputs.dependencies).LINUX_X64_BOOT_JDK_SHA256 }}" + + steps: + - name: Checkout the source + uses: actions/checkout@v2 + + - name: Restore boot JDK from cache + id: bootjdk + uses: actions/cache@v2 + with: + path: ~/bootjdk/${{ env.BOOT_JDK_VERSION }} + key: bootjdk-${{ runner.os }}-${{ env.BOOT_JDK_VERSION }}-${{ env.BOOT_JDK_SHA256 }}-v1 + + - name: Download boot JDK + run: | + mkdir -p "${HOME}/bootjdk/${BOOT_JDK_VERSION}" + wget -O "${HOME}/bootjdk/${BOOT_JDK_FILENAME}" "${BOOT_JDK_URL}" + echo "${BOOT_JDK_SHA256} ${HOME}/bootjdk/${BOOT_JDK_FILENAME}" | sha256sum -c >/dev/null - + tar -xf "${HOME}/bootjdk/${BOOT_JDK_FILENAME}" -C "${HOME}/bootjdk/${BOOT_JDK_VERSION}" + mv "${HOME}/bootjdk/${BOOT_JDK_VERSION}/"*/* "${HOME}/bootjdk/${BOOT_JDK_VERSION}/" + if: steps.bootjdk.outputs.cache-hit != 'true' + + - name: Restore jtreg artifact + id: jtreg_restore + uses: actions/download-artifact@v2 + with: + name: transient_jtreg_${{ needs.prerequisites.outputs.bundle_id }} + path: ~/jtreg/ + continue-on-error: true + + - name: Restore jtreg artifact (retry) + uses: actions/download-artifact@v2 + with: + name: transient_jtreg_${{ needs.prerequisites.outputs.bundle_id }} + path: ~/jtreg/ + if: steps.jtreg_restore.outcome == 'failure' + + - name: Restore build artifacts + id: build_restore + uses: actions/download-artifact@v2 + with: + name: transient_jdk-linux-x86${{ matrix.artifact }}_${{ needs.prerequisites.outputs.bundle_id }} + path: ~/jdk-linux-x86${{ matrix.artifact }} + continue-on-error: true + + - name: Restore build artifacts (retry) + uses: actions/download-artifact@v2 + with: + name: transient_jdk-linux-x86${{ matrix.artifact }}_${{ needs.prerequisites.outputs.bundle_id }} + path: ~/jdk-linux-x86${{ matrix.artifact }} + if: steps.build_restore.outcome == 'failure' + + - name: Unpack jdk + run: | + mkdir -p "${HOME}/jdk-linux-x86${{ matrix.artifact }}/jdk-${{ env.JDK_VERSION }}-internal+0_linux-x86_bin${{ matrix.artifact }}" + tar -xf "${HOME}/jdk-linux-x86${{ matrix.artifact }}/jdk-${{ env.JDK_VERSION }}-internal+0_linux-x86_bin${{ matrix.artifact }}.tar.gz" -C "${HOME}/jdk-linux-x86${{ matrix.artifact }}/jdk-${{ env.JDK_VERSION }}-internal+0_linux-x86_bin${{ matrix.artifact }}" + + - name: Unpack tests + run: | + mkdir -p "${HOME}/jdk-linux-x86${{ matrix.artifact }}/jdk-${{ env.JDK_VERSION }}-internal+0_linux-x86_bin-tests${{ matrix.artifact }}" + tar -xf "${HOME}/jdk-linux-x86${{ matrix.artifact }}/jdk-${{ env.JDK_VERSION }}-internal+0_linux-x86_bin-tests${{ matrix.artifact }}.tar.gz" -C "${HOME}/jdk-linux-x86${{ matrix.artifact }}/jdk-${{ env.JDK_VERSION }}-internal+0_linux-x86_bin-tests${{ matrix.artifact }}" + + - name: Find root of jdk image dir + run: | + imageroot=`find ${HOME}/jdk-linux-x86${{ matrix.artifact }}/jdk-${{ env.JDK_VERSION }}-internal+0_linux-x86_bin${{ matrix.artifact }} -name release -type f` + echo "imageroot=`dirname ${imageroot}`" >> $GITHUB_ENV + + - name: Run tests + run: > + JDK_IMAGE_DIR=${{ env.imageroot }} + TEST_IMAGE_DIR=${HOME}/jdk-linux-x86${{ matrix.artifact }}/jdk-${{ env.JDK_VERSION }}-internal+0_linux-x86_bin-tests${{ matrix.artifact }} + BOOT_JDK=${HOME}/bootjdk/${BOOT_JDK_VERSION} + JT_HOME=${HOME}/jtreg + make test-prebuilt + CONF_NAME=run-test-prebuilt + LOG_CMDLINES=true + JTREG_VERBOSE=fail,error,time + TEST="${{ matrix.suites }}" + TEST_OPTS_JAVA_OPTIONS= + JTREG_KEYWORDS="!headful" + JTREG="JAVA_OPTIONS=-XX:-CreateCoredumpOnCrash" + + - name: Check that all tests executed successfully + if: always() + run: > + if ! grep --include=test-summary.txt -lqr build/*/test-results -e "TEST SUCCESS" ; then + cat build/*/test-results/*/text/newfailures.txt ; + exit 1 ; + fi + + - name: Create suitable test log artifact name + if: always() + run: echo "logsuffix=`echo ${{ matrix.test }} | sed -e 's!/!_!'g -e 's! !_!'g`" >> $GITHUB_ENV + + - name: Package test results + if: always() + working-directory: build/run-test-prebuilt/test-results/ + run: > + zip -r9 + "$HOME/linux-x86${{ matrix.artifact }}_testresults_${{ env.logsuffix }}.zip" + . + continue-on-error: true + + - name: Package test support + if: always() + working-directory: build/run-test-prebuilt/test-support/ + run: > + zip -r9 + "$HOME/linux-x86${{ matrix.artifact }}_testsupport_${{ env.logsuffix }}.zip" + . + -i *.jtr + -i hs_err* + -i replay* + continue-on-error: true + + - name: Persist test results + if: always() + uses: actions/upload-artifact@v2 + with: + path: ~/linux-x86${{ matrix.artifact }}_testresults_${{ env.logsuffix }}.zip + continue-on-error: true + + - name: Persist test outputs + if: always() + uses: actions/upload-artifact@v2 + with: + path: ~/linux-x86${{ matrix.artifact }}_testsupport_${{ env.logsuffix }}.zip + continue-on-error: true + windows_x64_build: name: Windows x64 runs-on: "windows-latest" @@ -734,12 +952,41 @@ jobs: if: always() run: echo ("logsuffix=" + ("${{ matrix.test }}" -replace "/", "_" -replace " ", "_")) | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 - - name: Persist test logs + - name: Package test results + if: always() + working-directory: build/run-test-prebuilt/test-results/ + run: > + $env:Path = "$HOME\cygwin\cygwin64\bin;$env:Path" ; + zip -r9 + "$HOME/windows-x64${{ matrix.artifact }}_testresults_${{ env.logsuffix }}.zip" + . + continue-on-error: true + + - name: Package test support + if: always() + working-directory: build/run-test-prebuilt/test-support/ + run: > + $env:Path = "$HOME\cygwin\cygwin64\bin;$env:Path" ; + zip -r9 + "$HOME/windows-x64${{ matrix.artifact }}_testsupport_${{ env.logsuffix }}.zip" + . + -i *.jtr + -i hs_err* + -i replay* + continue-on-error: true + + - name: Persist test results + if: always() + uses: actions/upload-artifact@v2 + with: + path: ~/windows-x64${{ matrix.artifact }}_testresults_${{ env.logsuffix }}.zip + continue-on-error: true + + - name: Persist test outputs if: always() uses: actions/upload-artifact@v2 with: - name: windows-x64${{ matrix.artifact }}_testlogs_${{ env.logsuffix }} - path: build/*/test-results + path: ~/windows-x64${{ matrix.artifact }}_testsupport_${{ env.logsuffix }}.zip continue-on-error: true macos_x64_build: @@ -989,12 +1236,39 @@ jobs: if: always() run: echo "logsuffix=`echo ${{ matrix.test }} | sed -e 's!/!_!'g -e 's! !_!'g`" >> $GITHUB_ENV - - name: Persist test logs + - name: Package test results + if: always() + working-directory: build/run-test-prebuilt/test-results/ + run: > + zip -r9 + "$HOME/macos-x64${{ matrix.artifact }}_testresults_${{ env.logsuffix }}.zip" + . + continue-on-error: true + + - name: Package test support + if: always() + working-directory: build/run-test-prebuilt/test-support/ + run: > + zip -r9 + "$HOME/macos-x64${{ matrix.artifact }}_testsupport_${{ env.logsuffix }}.zip" + . + -i *.jtr + -i hs_err* + -i replay* + continue-on-error: true + + - name: Persist test results if: always() uses: actions/upload-artifact@v2 with: - name: macos-x64${{ matrix.artifact }}_testlogs_${{ env.logsuffix }} - path: build/*/test-results + path: ~/macos-x64${{ matrix.artifact }}_testresults_${{ env.logsuffix }}.zip + continue-on-error: true + + - name: Persist test outputs + if: always() + uses: actions/upload-artifact@v2 + with: + path: ~/macos-x64${{ matrix.artifact }}_testsupport_${{ env.logsuffix }}.zip continue-on-error: true artifacts: @@ -1003,7 +1277,9 @@ jobs: if: always() continue-on-error: true needs: + - prerequisites - linux_x64_test + - linux_x86_test - windows_x64_test - macos_x64_test diff --git a/make/Main.gmk b/make/Main.gmk index 31eedcd1f9d..cdb4be67c56 100644 --- a/make/Main.gmk +++ b/make/Main.gmk @@ -338,7 +338,7 @@ $(eval $(call SetupTarget, test-image-demos-jdk, \ $(eval $(call SetupTarget, generate-summary, \ MAKEFILE := GenerateModuleSummary, \ - DEPS := jmods buildtools-modules, \ + DEPS := jmods buildtools-modules runnable-buildjdk, \ )) ################################################################################ @@ -468,7 +468,7 @@ $(eval $(call SetupTarget, docs-jdk-api-javadoc, \ $(eval $(call SetupTarget, docs-jdk-api-modulegraph, \ MAKEFILE := Docs, \ TARGET := docs-jdk-api-modulegraph, \ - DEPS := buildtools-modules, \ + DEPS := buildtools-modules runnable-buildjdk, \ )) $(eval $(call SetupTarget, docs-javase-api-javadoc, \ @@ -479,7 +479,7 @@ $(eval $(call SetupTarget, docs-javase-api-javadoc, \ $(eval $(call SetupTarget, docs-javase-api-modulegraph, \ MAKEFILE := Docs, \ TARGET := docs-javase-api-modulegraph, \ - DEPS := buildtools-modules, \ + DEPS := buildtools-modules runnable-buildjdk, \ )) $(eval $(call SetupTarget, docs-reference-api-javadoc, \ @@ -490,7 +490,7 @@ $(eval $(call SetupTarget, docs-reference-api-javadoc, \ $(eval $(call SetupTarget, docs-reference-api-modulegraph, \ MAKEFILE := Docs, \ TARGET := docs-reference-api-modulegraph, \ - DEPS := buildtools-modules, \ + DEPS := buildtools-modules runnable-buildjdk, \ )) # The gensrc steps for jdk.jdi create html spec files. @@ -1083,6 +1083,18 @@ ifneq ($(COMPILE_TYPE), cross) exploded-image: exploded-image-optimize endif +# The runnable-buildjdk target guarantees that the buildjdk is done +# building and ready to be used. The exact set of dependencies it needs +# depends on what kind of buildjdk is used for the current configuration. +runnable-buildjdk: +ifeq ($(CREATE_BUILDJDK), true) + ifneq ($(CREATING_BUILDJDK), true) + runnable-buildjdk: create-buildjdk + endif +else ifeq ($(EXTERNAL_BUILDJDK), false) + runnable-buildjdk: exploded-image +endif + create-buildjdk: create-buildjdk-interim-image docs-jdk-api: docs-jdk-api-javadoc @@ -1186,7 +1198,7 @@ all-bundles: product-bundles test-bundles docs-bundles static-libs-bundles ALL_TARGETS += buildtools hotspot hotspot-libs hotspot-gensrc gensrc gendata \ copy java libs static-libs launchers jmods \ jdk.jdwp.agent-gensrc $(ALL_MODULES) demos \ - exploded-image-base exploded-image \ + exploded-image-base exploded-image runnable-buildjdk \ create-buildjdk docs-jdk-api docs-javase-api docs-reference-api docs-jdk \ docs-javase docs-reference docs-javadoc mac-bundles product-images legacy-images \ docs-image docs-javase-image docs-reference-image all-docs-images \ diff --git a/make/autoconf/spec.gmk.in b/make/autoconf/spec.gmk.in index d7751c80e93..b58ac1193df 100644 --- a/make/autoconf/spec.gmk.in +++ b/make/autoconf/spec.gmk.in @@ -761,7 +761,6 @@ TAR_SUPPORTS_TRANSFORM:=@TAR_SUPPORTS_TRANSFORM@ # Build setup ENABLE_AOT:=@ENABLE_AOT@ -ENABLE_INTREE_EC:=@ENABLE_INTREE_EC@ USE_EXTERNAL_LIBJPEG:=@USE_EXTERNAL_LIBJPEG@ USE_EXTERNAL_LIBGIF:=@USE_EXTERNAL_LIBGIF@ USE_EXTERNAL_LIBZ:=@USE_EXTERNAL_LIBZ@ diff --git a/make/conf/jib-profiles.js b/make/conf/jib-profiles.js index 05a2c527831..36460fee4b4 100644 --- a/make/conf/jib-profiles.js +++ b/make/conf/jib-profiles.js @@ -251,6 +251,8 @@ var getJibProfilesCommon = function (input, data) { configure_args: concat("--enable-jtreg-failure-handler", "--with-exclude-translations=de,es,fr,it,ko,pt_BR,sv,ca,tr,cs,sk,ja_JP_A,ja_JP_HA,ja_JP_HI,ja_JP_I,zh_TW,zh_HK", "--disable-manpages", + "--disable-jvm-feature-aot", + "--disable-jvm-feature-graal", "--disable-jvm-feature-shenandoahgc", versionArgs(input, common)) }; @@ -404,9 +406,9 @@ var getJibProfilesProfiles = function (input, common, data) { "linux-x64": { target_os: "linux", target_cpu: "x64", - dependencies: ["devkit", "gtest", "graphviz", "pandoc", "graalunit_lib"], + dependencies: ["devkit", "gtest", "graphviz", "pandoc"], configure_args: concat(common.configure_args_64bit, - "--with-zlib=system", + "--with-zlib=system", "--disable-dtrace", (isWsl(input) ? [ "--host=x86_64-unknown-linux-gnu", "--build=x86_64-unknown-linux-gnu" ] : [])), }, @@ -423,7 +425,7 @@ var getJibProfilesProfiles = function (input, common, data) { "macosx-x64": { target_os: "macosx", target_cpu: "x64", - dependencies: ["devkit", "gtest", "pandoc", "graalunit_lib"], + dependencies: ["devkit", "gtest", "pandoc"], configure_args: concat(common.configure_args_64bit, "--with-zlib=system", "--with-macosx-version-max=10.9.0", // Use system SetFile instead of the one in the devkit as the @@ -434,7 +436,7 @@ var getJibProfilesProfiles = function (input, common, data) { "windows-x64": { target_os: "windows", target_cpu: "x64", - dependencies: ["devkit", "gtest", "pandoc", "graalunit_lib"], + dependencies: ["devkit", "gtest", "pandoc"], configure_args: concat(common.configure_args_64bit), }, @@ -454,8 +456,6 @@ var getJibProfilesProfiles = function (input, common, data) { configure_args: [ "--openjdk-target=aarch64-linux-gnu", "--disable-jvm-feature-jvmci", - "--disable-jvm-feature-graal", - "--disable-jvm-feature-aot", ], }, @@ -687,11 +687,12 @@ var getJibProfilesProfiles = function (input, common, data) { dependencies: [ "boot_jdk", "devkit", "graphviz", "pandoc", buildJdkDep, ], - configure_args: [ + configure_args: concat( "--enable-full-docs", + versionArgs(input, common), "--with-build-jdk=" + input.get(buildJdkDep, "home_path") + (input.build_os == "macosx" ? "/Contents/Home" : "") - ], + ), default_make_targets: ["all-docs-bundles"], artifacts: { doc_api_spec: { @@ -1151,15 +1152,6 @@ var getJibProfilesDependencies = function (input, common) { configure_args: "", }, - graalunit_lib: { - organization: common.organization, - ext: "zip", - revision: "619_Apr_12_2018", - module: "graalunit-lib", - configure_args: "--with-graalunit-lib=" + input.get("graalunit_lib", "install_path"), - environment_name: "GRAALUNIT_LIB" - }, - gtest: { organization: common.organization, ext: "tar.gz", diff --git a/make/hotspot/lib/CompileJvm.gmk b/make/hotspot/lib/CompileJvm.gmk index 441c09a3853..e58f443c603 100644 --- a/make/hotspot/lib/CompileJvm.gmk +++ b/make/hotspot/lib/CompileJvm.gmk @@ -95,7 +95,7 @@ DISABLED_WARNINGS_clang := tautological-compare \ DISABLED_WARNINGS_xlc := tautological-compare shift-negative-value -DISABLED_WARNINGS_microsoft := 4100 4127 4201 4244 4291 4351 \ +DISABLED_WARNINGS_microsoft := 4100 4127 4146 4201 4244 4291 4351 \ 4511 4512 4514 4624 4996 ################################################################################ diff --git a/make/modules/java.base/Copy.gmk b/make/modules/java.base/Copy.gmk index 9071f4e6e37..040b7588ba1 100644 --- a/make/modules/java.base/Copy.gmk +++ b/make/modules/java.base/Copy.gmk @@ -182,12 +182,16 @@ endif ################################################################################ -$(eval $(call SetupCopyFiles, COPY_NET_PROPERTIES, \ - FILES := $(TOPDIR)/src/java.base/share/conf/net.properties, \ - DEST := $(CONF_DST_DIR), \ -)) +NET_PROPERTIES_SRCS := $(TOPDIR)/src/java.base/share/conf/net.properties \ + $(TOPDIR)/src/java.base/$(OPENJDK_TARGET_OS_TYPE)/conf/net.properties + +NET_PROPERTIES_DST := $(CONF_DST_DIR)/net.properties + +$(NET_PROPERTIES_DST): $(NET_PROPERTIES_SRCS) + $(call MakeTargetDir) + $(CAT) $(NET_PROPERTIES_SRCS) > $@ -TARGETS += $(COPY_NET_PROPERTIES) +TARGETS += $(NET_PROPERTIES_DST) ifeq ($(call isTargetOs, linux), true) $(eval $(call SetupCopyFiles, COPY_SDP_CONF, \ diff --git a/make/modules/jdk.crypto.ec/Lib.gmk b/make/modules/jdk.crypto.ec/Lib.gmk deleted file mode 100644 index eb1baccc930..00000000000 --- a/make/modules/jdk.crypto.ec/Lib.gmk +++ /dev/null @@ -1,49 +0,0 @@ -# -# 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 -# 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. -# - -include LibCommon.gmk - -################################################################################ - -ifeq ($(ENABLE_INTREE_EC), true) - $(eval $(call SetupJdkLibrary, BUILD_LIBSUNEC, \ - NAME := sunec, \ - TOOLCHAIN := TOOLCHAIN_LINK_CXX, \ - OPTIMIZATION := LOW, \ - CFLAGS := $(CFLAGS_JDKLIB) \ - -DMP_API_COMPATIBLE -DNSS_ECC_MORE_THAN_SUITE_B, \ - CXXFLAGS := $(CXXFLAGS_JDKLIB), \ - DISABLED_WARNINGS_gcc := sign-compare implicit-fallthrough unused-value, \ - DISABLED_WARNINGS_clang := sign-compare, \ - DISABLED_WARNINGS_microsoft := 4101 4244 4146 4018, \ - LDFLAGS := $(LDFLAGS_JDKLIB) $(LDFLAGS_CXX_JDK), \ - LDFLAGS_macosx := $(call SET_SHARED_LIBRARY_ORIGIN), \ - LIBS := $(LIBCXX), \ - )) - - TARGETS += $(BUILD_LIBSUNEC) -endif - -################################################################################ diff --git a/make/test/BuildMicrobenchmark.gmk b/make/test/BuildMicrobenchmark.gmk index 3bbbea47b8e..55e5026eb38 100644 --- a/make/test/BuildMicrobenchmark.gmk +++ b/make/test/BuildMicrobenchmark.gmk @@ -90,11 +90,10 @@ $(eval $(call SetupJavaCompilation, BUILD_JDK_MICROBENCHMARK, \ TARGET_RELEASE := $(TARGET_RELEASE_NEWJDK_UPGRADED), \ SMALL_JAVA := false, \ CLASSPATH := $(MICROBENCHMARK_CLASSPATH), \ - DISABLED_WARNINGS := processing rawtypes cast serial preview, \ + DISABLED_WARNINGS := processing rawtypes cast serial, \ SRC := $(MICROBENCHMARK_SRC), \ BIN := $(MICROBENCHMARK_CLASSES), \ JAVA_FLAGS := --add-modules jdk.unsupported --limit-modules java.management, \ - JAVAC_FLAGS := --enable-preview, \ )) $(BUILD_JDK_MICROBENCHMARK): $(JMH_COMPILE_JARS) diff --git a/src/demo/share/jfc/Notepad/Notepad.java b/src/demo/share/jfc/Notepad/Notepad.java index 3ebe3f07d22..cb4552f94cf 100644 --- a/src/demo/share/jfc/Notepad/Notepad.java +++ b/src/demo/share/jfc/Notepad/Notepad.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -60,7 +60,7 @@ * @author Timothy Prinzing */ @SuppressWarnings("serial") -class Notepad extends JPanel { +public class Notepad extends JPanel { protected static Properties properties; private static ResourceBundle resources; diff --git a/src/hotspot/cpu/aarch64/assembler_aarch64.hpp b/src/hotspot/cpu/aarch64/assembler_aarch64.hpp index 75b4451450d..ba352461e4a 100644 --- a/src/hotspot/cpu/aarch64/assembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/assembler_aarch64.hpp @@ -217,7 +217,7 @@ class Instruction_aarch64 { static void patch(address a, int msb, int lsb, uint64_t val) { int nbits = msb - lsb + 1; - guarantee(val < (1U << nbits), "Field too big for insn"); + guarantee(val < (1ULL << nbits), "Field too big for insn"); assert_cond(msb >= lsb); unsigned mask = (1U << nbits) - 1; val <<= lsb; @@ -445,8 +445,8 @@ class Address { } Register base() const { - guarantee((_mode == base_plus_offset | _mode == base_plus_offset_reg - | _mode == post | _mode == post_reg), + guarantee((_mode == base_plus_offset || _mode == base_plus_offset_reg + || _mode == post || _mode == post_reg), "wrong mode"); return _base; } diff --git a/src/hotspot/cpu/aarch64/frame_aarch64.cpp b/src/hotspot/cpu/aarch64/frame_aarch64.cpp index 8731d83b0f7..15c5e16f380 100644 --- a/src/hotspot/cpu/aarch64/frame_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/frame_aarch64.cpp @@ -662,11 +662,12 @@ intptr_t* frame::real_fp() const { #undef DESCRIBE_FP_OFFSET -#define DESCRIBE_FP_OFFSET(name) \ - { \ - uintptr_t *p = (uintptr_t *)fp; \ - printf("0x%016lx 0x%016lx %s\n", (uintptr_t)(p + frame::name##_offset), \ - p[frame::name##_offset], #name); \ +#define DESCRIBE_FP_OFFSET(name) \ + { \ + uintptr_t *p = (uintptr_t *)fp; \ + printf(INTPTR_FORMAT " " INTPTR_FORMAT " %s\n", \ + (uintptr_t)(p + frame::name##_offset), \ + p[frame::name##_offset], #name); \ } static THREAD_LOCAL uintptr_t nextfp; diff --git a/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.cpp index 5d9f191bba8..e4b62a523de 100644 --- a/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.cpp @@ -262,7 +262,7 @@ void ShenandoahBarrierSetAssembler::load_reference_barrier_not_null(MacroAssembl __ leave(); } -void ShenandoahBarrierSetAssembler::load_reference_barrier_native(MacroAssembler* masm, Register dst, Address load_addr) { +void ShenandoahBarrierSetAssembler::load_reference_barrier_weak(MacroAssembler* masm, Register dst, Address load_addr) { if (!ShenandoahLoadRefBarrier) { return; } @@ -272,7 +272,7 @@ void ShenandoahBarrierSetAssembler::load_reference_barrier_native(MacroAssembler Label is_null; Label done; - __ block_comment("load_reference_barrier_native { "); + __ block_comment("load_reference_barrier_weak { "); __ cbz(dst, is_null); @@ -286,7 +286,7 @@ void ShenandoahBarrierSetAssembler::load_reference_barrier_native(MacroAssembler __ mov(rscratch2, dst); __ push_call_clobbered_registers(); - __ mov(lr, CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_native)); + __ mov(lr, CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_weak)); __ lea(r1, load_addr); __ mov(r0, rscratch2); __ blr(lr); @@ -297,7 +297,7 @@ void ShenandoahBarrierSetAssembler::load_reference_barrier_native(MacroAssembler __ bind(done); __ leave(); __ bind(is_null); - __ block_comment("} load_reference_barrier_native"); + __ block_comment("} load_reference_barrier_weak"); } void ShenandoahBarrierSetAssembler::storeval_barrier(MacroAssembler* masm, Register dst, Register tmp) { @@ -352,8 +352,8 @@ void ShenandoahBarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet d BarrierSetAssembler::load_at(masm, decorators, type, dst, src, tmp1, tmp_thread); - if (ShenandoahBarrierSet::use_load_reference_barrier_native(decorators, type)) { - load_reference_barrier_native(masm, dst, src); + if (ShenandoahBarrierSet::use_load_reference_barrier_weak(decorators, type)) { + load_reference_barrier_weak(masm, dst, src); } else { load_reference_barrier(masm, dst, src); } @@ -477,7 +477,8 @@ void ShenandoahBarrierSetAssembler::cmpxchg_oop(MacroAssembler* masm, bool is_narrow = UseCompressedOops; Assembler::operand_size size = is_narrow ? Assembler::word : Assembler::xword; - assert_different_registers(addr, expected, new_val, tmp1, tmp2); + assert_different_registers(addr, expected, tmp1, tmp2); + assert_different_registers(addr, new_val, tmp1, tmp2); Label step4, done; @@ -669,8 +670,8 @@ void ShenandoahBarrierSetAssembler::gen_load_reference_barrier_stub(LIR_Assemble __ bind(slow_path); ce->store_parameter(res, 0); ce->store_parameter(addr, 1); - if (stub->is_native()) { - __ far_call(RuntimeAddress(bs->load_reference_barrier_native_rt_code_blob()->code_begin())); + if (stub->is_weak()) { + __ far_call(RuntimeAddress(bs->load_reference_barrier_weak_rt_code_blob()->code_begin())); } else { __ far_call(RuntimeAddress(bs->load_reference_barrier_rt_code_blob()->code_begin())); } @@ -728,15 +729,15 @@ void ShenandoahBarrierSetAssembler::generate_c1_pre_barrier_runtime_stub(StubAss __ epilogue(); } -void ShenandoahBarrierSetAssembler::generate_c1_load_reference_barrier_runtime_stub(StubAssembler* sasm, bool is_native) { +void ShenandoahBarrierSetAssembler::generate_c1_load_reference_barrier_runtime_stub(StubAssembler* sasm, bool is_weak) { __ prologue("shenandoah_load_reference_barrier", false); // arg0 : object to be resolved __ push_call_clobbered_registers(); __ load_parameter(0, r0); __ load_parameter(1, r1); - if (is_native) { - __ mov(lr, CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_native)); + if (is_weak) { + __ mov(lr, CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_weak)); } else if (UseCompressedOops) { __ mov(lr, CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_narrow)); } else { diff --git a/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.hpp index 88aa9a2b95f..30446b65b35 100644 --- a/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.hpp @@ -59,7 +59,7 @@ class ShenandoahBarrierSetAssembler: public BarrierSetAssembler { void resolve_forward_pointer_not_null(MacroAssembler* masm, Register dst, Register tmp = noreg); void load_reference_barrier(MacroAssembler* masm, Register dst, Address load_addr); void load_reference_barrier_not_null(MacroAssembler* masm, Register dst, Address load_addr); - void load_reference_barrier_native(MacroAssembler* masm, Register dst, Address load_addr); + void load_reference_barrier_weak(MacroAssembler* masm, Register dst, Address load_addr); address generate_shenandoah_lrb(StubCodeGenerator* cgen); @@ -72,7 +72,7 @@ class ShenandoahBarrierSetAssembler: public BarrierSetAssembler { void gen_pre_barrier_stub(LIR_Assembler* ce, ShenandoahPreBarrierStub* stub); void gen_load_reference_barrier_stub(LIR_Assembler* ce, ShenandoahLoadReferenceBarrierStub* stub); void generate_c1_pre_barrier_runtime_stub(StubAssembler* sasm); - void generate_c1_load_reference_barrier_runtime_stub(StubAssembler* sasm, bool is_native); + void generate_c1_load_reference_barrier_runtime_stub(StubAssembler* sasm, bool is_weak); #endif virtual void arraycopy_prologue(MacroAssembler* masm, DecoratorSet decorators, bool is_oop, diff --git a/src/hotspot/cpu/aarch64/globals_aarch64.hpp b/src/hotspot/cpu/aarch64/globals_aarch64.hpp index 294b6b13495..9ad1360fa91 100644 --- a/src/hotspot/cpu/aarch64/globals_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/globals_aarch64.hpp @@ -93,6 +93,8 @@ define_pd_global(intx, InlineSmallCode, 1000); "Use SIMD instructions in generated array equals code") \ product(bool, UseSimpleArrayEquals, false, \ "Use simpliest and shortest implementation for array equals") \ + product(bool, UseSIMDForBigIntegerShiftIntrinsics, true, \ + "Use SIMD instructions for left/right shift of BigInteger") \ product(bool, AvoidUnalignedAccesses, false, \ "Avoid generating unaligned memory accesses") \ product(bool, UseLSE, false, \ diff --git a/src/hotspot/cpu/aarch64/interp_masm_aarch64.cpp b/src/hotspot/cpu/aarch64/interp_masm_aarch64.cpp index 44b9f59bbb3..09632154630 100644 --- a/src/hotspot/cpu/aarch64/interp_masm_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/interp_masm_aarch64.cpp @@ -551,7 +551,9 @@ void InterpreterMacroAssembler::remove_activation( br(Assembler::AL, fast_path); bind(slow_path); push(state); - call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::at_unwind)); + set_last_Java_frame(esp, rfp, (address)pc(), rscratch1); + super_call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::at_unwind), rthread); + reset_last_Java_frame(true); pop(state); bind(fast_path); diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp index 23046ace7a2..19c3aefe115 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp @@ -1830,7 +1830,7 @@ bool MacroAssembler::try_merge_ldst(Register rt, const Address &adr, size_t size return true; } else { assert(size_in_bytes == 8 || size_in_bytes == 4, "only 8 bytes or 4 bytes load/store is supported."); - const unsigned mask = size_in_bytes - 1; + const uint64_t mask = size_in_bytes - 1; if (adr.getMode() == Address::base_plus_offset && (adr.offset() & mask) == 0) { // only supports base_plus_offset. code()->set_last_insn(pc()); @@ -2894,7 +2894,7 @@ void MacroAssembler::merge_ldst(Register rt, // Overwrite previous generated binary. code_section()->set_end(prev); - const int sz = prev_ldst->size_in_bytes(); + const size_t sz = prev_ldst->size_in_bytes(); assert(sz == 8 || sz == 4, "only supports 64/32bit merging."); if (!is_store) { BLOCK_COMMENT("merged ldr pair"); diff --git a/src/hotspot/cpu/aarch64/nativeInst_aarch64.hpp b/src/hotspot/cpu/aarch64/nativeInst_aarch64.hpp index d40c533a82c..dcf87913a88 100644 --- a/src/hotspot/cpu/aarch64/nativeInst_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/nativeInst_aarch64.hpp @@ -655,7 +655,7 @@ class NativeLdSt : public NativeInstruction { return 0; } } - size_t size_in_bytes() { return 1 << size(); } + size_t size_in_bytes() { return 1ULL << size(); } bool is_not_pre_post_index() { return (is_ldst_ur() || is_ldst_unsigned_offset()); } bool is_load() { assert(Instruction_aarch64::extract(uint_at(0), 23, 22) == 0b01 || diff --git a/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp b/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp index 089f56f88b6..92a07a84d2a 100644 --- a/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp @@ -1498,7 +1498,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm, // Generate stack overflow check if (UseStackBanging) { - __ bang_stack_with_offset(StackOverflow::stack_shadow_zone_size()); + __ bang_stack_with_offset(checked_cast(StackOverflow::stack_shadow_zone_size())); } else { Unimplemented(); } @@ -2445,7 +2445,7 @@ void SharedRuntime::generate_deopt_blob() { __ sub(sp, sp, r19); // Push interpreter frames in a loop - __ mov(rscratch1, (address)0xDEADDEAD); // Make a recognizable pattern + __ mov(rscratch1, (uint64_t)0xDEADDEAD); // Make a recognizable pattern __ mov(rscratch2, rscratch1); Label loop; __ bind(loop); diff --git a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp index a230e4e5bba..93ccbb7e859 100644 --- a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp @@ -1305,14 +1305,14 @@ class StubGenerator: public StubCodeGenerator { // Scan over array at a for count oops, verifying each one. // Preserves a and count, clobbers rscratch1 and rscratch2. - void verify_oop_array (size_t size, Register a, Register count, Register temp) { + void verify_oop_array (int size, Register a, Register count, Register temp) { Label loop, end; __ mov(rscratch1, a); __ mov(rscratch2, zr); __ bind(loop); __ cmp(rscratch2, count); __ br(Assembler::HS, end); - if (size == (size_t)wordSize) { + if (size == wordSize) { __ ldr(temp, Address(a, rscratch2, Address::lsl(exact_log2(size)))); __ verify_oop(temp); } else { @@ -1343,7 +1343,7 @@ class StubGenerator: public StubCodeGenerator { // disjoint_int_copy_entry is set to the no-overlap entry point // used by generate_conjoint_int_oop_copy(). // - address generate_disjoint_copy(size_t size, bool aligned, bool is_oop, address *entry, + address generate_disjoint_copy(int size, bool aligned, bool is_oop, address *entry, const char *name, bool dest_uninitialized = false) { Register s = c_rarg0, d = c_rarg1, count = c_rarg2; RegSet saved_reg = RegSet::of(s, d, count); @@ -1409,7 +1409,7 @@ class StubGenerator: public StubCodeGenerator { // the hardware handle it. The two dwords within qwords that span // cache line boundaries will still be loaded and stored atomicly. // - address generate_conjoint_copy(size_t size, bool aligned, bool is_oop, address nooverlap_target, + address generate_conjoint_copy(int size, bool aligned, bool is_oop, address nooverlap_target, address *entry, const char *name, bool dest_uninitialized = false) { Register s = c_rarg0, d = c_rarg1, count = c_rarg2; @@ -1660,7 +1660,7 @@ class StubGenerator: public StubCodeGenerator { address generate_disjoint_oop_copy(bool aligned, address *entry, const char *name, bool dest_uninitialized) { const bool is_oop = true; - const size_t size = UseCompressedOops ? sizeof (jint) : sizeof (jlong); + const int size = UseCompressedOops ? sizeof (jint) : sizeof (jlong); return generate_disjoint_copy(size, aligned, is_oop, entry, name, dest_uninitialized); } @@ -1678,7 +1678,7 @@ class StubGenerator: public StubCodeGenerator { address nooverlap_target, address *entry, const char *name, bool dest_uninitialized) { const bool is_oop = true; - const size_t size = UseCompressedOops ? sizeof (jint) : sizeof (jlong); + const int size = UseCompressedOops ? sizeof (jint) : sizeof (jlong); return generate_conjoint_copy(size, aligned, is_oop, nooverlap_target, entry, name, dest_uninitialized); } @@ -3968,6 +3968,238 @@ class StubGenerator: public StubCodeGenerator { return start; } + // Arguments: + // + // Input: + // c_rarg0 - newArr address + // c_rarg1 - oldArr address + // c_rarg2 - newIdx + // c_rarg3 - shiftCount + // c_rarg4 - numIter + // + address generate_bigIntegerRightShift() { + __ align(CodeEntryAlignment); + StubCodeMark mark(this, "StubRoutines", "bigIntegerRightShiftWorker"); + address start = __ pc(); + + Label ShiftSIMDLoop, ShiftTwoLoop, ShiftThree, ShiftTwo, ShiftOne, Exit; + + Register newArr = c_rarg0; + Register oldArr = c_rarg1; + Register newIdx = c_rarg2; + Register shiftCount = c_rarg3; + Register numIter = c_rarg4; + Register idx = numIter; + + Register newArrCur = rscratch1; + Register shiftRevCount = rscratch2; + Register oldArrCur = r13; + Register oldArrNext = r14; + + FloatRegister oldElem0 = v0; + FloatRegister oldElem1 = v1; + FloatRegister newElem = v2; + FloatRegister shiftVCount = v3; + FloatRegister shiftVRevCount = v4; + + __ cbz(idx, Exit); + + __ add(newArr, newArr, newIdx, Assembler::LSL, 2); + + // left shift count + __ movw(shiftRevCount, 32); + __ subw(shiftRevCount, shiftRevCount, shiftCount); + + // numIter too small to allow a 4-words SIMD loop, rolling back + __ cmp(numIter, (u1)4); + __ br(Assembler::LT, ShiftThree); + + __ dup(shiftVCount, __ T4S, shiftCount); + __ dup(shiftVRevCount, __ T4S, shiftRevCount); + __ negr(shiftVCount, __ T4S, shiftVCount); + + __ BIND(ShiftSIMDLoop); + + // Calculate the load addresses + __ sub(idx, idx, 4); + __ add(oldArrNext, oldArr, idx, Assembler::LSL, 2); + __ add(newArrCur, newArr, idx, Assembler::LSL, 2); + __ add(oldArrCur, oldArrNext, 4); + + // Load 4 words and process + __ ld1(oldElem0, __ T4S, Address(oldArrCur)); + __ ld1(oldElem1, __ T4S, Address(oldArrNext)); + __ ushl(oldElem0, __ T4S, oldElem0, shiftVCount); + __ ushl(oldElem1, __ T4S, oldElem1, shiftVRevCount); + __ orr(newElem, __ T16B, oldElem0, oldElem1); + __ st1(newElem, __ T4S, Address(newArrCur)); + + __ cmp(idx, (u1)4); + __ br(Assembler::LT, ShiftTwoLoop); + __ b(ShiftSIMDLoop); + + __ BIND(ShiftTwoLoop); + __ cbz(idx, Exit); + __ cmp(idx, (u1)1); + __ br(Assembler::EQ, ShiftOne); + + // Calculate the load addresses + __ sub(idx, idx, 2); + __ add(oldArrNext, oldArr, idx, Assembler::LSL, 2); + __ add(newArrCur, newArr, idx, Assembler::LSL, 2); + __ add(oldArrCur, oldArrNext, 4); + + // Load 2 words and process + __ ld1(oldElem0, __ T2S, Address(oldArrCur)); + __ ld1(oldElem1, __ T2S, Address(oldArrNext)); + __ ushl(oldElem0, __ T2S, oldElem0, shiftVCount); + __ ushl(oldElem1, __ T2S, oldElem1, shiftVRevCount); + __ orr(newElem, __ T8B, oldElem0, oldElem1); + __ st1(newElem, __ T2S, Address(newArrCur)); + __ b(ShiftTwoLoop); + + __ BIND(ShiftThree); + __ tbz(idx, 1, ShiftOne); + __ tbz(idx, 0, ShiftTwo); + __ ldrw(r10, Address(oldArr, 12)); + __ ldrw(r11, Address(oldArr, 8)); + __ lsrvw(r10, r10, shiftCount); + __ lslvw(r11, r11, shiftRevCount); + __ orrw(r12, r10, r11); + __ strw(r12, Address(newArr, 8)); + + __ BIND(ShiftTwo); + __ ldrw(r10, Address(oldArr, 8)); + __ ldrw(r11, Address(oldArr, 4)); + __ lsrvw(r10, r10, shiftCount); + __ lslvw(r11, r11, shiftRevCount); + __ orrw(r12, r10, r11); + __ strw(r12, Address(newArr, 4)); + + __ BIND(ShiftOne); + __ ldrw(r10, Address(oldArr, 4)); + __ ldrw(r11, Address(oldArr)); + __ lsrvw(r10, r10, shiftCount); + __ lslvw(r11, r11, shiftRevCount); + __ orrw(r12, r10, r11); + __ strw(r12, Address(newArr)); + + __ BIND(Exit); + __ ret(lr); + + return start; + } + + // Arguments: + // + // Input: + // c_rarg0 - newArr address + // c_rarg1 - oldArr address + // c_rarg2 - newIdx + // c_rarg3 - shiftCount + // c_rarg4 - numIter + // + address generate_bigIntegerLeftShift() { + __ align(CodeEntryAlignment); + StubCodeMark mark(this, "StubRoutines", "bigIntegerLeftShiftWorker"); + address start = __ pc(); + + Label ShiftSIMDLoop, ShiftTwoLoop, ShiftThree, ShiftTwo, ShiftOne, Exit; + + Register newArr = c_rarg0; + Register oldArr = c_rarg1; + Register newIdx = c_rarg2; + Register shiftCount = c_rarg3; + Register numIter = c_rarg4; + + Register shiftRevCount = rscratch1; + Register oldArrNext = rscratch2; + + FloatRegister oldElem0 = v0; + FloatRegister oldElem1 = v1; + FloatRegister newElem = v2; + FloatRegister shiftVCount = v3; + FloatRegister shiftVRevCount = v4; + + __ cbz(numIter, Exit); + + __ add(oldArrNext, oldArr, 4); + __ add(newArr, newArr, newIdx, Assembler::LSL, 2); + + // right shift count + __ movw(shiftRevCount, 32); + __ subw(shiftRevCount, shiftRevCount, shiftCount); + + // numIter too small to allow a 4-words SIMD loop, rolling back + __ cmp(numIter, (u1)4); + __ br(Assembler::LT, ShiftThree); + + __ dup(shiftVCount, __ T4S, shiftCount); + __ dup(shiftVRevCount, __ T4S, shiftRevCount); + __ negr(shiftVRevCount, __ T4S, shiftVRevCount); + + __ BIND(ShiftSIMDLoop); + + // load 4 words and process + __ ld1(oldElem0, __ T4S, __ post(oldArr, 16)); + __ ld1(oldElem1, __ T4S, __ post(oldArrNext, 16)); + __ ushl(oldElem0, __ T4S, oldElem0, shiftVCount); + __ ushl(oldElem1, __ T4S, oldElem1, shiftVRevCount); + __ orr(newElem, __ T16B, oldElem0, oldElem1); + __ st1(newElem, __ T4S, __ post(newArr, 16)); + __ sub(numIter, numIter, 4); + + __ cmp(numIter, (u1)4); + __ br(Assembler::LT, ShiftTwoLoop); + __ b(ShiftSIMDLoop); + + __ BIND(ShiftTwoLoop); + __ cbz(numIter, Exit); + __ cmp(numIter, (u1)1); + __ br(Assembler::EQ, ShiftOne); + + // load 2 words and process + __ ld1(oldElem0, __ T2S, __ post(oldArr, 8)); + __ ld1(oldElem1, __ T2S, __ post(oldArrNext, 8)); + __ ushl(oldElem0, __ T2S, oldElem0, shiftVCount); + __ ushl(oldElem1, __ T2S, oldElem1, shiftVRevCount); + __ orr(newElem, __ T8B, oldElem0, oldElem1); + __ st1(newElem, __ T2S, __ post(newArr, 8)); + __ sub(numIter, numIter, 2); + __ b(ShiftTwoLoop); + + __ BIND(ShiftThree); + __ ldrw(r10, __ post(oldArr, 4)); + __ ldrw(r11, __ post(oldArrNext, 4)); + __ lslvw(r10, r10, shiftCount); + __ lsrvw(r11, r11, shiftRevCount); + __ orrw(r12, r10, r11); + __ strw(r12, __ post(newArr, 4)); + __ tbz(numIter, 1, Exit); + __ tbz(numIter, 0, ShiftOne); + + __ BIND(ShiftTwo); + __ ldrw(r10, __ post(oldArr, 4)); + __ ldrw(r11, __ post(oldArrNext, 4)); + __ lslvw(r10, r10, shiftCount); + __ lsrvw(r11, r11, shiftRevCount); + __ orrw(r12, r10, r11); + __ strw(r12, __ post(newArr, 4)); + + __ BIND(ShiftOne); + __ ldrw(r10, Address(oldArr)); + __ ldrw(r11, Address(oldArrNext)); + __ lslvw(r10, r10, shiftCount); + __ lsrvw(r11, r11, shiftRevCount); + __ orrw(r12, r10, r11); + __ strw(r12, Address(newArr)); + + __ BIND(Exit); + __ ret(lr); + + return start; + } + void ghash_multiply(FloatRegister result_lo, FloatRegister result_hi, FloatRegister a, FloatRegister b, FloatRegister a1_xor_a0, FloatRegister tmp1, FloatRegister tmp2, FloatRegister tmp3, FloatRegister tmp4) { @@ -6224,6 +6456,11 @@ class StubGenerator: public StubCodeGenerator { StubRoutines::_mulAdd = generate_mulAdd(); } + if (UseSIMDForBigIntegerShiftIntrinsics) { + StubRoutines::_bigIntegerRightShiftWorker = generate_bigIntegerRightShift(); + StubRoutines::_bigIntegerLeftShiftWorker = generate_bigIntegerLeftShift(); + } + if (UseMontgomeryMultiplyIntrinsic) { StubCodeMark mark(this, "StubRoutines", "montgomeryMultiply"); MontgomeryMultiplyGenerator g(_masm, /*squaring*/false); diff --git a/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp b/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp index f1a30a9ae98..874d8ce2766 100644 --- a/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp @@ -1120,7 +1120,7 @@ void TemplateInterpreterGenerator::bang_stack_shadow_pages(bool native_call) { // an interpreter frame with greater than a page of locals, so each page // needs to be checked. Only true for non-native. if (UseStackBanging) { - const int n_shadow_pages = StackOverflow::stack_shadow_zone_size() / os::vm_page_size(); + const int n_shadow_pages = (int)(StackOverflow::stack_shadow_zone_size() / os::vm_page_size()); const int start_page = native_call ? n_shadow_pages : 1; const int page_size = os::vm_page_size(); for (int pages = start_page; pages <= n_shadow_pages ; pages++) { diff --git a/src/hotspot/cpu/x86/assembler_x86.cpp b/src/hotspot/cpu/x86/assembler_x86.cpp index 1f6b196d3ce..3933bac000f 100644 --- a/src/hotspot/cpu/x86/assembler_x86.cpp +++ b/src/hotspot/cpu/x86/assembler_x86.cpp @@ -9803,7 +9803,7 @@ void Assembler::cmpq(Register dst, int32_t imm32) { void Assembler::cmpq(Address dst, Register src) { InstructionMark im(this); - emit_int16(get_prefixq(dst, src), 0x3B); + emit_int16(get_prefixq(dst, src), 0x39); emit_operand(src, dst); } diff --git a/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.cpp b/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.cpp index 2d9d1c5215d..63ba5434856 100644 --- a/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.cpp @@ -336,7 +336,7 @@ void ShenandoahBarrierSetAssembler::load_reference_barrier_not_null(MacroAssembl #endif } -void ShenandoahBarrierSetAssembler::load_reference_barrier_native(MacroAssembler* masm, Register dst, Address src) { +void ShenandoahBarrierSetAssembler::load_reference_barrier_weak(MacroAssembler* masm, Register dst, Address src) { if (!ShenandoahLoadRefBarrier) { return; } @@ -344,7 +344,7 @@ void ShenandoahBarrierSetAssembler::load_reference_barrier_native(MacroAssembler Label done; Label not_null; Label slow_path; - __ block_comment("load_reference_barrier_native { "); + __ block_comment("load_reference_barrier_weak { "); // null check __ testptr(dst, dst); @@ -396,7 +396,7 @@ void ShenandoahBarrierSetAssembler::load_reference_barrier_native(MacroAssembler __ lea(rsi, src); save_xmm_registers(masm); - __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_native), dst, rsi); + __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_weak), dst, rsi); restore_xmm_registers(masm); #ifdef _LP64 @@ -420,7 +420,7 @@ void ShenandoahBarrierSetAssembler::load_reference_barrier_native(MacroAssembler } __ bind(done); - __ block_comment("load_reference_barrier_native { "); + __ block_comment("} load_reference_barrier_weak"); } void ShenandoahBarrierSetAssembler::storeval_barrier(MacroAssembler* masm, Register dst, Register tmp) { @@ -517,8 +517,8 @@ void ShenandoahBarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet d BarrierSetAssembler::load_at(masm, decorators, type, dst, src, tmp1, tmp_thread); - if (ShenandoahBarrierSet::use_load_reference_barrier_native(decorators, type)) { - load_reference_barrier_native(masm, dst, src); + if (ShenandoahBarrierSet::use_load_reference_barrier_weak(decorators, type)) { + load_reference_barrier_weak(masm, dst, src); } else { load_reference_barrier(masm, dst, src); } @@ -638,7 +638,8 @@ void ShenandoahBarrierSetAssembler::cmpxchg_oop(MacroAssembler* masm, bool exchange, Register tmp1, Register tmp2) { assert(ShenandoahCASBarrier, "Should only be used when CAS barrier is enabled"); assert(oldval == rax, "must be in rax for implicit use in cmpxchg"); - assert_different_registers(oldval, newval, tmp1, tmp2); + assert_different_registers(oldval, tmp1, tmp2); + assert_different_registers(newval, tmp1, tmp2); Label L_success, L_failure; @@ -870,8 +871,8 @@ void ShenandoahBarrierSetAssembler::gen_load_reference_barrier_stub(LIR_Assemble __ bind(slow_path); ce->store_parameter(res, 0); ce->store_parameter(addr, 1); - if (stub->is_native()) { - __ call(RuntimeAddress(bs->load_reference_barrier_native_rt_code_blob()->code_begin())); + if (stub->is_weak()) { + __ call(RuntimeAddress(bs->load_reference_barrier_weak_rt_code_blob()->code_begin())); } else { __ call(RuntimeAddress(bs->load_reference_barrier_rt_code_blob()->code_begin())); } @@ -938,7 +939,7 @@ void ShenandoahBarrierSetAssembler::generate_c1_pre_barrier_runtime_stub(StubAss __ epilogue(); } -void ShenandoahBarrierSetAssembler::generate_c1_load_reference_barrier_runtime_stub(StubAssembler* sasm, bool is_native) { +void ShenandoahBarrierSetAssembler::generate_c1_load_reference_barrier_runtime_stub(StubAssembler* sasm, bool is_weak) { __ prologue("shenandoah_load_reference_barrier", false); // arg0 : object to be resolved @@ -947,8 +948,8 @@ void ShenandoahBarrierSetAssembler::generate_c1_load_reference_barrier_runtime_s #ifdef _LP64 __ load_parameter(0, c_rarg0); __ load_parameter(1, c_rarg1); - if (is_native) { - __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_native), c_rarg0, c_rarg1); + if (is_weak) { + __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_weak), c_rarg0, c_rarg1); } else if (UseCompressedOops) { __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_narrow), c_rarg0, c_rarg1); } else { @@ -957,8 +958,8 @@ void ShenandoahBarrierSetAssembler::generate_c1_load_reference_barrier_runtime_s #else __ load_parameter(0, rax); __ load_parameter(1, rbx); - if (is_native) { - __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_native), rax, rbx); + if (is_weak) { + __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_weak), rax, rbx); } else { __ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier), rax, rbx); } diff --git a/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.hpp b/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.hpp index 60aa3b4600d..46f70771da4 100644 --- a/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/gc/shenandoah/shenandoahBarrierSetAssembler_x86.hpp @@ -70,11 +70,11 @@ class ShenandoahBarrierSetAssembler: public BarrierSetAssembler { void gen_pre_barrier_stub(LIR_Assembler* ce, ShenandoahPreBarrierStub* stub); void gen_load_reference_barrier_stub(LIR_Assembler* ce, ShenandoahLoadReferenceBarrierStub* stub); void generate_c1_pre_barrier_runtime_stub(StubAssembler* sasm); - void generate_c1_load_reference_barrier_runtime_stub(StubAssembler* sasm, bool is_native); + void generate_c1_load_reference_barrier_runtime_stub(StubAssembler* sasm, bool is_weak); #endif void load_reference_barrier(MacroAssembler* masm, Register dst, Address src); - void load_reference_barrier_native(MacroAssembler* masm, Register dst, Address src); + void load_reference_barrier_weak(MacroAssembler* masm, Register dst, Address src); void cmpxchg_oop(MacroAssembler* masm, Register res, Address addr, Register oldval, Register newval, diff --git a/src/hotspot/cpu/x86/interp_masm_x86.cpp b/src/hotspot/cpu/x86/interp_masm_x86.cpp index 2c7f861b1a2..9c1376a33c6 100644 --- a/src/hotspot/cpu/x86/interp_masm_x86.cpp +++ b/src/hotspot/cpu/x86/interp_masm_x86.cpp @@ -605,6 +605,10 @@ void InterpreterMacroAssembler::push_i(Register r) { push(r); } +void InterpreterMacroAssembler::push_i_or_ptr(Register r) { + push(r); +} + void InterpreterMacroAssembler::push_f(XMMRegister r) { subptr(rsp, wordSize); movflt(Address(rsp, 0), r); @@ -999,9 +1003,11 @@ void InterpreterMacroAssembler::remove_activation( jmp(fast_path); bind(slow_path); push(state); - call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::at_unwind)); - pop(state); + set_last_Java_frame(rthread, noreg, rbp, (address)pc()); + super_call_VM_leaf(CAST_FROM_FN_PTR(address, InterpreterRuntime::at_unwind), rthread); NOT_LP64(get_thread(rthread);) // call_VM clobbered it, restore + reset_last_Java_frame(rthread, true); + pop(state); bind(fast_path); // get the value of _do_not_unlock_if_synchronized into rdx diff --git a/src/hotspot/cpu/x86/interp_masm_x86.hpp b/src/hotspot/cpu/x86/interp_masm_x86.hpp index 3e2e33278a1..288b1bd1dfe 100644 --- a/src/hotspot/cpu/x86/interp_masm_x86.hpp +++ b/src/hotspot/cpu/x86/interp_masm_x86.hpp @@ -139,9 +139,18 @@ class InterpreterMacroAssembler: public MacroAssembler { // Expression stack void pop_ptr(Register r = rax); void pop_i(Register r = rax); + + // On x86, pushing a ptr or an int is semantically identical, but we + // maintain a distinction for clarity and for making it easier to change + // semantics in the future void push_ptr(Register r = rax); void push_i(Register r = rax); + // push_i_or_ptr is provided for when explicitly allowing either a ptr or + // an int might have some advantage, while still documenting the fact that a + // ptr might be pushed to the stack. + void push_i_or_ptr(Register r = rax); + void push_f(XMMRegister r); void pop_f(XMMRegister r); void pop_d(XMMRegister r); diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.cpp b/src/hotspot/cpu/x86/macroAssembler_x86.cpp index a8da3aa17b8..81303ea76c4 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.cpp @@ -2765,7 +2765,7 @@ void MacroAssembler::safepoint_poll(Label& slow_path, Register thread_reg, bool if (at_return) { // Note that when in_nmethod is set, the stack pointer is incremented before the poll. Therefore, // we may safely use rsp instead to perform the stack watermark check. - cmpq(Address(thread_reg, Thread::polling_word_offset()), in_nmethod ? rsp : rbp); + cmpq(in_nmethod ? rsp : rbp, Address(thread_reg, Thread::polling_word_offset())); jcc(Assembler::above, slow_path); return; } diff --git a/src/hotspot/cpu/x86/templateInterpreterGenerator_x86.cpp b/src/hotspot/cpu/x86/templateInterpreterGenerator_x86.cpp index f07eb9664ec..072b3d144fa 100644 --- a/src/hotspot/cpu/x86/templateInterpreterGenerator_x86.cpp +++ b/src/hotspot/cpu/x86/templateInterpreterGenerator_x86.cpp @@ -1761,9 +1761,6 @@ void TemplateInterpreterGenerator::set_vtos_entry_points(Template* t, address& vep) { assert(t->is_valid() && t->tos_in() == vtos, "illegal template"); Label L; - aep = __ pc(); // atos entry point - __ push_ptr(); - __ jmp(L); #ifndef _LP64 fep = __ pc(); // ftos entry point __ push(ftos); @@ -1782,8 +1779,8 @@ void TemplateInterpreterGenerator::set_vtos_entry_points(Template* t, lep = __ pc(); // ltos entry point __ push_l(); __ jmp(L); - bep = cep = sep = iep = __ pc(); // [bcsi]tos entry point - __ push_i(); + aep = bep = cep = sep = iep = __ pc(); // [abcsi]tos entry point + __ push_i_or_ptr(); vep = __ pc(); // vtos entry point __ bind(L); generate_and_dispatch(t); diff --git a/src/hotspot/cpu/x86/x86.ad b/src/hotspot/cpu/x86/x86.ad index c30820eed78..c6c8c172b0a 100644 --- a/src/hotspot/cpu/x86/x86.ad +++ b/src/hotspot/cpu/x86/x86.ad @@ -4425,8 +4425,7 @@ instruct insert8D(vec dst, vec src, regD val, immI idx, rRegL tmp, legVec vtmp) // =======================Int Reduction========================================== instruct reductionI(rRegI dst, rRegI src1, legVec src2, legVec vtmp1, legVec vtmp2) %{ - predicate(vector_element_basic_type(n->in(2)) == T_INT && - vector_length(n->in(2)) <= 16); // src2 + predicate(vector_element_basic_type(n->in(2)) == T_INT); // src2 match(Set dst (AddReductionVI src1 src2)); match(Set dst (MulReductionVI src1 src2)); match(Set dst (AndReductionV src1 src2)); @@ -4447,9 +4446,8 @@ instruct reductionI(rRegI dst, rRegI src1, legVec src2, legVec vtmp1, legVec vtm // =======================Long Reduction========================================== #ifdef _LP64 -instruct reductionL(rRegL dst, rRegL src1, vec src2, vec vtmp1, vec vtmp2) %{ - predicate(vector_element_basic_type(n->in(2)) == T_LONG && - vector_length(n->in(2)) < 8); // src2 +instruct reductionL(rRegL dst, rRegL src1, legVec src2, legVec vtmp1, legVec vtmp2) %{ + predicate(vector_element_basic_type(n->in(2)) == T_LONG && !VM_Version::supports_avx512dq()); match(Set dst (AddReductionVL src1 src2)); match(Set dst (MulReductionVL src1 src2)); match(Set dst (AndReductionV src1 src2)); @@ -4467,9 +4465,8 @@ instruct reductionL(rRegL dst, rRegL src1, vec src2, vec vtmp1, vec vtmp2) %{ ins_pipe( pipe_slow ); %} -instruct reduction8L(rRegL dst, rRegL src1, legVec src2, legVec vtmp1, legVec vtmp2) %{ - predicate(vector_element_basic_type(n->in(2)) == T_LONG && - vector_length(n->in(2)) == 8); // src2 +instruct reductionL_avx512dq(rRegL dst, rRegL src1, vec src2, vec vtmp1, vec vtmp2) %{ + predicate(vector_element_basic_type(n->in(2)) == T_LONG && VM_Version::supports_avx512dq()); match(Set dst (AddReductionVL src1 src2)); match(Set dst (MulReductionVL src1 src2)); match(Set dst (AndReductionV src1 src2)); @@ -4579,9 +4576,8 @@ instruct reduction8D(regD dst, legVec src, legVec vtmp1, legVec vtmp2) %{ // =======================Byte Reduction========================================== #ifdef _LP64 -instruct reductionB(rRegI dst, rRegI src1, vec src2, vec vtmp1, vec vtmp2) %{ - predicate(vector_element_basic_type(n->in(2)) == T_BYTE && - vector_length(n->in(2)) <= 32); // src2 +instruct reductionB(rRegI dst, rRegI src1, legVec src2, legVec vtmp1, legVec vtmp2) %{ + predicate(vector_element_basic_type(n->in(2)) == T_BYTE && !VM_Version::supports_avx512bw()); match(Set dst (AddReductionVI src1 src2)); match(Set dst (AndReductionV src1 src2)); match(Set dst ( OrReductionV src1 src2)); @@ -4598,9 +4594,8 @@ instruct reductionB(rRegI dst, rRegI src1, vec src2, vec vtmp1, vec vtmp2) %{ ins_pipe( pipe_slow ); %} -instruct reduction64B(rRegI dst, rRegI src1, legVec src2, legVec vtmp1, legVec vtmp2) %{ - predicate(vector_element_basic_type(n->in(2)) == T_BYTE && - vector_length(n->in(2)) == 64); // src2 +instruct reductionB_avx512bw(rRegI dst, rRegI src1, vec src2, vec vtmp1, vec vtmp2) %{ + predicate(vector_element_basic_type(n->in(2)) == T_BYTE && VM_Version::supports_avx512bw()); match(Set dst (AddReductionVI src1 src2)); match(Set dst (AndReductionV src1 src2)); match(Set dst ( OrReductionV src1 src2)); @@ -4621,8 +4616,7 @@ instruct reduction64B(rRegI dst, rRegI src1, legVec src2, legVec vtmp1, legVec v // =======================Short Reduction========================================== instruct reductionS(rRegI dst, rRegI src1, legVec src2, legVec vtmp1, legVec vtmp2) %{ - predicate(vector_element_basic_type(n->in(2)) == T_SHORT && - vector_length(n->in(2)) <= 32); // src2 + predicate(vector_element_basic_type(n->in(2)) == T_SHORT); // src2 match(Set dst (AddReductionVI src1 src2)); match(Set dst (MulReductionVI src1 src2)); match(Set dst (AndReductionV src1 src2)); @@ -5452,7 +5446,7 @@ instruct vmulL_mem(vec dst, vec src, memory mem) %{ ins_pipe( pipe_slow ); %} -instruct mul2L_reg(vec dst, vec src2, vec tmp) %{ +instruct mul2L_reg(vec dst, vec src2, legVec tmp) %{ predicate(vector_length(n) == 2 && !VM_Version::supports_avx512dq()); match(Set dst (MulVL dst src2)); effect(TEMP dst, TEMP tmp); @@ -5478,7 +5472,7 @@ instruct mul2L_reg(vec dst, vec src2, vec tmp) %{ ins_pipe( pipe_slow ); %} -instruct vmul4L_reg_avx(vec dst, vec src1, vec src2, vec tmp, vec tmp1) %{ +instruct vmul4L_reg_avx(vec dst, vec src1, vec src2, legVec tmp, legVec tmp1) %{ predicate(vector_length(n) == 4 && !VM_Version::supports_avx512dq()); match(Set dst (MulVL src1 src2)); effect(TEMP tmp1, TEMP tmp); @@ -6963,6 +6957,7 @@ instruct extractI(rRegI dst, legVec src, immU8 idx) %{ #ifdef _LP64 match(Set dst (ExtractB src idx)); #endif + format %{ "extractI $dst,$src,$idx\t!" %} ins_encode %{ assert($idx$$constant < (int)vector_length(this, $src), "out of bounds"); @@ -6981,6 +6976,7 @@ instruct vextractI(rRegI dst, legVec src, immI idx, legVec vtmp) %{ match(Set dst (ExtractB src idx)); #endif effect(TEMP vtmp); + format %{ "vextractI $dst,$src,$idx\t! using $vtmp as TEMP" %} ins_encode %{ assert($idx$$constant < (int)vector_length(this, $src), "out of bounds"); @@ -6995,6 +6991,7 @@ instruct vextractI(rRegI dst, legVec src, immI idx, legVec vtmp) %{ instruct extractL(rRegL dst, legVec src, immU8 idx) %{ predicate(vector_length(n->in(1)) <= 2); // src match(Set dst (ExtractL src idx)); + format %{ "extractL $dst,$src,$idx\t!" %} ins_encode %{ assert(UseSSE >= 4, "required"); assert($idx$$constant < (int)vector_length(this, $src), "out of bounds"); @@ -7009,6 +7006,7 @@ instruct vextractL(rRegL dst, legVec src, immU8 idx, legVec vtmp) %{ vector_length(n->in(1)) == 8); // src match(Set dst (ExtractL src idx)); effect(TEMP vtmp); + format %{ "vextractL $dst,$src,$idx\t! using $vtmp as TEMP" %} ins_encode %{ assert($idx$$constant < (int)vector_length(this, $src), "out of bounds"); @@ -7023,6 +7021,7 @@ instruct extractF(legRegF dst, legVec src, immU8 idx, rRegI tmp, legVec vtmp) %{ predicate(vector_length(n->in(1)) <= 4); match(Set dst (ExtractF src idx)); effect(TEMP dst, TEMP tmp, TEMP vtmp); + format %{ "extractF $dst,$src,$idx\t! using $tmp, $vtmp as TEMP" %} ins_encode %{ assert($idx$$constant < (int)vector_length(this, $src), "out of bounds"); @@ -7036,6 +7035,7 @@ instruct vextractF(legRegF dst, legVec src, immU8 idx, rRegI tmp, legVec vtmp) % vector_length(n->in(1)/*src*/) == 16); match(Set dst (ExtractF src idx)); effect(TEMP tmp, TEMP vtmp); + format %{ "vextractF $dst,$src,$idx\t! using $tmp, $vtmp as TEMP" %} ins_encode %{ assert($idx$$constant < (int)vector_length(this, $src), "out of bounds"); @@ -7048,6 +7048,7 @@ instruct vextractF(legRegF dst, legVec src, immU8 idx, rRegI tmp, legVec vtmp) % instruct extractD(legRegD dst, legVec src, immU8 idx) %{ predicate(vector_length(n->in(1)) == 2); // src match(Set dst (ExtractD src idx)); + format %{ "extractD $dst,$src,$idx\t!" %} ins_encode %{ assert($idx$$constant < (int)vector_length(this, $src), "out of bounds"); @@ -7061,6 +7062,7 @@ instruct vextractD(legRegD dst, legVec src, immU8 idx, legVec vtmp) %{ vector_length(n->in(1)) == 8); // src match(Set dst (ExtractD src idx)); effect(TEMP vtmp); + format %{ "vextractD $dst,$src,$idx\t! using $vtmp as TEMP" %} ins_encode %{ assert($idx$$constant < (int)vector_length(this, $src), "out of bounds"); diff --git a/src/hotspot/os/aix/os_aix.cpp b/src/hotspot/os/aix/os_aix.cpp index 552c345563a..71cc3056a55 100644 --- a/src/hotspot/os/aix/os_aix.cpp +++ b/src/hotspot/os/aix/os_aix.cpp @@ -2236,7 +2236,7 @@ bool os::can_execute_large_page_memory() { return false; } -char* os::pd_attempt_reserve_memory_at(char* requested_addr, size_t bytes, int file_desc) { +char* os::pd_attempt_map_memory_to_file_at(char* requested_addr, size_t bytes, int file_desc) { assert(file_desc >= 0, "file_desc is not valid"); char* result = NULL; diff --git a/src/hotspot/os/bsd/os_bsd.cpp b/src/hotspot/os/bsd/os_bsd.cpp index 68196755732..d95cb6807d2 100644 --- a/src/hotspot/os/bsd/os_bsd.cpp +++ b/src/hotspot/os/bsd/os_bsd.cpp @@ -1905,7 +1905,7 @@ bool os::can_execute_large_page_memory() { return false; } -char* os::pd_attempt_reserve_memory_at(char* requested_addr, size_t bytes, int file_desc) { +char* os::pd_attempt_map_memory_to_file_at(char* requested_addr, size_t bytes, int file_desc) { assert(file_desc >= 0, "file_desc is not valid"); char* result = pd_attempt_reserve_memory_at(requested_addr, bytes); if (result != NULL) { diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp index 8536a161e64..c9d07dfb0fe 100644 --- a/src/hotspot/os/linux/os_linux.cpp +++ b/src/hotspot/os/linux/os_linux.cpp @@ -4214,7 +4214,7 @@ bool os::can_execute_large_page_memory() { return UseTransparentHugePages || UseHugeTLBFS; } -char* os::pd_attempt_reserve_memory_at(char* requested_addr, size_t bytes, int file_desc) { +char* os::pd_attempt_map_memory_to_file_at(char* requested_addr, size_t bytes, int file_desc) { assert(file_desc >= 0, "file_desc is not valid"); char* result = pd_attempt_reserve_memory_at(requested_addr, bytes); if (result != NULL) { diff --git a/src/hotspot/os/posix/os_posix.cpp b/src/hotspot/os/posix/os_posix.cpp index 3da46a777a1..7298fb21638 100644 --- a/src/hotspot/os/posix/os_posix.cpp +++ b/src/hotspot/os/posix/os_posix.cpp @@ -297,37 +297,18 @@ char* os::replace_existing_mapping_with_file_mapping(char* base, size_t size, in return map_memory_to_file(base, size, fd); } -// Multiple threads can race in this code, and can remap over each other with MAP_FIXED, -// so on posix, unmap the section at the start and at the end of the chunk that we mapped -// rather than unmapping and remapping the whole chunk to get requested alignment. -char* os::reserve_memory_aligned(size_t size, size_t alignment, int file_desc) { +static size_t calculate_aligned_extra_size(size_t size, size_t alignment) { assert((alignment & (os::vm_allocation_granularity() - 1)) == 0, "Alignment must be a multiple of allocation granularity (page size)"); assert((size & (alignment -1)) == 0, "size must be 'alignment' aligned"); size_t extra_size = size + alignment; assert(extra_size >= size, "overflow, size is too large to allow alignment"); + return extra_size; +} - char* extra_base; - if (file_desc != -1) { - // For file mapping, we do not call os:reserve_memory_with_fd since: - // - we later chop away parts of the mapping using os::release_memory and that could fail if the - // original mmap call had been tied to an fd. - // - The memory API os::reserve_memory uses is an implementation detail. It may (and usually is) - // mmap but it also may System V shared memory which cannot be uncommitted as a whole, so - // chopping off and unmapping excess bits back and front (see below) would not work. - extra_base = reserve_mmapped_memory(extra_size, NULL); - if (extra_base != NULL) { - MemTracker::record_virtual_memory_reserve((address)extra_base, extra_size, CALLER_PC); - } - } else { - extra_base = os::reserve_memory(extra_size); - } - - if (extra_base == NULL) { - return NULL; - } - +// After a bigger chunk was mapped, unmaps start and end parts to get the requested alignment. +static char* chop_extra_memory(size_t size, size_t alignment, char* extra_base, size_t extra_size) { // Do manual alignment char* aligned_base = align_up(extra_base, alignment); @@ -349,13 +330,39 @@ char* os::reserve_memory_aligned(size_t size, size_t alignment, int file_desc) { os::release_memory(extra_base + begin_offset + size, end_offset); } - if (file_desc != -1) { - // After we have an aligned address, we can replace anonymous mapping with file mapping - if (replace_existing_mapping_with_file_mapping(aligned_base, size, file_desc) == NULL) { - vm_exit_during_initialization(err_msg("Error in mapping Java heap at the given filesystem directory")); - } - MemTracker::record_virtual_memory_commit((address)aligned_base, size, CALLER_PC); + return aligned_base; +} + +// Multiple threads can race in this code, and can remap over each other with MAP_FIXED, +// so on posix, unmap the section at the start and at the end of the chunk that we mapped +// rather than unmapping and remapping the whole chunk to get requested alignment. +char* os::reserve_memory_aligned(size_t size, size_t alignment) { + size_t extra_size = calculate_aligned_extra_size(size, alignment); + char* extra_base = os::reserve_memory(extra_size); + if (extra_base == NULL) { + return NULL; + } + return chop_extra_memory(size, alignment, extra_base, extra_size); +} + +char* os::map_memory_to_file_aligned(size_t size, size_t alignment, int file_desc) { + size_t extra_size = calculate_aligned_extra_size(size, alignment); + // For file mapping, we do not call os:map_memory_to_file(size,fd) since: + // - we later chop away parts of the mapping using os::release_memory and that could fail if the + // original mmap call had been tied to an fd. + // - The memory API os::reserve_memory uses is an implementation detail. It may (and usually is) + // mmap but it also may System V shared memory which cannot be uncommitted as a whole, so + // chopping off and unmapping excess bits back and front (see below) would not work. + char* extra_base = reserve_mmapped_memory(extra_size, NULL); + if (extra_base == NULL) { + return NULL; + } + char* aligned_base = chop_extra_memory(size, alignment, extra_base, extra_size); + // After we have an aligned address, we can replace anonymous mapping with file mapping + if (replace_existing_mapping_with_file_mapping(aligned_base, size, file_desc) == NULL) { + vm_exit_during_initialization(err_msg("Error in mapping Java heap at the given filesystem directory")); } + MemTracker::record_virtual_memory_commit((address)aligned_base, size, CALLER_PC); return aligned_base; } diff --git a/src/hotspot/os/windows/os_windows.cpp b/src/hotspot/os/windows/os_windows.cpp index 0416605e309..99ac2c074f3 100644 --- a/src/hotspot/os/windows/os_windows.cpp +++ b/src/hotspot/os/windows/os_windows.cpp @@ -3137,7 +3137,7 @@ void os::split_reserved_memory(char *base, size_t size, size_t split) { // Multiple threads can race in this code but it's not possible to unmap small sections of // virtual space to get requested alignment, like posix-like os's. // Windows prevents multiple thread from remapping over each other so this loop is thread-safe. -char* os::reserve_memory_aligned(size_t size, size_t alignment, int file_desc) { +static char* map_or_reserve_memory_aligned(size_t size, size_t alignment, int file_desc) { assert((alignment & (os::vm_allocation_granularity() - 1)) == 0, "Alignment must be a multiple of allocation granularity (page size)"); assert((size & (alignment -1)) == 0, "size must be 'alignment' aligned"); @@ -3148,7 +3148,9 @@ char* os::reserve_memory_aligned(size_t size, size_t alignment, int file_desc) { char* aligned_base = NULL; do { - char* extra_base = os::reserve_memory_with_fd(extra_size, file_desc); + char* extra_base = file_desc != -1 ? + os::map_memory_to_file(extra_size, file_desc) : + os::reserve_memory(extra_size); if (extra_base == NULL) { return NULL; } @@ -3161,13 +3163,23 @@ char* os::reserve_memory_aligned(size_t size, size_t alignment, int file_desc) { os::release_memory(extra_base, extra_size); } - aligned_base = os::attempt_reserve_memory_at(aligned_base, size, file_desc); + aligned_base = file_desc != -1 ? + os::attempt_map_memory_to_file_at(aligned_base, size, file_desc) : + os::attempt_reserve_memory_at(aligned_base, size); } while (aligned_base == NULL); return aligned_base; } +char* os::reserve_memory_aligned(size_t size, size_t alignment) { + return map_or_reserve_memory_aligned(size, alignment, -1 /* file_desc */); +} + +char* os::map_memory_to_file_aligned(size_t size, size_t alignment, int fd) { + return map_or_reserve_memory_aligned(size, alignment, fd); +} + char* os::pd_reserve_memory(size_t bytes) { return pd_attempt_reserve_memory_at(NULL /* addr */, bytes); } @@ -3205,7 +3217,7 @@ char* os::pd_attempt_reserve_memory_at(char* addr, size_t bytes) { return res; } -char* os::pd_attempt_reserve_memory_at(char* requested_addr, size_t bytes, int file_desc) { +char* os::pd_attempt_map_memory_to_file_at(char* requested_addr, size_t bytes, int file_desc) { assert(file_desc >= 0, "file_desc is not valid"); return map_memory_to_file(requested_addr, bytes, file_desc); } diff --git a/src/hotspot/os_cpu/aix_ppc/os_aix_ppc.cpp b/src/hotspot/os_cpu/aix_ppc/os_aix_ppc.cpp index 868fe4c529f..ca1c74aeee2 100644 --- a/src/hotspot/os_cpu/aix_ppc/os_aix_ppc.cpp +++ b/src/hotspot/os_cpu/aix_ppc/os_aix_ppc.cpp @@ -184,7 +184,7 @@ JVM_handle_aix_signal(int sig, siginfo_t* info, void* ucVoid, int abort_if_unrec // avoid unnecessary crash when libjsig is not preloaded, try handle signals // that do not require siginfo/ucontext first. - if (sig == SIGPIPE) { + if (sig == SIGPIPE || sig == SIGXFSZ) { if (PosixSignals::chained_handler(sig, info, ucVoid)) { return 1; } else { diff --git a/src/hotspot/os_cpu/bsd_zero/atomic_bsd_zero.hpp b/src/hotspot/os_cpu/bsd_zero/atomic_bsd_zero.hpp index f1595ee9e7d..b9ee395bc30 100644 --- a/src/hotspot/os_cpu/bsd_zero/atomic_bsd_zero.hpp +++ b/src/hotspot/os_cpu/bsd_zero/atomic_bsd_zero.hpp @@ -184,7 +184,9 @@ inline D Atomic::PlatformAdd<4>::add_and_fetch(D volatile* dest, I add_value, #ifdef M68K return add_using_helper(m68k_add_and_fetch, dest, add_value); #else - return __sync_add_and_fetch(dest, add_value); + D res = __atomic_add_fetch(dest, add_value, __ATOMIC_RELEASE); + FULL_MEM_BARRIER; + return res; #endif // M68K #endif // ARM } @@ -196,7 +198,9 @@ inline D Atomic::PlatformAdd<8>::add_and_fetch(D volatile* dest, I add_value, STATIC_ASSERT(8 == sizeof(I)); STATIC_ASSERT(8 == sizeof(D)); - return __sync_add_and_fetch(dest, add_value); + D res = __atomic_add_fetch(dest, add_value, __ATOMIC_RELEASE); + FULL_MEM_BARRIER; + return res; } template<> diff --git a/src/hotspot/os_cpu/linux_ppc/os_linux_ppc.cpp b/src/hotspot/os_cpu/linux_ppc/os_linux_ppc.cpp index 49e901a2a00..288e2a3ece6 100644 --- a/src/hotspot/os_cpu/linux_ppc/os_linux_ppc.cpp +++ b/src/hotspot/os_cpu/linux_ppc/os_linux_ppc.cpp @@ -206,7 +206,7 @@ JVM_handle_linux_signal(int sig, // avoid unnecessary crash when libjsig is not preloaded, try handle signals // that do not require siginfo/ucontext first. - if (sig == SIGPIPE) { + if (sig == SIGPIPE || sig == SIGXFSZ) { if (PosixSignals::chained_handler(sig, info, ucVoid)) { return true; } else { diff --git a/src/hotspot/os_cpu/linux_s390/os_linux_s390.cpp b/src/hotspot/os_cpu/linux_s390/os_linux_s390.cpp index d5181b48339..64d5fd8d512 100644 --- a/src/hotspot/os_cpu/linux_s390/os_linux_s390.cpp +++ b/src/hotspot/os_cpu/linux_s390/os_linux_s390.cpp @@ -227,7 +227,7 @@ JVM_handle_linux_signal(int sig, // avoid unnecessary crash when libjsig is not preloaded, try handle signals // that do not require siginfo/ucontext first. - if (sig == SIGPIPE) { + if (sig == SIGPIPE || sig == SIGXFSZ) { if (PosixSignals::chained_handler(sig, info, ucVoid)) { return true; } else { diff --git a/src/hotspot/os_cpu/linux_zero/atomic_linux_zero.hpp b/src/hotspot/os_cpu/linux_zero/atomic_linux_zero.hpp index b44521c1303..e373b90bd9b 100644 --- a/src/hotspot/os_cpu/linux_zero/atomic_linux_zero.hpp +++ b/src/hotspot/os_cpu/linux_zero/atomic_linux_zero.hpp @@ -49,7 +49,9 @@ inline D Atomic::PlatformAdd<4>::add_and_fetch(D volatile* dest, I add_value, STATIC_ASSERT(4 == sizeof(I)); STATIC_ASSERT(4 == sizeof(D)); - return __sync_add_and_fetch(dest, add_value); + D res = __atomic_add_fetch(dest, add_value, __ATOMIC_RELEASE); + FULL_MEM_BARRIER; + return res; } template<> @@ -58,7 +60,10 @@ inline D Atomic::PlatformAdd<8>::add_and_fetch(D volatile* dest, I add_value, atomic_memory_order order) const { STATIC_ASSERT(8 == sizeof(I)); STATIC_ASSERT(8 == sizeof(D)); - return __sync_add_and_fetch(dest, add_value); + + D res = __atomic_add_fetch(dest, add_value, __ATOMIC_RELEASE); + FULL_MEM_BARRIER; + return res; } template<> diff --git a/src/hotspot/share/asm/assembler.cpp b/src/hotspot/share/asm/assembler.cpp index 3a0b3ce0b3b..66e3052bdeb 100644 --- a/src/hotspot/share/asm/assembler.cpp +++ b/src/hotspot/share/asm/assembler.cpp @@ -199,19 +199,6 @@ void Label::patch_instructions(MacroAssembler* masm) { continue; } -#ifdef ASSERT - // Cross-section branches only work if the - // intermediate section boundaries are frozen. - if (target_sect != branch_sect) { - for (int n = MIN2(target_sect, branch_sect), - nlimit = (target_sect + branch_sect) - n; - n < nlimit; n++) { - CodeSection* cs = cb->code_section(n); - assert(cs->is_frozen(), "cross-section branch needs stable offsets"); - } - } -#endif //ASSERT - // Push the target offset into the branch instruction. masm->pd_patch_instruction(branch, target, file, line); } diff --git a/src/hotspot/share/asm/codeBuffer.cpp b/src/hotspot/share/asm/codeBuffer.cpp index f932d907e1b..db2178f9977 100644 --- a/src/hotspot/share/asm/codeBuffer.cpp +++ b/src/hotspot/share/asm/codeBuffer.cpp @@ -176,28 +176,6 @@ void CodeBuffer::initialize_section_size(CodeSection* cs, csize_t size) { if (_insts.has_locs()) cs->initialize_locs(1); } -void CodeBuffer::freeze_section(CodeSection* cs) { - CodeSection* next_cs = (cs == consts())? NULL: code_section(cs->index()+1); - csize_t frozen_size = cs->size(); - if (next_cs != NULL) { - frozen_size = next_cs->align_at_start(frozen_size); - } - address old_limit = cs->limit(); - address new_limit = cs->start() + frozen_size; - relocInfo* old_locs_limit = cs->locs_limit(); - relocInfo* new_locs_limit = cs->locs_end(); - // Patch the limits. - cs->_limit = new_limit; - cs->_locs_limit = new_locs_limit; - cs->_frozen = true; - if (next_cs != NULL && !next_cs->is_allocated() && !next_cs->is_frozen()) { - // Give remaining buffer space to the following section. - next_cs->initialize(new_limit, old_limit - new_limit); - next_cs->initialize_shared_locs(new_locs_limit, - old_locs_limit - new_locs_limit); - } -} - void CodeBuffer::set_blob(BufferBlob* blob) { _blob = blob; if (blob != NULL) { @@ -257,11 +235,6 @@ int CodeBuffer::locator(address addr) const { return -1; } -address CodeBuffer::locator_address(int locator) const { - if (locator < 0) return NULL; - address start = code_section(locator_sect(locator))->start(); - return start + locator_pos(locator); -} bool CodeBuffer::is_backward_branch(Label& L) { return L.is_bound() && insts_end() <= locator_address(L.loc()); @@ -506,18 +479,6 @@ void CodeBuffer::compute_final_layout(CodeBuffer* dest) const { } else { guarantee(padding == 0, "In first iteration no padding should be needed."); } - #ifdef ASSERT - if (prev_cs != NULL && prev_cs->is_frozen() && n < (SECT_LIMIT - 1)) { - // Make sure the ends still match up. - // This is important because a branch in a frozen section - // might target code in a following section, via a Label, - // and without a relocation record. See Label::patch_instructions. - address dest_start = buf+buf_offset; - csize_t start2start = cs->start() - prev_cs->start(); - csize_t dest_start2start = dest_start - prev_dest_cs->start(); - assert(start2start == dest_start2start, "cannot stretch frozen sect"); - } - #endif //ASSERT prev_dest_cs = dest_cs; prev_cs = cs; } @@ -896,9 +857,6 @@ void CodeBuffer::expand(CodeSection* which_cs, csize_t amount) { // Resizing must be allowed { if (blob() == NULL) return; // caller must check for blob == NULL - for (int n = 0; n < (int)SECT_LIMIT; n++) { - guarantee(!code_section(n)->is_frozen(), "resizing not allowed when frozen"); - } } // Figure new capacity for each section. @@ -1224,9 +1182,8 @@ void CodeBuffer::decode() { void CodeSection::print(const char* name) { csize_t locs_size = locs_end() - locs_start(); - tty->print_cr(" %7s.code = " PTR_FORMAT " : " PTR_FORMAT " : " PTR_FORMAT " (%d of %d)%s", - name, p2i(start()), p2i(end()), p2i(limit()), size(), capacity(), - is_frozen()? " [frozen]": ""); + tty->print_cr(" %7s.code = " PTR_FORMAT " : " PTR_FORMAT " : " PTR_FORMAT " (%d of %d)", + name, p2i(start()), p2i(end()), p2i(limit()), size(), capacity()); tty->print_cr(" %7s.locs = " PTR_FORMAT " : " PTR_FORMAT " : " PTR_FORMAT " (%d of %d) point=%d", name, p2i(locs_start()), p2i(locs_end()), p2i(locs_limit()), locs_size, locs_capacity(), locs_point_off()); if (PrintRelocations) { diff --git a/src/hotspot/share/asm/codeBuffer.hpp b/src/hotspot/share/asm/codeBuffer.hpp index 95055246223..255342cbbd0 100644 --- a/src/hotspot/share/asm/codeBuffer.hpp +++ b/src/hotspot/share/asm/codeBuffer.hpp @@ -92,7 +92,6 @@ class CodeSection { relocInfo* _locs_limit; // first byte after relocation information buf address _locs_point; // last relocated position (grows upward) bool _locs_own; // did I allocate the locs myself? - bool _frozen; // no more expansion of this section bool _scratch_emit; // Buffer is used for scratch emit, don't relocate. char _index; // my section number (SECT_INST, etc.) CodeBuffer* _outer; // enclosing CodeBuffer @@ -109,7 +108,6 @@ class CodeSection { _locs_limit = NULL; _locs_point = NULL; _locs_own = false; - _frozen = false; _scratch_emit = false; debug_only(_index = (char)-1); debug_only(_outer = (CodeBuffer*)badAddress); @@ -161,12 +159,10 @@ class CodeSection { address locs_point() const { return _locs_point; } csize_t locs_point_off() const{ return (csize_t)(_locs_point - _start); } csize_t locs_capacity() const { return (csize_t)(_locs_limit - _locs_start); } - csize_t locs_remaining()const { return (csize_t)(_locs_limit - _locs_end); } int index() const { return _index; } bool is_allocated() const { return _start != NULL; } bool is_empty() const { return _start == _end; } - bool is_frozen() const { return _frozen; } bool has_locs() const { return _locs_end != NULL; } // Mark scratch buffer. @@ -184,8 +180,6 @@ class CodeSection { void set_end(address pc) { assert(allocates2(pc), "not in CodeBuffer memory: " INTPTR_FORMAT " <= " INTPTR_FORMAT " <= " INTPTR_FORMAT, p2i(_start), p2i(pc), p2i(_limit)); _end = pc; } void set_mark(address pc) { assert(contains2(pc), "not in codeBuffer"); _mark = pc; } - void set_mark_off(int offset) { assert(contains2(offset+_start),"not in codeBuffer"); - _mark = offset + _start; } void set_mark() { _mark = _end; } void clear_mark() { _mark = NULL; } @@ -259,10 +253,6 @@ class CodeSection { csize_t align_at_start(csize_t off) const { return (csize_t) align_up(off, alignment()); } - // Mark a section frozen. Assign its remaining space to - // the following section. It will never expand after this point. - inline void freeze(); // { _outer->freeze_section(this); } - // Ensure there's enough space left in the current section. // Return true if there was an expansion. bool maybe_expand_to_ensure_remaining(csize_t amount); @@ -463,8 +453,6 @@ class CodeBuffer: public StackObj { void initialize_section_size(CodeSection* cs, csize_t size); - void freeze_section(CodeSection* cs); - // helper for CodeBuffer::expand() void take_over_code_from(CodeBuffer* cs); @@ -556,7 +544,11 @@ class CodeBuffer: public StackObj { static int locator_sect(int locator) { return locator & sect_mask; } static int locator(int pos, int sect) { return (pos << sect_bits) | sect; } int locator(address addr) const; - address locator_address(int locator) const; + address locator_address(int locator) const { + if (locator < 0) return NULL; + address start = code_section(locator_sect(locator))->start(); + return start + locator_pos(locator); + } // Heuristic for pre-packing the taken/not-taken bit of a predicted branch. bool is_backward_branch(Label& L); @@ -573,10 +565,8 @@ class CodeBuffer: public StackObj { address insts_begin() const { return _insts.start(); } address insts_end() const { return _insts.end(); } void set_insts_end(address end) { _insts.set_end(end); } - address insts_limit() const { return _insts.limit(); } address insts_mark() const { return _insts.mark(); } void set_insts_mark() { _insts.set_mark(); } - void clear_insts_mark() { _insts.clear_mark(); } // is there anything in the buffer other than the current section? bool is_pure() const { return insts_size() == total_content_size(); } @@ -648,12 +638,6 @@ class CodeBuffer: public StackObj { _code_strings.free(); // sets _strings Null as a side-effect. } } - - // Print the comment associated with offset on stream, if there is one. - virtual void print_block_comment(outputStream* stream, address block_begin) { - intptr_t offset = (intptr_t)(block_begin - _total_start); // I assume total_start is not correct for all code sections. - _code_strings.print_block_comment(stream, offset); - } #endif // Code generation @@ -679,9 +663,6 @@ class CodeBuffer: public StackObj { } } - // Transform an address from the code in this code buffer to a specified code buffer - address transform_address(const CodeBuffer &cb, address addr) const; - void block_comment(intptr_t offset, const char * comment) PRODUCT_RETURN; const char* code_string(const char* str) PRODUCT_RETURN_(return NULL;); @@ -710,11 +691,6 @@ class CodeBuffer: public StackObj { }; - -inline void CodeSection::freeze() { - _outer->freeze_section(this); -} - inline bool CodeSection::maybe_expand_to_ensure_remaining(csize_t amount) { if (remaining() < amount) { _outer->expand(this, amount); return true; } return false; diff --git a/src/hotspot/share/c1/c1_CFGPrinter.cpp b/src/hotspot/share/c1/c1_CFGPrinter.cpp index 21244d92a18..9cd617d5428 100644 --- a/src/hotspot/share/c1/c1_CFGPrinter.cpp +++ b/src/hotspot/share/c1/c1_CFGPrinter.cpp @@ -325,7 +325,7 @@ void CFGPrinterOutput::print_intervals(IntervalList* intervals, const char* name for (int i = 0; i < intervals->length(); i++) { if (intervals->at(i) != NULL) { - intervals->at(i)->print_on(output()); + intervals->at(i)->print_on(output(), true); } } diff --git a/src/hotspot/share/c1/c1_LinearScan.cpp b/src/hotspot/share/c1/c1_LinearScan.cpp index dcac52014db..782fa7ada03 100644 --- a/src/hotspot/share/c1/c1_LinearScan.cpp +++ b/src/hotspot/share/c1/c1_LinearScan.cpp @@ -3212,6 +3212,12 @@ void LinearScan::print_reg_num(outputStream* out, int reg_num) { return; } + LIR_Opr opr = get_operand(reg_num); + assert(opr->is_valid(), "unknown register"); + opr->print(out); +} + +LIR_Opr LinearScan::get_operand(int reg_num) { LIR_Opr opr = LIR_OprFact::illegal(); #ifdef X86 @@ -3231,9 +3237,9 @@ void LinearScan::print_reg_num(outputStream* out, int reg_num) { opr = LIR_OprFact::single_xmm(reg_num - pd_first_xmm_reg); #endif } else { - assert(false, "unknown register"); + // reg_num == -1 or a virtual register, return the illegal operand } - opr->print(out); + return opr; } Interval* LinearScan::find_interval_at(int reg_num) const { @@ -4598,7 +4604,7 @@ bool Interval::intersects_any_children_of(Interval* interval) const { #ifndef PRODUCT -void Interval::print_on(outputStream* out) const { +void Interval::print_on(outputStream* out, bool is_cfg_printer) const { const char* SpillState2Name[] = { "no definition", "no spill store", "one spill store", "store at definition", "start in memory", "no optimization" }; const char* UseKind2Name[] = { "N", "L", "S", "M" }; @@ -4608,18 +4614,29 @@ void Interval::print_on(outputStream* out) const { } else { type_name = type2name(type()); } - out->print("%d %s ", reg_num(), type_name); - if (reg_num() < LIR_OprDesc::vreg_base) { - LinearScan::print_reg_num(out, assigned_reg()); - } else if (assigned_reg() != -1 && (LinearScan::num_physical_regs(type()) == 1 || assigned_regHi() != -1)) { - LinearScan::calc_operand_for_interval(this)->print(out); + + if (is_cfg_printer) { + // Special version for compatibility with C1 Visualizer. + LIR_Opr opr = LinearScan::get_operand(reg_num()); + if (opr->is_valid()) { + out->print("\""); + opr->print(out); + out->print("\" "); + } } else { - // Virtual register that has no assigned register yet. - out->print("[ANY]"); + // Improved output for normal debugging. + if (reg_num() < LIR_OprDesc::vreg_base) { + LinearScan::print_reg_num(out, assigned_reg()); + } else if (assigned_reg() != -1 && (LinearScan::num_physical_regs(type()) == 1 || assigned_regHi() != -1)) { + LinearScan::calc_operand_for_interval(this)->print(out); + } else { + // Virtual register that has no assigned register yet. + out->print("[ANY]"); + } + out->print(" "); } - - out->print(" %d %d ", split_parent()->reg_num(), (register_hint(false) != NULL ? register_hint(false)->reg_num() : -1)); + out->print("%d %d ", split_parent()->reg_num(), (register_hint(false) != NULL ? register_hint(false)->reg_num() : -1)); // print ranges Range* cur = _first; diff --git a/src/hotspot/share/c1/c1_LinearScan.hpp b/src/hotspot/share/c1/c1_LinearScan.hpp index 8d86a0d7836..0249453d9c1 100644 --- a/src/hotspot/share/c1/c1_LinearScan.hpp +++ b/src/hotspot/share/c1/c1_LinearScan.hpp @@ -369,6 +369,7 @@ class LinearScan : public CompilationResourceObj { void print_lir(int level, const char* label, bool hir_valid = true); static void print_reg_num(int reg_num) { print_reg_num(tty, reg_num); } static void print_reg_num(outputStream* out, int reg_num); + static LIR_Opr get_operand(int reg_num); #endif #ifdef ASSERT @@ -633,7 +634,11 @@ class Interval : public CompilationResourceObj { // printing #ifndef PRODUCT void print() const { print_on(tty); } - void print_on(outputStream* out) const; + void print_on(outputStream* out) const { + print_on(out, false); + } + // Special version for compatibility with C1 Visualizer. + void print_on(outputStream* out, bool is_cfg_printer) const; // Used for debugging void print_parent() const; diff --git a/src/hotspot/share/ci/ciEnv.cpp b/src/hotspot/share/ci/ciEnv.cpp index 1a95e2efbf0..f4d550460d6 100644 --- a/src/hotspot/share/ci/ciEnv.cpp +++ b/src/hotspot/share/ci/ciEnv.cpp @@ -761,34 +761,29 @@ Method* ciEnv::lookup_method(ciInstanceKlass* accessor, Symbol* sig, Bytecodes::Code bc, constantTag tag) { - // Accessibility checks are performed in ciEnv::get_method_by_index_impl. - assert(check_klass_accessibility(accessor, holder->get_Klass()), "holder not accessible"); - InstanceKlass* accessor_klass = accessor->get_instanceKlass(); Klass* holder_klass = holder->get_Klass(); - Method* dest_method; - LinkInfo link_info(holder_klass, name, sig, accessor_klass, LinkInfo::AccessCheck::required, LinkInfo::LoaderConstraintCheck::required, tag); + + // Accessibility checks are performed in ciEnv::get_method_by_index_impl. + assert(check_klass_accessibility(accessor, holder_klass), "holder not accessible"); + + LinkInfo link_info(holder_klass, name, sig, accessor_klass, + LinkInfo::AccessCheck::required, + LinkInfo::LoaderConstraintCheck::required, + tag); switch (bc) { - case Bytecodes::_invokestatic: - dest_method = - LinkResolver::resolve_static_call_or_null(link_info); - break; - case Bytecodes::_invokespecial: - dest_method = - LinkResolver::resolve_special_call_or_null(link_info); - break; - case Bytecodes::_invokeinterface: - dest_method = - LinkResolver::linktime_resolve_interface_method_or_null(link_info); - break; - case Bytecodes::_invokevirtual: - dest_method = - LinkResolver::linktime_resolve_virtual_method_or_null(link_info); - break; - default: ShouldNotReachHere(); + case Bytecodes::_invokestatic: + return LinkResolver::resolve_static_call_or_null(link_info); + case Bytecodes::_invokespecial: + return LinkResolver::resolve_special_call_or_null(link_info); + case Bytecodes::_invokeinterface: + return LinkResolver::linktime_resolve_interface_method_or_null(link_info); + case Bytecodes::_invokevirtual: + return LinkResolver::linktime_resolve_virtual_method_or_null(link_info); + default: + fatal("Unhandled bytecode: %s", Bytecodes::name(bc)); + return NULL; // silence compiler warnings } - - return dest_method; } diff --git a/src/hotspot/share/ci/ciMemberName.cpp b/src/hotspot/share/ci/ciMemberName.cpp index 978ba2b975c..4306e6e649e 100644 --- a/src/hotspot/share/ci/ciMemberName.cpp +++ b/src/hotspot/share/ci/ciMemberName.cpp @@ -34,11 +34,6 @@ // Return: MN.vmtarget ciMethod* ciMemberName::get_vmtarget() const { VM_ENTRY_MARK; - // FIXME: Share code with ciMethodHandle::get_vmtarget - Metadata* vmtarget = java_lang_invoke_MemberName::vmtarget(get_oop()); - if (vmtarget->is_method()) - return CURRENT_ENV->get_method((Method*) vmtarget); - // FIXME: What if the vmtarget is a Klass? - assert(false, ""); - return NULL; + Method* vmtarget = java_lang_invoke_MemberName::vmtarget(get_oop()); + return CURRENT_ENV->get_method(vmtarget); } diff --git a/src/hotspot/share/ci/ciMethodData.cpp b/src/hotspot/share/ci/ciMethodData.cpp index fae10b58eb2..76dde0b9f74 100644 --- a/src/hotspot/share/ci/ciMethodData.cpp +++ b/src/hotspot/share/ci/ciMethodData.cpp @@ -335,7 +335,10 @@ ciProfileData* ciMethodData::data_at(int data_index) { return NULL; } DataLayout* data_layout = data_layout_at(data_index); + return data_from(data_layout); +} +ciProfileData* ciMethodData::data_from(DataLayout* data_layout) { switch (data_layout->tag()) { case DataLayout::no_tag: default: @@ -376,6 +379,16 @@ ciProfileData* ciMethodData::next_data(ciProfileData* current) { return next; } +DataLayout* ciMethodData::next_data_layout(DataLayout* current) { + int current_index = dp_to_di((address)current); + int next_index = current_index + current->size_in_bytes(); + if (out_of_bounds(next_index)) { + return NULL; + } + DataLayout* next = data_layout_at(next_index); + return next; +} + ciProfileData* ciMethodData::bci_to_extra_data(int bci, ciMethod* m, bool& two_free_slots) { DataLayout* dp = extra_data_base(); DataLayout* end = args_data_limit(); @@ -413,12 +426,12 @@ ciProfileData* ciMethodData::bci_to_extra_data(int bci, ciMethod* m, bool& two_f ciProfileData* ciMethodData::bci_to_data(int bci, ciMethod* m) { // If m is not NULL we look for a SpeculativeTrapData entry if (m == NULL) { - ciProfileData* data = data_before(bci); - for ( ; is_valid(data); data = next_data(data)) { - if (data->bci() == bci) { - set_hint_di(dp_to_di(data->dp())); - return data; - } else if (data->bci() > bci) { + DataLayout* data_layout = data_layout_before(bci); + for ( ; is_valid(data_layout); data_layout = next_data_layout(data_layout)) { + if (data_layout->bci() == bci) { + set_hint_di(dp_to_di((address)data_layout)); + return data_from(data_layout); + } else if (data_layout->bci() > bci) { break; } } diff --git a/src/hotspot/share/ci/ciMethodData.hpp b/src/hotspot/share/ci/ciMethodData.hpp index 09f692fd7a6..2e78e5f3bad 100644 --- a/src/hotspot/share/ci/ciMethodData.hpp +++ b/src/hotspot/share/ci/ciMethodData.hpp @@ -379,7 +379,7 @@ class ciMethodData : public ciMetadata { // Data entries intptr_t* _data; - // Cached hint for data_before() + // Cached hint for data_layout_before() int _hint_di; // Is data attached? And is it mature? @@ -445,17 +445,17 @@ class ciMethodData : public ciMetadata { assert(!out_of_bounds(di), "hint_di out of bounds"); _hint_di = di; } - ciProfileData* data_before(int bci) { + + DataLayout* data_layout_before(int bci) { // avoid SEGV on this edge case if (data_size() == 0) return NULL; - int hint = hint_di(); - if (data_layout_at(hint)->bci() <= bci) - return data_at(hint); - return first_data(); + DataLayout* layout = data_layout_at(hint_di()); + if (layout->bci() <= bci) + return layout; + return data_layout_at(first_di()); } - // What is the index of the first data entry? int first_di() { return 0; } @@ -469,6 +469,7 @@ class ciMethodData : public ciMetadata { template void dump_replay_data_call_type_helper(outputStream* out, int round, int& count, T* call_type_data); template void dump_replay_data_receiver_type_helper(outputStream* out, int round, int& count, T* call_type_data); void dump_replay_data_extra_data_helper(outputStream* out, int round, int& count); + ciProfileData* data_from(DataLayout* data_layout); public: bool is_method_data() const { return true; } @@ -519,7 +520,9 @@ class ciMethodData : public ciMetadata { // Walk through the data in order. ciProfileData* first_data() { return data_at(first_di()); } ciProfileData* next_data(ciProfileData* current); + DataLayout* next_data_layout(DataLayout* current); bool is_valid(ciProfileData* current) { return current != NULL; } + bool is_valid(DataLayout* current) { return current != NULL; } DataLayout* extra_data_base() const { return data_layout_at(data_size()); } DataLayout* args_data_limit() const { return data_layout_at(data_size() + extra_data_size() - diff --git a/src/hotspot/share/ci/ciMethodHandle.cpp b/src/hotspot/share/ci/ciMethodHandle.cpp index be6b76bd49a..49de75353a6 100644 --- a/src/hotspot/share/ci/ciMethodHandle.cpp +++ b/src/hotspot/share/ci/ciMethodHandle.cpp @@ -36,11 +36,6 @@ ciMethod* ciMethodHandle::get_vmtarget() const { VM_ENTRY_MARK; oop form_oop = java_lang_invoke_MethodHandle::form(get_oop()); oop vmentry_oop = java_lang_invoke_LambdaForm::vmentry(form_oop); - // FIXME: Share code with ciMemberName::get_vmtarget - Metadata* vmtarget = java_lang_invoke_MemberName::vmtarget(vmentry_oop); - if (vmtarget->is_method()) - return CURRENT_ENV->get_method((Method*) vmtarget); - // FIXME: What if the vmtarget is a Klass? - assert(false, ""); - return NULL; + Method* vmtarget = java_lang_invoke_MemberName::vmtarget(vmentry_oop); + return CURRENT_ENV->get_method(vmtarget); } diff --git a/src/hotspot/share/classfile/classFileParser.cpp b/src/hotspot/share/classfile/classFileParser.cpp index d5dbf6c3f4d..21cd57ad979 100644 --- a/src/hotspot/share/classfile/classFileParser.cpp +++ b/src/hotspot/share/classfile/classFileParser.cpp @@ -3645,12 +3645,6 @@ bool ClassFileParser::supports_sealed_types() { Arguments::enable_preview(); } -bool ClassFileParser::supports_records() { - return _major_version == JVM_CLASSFILE_MAJOR_VERSION && - _minor_version == JAVA_PREVIEW_MINOR_VERSION && - Arguments::enable_preview(); -} - void ClassFileParser::parse_classfile_attributes(const ClassFileStream* const cfs, ConstantPool* cp, ClassFileParser::ClassAnnotationCollector* parsed_annotations, @@ -3898,67 +3892,34 @@ void ClassFileParser::parse_classfile_attributes(const ClassFileStream* const cf "Nest-host class_info_index %u has bad constant type in class file %s", class_info_index, CHECK); _nest_host = class_info_index; - } else if (_major_version >= JAVA_14_VERSION) { + + } else if (_major_version >= JAVA_16_VERSION) { if (tag == vmSymbols::tag_record()) { - // Skip over Record attribute if not supported or if super class is - // not java.lang.Record. - if (supports_records() && - cp->klass_name_at(_super_class_index) == vmSymbols::java_lang_Record()) { - if (parsed_record_attribute) { - classfile_parse_error("Multiple Record attributes in class file %s", THREAD); + if (parsed_record_attribute) { + classfile_parse_error("Multiple Record attributes in class file %s", THREAD); + return; + } + parsed_record_attribute = true; + record_attribute_start = cfs->current(); + record_attribute_length = attribute_length; + } else if (tag == vmSymbols::tag_permitted_subclasses()) { + if (supports_sealed_types()) { + if (parsed_permitted_subclasses_attribute) { + classfile_parse_error("Multiple PermittedSubclasses attributes in class file %s", CHECK); return; } - // Check that class is final and not abstract. - if (!_access_flags.is_final() || _access_flags.is_abstract()) { - classfile_parse_error("Record attribute in non-final or abstract class file %s", THREAD); + // Classes marked ACC_FINAL cannot have a PermittedSubclasses attribute. + if (_access_flags.is_final()) { + classfile_parse_error("PermittedSubclasses attribute in final class file %s", CHECK); return; } - parsed_record_attribute = true; - record_attribute_start = cfs->current(); - record_attribute_length = attribute_length; - } else if (log_is_enabled(Info, class, record)) { - // Log why the Record attribute was ignored. Note that if the - // class file version is JVM_CLASSFILE_MAJOR_VERSION.65535 and - // --enable-preview wasn't specified then a java.lang.UnsupportedClassVersionError - // exception would have been thrown. - ResourceMark rm(THREAD); - if (supports_records()) { - log_info(class, record)( - "Ignoring Record attribute in class %s because super type is not java.lang.Record", - _class_name->as_C_string()); - } else { - log_info(class, record)( - "Ignoring Record attribute in class %s because class file version is not %d.65535", - _class_name->as_C_string(), JVM_CLASSFILE_MAJOR_VERSION); - } + parsed_permitted_subclasses_attribute = true; + permitted_subclasses_attribute_start = cfs->current(); + permitted_subclasses_attribute_length = attribute_length; } - cfs->skip_u1(attribute_length, CHECK); - } else if (_major_version >= JAVA_15_VERSION) { - // Check for PermittedSubclasses tag - if (tag == vmSymbols::tag_permitted_subclasses()) { - if (supports_sealed_types()) { - if (parsed_permitted_subclasses_attribute) { - classfile_parse_error("Multiple PermittedSubclasses attributes in class file %s", THREAD); - return; - } - // Classes marked ACC_FINAL cannot have a PermittedSubclasses attribute. - if (_access_flags.is_final()) { - classfile_parse_error("PermittedSubclasses attribute in final class file %s", THREAD); - return; - } - parsed_permitted_subclasses_attribute = true; - permitted_subclasses_attribute_start = cfs->current(); - permitted_subclasses_attribute_length = attribute_length; - } - cfs->skip_u1(attribute_length, CHECK); - } else { - // Unknown attribute - cfs->skip_u1(attribute_length, CHECK); - } - } else { - // Unknown attribute - cfs->skip_u1(attribute_length, CHECK); } + // Skip attribute_length for any attribute where major_verson >= JAVA_16_VERSION + cfs->skip_u1(attribute_length, CHECK); } else { // Unknown attribute cfs->skip_u1(attribute_length, CHECK); @@ -4452,13 +4413,7 @@ void ClassFileParser::check_super_class_access(const InstanceKlass* this_klass, const InstanceKlass* super_ik = InstanceKlass::cast(super); if (super->is_final()) { - ResourceMark rm(THREAD); - Exceptions::fthrow( - THREAD_AND_LOCATION, - vmSymbols::java_lang_VerifyError(), - "class %s cannot inherit from final class %s", - this_klass->external_name(), - super_ik->external_name()); + classfile_icce_error("class %s cannot inherit from final class %s", super_ik, THREAD); return; } @@ -4603,15 +4558,12 @@ static void check_final_method_override(const InstanceKlass* this_klass, TRAPS) if (can_access) { // this class can access super final method and therefore override ResourceMark rm(THREAD); - Exceptions::fthrow(THREAD_AND_LOCATION, - vmSymbols::java_lang_VerifyError(), - "class %s overrides final method %s.%s%s", - this_klass->external_name(), - super_m->method_holder()->external_name(), - name->as_C_string(), - signature->as_C_string() - ); - return; + THROW_MSG(vmSymbols::java_lang_IncompatibleClassChangeError(), + err_msg("class %s overrides final method %s.%s%s", + this_klass->external_name(), + super_m->method_holder()->external_name(), + name->as_C_string(), + signature->as_C_string())); } } diff --git a/src/hotspot/share/classfile/classListParser.cpp b/src/hotspot/share/classfile/classListParser.cpp index 9bc9aa439ab..0f7b78de4d7 100644 --- a/src/hotspot/share/classfile/classListParser.cpp +++ b/src/hotspot/share/classfile/classListParser.cpp @@ -37,6 +37,7 @@ #include "interpreter/linkResolver.hpp" #include "logging/log.hpp" #include "logging/logTag.hpp" +#include "memory/archiveUtils.hpp" #include "memory/metaspaceShared.hpp" #include "memory/resourceArea.hpp" #include "oops/constantPool.hpp" @@ -115,13 +116,6 @@ bool ClassListParser::parse_one_line() { _line_len = len; } - // Check if the line is output TRACE_RESOLVE - if (strncmp(_line, LambdaFormInvokers::lambda_form_invoker_tag(), - strlen(LambdaFormInvokers::lambda_form_invoker_tag())) == 0) { - LambdaFormInvokers::append(os::strdup((const char*)_line, mtInternal)); - continue; - } - // valid line break; } @@ -133,6 +127,7 @@ bool ClassListParser::parse_one_line() { _source = NULL; _interfaces_specified = false; _indy_items->clear(); + _lambda_form_line = false; if (_line[0] == '@') { return parse_at_tags(); @@ -185,8 +180,8 @@ bool ClassListParser::parse_one_line() { return true; } -void ClassListParser::split_tokens_by_whitespace() { - int start = 0; +void ClassListParser::split_tokens_by_whitespace(int offset) { + int start = offset; int end; bool done = false; while (!done) { @@ -203,19 +198,40 @@ void ClassListParser::split_tokens_by_whitespace() { } } +int ClassListParser::split_at_tag_from_line() { + _token = _line; + char* ptr; + if ((ptr = strchr(_line, ' ')) == NULL) { + error("Too few items following the @ tag \"%s\" line #%d", _line, _line_no); + return 0; + } + *ptr++ = '\0'; + while (*ptr == ' ' || *ptr == '\t') ptr++; + return (int)(ptr - _line); +} + bool ClassListParser::parse_at_tags() { assert(_line[0] == '@', "must be"); - split_tokens_by_whitespace(); - if (strcmp(_indy_items->at(0), LAMBDA_PROXY_TAG) == 0) { - if (_indy_items->length() < 3) { - error("Line with @ tag has too few items \"%s\" line #%d", _line, _line_no); + int offset; + if ((offset = split_at_tag_from_line()) == 0) { + return false; + } + + if (strcmp(_token, LAMBDA_PROXY_TAG) == 0) { + split_tokens_by_whitespace(offset); + if (_indy_items->length() < 2) { + error("Line with @ tag has too few items \"%s\" line #%d", _token, _line_no); return false; } // set the class name - _class_name = _indy_items->at(1); + _class_name = _indy_items->at(0); + return true; + } else if (strcmp(_token, LAMBDA_FORM_TAG) == 0) { + LambdaFormInvokers::append(os::strdup((const char*)(_line + offset), mtInternal)); + _lambda_form_line = true; return true; } else { - error("Invalid @ tag at the beginning of line \"%s\" line #%d", _line, _line_no); + error("Invalid @ tag at the beginning of line \"%s\" line #%d", _token, _line_no); return false; } } @@ -432,7 +448,7 @@ bool ClassListParser::is_matching_cp_entry(constantPoolHandle &pool, int cp_inde CDSIndyInfo cii; populate_cds_indy_info(pool, cp_index, &cii, THREAD); GrowableArray* items = cii.items(); - int indy_info_offset = 2; + int indy_info_offset = 1; if (_indy_items->length() - indy_info_offset != items->length()) { return false; } @@ -557,6 +573,7 @@ Klass* ClassListParser::load_current_class(TRAPS) { klass = java_lang_Class::as_Klass(obj); } else { // load classes in bootclasspath/a if (HAS_PENDING_EXCEPTION) { + ArchiveUtils::check_for_oom(PENDING_EXCEPTION); // exit on OOM CLEAR_PENDING_EXCEPTION; } @@ -567,6 +584,8 @@ Klass* ClassListParser::load_current_class(TRAPS) { } else { if (!HAS_PENDING_EXCEPTION) { THROW_NULL(vmSymbols::java_lang_ClassNotFoundException()); + } else { + ArchiveUtils::check_for_oom(PENDING_EXCEPTION); // exit on OOM } } } @@ -575,6 +594,9 @@ Klass* ClassListParser::load_current_class(TRAPS) { // If "source:" tag is specified, all super class and super interfaces must be specified in the // class list file. klass = load_class_from_source(class_name_symbol, CHECK_NULL); + if (HAS_PENDING_EXCEPTION) { + ArchiveUtils::check_for_oom(PENDING_EXCEPTION); // exit on OOM + } } if (klass != NULL && klass->is_instance_klass() && is_id_specified()) { diff --git a/src/hotspot/share/classfile/classListParser.hpp b/src/hotspot/share/classfile/classListParser.hpp index bbbaf0720a6..dd5cf0b62ff 100644 --- a/src/hotspot/share/classfile/classListParser.hpp +++ b/src/hotspot/share/classfile/classListParser.hpp @@ -30,7 +30,8 @@ #include "utilities/growableArray.hpp" #include "utilities/hashtable.inline.hpp" -#define LAMBDA_PROXY_TAG "@lambda-proxy:" +#define LAMBDA_PROXY_TAG "@lambda-proxy" +#define LAMBDA_FORM_TAG "@lambda-form-invoker" class ID2KlassTable : public KVHashtable { public: @@ -99,6 +100,7 @@ class ClassListParser : public StackObj { GrowableArray* _interfaces; bool _interfaces_specified; const char* _source; + bool _lambda_form_line; bool parse_int_option(const char* option_name, int* value); bool parse_uint_option(const char* option_name, int* value); @@ -120,7 +122,8 @@ class ClassListParser : public StackObj { return _instance; } bool parse_one_line(); - void split_tokens_by_whitespace(); + void split_tokens_by_whitespace(int offset); + int split_at_tag_from_line(); bool parse_at_tags(); char* _token; void error(const char* msg, ...); @@ -162,6 +165,8 @@ class ClassListParser : public StackObj { bool is_loading_from_source(); + bool lambda_form_line() { return _lambda_form_line; } + // Look up the super or interface of the current class being loaded // (in this->load_current_class()). InstanceKlass* lookup_super_for_current_class(Symbol* super_name); diff --git a/src/hotspot/share/classfile/javaClasses.hpp b/src/hotspot/share/classfile/javaClasses.hpp index 23fa7b64e48..a6fc3ad2ff1 100644 --- a/src/hotspot/share/classfile/javaClasses.hpp +++ b/src/hotspot/share/classfile/javaClasses.hpp @@ -322,6 +322,8 @@ class java_lang_Class : AllStatic { static oop class_data(oop java_class); static void set_class_data(oop java_class, oop classData); + static int component_mirror_offset() { return _component_mirror_offset; } + static oop class_loader(oop java_class); static void set_module(oop java_class, oop module); static oop module(oop java_class); diff --git a/src/hotspot/share/classfile/lambdaFormInvokers.cpp b/src/hotspot/share/classfile/lambdaFormInvokers.cpp index aeca99a14df..ca7dc211e32 100644 --- a/src/hotspot/share/classfile/lambdaFormInvokers.cpp +++ b/src/hotspot/share/classfile/lambdaFormInvokers.cpp @@ -66,9 +66,7 @@ void LambdaFormInvokers::regenerate_holder_classes(TRAPS) { int len = _lambdaform_lines->length(); objArrayHandle list_lines = oopFactory::new_objArray_handle(SystemDictionary::String_klass(), len, CHECK); for (int i = 0; i < len; i++) { - char* record = _lambdaform_lines->at(i); - record += strlen(lambda_form_invoker_tag()) + 1; // skip the @lambda_form_invoker prefix - Handle h_line = java_lang_String::create_from_str(record, CHECK); + Handle h_line = java_lang_String::create_from_str(_lambdaform_lines->at(i), CHECK); list_lines->obj_at_put(i, h_line()); } diff --git a/src/hotspot/share/classfile/lambdaFormInvokers.hpp b/src/hotspot/share/classfile/lambdaFormInvokers.hpp index e587deba8c5..d21fb8e64ca 100644 --- a/src/hotspot/share/classfile/lambdaFormInvokers.hpp +++ b/src/hotspot/share/classfile/lambdaFormInvokers.hpp @@ -42,9 +42,5 @@ class LambdaFormInvokers : public AllStatic { static GrowableArray* lambdaform_lines() { return _lambdaform_lines; } - - static const char* lambda_form_invoker_tag() { - return "@lambda-form-invoker"; - } }; #endif // SHARE_MEMORY_LAMBDAFORMINVOKERS_HPP diff --git a/src/hotspot/share/classfile/systemDictionaryShared.cpp b/src/hotspot/share/classfile/systemDictionaryShared.cpp index b617a66c17b..2cd54604d5b 100644 --- a/src/hotspot/share/classfile/systemDictionaryShared.cpp +++ b/src/hotspot/share/classfile/systemDictionaryShared.cpp @@ -1179,19 +1179,24 @@ InstanceKlass* SystemDictionaryShared::acquire_class_for_current_thread( return shared_klass; } -static ResourceHashtable< +class LoadedUnregisteredClassesTable : public ResourceHashtable< Symbol*, bool, primitive_hash, primitive_equals, 6661, // prime number - ResourceObj::C_HEAP> _loaded_unregistered_classes; + ResourceObj::C_HEAP> {}; + +static LoadedUnregisteredClassesTable* _loaded_unregistered_classes = NULL; bool SystemDictionaryShared::add_unregistered_class(InstanceKlass* k, TRAPS) { // We don't allow duplicated unregistered classes of the same name. assert(DumpSharedSpaces, "only when dumping"); Symbol* name = k->name(); + if (_loaded_unregistered_classes == NULL) { + _loaded_unregistered_classes = new (ResourceObj::C_HEAP, mtClass)LoadedUnregisteredClassesTable(); + } bool created = false; - _loaded_unregistered_classes.put_if_absent(name, true, &created); + _loaded_unregistered_classes->put_if_absent(name, true, &created); if (created) { MutexLocker mu_r(THREAD, Compile_lock); // add_to_hierarchy asserts this. SystemDictionary::add_to_hierarchy(k, CHECK_false); diff --git a/src/hotspot/share/classfile/vmSymbols.hpp b/src/hotspot/share/classfile/vmSymbols.hpp index c86927f57b3..df2737f743f 100644 --- a/src/hotspot/share/classfile/vmSymbols.hpp +++ b/src/hotspot/share/classfile/vmSymbols.hpp @@ -147,6 +147,7 @@ \ /* Java runtime version access */ \ template(java_lang_VersionProps, "java/lang/VersionProps") \ + template(java_version_name, "java_version") \ template(java_runtime_name_name, "java_runtime_name") \ template(java_runtime_version_name, "java_runtime_version") \ template(java_runtime_vendor_version_name, "VENDOR_VERSION") \ diff --git a/src/hotspot/share/compiler/compilerDirectives.cpp b/src/hotspot/share/compiler/compilerDirectives.cpp index b940a7e8e36..753f9798a83 100644 --- a/src/hotspot/share/compiler/compilerDirectives.cpp +++ b/src/hotspot/share/compiler/compilerDirectives.cpp @@ -322,7 +322,6 @@ class DirectiveSetPtr { // - if some option is changed we need to copy directiveset since it no longer can be shared // - Need to free copy after use // - Requires a modified bit so we don't overwrite options that is set by directives - DirectiveSet* DirectiveSet::compilecommand_compatibility_init(const methodHandle& method) { // Early bail out - checking all options is expensive - we rely on them not being used // Only set a flag if it has not been modified and value changes. @@ -360,6 +359,7 @@ DirectiveSet* DirectiveSet::compilecommand_compatibility_init(const methodHandle } // inline and dontinline (including exclude) are implemented in the directiveset accessors + // ignore flags whose cc_flags are X #define init_default_cc(name, type, dvalue, cc_flag) { type v; if (!_modified[name##Index] && CompilerOracle::has_option_value(method, #cc_flag, v) && v != this->name##Option) { set.cloned()->name##Option = v; } } compilerdirectives_common_flags(init_default_cc) compilerdirectives_c2_flags(init_default_cc) diff --git a/src/hotspot/share/compiler/compilerDirectives.hpp b/src/hotspot/share/compiler/compilerDirectives.hpp index a04c13ea061..a67e534a9b2 100644 --- a/src/hotspot/share/compiler/compilerDirectives.hpp +++ b/src/hotspot/share/compiler/compilerDirectives.hpp @@ -36,8 +36,8 @@ #define compilerdirectives_common_flags(cflags) \ cflags(Enable, bool, false, X) \ cflags(Exclude, bool, false, X) \ - cflags(BreakAtExecute, bool, false, X) \ - cflags(BreakAtCompile, bool, false, X) \ + cflags(BreakAtExecute, bool, false, BreakAtExecute) \ + cflags(BreakAtCompile, bool, false, BreakAtCompile) \ cflags(Log, bool, LogCompilation, X) \ cflags(PrintAssembly, bool, PrintAssembly, PrintAssembly) \ cflags(PrintInlining, bool, PrintInlining, PrintInlining) \ diff --git a/src/hotspot/share/gc/g1/g1Allocator.cpp b/src/hotspot/share/gc/g1/g1Allocator.cpp index cb172b5f5b5..c20b4400cad 100644 --- a/src/hotspot/share/gc/g1/g1Allocator.cpp +++ b/src/hotspot/share/gc/g1/g1Allocator.cpp @@ -281,22 +281,9 @@ HeapWord* G1Allocator::old_attempt_allocation(size_t min_word_size, return result; } -uint G1PLABAllocator::calc_survivor_alignment_bytes() { - assert(SurvivorAlignmentInBytes >= ObjectAlignmentInBytes, "sanity"); - if (SurvivorAlignmentInBytes == ObjectAlignmentInBytes) { - // No need to align objects in the survivors differently, return 0 - // which means "survivor alignment is not used". - return 0; - } else { - assert(SurvivorAlignmentInBytes > 0, "sanity"); - return SurvivorAlignmentInBytes; - } -} - G1PLABAllocator::G1PLABAllocator(G1Allocator* allocator) : _g1h(G1CollectedHeap::heap()), - _allocator(allocator), - _survivor_alignment_bytes(calc_survivor_alignment_bytes()) { + _allocator(allocator) { for (region_type_t state = 0; state < G1HeapRegionAttr::Num; state++) { _direct_allocated[state] = 0; uint length = alloc_buffers_length(state); diff --git a/src/hotspot/share/gc/g1/g1Allocator.hpp b/src/hotspot/share/gc/g1/g1Allocator.hpp index f0702b4d6c2..4346171466f 100644 --- a/src/hotspot/share/gc/g1/g1Allocator.hpp +++ b/src/hotspot/share/gc/g1/g1Allocator.hpp @@ -149,13 +149,6 @@ class G1PLABAllocator : public CHeapObj { PLAB** _alloc_buffers[G1HeapRegionAttr::Num]; - // The survivor alignment in effect in bytes. - // == 0 : don't align survivors - // != 0 : align survivors to that alignment - // These values were chosen to favor the non-alignment case since some - // architectures have a special compare against zero instructions. - const uint _survivor_alignment_bytes; - // Number of words allocated directly (not counting PLAB allocation). size_t _direct_allocated[G1HeapRegionAttr::Num]; @@ -168,10 +161,6 @@ class G1PLABAllocator : public CHeapObj { // active NUMA nodes. inline uint alloc_buffers_length(region_type_t dest) const; - // Calculate the survivor space object alignment in bytes. Returns that or 0 if - // there are no restrictions on survivor alignment. - static uint calc_survivor_alignment_bytes(); - bool may_throw_away_buffer(size_t const allocation_word_sz, size_t const buffer_size) const; public: G1PLABAllocator(G1Allocator* allocator); diff --git a/src/hotspot/share/gc/g1/g1Allocator.inline.hpp b/src/hotspot/share/gc/g1/g1Allocator.inline.hpp index 5b6ab355c4d..6d484292051 100644 --- a/src/hotspot/share/gc/g1/g1Allocator.inline.hpp +++ b/src/hotspot/share/gc/g1/g1Allocator.inline.hpp @@ -105,11 +105,7 @@ inline HeapWord* G1PLABAllocator::plab_allocate(G1HeapRegionAttr dest, size_t word_sz, uint node_index) { PLAB* buffer = alloc_buffer(dest, node_index); - if (_survivor_alignment_bytes == 0 || !dest.is_young()) { - return buffer->allocate(word_sz); - } else { - return buffer->allocate_aligned(word_sz, _survivor_alignment_bytes); - } + return buffer->allocate(word_sz); } inline HeapWord* G1PLABAllocator::allocate(G1HeapRegionAttr dest, diff --git a/src/hotspot/share/gc/g1/g1BiasedArray.cpp b/src/hotspot/share/gc/g1/g1BiasedArray.cpp index 0d9a3caf4eb..ce0196ee5bb 100644 --- a/src/hotspot/share/gc/g1/g1BiasedArray.cpp +++ b/src/hotspot/share/gc/g1/g1BiasedArray.cpp @@ -26,11 +26,23 @@ #include "gc/g1/g1BiasedArray.hpp" #include "memory/padded.inline.hpp" +G1BiasedMappedArrayBase::G1BiasedMappedArrayBase() : + _alloc_base(NULL), + _base(NULL), + _length(0), + _biased_base(NULL), + _bias(0), + _shift_by(0) { } + +G1BiasedMappedArrayBase::~G1BiasedMappedArrayBase() { + FreeHeap(_alloc_base); +} + // Allocate a new array, generic version. address G1BiasedMappedArrayBase::create_new_base_array(size_t length, size_t elem_size) { assert(length > 0, "just checking"); assert(elem_size > 0, "just checking"); - return PaddedPrimitiveArray::create_unfreeable(length * elem_size); + return PaddedPrimitiveArray::create(length * elem_size, &_alloc_base); } #ifndef PRODUCT diff --git a/src/hotspot/share/gc/g1/g1BiasedArray.hpp b/src/hotspot/share/gc/g1/g1BiasedArray.hpp index 248abbabf1e..7c604706566 100644 --- a/src/hotspot/share/gc/g1/g1BiasedArray.hpp +++ b/src/hotspot/share/gc/g1/g1BiasedArray.hpp @@ -25,6 +25,7 @@ #ifndef SHARE_GC_G1_G1BIASEDARRAY_HPP #define SHARE_GC_G1_G1BIASEDARRAY_HPP +#include "memory/allocation.hpp" #include "memory/memRegion.hpp" #include "utilities/debug.hpp" #include "utilities/powerOfTwo.hpp" @@ -32,10 +33,14 @@ // Implements the common base functionality for arrays that contain provisions // for accessing its elements using a biased index. // The element type is defined by the instantiating the template. -class G1BiasedMappedArrayBase { +class G1BiasedMappedArrayBase : public CHeapObj { friend class VMStructs; + + void* _alloc_base; // the address the unpadded array has been allocated to + public: typedef size_t idx_t; + protected: address _base; // the real base address size_t _length; // the length of the array @@ -44,12 +49,10 @@ class G1BiasedMappedArrayBase { uint _shift_by; // the amount of bits to shift right when mapping to an index of the array. protected: - - G1BiasedMappedArrayBase() : _base(NULL), _length(0), _biased_base(NULL), - _bias(0), _shift_by(0) { } + G1BiasedMappedArrayBase(); // Allocate a new array, generic version. - static address create_new_base_array(size_t length, size_t elem_size); + address create_new_base_array(size_t length, size_t elem_size); // Initialize the members of this class. The biased start address of this array // is the bias (in elements) multiplied by the element size. @@ -90,8 +93,10 @@ class G1BiasedMappedArrayBase { void verify_biased_index_inclusive_end(idx_t biased_index) const PRODUCT_RETURN; public: - // Return the length of the array in elements. - size_t length() const { return _length; } + virtual ~G1BiasedMappedArrayBase(); + + // Return the length of the array in elements. + size_t length() const { return _length; } }; // Array that provides biased access and mapping from (valid) addresses in the diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMarkThread.cpp b/src/hotspot/share/gc/g1/g1ConcurrentMarkThread.cpp index 23879d7bbed..b58d8c66d8b 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentMarkThread.cpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentMarkThread.cpp @@ -108,7 +108,7 @@ void G1ConcurrentMarkThread::delay_to_keep_mmu(bool remark) { jlong sleep_time_ms = ceil(sleep_time_sec * MILLIUNITS); if (sleep_time_ms <= 0) { break; // Passed end time. - } else if (ml.wait(sleep_time_ms, Monitor::_no_safepoint_check_flag)) { + } else if (ml.wait(sleep_time_ms)) { break; // Timeout => reached end time. } // Other (possibly spurious) wakeup. Retry with updated sleep time. diff --git a/src/hotspot/share/gc/g1/g1RegionToSpaceMapper.cpp b/src/hotspot/share/gc/g1/g1RegionToSpaceMapper.cpp index 88907a6f87f..69e0778a904 100644 --- a/src/hotspot/share/gc/g1/g1RegionToSpaceMapper.cpp +++ b/src/hotspot/share/gc/g1/g1RegionToSpaceMapper.cpp @@ -220,7 +220,7 @@ static bool map_nvdimm_space(ReservedSpace rs) { return false; } // commit this memory in nv-dimm - char* ret = os::attempt_reserve_memory_at(rs.base(), rs.size(), _backing_fd); + char* ret = os::attempt_map_memory_to_file_at(rs.base(), rs.size(), _backing_fd); if (ret != rs.base()) { if (ret != NULL) { diff --git a/src/hotspot/share/gc/g1/heapRegion.cpp b/src/hotspot/share/gc/g1/heapRegion.cpp index eadde715f6f..b901ceb15fd 100644 --- a/src/hotspot/share/gc/g1/heapRegion.cpp +++ b/src/hotspot/share/gc/g1/heapRegion.cpp @@ -516,9 +516,6 @@ class G1VerificationClosure : public BasicOopIterateClosure { obj->print_on(out); #endif // PRODUCT } - - // This closure provides its own oop verification code. - debug_only(virtual bool should_verify_oops() { return false; }) }; class VerifyLiveClosure : public G1VerificationClosure { @@ -655,9 +652,6 @@ class G1Mux2Closure : public BasicOopIterateClosure { } virtual inline void do_oop(oop* p) { do_oop_work(p); } virtual inline void do_oop(narrowOop* p) { do_oop_work(p); } - - // This closure provides its own oop verification code. - debug_only(virtual bool should_verify_oops() { return false; }) }; void HeapRegion::verify(VerifyOption vo, diff --git a/src/hotspot/share/gc/parallel/psCompactionManager.inline.hpp b/src/hotspot/share/gc/parallel/psCompactionManager.inline.hpp index 979db9e2870..48b9875672f 100644 --- a/src/hotspot/share/gc/parallel/psCompactionManager.inline.hpp +++ b/src/hotspot/share/gc/parallel/psCompactionManager.inline.hpp @@ -47,9 +47,6 @@ class PCMarkAndPushClosure: public OopClosure { template void do_oop_nv(T* p) { _compaction_manager->mark_and_push(p); } virtual void do_oop(oop* p) { do_oop_nv(p); } virtual void do_oop(narrowOop* p) { do_oop_nv(p); } - - // This closure provides its own oop verification code. - debug_only(virtual bool should_verify_oops() { return false; }) }; class PCIterateMarkAndPushClosure: public MetadataVisitingOopIterateClosure { @@ -64,9 +61,6 @@ class PCIterateMarkAndPushClosure: public MetadataVisitingOopIterateClosure { void do_klass_nv(Klass* k) { _compaction_manager->follow_klass(k); } void do_cld_nv(ClassLoaderData* cld) { _compaction_manager->follow_class_loader(cld); } - - // This closure provides its own oop verification code. - debug_only(virtual bool should_verify_oops() { return false; }) }; inline bool ParCompactionManager::steal(int queue_num, oop& t) { diff --git a/src/hotspot/share/gc/parallel/psParallelCompact.inline.hpp b/src/hotspot/share/gc/parallel/psParallelCompact.inline.hpp index df4f1c41cda..688da81e9c2 100644 --- a/src/hotspot/share/gc/parallel/psParallelCompact.inline.hpp +++ b/src/hotspot/share/gc/parallel/psParallelCompact.inline.hpp @@ -134,8 +134,6 @@ class PCAdjustPointerClosure: public BasicOopIterateClosure { virtual void do_oop(oop* p) { do_oop_nv(p); } virtual void do_oop(narrowOop* p) { do_oop_nv(p); } - // This closure provides its own oop verification code. - debug_only(virtual bool should_verify_oops() { return false; }) virtual ReferenceIterationMode reference_iteration_mode() { return DO_FIELDS; } private: ParCompactionManager* _cm; diff --git a/src/hotspot/share/gc/parallel/psPromotionLAB.inline.hpp b/src/hotspot/share/gc/parallel/psPromotionLAB.inline.hpp index 1c883058310..b852324e877 100644 --- a/src/hotspot/share/gc/parallel/psPromotionLAB.inline.hpp +++ b/src/hotspot/share/gc/parallel/psPromotionLAB.inline.hpp @@ -32,20 +32,14 @@ HeapWord* PSYoungPromotionLAB::allocate(size_t size) { // Can't assert this, when young fills, we keep the LAB around, but flushed. // assert(_state != flushed, "Sanity"); - HeapWord* obj = CollectedHeap::align_allocation_or_fail(top(), end(), SurvivorAlignmentInBytes); - if (obj == NULL) { - return NULL; - } - + HeapWord* obj = top(); HeapWord* new_top = obj + size; // The 'new_top>obj' check is needed to detect overflow of obj+size. if (new_top > obj && new_top <= end()) { set_top(new_top); - assert(is_aligned(obj, SurvivorAlignmentInBytes) && is_object_aligned(new_top), - "checking alignment"); + assert(is_object_aligned(new_top), "checking alignment"); return obj; } else { - set_top(obj); return NULL; } } diff --git a/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp b/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp index 3dc587da9e0..d97694466d5 100644 --- a/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp +++ b/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp @@ -97,9 +97,6 @@ class PSPushContentsClosure: public BasicOopIterateClosure { virtual void do_oop(oop* p) { do_oop_nv(p); } virtual void do_oop(narrowOop* p) { do_oop_nv(p); } - - // Don't use the oop verification code in the oop_oop_iterate framework. - debug_only(virtual bool should_verify_oops() { return false; }) }; // diff --git a/src/hotspot/share/gc/serial/defNewGeneration.cpp b/src/hotspot/share/gc/serial/defNewGeneration.cpp index 2fe070f7ee4..296415542ad 100644 --- a/src/hotspot/share/gc/serial/defNewGeneration.cpp +++ b/src/hotspot/share/gc/serial/defNewGeneration.cpp @@ -711,7 +711,7 @@ oop DefNewGeneration::copy_to_survivor_space(oop old) { // Try allocating obj in to-space (unless too old) if (old->age() < tenuring_threshold()) { - obj = (oop) to()->allocate_aligned(s); + obj = (oop) to()->allocate(s); } // Otherwise try allocating obj tenured diff --git a/src/hotspot/share/gc/serial/defNewGeneration.inline.hpp b/src/hotspot/share/gc/serial/defNewGeneration.inline.hpp index 744d03c088d..67dce43e7b6 100644 --- a/src/hotspot/share/gc/serial/defNewGeneration.inline.hpp +++ b/src/hotspot/share/gc/serial/defNewGeneration.inline.hpp @@ -45,7 +45,7 @@ inline void DefNewGeneration::KeepAliveClosure::do_oop_work(T* p) { } #endif // ASSERT - Devirtualizer::do_oop_no_verify(_cl, p); + Devirtualizer::do_oop(_cl, p); // Card marking is trickier for weak refs. // This oop is a 'next' field which was filled in while we @@ -77,7 +77,7 @@ inline void DefNewGeneration::FastKeepAliveClosure::do_oop_work(T* p) { } #endif // ASSERT - Devirtualizer::do_oop_no_verify(_cl, p); + Devirtualizer::do_oop(_cl, p); // Optimized for Defnew generation if it's the youngest generation: // we set a younger_gen card if we have an older->youngest diff --git a/src/hotspot/share/gc/serial/markSweep.hpp b/src/hotspot/share/gc/serial/markSweep.hpp index 58a4128d8cf..e09d7d06833 100644 --- a/src/hotspot/share/gc/serial/markSweep.hpp +++ b/src/hotspot/share/gc/serial/markSweep.hpp @@ -191,9 +191,6 @@ class AdjustPointerClosure: public BasicOopIterateClosure { virtual void do_oop(oop* p); virtual void do_oop(narrowOop* p); virtual ReferenceIterationMode reference_iteration_mode() { return DO_FIELDS; } - - // This closure provides its own oop verification code. - debug_only(virtual bool should_verify_oops() { return false; }) }; class PreservedMark { diff --git a/src/hotspot/share/gc/shared/collectedHeap.hpp b/src/hotspot/share/gc/shared/collectedHeap.hpp index e46ecc3dcf4..5df7ad7badb 100644 --- a/src/hotspot/share/gc/shared/collectedHeap.hpp +++ b/src/hotspot/share/gc/shared/collectedHeap.hpp @@ -310,12 +310,6 @@ class CollectedHeap : public CHeapObj { virtual size_t min_dummy_object_size() const; size_t tlab_alloc_reserve() const; - // Return the address "addr" aligned by "alignment_in_bytes" if such - // an address is below "end". Return NULL otherwise. - inline static HeapWord* align_allocation_or_fail(HeapWord* addr, - HeapWord* end, - unsigned short alignment_in_bytes); - // Some heaps may offer a contiguous region for shared non-blocking // allocation, via inlined code (by exporting the address of the top and // end fields defining the extent of the contiguous allocation region.) diff --git a/src/hotspot/share/gc/shared/collectedHeap.inline.hpp b/src/hotspot/share/gc/shared/collectedHeap.inline.hpp index 2d03f7a36b4..94b3b50238f 100644 --- a/src/hotspot/share/gc/shared/collectedHeap.inline.hpp +++ b/src/hotspot/share/gc/shared/collectedHeap.inline.hpp @@ -30,43 +30,6 @@ #include "oops/oop.inline.hpp" #include "utilities/align.hpp" -inline HeapWord* CollectedHeap::align_allocation_or_fail(HeapWord* addr, - HeapWord* end, - unsigned short alignment_in_bytes) { - if (alignment_in_bytes <= ObjectAlignmentInBytes) { - return addr; - } - - assert(is_aligned(addr, HeapWordSize), - "Address " PTR_FORMAT " is not properly aligned.", p2i(addr)); - assert(is_aligned(alignment_in_bytes, HeapWordSize), - "Alignment size %u is incorrect.", alignment_in_bytes); - - HeapWord* new_addr = align_up(addr, alignment_in_bytes); - size_t padding = pointer_delta(new_addr, addr); - - if (padding == 0) { - return addr; - } - - if (padding < CollectedHeap::min_fill_size()) { - padding += alignment_in_bytes / HeapWordSize; - assert(padding >= CollectedHeap::min_fill_size(), - "alignment_in_bytes %u is expect to be larger " - "than the minimum object size", alignment_in_bytes); - new_addr = addr + padding; - } - - assert(new_addr > addr, "Unexpected arithmetic overflow " - PTR_FORMAT " not greater than " PTR_FORMAT, p2i(new_addr), p2i(addr)); - if(new_addr < end) { - CollectedHeap::fill_with_object(addr, padding); - return new_addr; - } else { - return NULL; - } -} - inline oop CollectedHeap::obj_allocate(Klass* klass, int size, TRAPS) { ObjAllocator allocator(klass, size, THREAD); return allocator.allocate(); diff --git a/src/hotspot/share/gc/shared/jvmFlagConstraintsGC.cpp b/src/hotspot/share/gc/shared/jvmFlagConstraintsGC.cpp index 32ac7541e43..70043c430b4 100644 --- a/src/hotspot/share/gc/shared/jvmFlagConstraintsGC.cpp +++ b/src/hotspot/share/gc/shared/jvmFlagConstraintsGC.cpp @@ -438,22 +438,3 @@ JVMFlag::Error MaxMetaspaceSizeConstraintFunc(size_t value, bool verbose) { } } -JVMFlag::Error SurvivorAlignmentInBytesConstraintFunc(intx value, bool verbose) { - if (value != 0) { - if (!is_power_of_2(value)) { - JVMFlag::printError(verbose, - "SurvivorAlignmentInBytes (" INTX_FORMAT ") must be " - "power of 2\n", - value); - return JVMFlag::VIOLATES_CONSTRAINT; - } - if (value < ObjectAlignmentInBytes) { - JVMFlag::printError(verbose, - "SurvivorAlignmentInBytes (" INTX_FORMAT ") must be " - "greater than or equal to ObjectAlignmentInBytes (" INTX_FORMAT ")\n", - value, ObjectAlignmentInBytes); - return JVMFlag::VIOLATES_CONSTRAINT; - } - } - return JVMFlag::SUCCESS; -} diff --git a/src/hotspot/share/gc/shared/jvmFlagConstraintsGC.hpp b/src/hotspot/share/gc/shared/jvmFlagConstraintsGC.hpp index 1f9ecbd40f6..5bbfac68b66 100644 --- a/src/hotspot/share/gc/shared/jvmFlagConstraintsGC.hpp +++ b/src/hotspot/share/gc/shared/jvmFlagConstraintsGC.hpp @@ -67,8 +67,7 @@ f(uintx, TLABWasteIncrementConstraintFunc) \ f(uintx, SurvivorRatioConstraintFunc) \ f(size_t, MetaspaceSizeConstraintFunc) \ - f(size_t, MaxMetaspaceSizeConstraintFunc) \ - f(intx, SurvivorAlignmentInBytesConstraintFunc) + f(size_t, MaxMetaspaceSizeConstraintFunc) SHARED_GC_CONSTRAINTS(DECLARE_CONSTRAINT) diff --git a/src/hotspot/share/gc/shared/plab.inline.hpp b/src/hotspot/share/gc/shared/plab.inline.hpp index 38ef672f7c8..b0698da8a33 100644 --- a/src/hotspot/share/gc/shared/plab.inline.hpp +++ b/src/hotspot/share/gc/shared/plab.inline.hpp @@ -30,18 +30,6 @@ #include "memory/allocation.inline.hpp" #include "runtime/atomic.hpp" -inline HeapWord* PLAB::allocate_aligned(size_t word_sz, unsigned short alignment_in_bytes) { - HeapWord* res = CollectedHeap::align_allocation_or_fail(_top, _end, alignment_in_bytes); - if (res == NULL) { - return NULL; - } - - // Set _top so that allocate(), which expects _top to be correctly set, - // can be used below. - _top = res; - return allocate(word_sz); -} - void PLABStats::add_allocated(size_t v) { Atomic::add(&_allocated, v); } diff --git a/src/hotspot/share/gc/shared/pretouchTask.cpp b/src/hotspot/share/gc/shared/pretouchTask.cpp index eb0ffbb5bab..4398d3924cc 100644 --- a/src/hotspot/share/gc/shared/pretouchTask.cpp +++ b/src/hotspot/share/gc/shared/pretouchTask.cpp @@ -28,17 +28,21 @@ #include "runtime/globals.hpp" #include "runtime/os.hpp" -PretouchTask::PretouchTask(const char* task_name, char* start_address, char* end_address, size_t page_size) : +PretouchTask::PretouchTask(const char* task_name, + char* start_address, + char* end_address, + size_t page_size, + size_t chunk_size) : AbstractGangTask(task_name), _cur_addr(start_address), _start_addr(start_address), _end_addr(end_address), - _page_size(0) { -#ifdef LINUX - _page_size = UseTransparentHugePages ? (size_t)os::vm_page_size(): page_size; -#else - _page_size = page_size; -#endif + _page_size(page_size), + _chunk_size(chunk_size) { + + assert(chunk_size >= page_size, + "Chunk size " SIZE_FORMAT " is smaller than page size " SIZE_FORMAT, + chunk_size, page_size); } size_t PretouchTask::chunk_size() { @@ -46,15 +50,13 @@ size_t PretouchTask::chunk_size() { } void PretouchTask::work(uint worker_id) { - size_t const actual_chunk_size = MAX2(chunk_size(), _page_size); - while (true) { - char* touch_addr = Atomic::fetch_and_add(&_cur_addr, actual_chunk_size); + char* touch_addr = Atomic::fetch_and_add(&_cur_addr, _chunk_size); if (touch_addr < _start_addr || touch_addr >= _end_addr) { break; } - char* end_addr = touch_addr + MIN2(actual_chunk_size, pointer_delta(_end_addr, touch_addr, sizeof(char))); + char* end_addr = touch_addr + MIN2(_chunk_size, pointer_delta(_end_addr, touch_addr, sizeof(char))); os::pretouch_memory(touch_addr, end_addr, _page_size); } @@ -62,13 +64,25 @@ void PretouchTask::work(uint worker_id) { void PretouchTask::pretouch(const char* task_name, char* start_address, char* end_address, size_t page_size, WorkGang* pretouch_gang) { - PretouchTask task(task_name, start_address, end_address, page_size); + +#ifdef LINUX + // When using THP we need to always pre-touch using small pages as the OS will + // initially always use small pages. + page_size = UseTransparentHugePages ? (size_t)os::vm_page_size() : page_size; +#endif + size_t chunk_size = MAX2(PretouchTask::chunk_size(), page_size); + + PretouchTask task(task_name, start_address, end_address, page_size, chunk_size); size_t total_bytes = pointer_delta(end_address, start_address, sizeof(char)); + if (total_bytes == 0) { + return; + } + if (pretouch_gang != NULL) { - size_t num_chunks = MAX2((size_t)1, total_bytes / MAX2(PretouchTask::chunk_size(), page_size)); + size_t num_chunks = (total_bytes + chunk_size - 1) / chunk_size; - uint num_workers = MIN2((uint)num_chunks, pretouch_gang->total_workers()); + uint num_workers = (uint)MIN2(num_chunks, (size_t)pretouch_gang->total_workers()); log_debug(gc, heap)("Running %s with %u workers for " SIZE_FORMAT " work units pre-touching " SIZE_FORMAT "B.", task.name(), num_workers, num_chunks, total_bytes); diff --git a/src/hotspot/share/gc/shared/pretouchTask.hpp b/src/hotspot/share/gc/shared/pretouchTask.hpp index 1883afa7c48..49cd48dc9cf 100644 --- a/src/hotspot/share/gc/shared/pretouchTask.hpp +++ b/src/hotspot/share/gc/shared/pretouchTask.hpp @@ -32,9 +32,10 @@ class PretouchTask : public AbstractGangTask { char* const _start_addr; char* const _end_addr; size_t _page_size; + size_t _chunk_size; public: - PretouchTask(const char* task_name, char* start_address, char* end_address, size_t page_size); + PretouchTask(const char* task_name, char* start_address, char* end_address, size_t page_size, size_t chunk_size); virtual void work(uint worker_id); diff --git a/src/hotspot/share/gc/shared/space.cpp b/src/hotspot/share/gc/shared/space.cpp index c267f1c0c3e..7b099a7d01a 100644 --- a/src/hotspot/share/gc/shared/space.cpp +++ b/src/hotspot/share/gc/shared/space.cpp @@ -567,27 +567,6 @@ inline HeapWord* ContiguousSpace::par_allocate_impl(size_t size) { } while (true); } -HeapWord* ContiguousSpace::allocate_aligned(size_t size) { - assert(Heap_lock->owned_by_self() || (SafepointSynchronize::is_at_safepoint() && Thread::current()->is_VM_thread()), "not locked"); - HeapWord* end_value = end(); - - HeapWord* obj = CollectedHeap::align_allocation_or_fail(top(), end_value, SurvivorAlignmentInBytes); - if (obj == NULL) { - return NULL; - } - - if (pointer_delta(end_value, obj) >= size) { - HeapWord* new_top = obj + size; - set_top(new_top); - assert(::is_aligned(obj, SurvivorAlignmentInBytes) && is_aligned(new_top), - "checking alignment"); - return obj; - } else { - set_top(obj); - return NULL; - } -} - // Requires locking. HeapWord* ContiguousSpace::allocate(size_t size) { return allocate_impl(size); diff --git a/src/hotspot/share/gc/shared/space.hpp b/src/hotspot/share/gc/shared/space.hpp index 0b760364bbc..48eadafaf80 100644 --- a/src/hotspot/share/gc/shared/space.hpp +++ b/src/hotspot/share/gc/shared/space.hpp @@ -560,7 +560,6 @@ class ContiguousSpace: public CompactibleSpace { // Allocation (return NULL if full) virtual HeapWord* allocate(size_t word_size); virtual HeapWord* par_allocate(size_t word_size); - HeapWord* allocate_aligned(size_t word_size); // Iteration void oop_iterate(OopIterateClosure* cl); diff --git a/src/hotspot/share/gc/shenandoah/c1/shenandoahBarrierSetC1.cpp b/src/hotspot/share/gc/shenandoah/c1/shenandoahBarrierSetC1.cpp index 9754f495034..d449672a34d 100644 --- a/src/hotspot/share/gc/shenandoah/c1/shenandoahBarrierSetC1.cpp +++ b/src/hotspot/share/gc/shenandoah/c1/shenandoahBarrierSetC1.cpp @@ -211,8 +211,8 @@ void ShenandoahBarrierSetC1::load_at_resolved(LIRAccess& access, LIR_Opr result) if (ShenandoahBarrierSet::need_load_reference_barrier(decorators, type)) { LIR_Opr tmp = gen->new_register(T_OBJECT); BarrierSetC1::load_at_resolved(access, tmp); - bool is_native = ShenandoahBarrierSet::use_load_reference_barrier_native(decorators, type); - tmp = load_reference_barrier(gen, tmp, access.resolved_addr(), is_native); + bool is_weak = ShenandoahBarrierSet::use_load_reference_barrier_weak(decorators, type); + tmp = load_reference_barrier(gen, tmp, access.resolved_addr(), is_weak); __ move(tmp, result); } else { BarrierSetC1::load_at_resolved(access, result); @@ -251,14 +251,14 @@ class C1ShenandoahPreBarrierCodeGenClosure : public StubAssemblerCodeGenClosure class C1ShenandoahLoadReferenceBarrierCodeGenClosure : public StubAssemblerCodeGenClosure { private: - const bool _is_native; + const bool _is_weak; public: - C1ShenandoahLoadReferenceBarrierCodeGenClosure(bool is_native) : _is_native(is_native) {} + C1ShenandoahLoadReferenceBarrierCodeGenClosure(bool is_weak) : _is_weak(is_weak) {} virtual OopMapSet* generate_code(StubAssembler* sasm) { ShenandoahBarrierSetAssembler* bs = (ShenandoahBarrierSetAssembler*)BarrierSet::barrier_set()->barrier_set_assembler(); - bs->generate_c1_load_reference_barrier_runtime_stub(sasm, _is_native); + bs->generate_c1_load_reference_barrier_runtime_stub(sasm, _is_weak); return NULL; } }; @@ -274,9 +274,9 @@ void ShenandoahBarrierSetC1::generate_c1_runtime_stubs(BufferBlob* buffer_blob) "shenandoah_load_reference_barrier_slow", false, &lrb_code_gen_cl); - C1ShenandoahLoadReferenceBarrierCodeGenClosure lrb_native_code_gen_cl(true); - _load_reference_barrier_native_rt_code_blob = Runtime1::generate_blob(buffer_blob, -1, - "shenandoah_load_reference_barrier_native_slow", - false, &lrb_native_code_gen_cl); + C1ShenandoahLoadReferenceBarrierCodeGenClosure lrb_weak_code_gen_cl(true); + _load_reference_barrier_weak_rt_code_blob = Runtime1::generate_blob(buffer_blob, -1, + "shenandoah_load_reference_barrier_weak_slow", + false, &lrb_weak_code_gen_cl); } } diff --git a/src/hotspot/share/gc/shenandoah/c1/shenandoahBarrierSetC1.hpp b/src/hotspot/share/gc/shenandoah/c1/shenandoahBarrierSetC1.hpp index e97f3af0926..c3b6ba63c0f 100644 --- a/src/hotspot/share/gc/shenandoah/c1/shenandoahBarrierSetC1.hpp +++ b/src/hotspot/share/gc/shenandoah/c1/shenandoahBarrierSetC1.hpp @@ -94,10 +94,10 @@ class ShenandoahLoadReferenceBarrierStub: public CodeStub { LIR_Opr _result; LIR_Opr _tmp1; LIR_Opr _tmp2; - bool _is_native; + bool _is_weak; public: - ShenandoahLoadReferenceBarrierStub(LIR_Opr obj, LIR_Opr addr, LIR_Opr result, LIR_Opr tmp1, LIR_Opr tmp2, bool is_native) : - _obj(obj), _addr(addr), _result(result), _tmp1(tmp1), _tmp2(tmp2), _is_native(is_native) + ShenandoahLoadReferenceBarrierStub(LIR_Opr obj, LIR_Opr addr, LIR_Opr result, LIR_Opr tmp1, LIR_Opr tmp2, bool is_weak) : + _obj(obj), _addr(addr), _result(result), _tmp1(tmp1), _tmp2(tmp2), _is_weak(is_weak) { assert(_obj->is_register(), "should be register"); assert(_addr->is_register(), "should be register"); @@ -111,7 +111,7 @@ class ShenandoahLoadReferenceBarrierStub: public CodeStub { LIR_Opr result() const { return _result; } LIR_Opr tmp1() const { return _tmp1; } LIR_Opr tmp2() const { return _tmp2; } - bool is_native() const { return _is_native; } + bool is_weak() const { return _is_weak; } virtual void emit_code(LIR_Assembler* e); virtual void visit(LIR_OpVisitState* visitor) { @@ -191,7 +191,7 @@ class ShenandoahBarrierSetC1 : public BarrierSetC1 { private: CodeBlob* _pre_barrier_c1_runtime_code_blob; CodeBlob* _load_reference_barrier_rt_code_blob; - CodeBlob* _load_reference_barrier_native_rt_code_blob; + CodeBlob* _load_reference_barrier_weak_rt_code_blob; void pre_barrier(LIRGenerator* gen, CodeEmitInfo* info, DecoratorSet decorators, LIR_Opr addr_opr, LIR_Opr pre_val); @@ -215,9 +215,9 @@ class ShenandoahBarrierSetC1 : public BarrierSetC1 { return _load_reference_barrier_rt_code_blob; } - CodeBlob* load_reference_barrier_native_rt_code_blob() { - assert(_load_reference_barrier_native_rt_code_blob != NULL, ""); - return _load_reference_barrier_native_rt_code_blob; + CodeBlob* load_reference_barrier_weak_rt_code_blob() { + assert(_load_reference_barrier_weak_rt_code_blob != NULL, ""); + return _load_reference_barrier_weak_rt_code_blob; } protected: diff --git a/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp b/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp index f3bdac34e55..47effbc4856 100644 --- a/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp +++ b/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp @@ -305,7 +305,7 @@ bool ShenandoahBarrierSetC2::is_shenandoah_lrb_call(Node* call) { address entry_point = call->as_CallLeaf()->entry_point(); return (entry_point == CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier)) || (entry_point == CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_narrow)) || - (entry_point == CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_native)); + (entry_point == CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_weak)); } bool ShenandoahBarrierSetC2::is_shenandoah_marking_if(PhaseTransform *phase, Node* n) { @@ -547,7 +547,7 @@ Node* ShenandoahBarrierSetC2::load_at_resolved(C2Access& access, const Type* val if (ShenandoahBarrierSet::need_load_reference_barrier(decorators, type)) { load = new ShenandoahLoadReferenceBarrierNode(NULL, load, - ShenandoahBarrierSet::use_load_reference_barrier_native(decorators, type)); + ShenandoahBarrierSet::use_load_reference_barrier_weak(decorators, type)); if (access.is_parse_access()) { load = static_cast(access).kit()->gvn().transform(load); } else { @@ -1059,14 +1059,19 @@ Node* ShenandoahBarrierSetC2::ideal_node(PhaseGVN* phase, Node* n, bool can_resh if (n->Opcode() == Op_CmpP) { Node* in1 = n->in(1); Node* in2 = n->in(2); + + // If one input is NULL, then step over the barriers (except LRB native) on the other input if (in1->bottom_type() == TypePtr::NULL_PTR && - (in1->Opcode() != Op_ShenandoahLoadReferenceBarrier || !((ShenandoahLoadReferenceBarrierNode*)in1)->is_native())) { + !((in2->Opcode() == Op_ShenandoahLoadReferenceBarrier) && + ((ShenandoahLoadReferenceBarrierNode*)in2)->is_weak())) { in2 = step_over_gc_barrier(in2); } if (in2->bottom_type() == TypePtr::NULL_PTR && - (in2->Opcode() != Op_ShenandoahLoadReferenceBarrier || !((ShenandoahLoadReferenceBarrierNode*)in2)->is_native())) { + !((in1->Opcode() == Op_ShenandoahLoadReferenceBarrier) && + ((ShenandoahLoadReferenceBarrierNode*)in1)->is_weak())) { in1 = step_over_gc_barrier(in1); } + PhaseIterGVN* igvn = phase->is_IterGVN(); if (in1 != n->in(1)) { if (igvn != NULL) { diff --git a/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp b/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp index 218550dc36b..a228d0d8215 100644 --- a/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp +++ b/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp @@ -956,7 +956,7 @@ void ShenandoahBarrierC2Support::test_in_cset(Node*& ctrl, Node*& not_cset_ctrl, phase->register_new_node(cset_bool, old_ctrl); } -void ShenandoahBarrierC2Support::call_lrb_stub(Node*& ctrl, Node*& val, Node* load_addr, Node*& result_mem, Node* raw_mem, bool is_native, PhaseIdealLoop* phase) { +void ShenandoahBarrierC2Support::call_lrb_stub(Node*& ctrl, Node*& val, Node* load_addr, Node*& result_mem, Node* raw_mem, bool is_weak, PhaseIdealLoop* phase) { IdealLoopTree*loop = phase->get_loop(ctrl); const TypePtr* obj_type = phase->igvn().type(val)->is_oopptr(); @@ -971,9 +971,9 @@ void ShenandoahBarrierC2Support::call_lrb_stub(Node*& ctrl, Node*& val, Node* lo CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_narrow) : CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier); - address calladdr = is_native ? CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_native) - : target; - const char* name = is_native ? "load_reference_barrier_native" : "load_reference_barrier"; + address calladdr = is_weak ? CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_weak) + : target; + const char* name = is_weak ? "load_reference_barrier_native" : "load_reference_barrier"; Node* call = new CallLeafNode(ShenandoahBarrierSetC2::shenandoah_load_reference_barrier_Type(), calladdr, name, TypeRawPtr::BOTTOM); call->init_req(TypeFunc::Control, ctrl); @@ -1338,7 +1338,7 @@ void ShenandoahBarrierC2Support::pin_and_expand(PhaseIdealLoop* phase) { // even for non-cset objects to prevent ressurrection of such objects. // Wires !in_cset(obj) to slot 2 of region and phis Node* not_cset_ctrl = NULL; - if (!lrb->is_native()) { + if (!lrb->is_weak()) { test_in_cset(ctrl, not_cset_ctrl, val, raw_mem, phase); } if (not_cset_ctrl != NULL) { @@ -1389,7 +1389,7 @@ void ShenandoahBarrierC2Support::pin_and_expand(PhaseIdealLoop* phase) { } } } - call_lrb_stub(ctrl, val, addr, result_mem, raw_mem, lrb->is_native(), phase); + call_lrb_stub(ctrl, val, addr, result_mem, raw_mem, lrb->is_weak(), phase); region->init_req(_evac_path, ctrl); val_phi->init_req(_evac_path, val); raw_mem_phi->init_req(_evac_path, result_mem); @@ -2314,12 +2314,12 @@ void MemoryGraphFixer::collect_memory_nodes() { Node* m = _memory_nodes[c->in(k)->_idx]; assert(m != NULL, "expect memory state"); if (u->in(k) != m) { - phi = NULL; + phi = NodeSentinel; } } } } - if (phi == NULL) { + if (phi == NodeSentinel) { phi = new PhiNode(c, Type::MEMORY, _phase->C->get_adr_type(_alias)); for (uint k = 1; k < c->req(); k++) { Node* m = _memory_nodes[c->in(k)->_idx]; @@ -2328,8 +2328,11 @@ void MemoryGraphFixer::collect_memory_nodes() { } } } - assert(phi != NULL, ""); - regions.map(c->_idx, phi); + if (phi != NULL) { + regions.map(c->_idx, phi); + } else { + assert(c->unique_ctrl_out()->Opcode() == Op_Halt, "expected memory state"); + } } Node* current_region = regions[c->_idx]; if (current_region != prev_region) { @@ -2340,7 +2343,7 @@ void MemoryGraphFixer::collect_memory_nodes() { } } else if (prev_mem == NULL || prev_mem->is_Phi() || ctrl_or_self(prev_mem) != c) { Node* m = _memory_nodes[_phase->idom(c)->_idx]; - assert(m != NULL, "expect memory state"); + assert(m != NULL || c->Opcode() == Op_Halt, "expect memory state"); if (m != prev_mem) { _memory_nodes.map(c->_idx, m); progress = true; @@ -2364,7 +2367,8 @@ void MemoryGraphFixer::collect_memory_nodes() { Node* c = rpo_list.at(i); if (c->is_Region() && (_include_lsm || !c->is_OuterStripMinedLoop())) { Node* n = regions[c->_idx]; - if (n->is_Phi() && n->_idx >= last && n->in(0) == c) { + assert(n != NULL || c->unique_ctrl_out()->Opcode() == Op_Halt, "expected memory state"); + if (n != NULL && n->is_Phi() && n->_idx >= last && n->in(0) == c) { _phase->register_new_node(n, c); } } @@ -2373,10 +2377,12 @@ void MemoryGraphFixer::collect_memory_nodes() { Node* c = rpo_list.at(i); if (c->is_Region() && (_include_lsm || !c->is_OuterStripMinedLoop())) { Node* n = regions[c->_idx]; + assert(n != NULL || c->unique_ctrl_out()->Opcode() == Op_Halt, "expected memory state"); for (DUIterator_Fast imax, i = c->fast_outs(imax); i < imax; i++) { Node* u = c->fast_out(i); if (u->is_Phi() && u->bottom_type() == Type::MEMORY && u != n) { + assert(c->unique_ctrl_out()->Opcode() != Op_Halt, "expected memory state"); if (u->adr_type() == TypePtr::BOTTOM) { fix_memory_uses(u, n, n, c); } else if (_phase->C->get_alias_index(u->adr_type()) == _alias) { @@ -2879,13 +2885,13 @@ void MemoryGraphFixer::fix_memory_uses(Node* mem, Node* replacement, Node* rep_p } } -ShenandoahLoadReferenceBarrierNode::ShenandoahLoadReferenceBarrierNode(Node* ctrl, Node* obj, bool native) -: Node(ctrl, obj), _native(native) { +ShenandoahLoadReferenceBarrierNode::ShenandoahLoadReferenceBarrierNode(Node* ctrl, Node* obj, bool weak) +: Node(ctrl, obj), _weak(weak) { ShenandoahBarrierSetC2::bsc2()->state()->add_load_reference_barrier(this); } -bool ShenandoahLoadReferenceBarrierNode::is_native() const { - return _native; +bool ShenandoahLoadReferenceBarrierNode::is_weak() const { + return _weak; } uint ShenandoahLoadReferenceBarrierNode::size_of() const { @@ -2893,12 +2899,12 @@ uint ShenandoahLoadReferenceBarrierNode::size_of() const { } uint ShenandoahLoadReferenceBarrierNode::hash() const { - return Node::hash() + (_native ? 1 : 0); + return Node::hash() + (_weak ? 1 : 0); } bool ShenandoahLoadReferenceBarrierNode::cmp( const Node &n ) const { return Node::cmp(n) && n.Opcode() == Op_ShenandoahLoadReferenceBarrier && - _native == ((const ShenandoahLoadReferenceBarrierNode&)n)._native; + _weak == ((const ShenandoahLoadReferenceBarrierNode&)n)._weak; } const Type* ShenandoahLoadReferenceBarrierNode::bottom_type() const { diff --git a/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.hpp b/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.hpp index 91c8d167abf..715eefd1cbc 100644 --- a/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.hpp +++ b/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.hpp @@ -60,7 +60,7 @@ class ShenandoahBarrierC2Support : public AllStatic { static void test_null(Node*& ctrl, Node* val, Node*& null_ctrl, PhaseIdealLoop* phase); static void test_gc_state(Node*& ctrl, Node* raw_mem, Node*& heap_stable_ctrl, PhaseIdealLoop* phase, int flags); - static void call_lrb_stub(Node*& ctrl, Node*& val, Node* load_addr, Node*& result_mem, Node* raw_mem, bool is_native, PhaseIdealLoop* phase); + static void call_lrb_stub(Node*& ctrl, Node*& val, Node* load_addr, Node*& result_mem, Node* raw_mem, bool is_weak, PhaseIdealLoop* phase); static void test_in_cset(Node*& ctrl, Node*& not_cset_ctrl, Node* val, Node* raw_mem, PhaseIdealLoop* phase); static void move_gc_state_test_out_of_loop(IfNode* iff, PhaseIdealLoop* phase); static void merge_back_to_back_tests(Node* n, PhaseIdealLoop* phase); @@ -229,12 +229,12 @@ class ShenandoahLoadReferenceBarrierNode : public Node { }; private: - bool _native; + bool _weak; public: ShenandoahLoadReferenceBarrierNode(Node* ctrl, Node* val, bool native); - bool is_native() const; + bool is_weak() const; virtual int Opcode() const; virtual const Type* bottom_type() const; virtual const Type* Value(PhaseGVN* phase) const; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahAsserts.cpp b/src/hotspot/share/gc/shenandoah/shenandoahAsserts.cpp index d5cc677786e..f7b9609eafd 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahAsserts.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahAsserts.cpp @@ -175,6 +175,16 @@ void ShenandoahAsserts::assert_in_heap(void* interior_loc, oop obj, const char * } } +void ShenandoahAsserts::assert_in_heap_or_null(void* interior_loc, oop obj, const char *file, int line) { + ShenandoahHeap* heap = ShenandoahHeap::heap(); + + if (obj != NULL && !heap->is_in(obj)) { + print_failure(_safe_unknown, obj, interior_loc, NULL, "Shenandoah assert_in_heap_or_null failed", + "oop must point to a heap address", + file, line); + } +} + void ShenandoahAsserts::assert_correct(void* interior_loc, oop obj, const char* file, int line) { ShenandoahHeap* heap = ShenandoahHeap::heap(); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahAsserts.hpp b/src/hotspot/share/gc/shenandoah/shenandoahAsserts.hpp index 42d0e60bba3..6fd890edb63 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahAsserts.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahAsserts.hpp @@ -54,6 +54,7 @@ class ShenandoahAsserts { const char *file, int line); static void assert_in_heap(void* interior_loc, oop obj, const char* file, int line); + static void assert_in_heap_or_null(void* interior_loc, oop obj, const char* file, int line); static void assert_in_correct_region(void* interior_loc, oop obj, const char* file, int line); static void assert_correct(void* interior_loc, oop obj, const char* file, int line); @@ -76,6 +77,8 @@ class ShenandoahAsserts { #ifdef ASSERT #define shenandoah_assert_in_heap(interior_loc, obj) \ ShenandoahAsserts::assert_in_heap(interior_loc, obj, __FILE__, __LINE__) +#define shenandoah_assert_in_heap_or_null(interior_loc, obj) \ + ShenandoahAsserts::assert_in_heap_or_null(interior_loc, obj, __FILE__, __LINE__) #define shenandoah_assert_in_correct_region(interior_loc, obj) \ ShenandoahAsserts::assert_in_correct_region(interior_loc, obj, __FILE__, __LINE__) @@ -149,6 +152,7 @@ class ShenandoahAsserts { ShenandoahAsserts::assert_heaplocked_or_safepoint(__FILE__, __LINE__) #else #define shenandoah_assert_in_heap(interior_loc, obj) +#define shenandoah_assert_in_heap_or_null(interior_loc, obj) #define shenandoah_assert_in_correct_region(interior_loc, obj) #define shenandoah_assert_correct_if(interior_loc, obj, condition) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.cpp b/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.cpp index dc9dd4ee398..cb23dd7e86a 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.cpp @@ -87,7 +87,7 @@ bool ShenandoahBarrierSet::need_load_reference_barrier(DecoratorSet decorators, return is_reference_type(type); } -bool ShenandoahBarrierSet::use_load_reference_barrier_native(DecoratorSet decorators, BasicType type) { +bool ShenandoahBarrierSet::use_load_reference_barrier_weak(DecoratorSet decorators, BasicType type) { assert(need_load_reference_barrier(decorators, type), "Should be subset of LRB"); assert(is_reference_type(type), "Why we here?"); // Native load reference barrier is only needed for concurrent root processing @@ -95,7 +95,7 @@ bool ShenandoahBarrierSet::use_load_reference_barrier_native(DecoratorSet decora return false; } - return (decorators & IN_NATIVE) != 0; + return ((decorators & IN_NATIVE) != 0) && ((decorators & ON_STRONG_OOP_REF) == 0); } bool ShenandoahBarrierSet::need_keep_alive_barrier(DecoratorSet decorators,BasicType type) { @@ -109,41 +109,6 @@ bool ShenandoahBarrierSet::need_keep_alive_barrier(DecoratorSet decorators,Basic return (on_weak_ref || unknown) && keep_alive; } -oop ShenandoahBarrierSet::load_reference_barrier_not_null(oop obj) { - if (ShenandoahLoadRefBarrier && _heap->has_forwarded_objects()) { - return load_reference_barrier_impl(obj); - } else { - return obj; - } -} - -oop ShenandoahBarrierSet::load_reference_barrier(oop obj) { - if (obj != NULL) { - return load_reference_barrier_not_null(obj); - } else { - return obj; - } -} - -oop ShenandoahBarrierSet::load_reference_barrier_impl(oop obj) { - assert(ShenandoahLoadRefBarrier, "should be enabled"); - if (!CompressedOops::is_null(obj)) { - bool evac_in_progress = _heap->is_evacuation_in_progress(); - oop fwd = resolve_forwarded_not_null(obj); - if (evac_in_progress && - _heap->in_collection_set(obj) && - obj == fwd) { - Thread *t = Thread::current(); - ShenandoahEvacOOMScope oom_evac_scope(t); - return _heap->evacuate_object(obj, t); - } else { - return fwd; - } - } else { - return obj; - } -} - void ShenandoahBarrierSet::on_thread_create(Thread* thread) { // Create thread local data ShenandoahThreadLocalData::create(thread); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.hpp b/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.hpp index 5d8194ae26d..391000cd3df 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.hpp @@ -53,7 +53,7 @@ class ShenandoahBarrierSet: public BarrierSet { } static bool need_load_reference_barrier(DecoratorSet decorators, BasicType type); - static bool use_load_reference_barrier_native(DecoratorSet decorators, BasicType type); + static bool use_load_reference_barrier_weak(DecoratorSet decorators, BasicType type); static bool need_keep_alive_barrier(DecoratorSet decorators, BasicType type); void print_on(outputStream* st) const; @@ -87,14 +87,13 @@ class ShenandoahBarrierSet: public BarrierSet { inline void enqueue(oop obj); - oop load_reference_barrier(oop obj); - oop load_reference_barrier_not_null(oop obj); + inline oop load_reference_barrier(oop obj); template inline oop load_reference_barrier_mutator(oop obj, T* load_addr); - template - inline oop load_reference_barrier_native(oop obj, T* load_addr); + template + inline oop load_reference_barrier(oop obj, T* load_addr); private: template @@ -111,8 +110,6 @@ class ShenandoahBarrierSet: public BarrierSet { template inline void arraycopy_work(T* src, size_t count); - oop load_reference_barrier_impl(oop obj); - inline bool need_bulk_update(HeapWord* dst); public: // Callbacks for runtime accesses. diff --git a/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.inline.hpp index b98b1168f3a..a392915bc5b 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.inline.hpp @@ -76,23 +76,47 @@ inline oop ShenandoahBarrierSet::load_reference_barrier_mutator(oop obj, T* load return fwd; } -template -inline oop ShenandoahBarrierSet::load_reference_barrier_native(oop obj, T* load_addr) { - if (CompressedOops::is_null(obj)) { - return NULL; +inline oop ShenandoahBarrierSet::load_reference_barrier(oop obj) { + if (!ShenandoahLoadRefBarrier) { + return obj; + } + if (_heap->has_forwarded_objects() && + _heap->in_collection_set(obj)) { // Subsumes NULL-check + assert(obj != NULL, "cset check must have subsumed NULL-check"); + oop fwd = resolve_forwarded_not_null(obj); + // TODO: It should not be necessary to check evac-in-progress here. + // We do it for mark-compact, which may have forwarded objects, + // and objects in cset and gets here via runtime barriers. + // We can probably fix this as soon as mark-compact has its own + // marking phase. + if (obj == fwd && _heap->is_evacuation_in_progress()) { + Thread* t = Thread::current(); + ShenandoahEvacOOMScope oom_evac_scope(t); + return _heap->evacuate_object(obj, t); + } + return fwd; } + return obj; +} + +template +inline oop ShenandoahBarrierSet::load_reference_barrier(oop obj, T* load_addr) { - ShenandoahMarkingContext* const marking_context = _heap->marking_context(); - if (_heap->is_concurrent_weak_root_in_progress() && !marking_context->is_marked(obj)) { + // Prevent resurrection of unreachable non-strorg references. + if (!HasDecorator::value && obj != NULL && + _heap->is_concurrent_weak_root_in_progress() && + !_heap->marking_context()->is_marked(obj)) { Thread* thr = Thread::current(); if (thr->is_Java_thread()) { return NULL; } else { + // This path is sometimes (rarely) taken by GC threads. + // See e.g.: https://bugs.openjdk.java.net/browse/JDK-8237874 return obj; } } - oop fwd = load_reference_barrier_not_null(obj); + oop fwd = load_reference_barrier(obj); if (ShenandoahSelfFixing && load_addr != NULL && fwd != obj) { // Since we are here and we know the load address, update the reference. ShenandoahHeap::cas_oop(fwd, load_addr, obj); @@ -128,8 +152,7 @@ inline void ShenandoahBarrierSet::satb_barrier(T *field) { } inline void ShenandoahBarrierSet::satb_enqueue(oop value) { - assert(value != NULL, "checked before"); - if (ShenandoahSATBBarrier && _heap->is_concurrent_mark_in_progress()) { + if (value != NULL && ShenandoahSATBBarrier && _heap->is_concurrent_mark_in_progress()) { enqueue(value); } } @@ -142,7 +165,6 @@ inline void ShenandoahBarrierSet::storeval_barrier(oop obj) { inline void ShenandoahBarrierSet::keep_alive_if_weak(DecoratorSet decorators, oop value) { assert((decorators & ON_UNKNOWN_OOP_REF) == 0, "Reference strength must be known"); - assert(value != NULL, "checked by caller"); const bool on_strong_oop_ref = (decorators & ON_STRONG_OOP_REF) != 0; const bool peek = (decorators & AS_NO_KEEPALIVE) != 0; if (!peek && !on_strong_oop_ref) { @@ -152,7 +174,6 @@ inline void ShenandoahBarrierSet::keep_alive_if_weak(DecoratorSet decorators, oo template inline void ShenandoahBarrierSet::keep_alive_if_weak(oop value) { - assert(value != NULL, "checked by caller"); assert((decorators & ON_UNKNOWN_OOP_REF) == 0, "Reference strength must be known"); if (!HasDecorator::value && !HasDecorator::value) { @@ -166,10 +187,8 @@ inline oop ShenandoahBarrierSet::AccessBarrier::oop_loa oop value = Raw::oop_load_not_in_heap(addr); if (value != NULL) { ShenandoahBarrierSet *const bs = ShenandoahBarrierSet::barrier_set(); - value = bs->load_reference_barrier_native(value, addr); - if (value != NULL) { - bs->keep_alive_if_weak(value); - } + value = bs->load_reference_barrier(value, addr); + bs->keep_alive_if_weak(value); } return value; } @@ -178,23 +197,19 @@ template template inline oop ShenandoahBarrierSet::AccessBarrier::oop_load_in_heap(T* addr) { oop value = Raw::oop_load_in_heap(addr); - if (value != NULL) { - ShenandoahBarrierSet *const bs = ShenandoahBarrierSet::barrier_set(); - value = bs->load_reference_barrier_not_null(value); - bs->keep_alive_if_weak(value); - } + ShenandoahBarrierSet *const bs = ShenandoahBarrierSet::barrier_set(); + value = bs->load_reference_barrier(value); + bs->keep_alive_if_weak(value); return value; } template inline oop ShenandoahBarrierSet::AccessBarrier::oop_load_in_heap_at(oop base, ptrdiff_t offset) { oop value = Raw::oop_load_in_heap_at(base, offset); - if (value != NULL) { - ShenandoahBarrierSet *const bs = ShenandoahBarrierSet::barrier_set(); - value = bs->load_reference_barrier_not_null(value); - bs->keep_alive_if_weak(AccessBarrierSupport::resolve_possibly_unknown_oop_ref_strength(base, offset), - value); - } + ShenandoahBarrierSet *const bs = ShenandoahBarrierSet::barrier_set(); + value = bs->load_reference_barrier(value); + bs->keep_alive_if_weak(AccessBarrierSupport::resolve_possibly_unknown_oop_ref_strength(base, offset), + value); return value; } @@ -239,10 +254,8 @@ inline oop ShenandoahBarrierSet::AccessBarrier::oop_ato // Note: We don't need a keep-alive-barrier here. We already enqueue any loaded reference for SATB anyway, // because it must be the previous value. - if (res != NULL) { - res = ShenandoahBarrierSet::barrier_set()->load_reference_barrier_not_null(res); - bs->satb_enqueue(res); - } + res = ShenandoahBarrierSet::barrier_set()->load_reference_barrier(res); + bs->satb_enqueue(res); return res; } @@ -267,10 +280,8 @@ inline oop ShenandoahBarrierSet::AccessBarrier::oop_ato // Note: We don't need a keep-alive-barrier here. We already enqueue any loaded reference for SATB anyway, // because it must be the previous value. - if (previous != NULL) { - previous = ShenandoahBarrierSet::barrier_set()->load_reference_barrier_not_null(previous); - bs->satb_enqueue(previous); - } + previous = ShenandoahBarrierSet::barrier_set()->load_reference_barrier(previous); + bs->satb_enqueue(previous); return previous; } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahCollectionSet.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahCollectionSet.inline.hpp index fbb34b808c5..a327524a72d 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahCollectionSet.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahCollectionSet.inline.hpp @@ -40,12 +40,12 @@ bool ShenandoahCollectionSet::is_in(ShenandoahHeapRegion* r) const { } bool ShenandoahCollectionSet::is_in(oop p) const { - shenandoah_assert_in_heap(NULL, p); + shenandoah_assert_in_heap_or_null(NULL, p); return is_in_loc(cast_from_oop(p)); } bool ShenandoahCollectionSet::is_in_loc(void* p) const { - assert(_heap->is_in(p), "Must be in the heap"); + assert(p == NULL || _heap->is_in(p), "Must be in the heap"); uintx index = ((uintx) p) >> _region_size_bytes_shift; // no need to subtract the bottom of the heap from p, // _biased_cset_map is biased diff --git a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.inline.hpp index f1504b1d46d..fb1e0b0b2fd 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.inline.hpp @@ -133,7 +133,7 @@ inline void ShenandoahConcurrentMark::do_chunked_array_start(ShenandoahObjToScan assert(pushed, "overflow queue should always succeed pushing"); } - // Split out tasks, as suggested in ObjArrayChunkedTask docs. Record the last + // Split out tasks, as suggested in ShenandoahMarkTask docs. Record the last // successful right boundary to figure out the irregular tail. while ((1 << pow) > (int)ObjArrayMarkingStride && (chunk*2 < ShenandoahMarkTask::chunk_size())) { @@ -166,7 +166,7 @@ inline void ShenandoahConcurrentMark::do_chunked_array(ShenandoahObjToScanQueue* assert (ObjArrayMarkingStride > 0, "sanity"); - // Split out tasks, as suggested in ObjArrayChunkedTask docs. Avoid pushing tasks that + // Split out tasks, as suggested in ShenandoahMarkTask docs. Avoid pushing tasks that // are known to start beyond the array. while ((1 << pow) > (int)ObjArrayMarkingStride && (chunk*2 < ShenandoahMarkTask::chunk_size())) { pow--; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp index c10c24ce795..67adf336996 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp @@ -184,14 +184,14 @@ jint ShenandoahHeap::initialize() { assert((((size_t) base()) & ShenandoahHeapRegion::region_size_bytes_mask()) == 0, "Misaligned heap: " PTR_FORMAT, p2i(base())); -#if SHENANDOAH_OPTIMIZED_OBJTASK - // The optimized ObjArrayChunkedTask takes some bits away from the full object bits. +#if SHENANDOAH_OPTIMIZED_MARKTASK + // The optimized ShenandoahMarkTask takes some bits away from the full object bits. // Fail if we ever attempt to address more than we can. - if ((uintptr_t)heap_rs.end() >= ObjArrayChunkedTask::max_addressable()) { + if ((uintptr_t)heap_rs.end() >= ShenandoahMarkTask::max_addressable()) { FormatBuffer<512> buf("Shenandoah reserved [" PTR_FORMAT ", " PTR_FORMAT") for the heap, \n" "but max object address is " PTR_FORMAT ". Try to reduce heap size, or try other \n" "VM options that allocate heap at lower addresses (HeapBaseMinAddress, AllocateHeapAt, etc).", - p2i(heap_rs.base()), p2i(heap_rs.end()), ObjArrayChunkedTask::max_addressable()); + p2i(heap_rs.base()), p2i(heap_rs.end()), ShenandoahMarkTask::max_addressable()); vm_exit_during_initialization("Fatal Error", buf); } #endif diff --git a/src/hotspot/share/gc/shenandoah/shenandoahRootVerifier.cpp b/src/hotspot/share/gc/shenandoah/shenandoahRootVerifier.cpp index 84fde873dda..6e3c826a80e 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahRootVerifier.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahRootVerifier.cpp @@ -41,15 +41,17 @@ #include "utilities/debug.hpp" ShenandoahGCStateResetter::ShenandoahGCStateResetter() : - _gc_state(ShenandoahHeap::heap()->gc_state()), + _heap(ShenandoahHeap::heap()), + _gc_state(_heap->gc_state()), _concurrent_weak_root_in_progress(ShenandoahHeap::heap()->is_concurrent_weak_root_in_progress()) { + _heap->_gc_state.clear(); + _heap->set_concurrent_weak_root_in_progress(false); } ShenandoahGCStateResetter::~ShenandoahGCStateResetter() { - ShenandoahHeap* const heap = ShenandoahHeap::heap(); - heap->_gc_state.set(_gc_state); - assert(heap->gc_state() == _gc_state, "Should be restored"); - heap->set_concurrent_weak_root_in_progress(_concurrent_weak_root_in_progress); + _heap->_gc_state.set(_gc_state); + assert(_heap->gc_state() == _gc_state, "Should be restored"); + _heap->set_concurrent_weak_root_in_progress(_concurrent_weak_root_in_progress); } // Check for overflow of number of root types. diff --git a/src/hotspot/share/gc/shenandoah/shenandoahRootVerifier.hpp b/src/hotspot/share/gc/shenandoah/shenandoahRootVerifier.hpp index a0171a684cf..3668c240190 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahRootVerifier.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahRootVerifier.hpp @@ -30,6 +30,7 @@ class ShenandoahGCStateResetter : public StackObj { private: + ShenandoahHeap* const _heap; const char _gc_state; const bool _concurrent_weak_root_in_progress; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahRuntime.cpp b/src/hotspot/share/gc/shenandoah/shenandoahRuntime.cpp index 38135a5e33d..69cbdca1f94 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahRuntime.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahRuntime.cpp @@ -66,6 +66,6 @@ JRT_LEAF(void, ShenandoahRuntime::shenandoah_clone_barrier(oopDesc* src)) ShenandoahBarrierSet::barrier_set()->clone_barrier(s); JRT_END -JRT_LEAF(oopDesc*, ShenandoahRuntime::load_reference_barrier_native(oopDesc * src, oop* load_addr)) - return (oopDesc*) ShenandoahBarrierSet::barrier_set()->load_reference_barrier_native(oop(src), load_addr); +JRT_LEAF(oopDesc*, ShenandoahRuntime::load_reference_barrier_weak(oopDesc * src, oop* load_addr)) + return (oopDesc*) ShenandoahBarrierSet::barrier_set()->load_reference_barrier(oop(src), load_addr); JRT_END diff --git a/src/hotspot/share/gc/shenandoah/shenandoahRuntime.hpp b/src/hotspot/share/gc/shenandoah/shenandoahRuntime.hpp index a0b2582d4e7..b42164a3724 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahRuntime.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahRuntime.hpp @@ -41,7 +41,7 @@ class ShenandoahRuntime : public AllStatic { static oopDesc* load_reference_barrier(oopDesc* src, oop* load_addr); static oopDesc* load_reference_barrier_narrow(oopDesc* src, narrowOop* load_addr); - static oopDesc* load_reference_barrier_native(oopDesc* src, oop* load_addr); + static oopDesc* load_reference_barrier_weak(oopDesc* src, oop* load_addr); static void shenandoah_clone_barrier(oopDesc* src); }; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahTaskqueue.hpp b/src/hotspot/share/gc/shenandoah/shenandoahTaskqueue.hpp index 0881779c9d9..40853015a65 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahTaskqueue.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahTaskqueue.hpp @@ -32,6 +32,7 @@ #include "runtime/atomic.hpp" #include "runtime/mutex.hpp" #include "runtime/thread.hpp" +#include "utilities/debug.hpp" template class BufferedOverflowTaskQueue: public OverflowTaskQueue @@ -60,7 +61,7 @@ class BufferedOverflowTaskQueue: public OverflowTaskQueue E _elem; }; -// ObjArrayChunkedTask +// ShenandoahMarkTask // // Encodes both regular oops, and the array oops plus chunking data for parallel array processing. // The design goal is to make the regular oop ops very fast, because that would be the prevailing @@ -123,54 +124,54 @@ class BufferedOverflowTaskQueue: public OverflowTaskQueue #endif #ifdef _LP64 -#define SHENANDOAH_OPTIMIZED_OBJTASK 1 +#define SHENANDOAH_OPTIMIZED_MARKTASK 1 #else -#define SHENANDOAH_OPTIMIZED_OBJTASK 0 +#define SHENANDOAH_OPTIMIZED_MARKTASK 0 #endif -#if SHENANDOAH_OPTIMIZED_OBJTASK -class ObjArrayChunkedTask +#if SHENANDOAH_OPTIMIZED_MARKTASK +class ShenandoahMarkTask { -public: - enum { - chunk_bits = 10, - pow_bits = 5, - oop_bits = sizeof(uintptr_t)*8 - chunk_bits - pow_bits - }; - enum { - oop_shift = 0, - pow_shift = oop_shift + oop_bits, - chunk_shift = pow_shift + pow_bits - }; +private: + // Everything is encoded into this field... + uintptr_t _obj; -public: - ObjArrayChunkedTask(oop o = NULL) { - assert(decode_oop(encode_oop(o)) == o, "oop can be encoded: " PTR_FORMAT, p2i(o)); - _obj = encode_oop(o); - } - ObjArrayChunkedTask(oop o, int chunk, int pow) { - assert(decode_oop(encode_oop(o)) == o, "oop can be encoded: " PTR_FORMAT, p2i(o)); - assert(decode_chunk(encode_chunk(chunk)) == chunk, "chunk can be encoded: %d", chunk); - assert(decode_pow(encode_pow(pow)) == pow, "pow can be encoded: %d", pow); - _obj = encode_oop(o) | encode_chunk(chunk) | encode_pow(pow); - } + // ...with these: + static const uint8_t chunk_bits = 10; + static const uint8_t pow_bits = 5; + static const uint8_t oop_bits = sizeof(uintptr_t)*8 - chunk_bits - pow_bits; - // Trivially copyable. + static const uint8_t oop_shift = 0; + static const uint8_t pow_shift = oop_bits; + static const uint8_t chunk_shift = oop_bits + pow_bits; + + static const uintptr_t oop_extract_mask = right_n_bits(oop_bits); + static const uintptr_t chunk_pow_extract_mask = ~right_n_bits(oop_bits); + + static const int chunk_range_mask = right_n_bits(chunk_bits); + static const int pow_range_mask = right_n_bits(pow_bits); inline oop decode_oop(uintptr_t val) const { - return (oop) reinterpret_cast((val >> oop_shift) & right_n_bits(oop_bits)); + STATIC_ASSERT(oop_shift == 0); + return cast_to_oop(val & oop_extract_mask); + } + + inline bool decode_not_chunked(uintptr_t val) const { + // No need to shift for a comparison to zero + return (val & chunk_pow_extract_mask) == 0; } inline int decode_chunk(uintptr_t val) const { - return (int) ((val >> chunk_shift) & right_n_bits(chunk_bits)); + return (int) ((val >> chunk_shift) & chunk_range_mask); } inline int decode_pow(uintptr_t val) const { - return (int) ((val >> pow_shift) & right_n_bits(pow_bits)); + return (int) ((val >> pow_shift) & pow_range_mask); } inline uintptr_t encode_oop(oop obj) const { - return ((uintptr_t)(void*) obj) << oop_shift; + STATIC_ASSERT(oop_shift == 0); + return cast_from_oop(obj); } inline uintptr_t encode_chunk(int chunk) const { @@ -181,12 +182,36 @@ class ObjArrayChunkedTask return ((uintptr_t) pow) << pow_shift; } - inline oop obj() const { return decode_oop(_obj); } - inline int chunk() const { return decode_chunk(_obj); } - inline int pow() const { return decode_pow(_obj); } - inline bool is_not_chunked() const { return (_obj & ~right_n_bits(oop_bits + pow_bits)) == 0; } +public: + ShenandoahMarkTask(oop o = NULL) { + uintptr_t enc = encode_oop(o); + assert(decode_oop(enc) == o, "oop encoding should work: " PTR_FORMAT, p2i(o)); + assert(decode_not_chunked(enc), "task should not be chunked"); + _obj = enc; + } + + ShenandoahMarkTask(oop o, int chunk, int pow) { + uintptr_t enc_oop = encode_oop(o); + uintptr_t enc_chunk = encode_chunk(chunk); + uintptr_t enc_pow = encode_pow(pow); + uintptr_t enc = enc_oop | enc_chunk | enc_pow; + assert(decode_oop(enc) == o, "oop encoding should work: " PTR_FORMAT, p2i(o)); + assert(decode_chunk(enc) == chunk, "chunk encoding should work: %d", chunk); + assert(decode_pow(enc) == pow, "pow encoding should work: %d", pow); + assert(!decode_not_chunked(enc), "task should be chunked"); + _obj = enc; + } + + // Trivially copyable. + +public: + inline oop obj() const { return decode_oop(_obj); } + inline int chunk() const { return decode_chunk(_obj); } + inline int pow() const { return decode_pow(_obj); } - DEBUG_ONLY(bool is_valid() const); // Tasks to be pushed/popped must be valid. + inline bool is_not_chunked() const { return decode_not_chunked(_obj); } + + DEBUG_ONLY(bool is_valid() const;) // Tasks to be pushed/popped must be valid. static uintptr_t max_addressable() { return nth_bit(oop_bits); @@ -195,35 +220,36 @@ class ObjArrayChunkedTask static int chunk_size() { return nth_bit(chunk_bits); } - -private: - uintptr_t _obj; }; #else -class ObjArrayChunkedTask +class ShenandoahMarkTask { +private: + static const uint8_t chunk_bits = 10; + static const uint8_t pow_bits = 5; + + static const int chunk_max = nth_bit(chunk_bits) - 1; + static const int pow_max = nth_bit(pow_bits) - 1; + + oop _obj; + int _chunk; + int _pow; + public: - enum { - chunk_bits = 10, - pow_bits = 5, - }; -public: - ObjArrayChunkedTask(oop o = NULL, int chunk = 0, int pow = 0): _obj(o) { - assert(0 <= chunk && chunk < nth_bit(chunk_bits), "chunk is sane: %d", chunk); - assert(0 <= pow && pow < nth_bit(pow_bits), "pow is sane: %d", pow); - _chunk = chunk; - _pow = pow; + ShenandoahMarkTask(oop o = NULL, int chunk = 0, int pow = 0): + _obj(o), _chunk(chunk), _pow(pow) { + assert(0 <= chunk && chunk <= chunk_max, "chunk is in range: %d", chunk); + assert(0 <= pow && pow <= pow_max, "pow is in range: %d", pow); } // Trivially copyable. - inline oop obj() const { return _obj; } - inline int chunk() const { return _chunk; } - inline int pow() const { return _pow; } - + inline oop obj() const { return _obj; } + inline int chunk() const { return _chunk; } + inline int pow() const { return _pow; } inline bool is_not_chunked() const { return _chunk == 0; } - DEBUG_ONLY(bool is_valid() const); // Tasks to be pushed/popped must be valid. + DEBUG_ONLY(bool is_valid() const;) // Tasks to be pushed/popped must be valid. static size_t max_addressable() { return sizeof(oop); @@ -232,19 +258,13 @@ class ObjArrayChunkedTask static int chunk_size() { return nth_bit(chunk_bits); } - -private: - oop _obj; - int _chunk; - int _pow; }; -#endif // SHENANDOAH_OPTIMIZED_OBJTASK +#endif // SHENANDOAH_OPTIMIZED_MARKTASK #ifdef _MSC_VER #pragma warning(pop) #endif -typedef ObjArrayChunkedTask ShenandoahMarkTask; typedef BufferedOverflowTaskQueue ShenandoahBufferedOverflowTaskQueue; typedef Padded ShenandoahObjToScanQueue; diff --git a/src/hotspot/share/gc/z/zAttachedArray.hpp b/src/hotspot/share/gc/z/zAttachedArray.hpp index 319a9084e12..edbdeafadef 100644 --- a/src/hotspot/share/gc/z/zAttachedArray.hpp +++ b/src/hotspot/share/gc/z/zAttachedArray.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2020, 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,8 +32,12 @@ class ZAttachedArray { const size_t _length; static size_t object_size(); + static size_t array_size(size_t length); public: + template + static void* alloc(Allocator* allocator, size_t length); + static void* alloc(size_t length); static void free(ObjectT* obj); diff --git a/src/hotspot/share/gc/z/zAttachedArray.inline.hpp b/src/hotspot/share/gc/z/zAttachedArray.inline.hpp index 81015e44b94..f52f83186e4 100644 --- a/src/hotspot/share/gc/z/zAttachedArray.inline.hpp +++ b/src/hotspot/share/gc/z/zAttachedArray.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2020, 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 @@ -34,13 +34,35 @@ inline size_t ZAttachedArray::object_size() { } template -inline void* ZAttachedArray::alloc(size_t length) { - const size_t array_size = sizeof(ArrayT) * length; - char* const addr = AllocateHeap(object_size() + array_size, mtGC); - ::new (addr + object_size()) ArrayT[length]; +inline size_t ZAttachedArray::array_size(size_t length) { + return sizeof(ArrayT) * length; +} + +template +template +inline void* ZAttachedArray::alloc(Allocator* allocator, size_t length) { + // Allocate memory for object and array + const size_t size = object_size() + array_size(length); + void* const addr = allocator->alloc(size); + + // Placement new array + void* const array_addr = reinterpret_cast(addr) + object_size(); + ::new (array_addr) ArrayT[length]; + + // Return pointer to object return addr; } +template +inline void* ZAttachedArray::alloc(size_t length) { + struct Allocator { + void* alloc(size_t size) const { + return AllocateHeap(size, mtGC); + } + } allocator; + return alloc(&allocator, length); +} + template inline void ZAttachedArray::free(ObjectT* obj) { FreeHeap(obj); diff --git a/src/hotspot/share/gc/z/zBarrierSetNMethod.cpp b/src/hotspot/share/gc/z/zBarrierSetNMethod.cpp index f52fcd940ca..bfb8a17e872 100644 --- a/src/hotspot/share/gc/z/zBarrierSetNMethod.cpp +++ b/src/hotspot/share/gc/z/zBarrierSetNMethod.cpp @@ -55,7 +55,7 @@ bool ZBarrierSetNMethod::nmethod_entry_barrier(nmethod* nm) { // Heal oops and disarm ZNMethodOopClosure cl; - ZNMethod::nmethod_oops_do(nm, &cl); + ZNMethod::nmethod_oops_do_inner(nm, &cl); disarm(nm); return true; diff --git a/src/hotspot/share/gc/z/zForwarding.cpp b/src/hotspot/share/gc/z/zForwarding.cpp index 6ccd2ea4478..139ff6443d8 100644 --- a/src/hotspot/share/gc/z/zForwarding.cpp +++ b/src/hotspot/share/gc/z/zForwarding.cpp @@ -23,31 +23,7 @@ #include "precompiled.hpp" #include "gc/z/zForwarding.inline.hpp" -#include "gc/z/zPage.inline.hpp" #include "utilities/debug.hpp" -#include "utilities/powerOfTwo.hpp" - -ZForwarding* ZForwarding::create(ZPage* page) { - // Allocate table for linear probing. The size of the table must be - // a power of two to allow for quick and inexpensive indexing/masking. - // The table is sized to have a load factor of 50%, i.e. sized to have - // double the number of entries actually inserted. - assert(page->live_objects() > 0, "Invalid value"); - const size_t nentries = round_up_power_of_2(page->live_objects() * 2); - return ::new (AttachedArray::alloc(nentries)) ZForwarding(page, nentries); -} - -void ZForwarding::destroy(ZForwarding* forwarding) { - AttachedArray::free(forwarding); -} - -ZForwarding::ZForwarding(ZPage* page, size_t nentries) : - _virtual(page->virtual_memory()), - _object_alignment_shift(page->object_alignment_shift()), - _entries(nentries), - _page(page), - _refcount(1), - _pinned(false) {} void ZForwarding::verify() const { guarantee(_refcount > 0, "Invalid refcount"); diff --git a/src/hotspot/share/gc/z/zForwarding.hpp b/src/hotspot/share/gc/z/zForwarding.hpp index b91e6f702c8..6a5bde71908 100644 --- a/src/hotspot/share/gc/z/zForwarding.hpp +++ b/src/hotspot/share/gc/z/zForwarding.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,6 +28,7 @@ #include "gc/z/zForwardingEntry.hpp" #include "gc/z/zVirtualMemory.hpp" +class ZForwardingAllocator; class ZPage; typedef size_t ZForwardingCursor; @@ -57,8 +58,8 @@ class ZForwarding { ZForwarding(ZPage* page, size_t nentries); public: - static ZForwarding* create(ZPage* page); - static void destroy(ZForwarding* forwarding); + static uint32_t nentries(const ZPage* page); + static ZForwarding* alloc(ZForwardingAllocator* allocator, ZPage* page); uintptr_t start() const; size_t size() const; diff --git a/src/hotspot/share/gc/z/zForwarding.inline.hpp b/src/hotspot/share/gc/z/zForwarding.inline.hpp index a142f30952e..80bb72002e1 100644 --- a/src/hotspot/share/gc/z/zForwarding.inline.hpp +++ b/src/hotspot/share/gc/z/zForwarding.inline.hpp @@ -26,11 +26,38 @@ #include "gc/z/zAttachedArray.inline.hpp" #include "gc/z/zForwarding.hpp" +#include "gc/z/zForwardingAllocator.inline.hpp" #include "gc/z/zHash.inline.hpp" #include "gc/z/zHeap.hpp" +#include "gc/z/zPage.inline.hpp" #include "gc/z/zVirtualMemory.inline.hpp" #include "runtime/atomic.hpp" #include "utilities/debug.hpp" +#include "utilities/powerOfTwo.hpp" + +inline uint32_t ZForwarding::nentries(const ZPage* page) { + // The number returned by the function is used to size the hash table of + // forwarding entries for this page. This hash table uses linear probing. + // The size of the table must be a power of two to allow for quick and + // inexpensive indexing/masking. The table is also sized to have a load + // factor of 50%, i.e. sized to have double the number of entries actually + // inserted, to allow for good lookup/insert performance. + return round_up_power_of_2(page->live_objects() * 2); +} + +inline ZForwarding* ZForwarding::alloc(ZForwardingAllocator* allocator, ZPage* page) { + const size_t nentries = ZForwarding::nentries(page); + void* const addr = AttachedArray::alloc(allocator, nentries); + return ::new (addr) ZForwarding(page, nentries); +} + +inline ZForwarding::ZForwarding(ZPage* page, size_t nentries) : + _virtual(page->virtual_memory()), + _object_alignment_shift(page->object_alignment_shift()), + _entries(nentries), + _page(page), + _refcount(1), + _pinned(false) {} inline uintptr_t ZForwarding::start() const { return _virtual.start(); diff --git a/src/hotspot/share/gc/z/zForwardingAllocator.cpp b/src/hotspot/share/gc/z/zForwardingAllocator.cpp new file mode 100644 index 00000000000..6550259966b --- /dev/null +++ b/src/hotspot/share/gc/z/zForwardingAllocator.cpp @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include "precompiled.hpp" +#include "gc/z/zForwardingAllocator.hpp" +#include "memory/allocation.inline.hpp" + +ZForwardingAllocator::ZForwardingAllocator() : + _start(NULL), + _end(NULL), + _top(NULL) {} + +ZForwardingAllocator::~ZForwardingAllocator() { + FREE_C_HEAP_ARRAY(char, _start); +} + +void ZForwardingAllocator::reset(size_t size) { + _start = _top = REALLOC_C_HEAP_ARRAY(char, _start, size, mtGC); + _end = _start + size; +} diff --git a/src/hotspot/share/gc/z/zForwardingAllocator.hpp b/src/hotspot/share/gc/z/zForwardingAllocator.hpp new file mode 100644 index 00000000000..8424fe6cd70 --- /dev/null +++ b/src/hotspot/share/gc/z/zForwardingAllocator.hpp @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#ifndef SHARE_GC_Z_ZFORWARDINGALLOCATOR_HPP +#define SHARE_GC_Z_ZFORWARDINGALLOCATOR_HPP + +#include "utilities/globalDefinitions.hpp" + +class ZForwardingAllocator { +private: + char* _start; + char* _end; + char* _top; + +public: + ZForwardingAllocator(); + ~ZForwardingAllocator(); + + void reset(size_t size); + size_t size() const; + bool is_full() const; + + void* alloc(size_t size); +}; + +#endif // SHARE_GC_Z_ZFORWARDINGALLOCATOR_HPP diff --git a/src/hotspot/share/gc/z/zForwardingTable.cpp b/src/hotspot/share/gc/z/zForwardingAllocator.inline.hpp similarity index 56% rename from src/hotspot/share/gc/z/zForwardingTable.cpp rename to src/hotspot/share/gc/z/zForwardingAllocator.inline.hpp index 926ae7fe63e..eea8110b1a5 100644 --- a/src/hotspot/share/gc/z/zForwardingTable.cpp +++ b/src/hotspot/share/gc/z/zForwardingAllocator.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 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 @@ -21,28 +21,25 @@ * questions. */ -#include "precompiled.hpp" -#include "gc/z/zForwarding.inline.hpp" -#include "gc/z/zForwardingTable.inline.hpp" -#include "gc/z/zGlobals.hpp" -#include "gc/z/zGranuleMap.inline.hpp" -#include "utilities/debug.hpp" - -ZForwardingTable::ZForwardingTable() : - _map(ZAddressOffsetMax) {} +#ifndef SHARE_GC_Z_ZFORWARDINGALLOCATOR_INLINE_HPP +#define SHARE_GC_Z_ZFORWARDINGALLOCATOR_INLINE_HPP -void ZForwardingTable::insert(ZForwarding* forwarding) { - const uintptr_t offset = forwarding->start(); - const size_t size = forwarding->size(); +#include "gc/z/zForwardingAllocator.hpp" +#include "runtime/atomic.hpp" +#include "utilities/debug.hpp" - assert(_map.get(offset) == NULL, "Invalid entry"); - _map.put(offset, size, forwarding); +inline size_t ZForwardingAllocator::size() const { + return _end - _start; } -void ZForwardingTable::remove(ZForwarding* forwarding) { - const uintptr_t offset = forwarding->start(); - const size_t size = forwarding->size(); +inline bool ZForwardingAllocator::is_full() const { + return _top == _end; +} - assert(_map.get(offset) == forwarding, "Invalid entry"); - _map.put(offset, size, NULL); +inline void* ZForwardingAllocator::alloc(size_t size) { + char* const addr = Atomic::fetch_and_add(&_top, size); + assert(addr + size <= _end, "Allocation should never fail"); + return addr; } + +#endif // SHARE_GC_Z_ZFORWARDINGALLOCATOR_INLINE_HPP diff --git a/src/hotspot/share/gc/z/zForwardingTable.inline.hpp b/src/hotspot/share/gc/z/zForwardingTable.inline.hpp index 3561711c43b..be2fbe3ee3b 100644 --- a/src/hotspot/share/gc/z/zForwardingTable.inline.hpp +++ b/src/hotspot/share/gc/z/zForwardingTable.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2020, 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,12 +25,34 @@ #define SHARE_GC_Z_ZFORWARDINGTABLE_INLINE_HPP #include "gc/z/zAddress.inline.hpp" +#include "gc/z/zForwarding.inline.hpp" #include "gc/z/zForwardingTable.hpp" +#include "gc/z/zGlobals.hpp" #include "gc/z/zGranuleMap.inline.hpp" +#include "utilities/debug.hpp" + +inline ZForwardingTable::ZForwardingTable() : + _map(ZAddressOffsetMax) {} inline ZForwarding* ZForwardingTable::get(uintptr_t addr) const { assert(!ZAddress::is_null(addr), "Invalid address"); return _map.get(ZAddress::offset(addr)); } +inline void ZForwardingTable::insert(ZForwarding* forwarding) { + const uintptr_t offset = forwarding->start(); + const size_t size = forwarding->size(); + + assert(_map.get(offset) == NULL, "Invalid entry"); + _map.put(offset, size, forwarding); +} + +inline void ZForwardingTable::remove(ZForwarding* forwarding) { + const uintptr_t offset = forwarding->start(); + const size_t size = forwarding->size(); + + assert(_map.get(offset) == forwarding, "Invalid entry"); + _map.put(offset, size, NULL); +} + #endif // SHARE_GC_Z_ZFORWARDINGTABLE_INLINE_HPP diff --git a/src/hotspot/share/gc/z/zHeap.cpp b/src/hotspot/share/gc/z/zHeap.cpp index 97743a41921..86778981947 100644 --- a/src/hotspot/share/gc/z/zHeap.cpp +++ b/src/hotspot/share/gc/z/zHeap.cpp @@ -24,6 +24,7 @@ #include "precompiled.hpp" #include "gc/shared/locationPrinter.hpp" #include "gc/z/zAddress.inline.hpp" +#include "gc/z/zArray.inline.hpp" #include "gc/z/zGlobals.hpp" #include "gc/z/zHeap.inline.hpp" #include "gc/z/zHeapIterator.hpp" @@ -65,7 +66,7 @@ ZHeap::ZHeap() : _reference_processor(&_workers), _weak_roots_processor(&_workers), _relocate(&_workers), - _relocation_set(), + _relocation_set(&_workers), _unload(&_workers), _serviceability(min_capacity(), max_capacity()) { // Install global heap instance @@ -220,6 +221,17 @@ void ZHeap::free_page(ZPage* page, bool reclaimed) { _page_allocator.free_page(page, reclaimed); } +void ZHeap::free_pages(const ZArray* pages, bool reclaimed) { + // Remove page table entries + ZArrayIterator iter(pages); + for (ZPage* page; iter.next(&page);) { + _page_table.remove(page); + } + + // Free pages + _page_allocator.free_pages(pages, reclaimed); +} + void ZHeap::flip_to_marked() { ZVerifyViewsFlip flip(&_page_allocator); ZAddress::flip_to_marked(); @@ -349,6 +361,16 @@ void ZHeap::process_non_strong_references() { _reference_processor.enqueue_references(); } +void ZHeap::free_garbage_pages(ZRelocationSetSelector* selector, int bulk) { + // Freeing garbage pages in bulk is an optimization to avoid grabbing + // the page allocator lock, and trying to satisfy stalled allocations + // too frequently. + if (selector->should_free_garbage_pages(bulk)) { + free_pages(selector->garbage_pages(), true /* reclaimed */); + selector->clear_garbage_pages(); + } +} + void ZHeap::select_relocation_set() { // Do not allow pages to be deleted _page_allocator.enable_deferred_delete(); @@ -369,16 +391,22 @@ void ZHeap::select_relocation_set() { // Register garbage page selector.register_garbage_page(page); - // Reclaim page immediately - free_page(page, true /* reclaimed */); + // Reclaim garbage pages in bulk + free_garbage_pages(&selector, 64 /* bulk */); } } + // Reclaim remaining garbage pages + free_garbage_pages(&selector, 0 /* bulk */); + // Allow pages to be deleted _page_allocator.disable_deferred_delete(); - // Select pages to relocate - selector.select(&_relocation_set); + // Select relocation set + selector.select(); + + // Install relocation set + _relocation_set.install(&selector); // Setup forwarding table ZRelocationSetIterator rs_iter(&_relocation_set); diff --git a/src/hotspot/share/gc/z/zHeap.hpp b/src/hotspot/share/gc/z/zHeap.hpp index 338002a89c6..47bebc745f3 100644 --- a/src/hotspot/share/gc/z/zHeap.hpp +++ b/src/hotspot/share/gc/z/zHeap.hpp @@ -25,6 +25,7 @@ #define SHARE_GC_Z_ZHEAP_HPP #include "gc/z/zAllocationFlags.hpp" +#include "gc/z/zArray.hpp" #include "gc/z/zForwardingTable.hpp" #include "gc/z/zMark.hpp" #include "gc/z/zObjectAllocator.hpp" @@ -40,6 +41,7 @@ class ThreadClosure; class ZPage; +class ZRelocationSetSelector; class ZHeap { friend class VMStructs; @@ -63,6 +65,8 @@ class ZHeap { void flip_to_marked(); void flip_to_remapped(); + void free_garbage_pages(ZRelocationSetSelector* selector, int bulk); + void out_of_memory(); public: @@ -110,6 +114,7 @@ class ZHeap { ZPage* alloc_page(uint8_t type, size_t size, ZAllocationFlags flags); void undo_alloc_page(ZPage* page); void free_page(ZPage* page, bool reclaimed); + void free_pages(const ZArray* pages, bool reclaimed); // Object allocation uintptr_t alloc_tlab(size_t size); diff --git a/src/hotspot/share/gc/z/zHeapIterator.cpp b/src/hotspot/share/gc/z/zHeapIterator.cpp index b172e46c703..4fd0d22497f 100644 --- a/src/hotspot/share/gc/z/zHeapIterator.cpp +++ b/src/hotspot/share/gc/z/zHeapIterator.cpp @@ -23,12 +23,14 @@ #include "precompiled.hpp" #include "classfile/classLoaderData.hpp" +#include "gc/shared/barrierSetNMethod.hpp" #include "gc/shared/taskqueue.inline.hpp" #include "gc/z/zAddress.inline.hpp" #include "gc/z/zGlobals.hpp" #include "gc/z/zGranuleMap.inline.hpp" #include "gc/z/zHeapIterator.hpp" #include "gc/z/zLock.inline.hpp" +#include "gc/z/zNMethod.hpp" #include "gc/z/zOop.inline.hpp" #include "memory/iterator.inline.hpp" #include "utilities/bitMap.inline.hpp" @@ -92,8 +94,8 @@ class ZHeapIteratorContext { } }; -template -class ZHeapIteratorRootOopClosure : public ZRootsIteratorClosure { +template +class ZHeapIteratorRootOopClosure : public OopClosure { private: const ZHeapIteratorContext& _context; @@ -102,11 +104,7 @@ class ZHeapIteratorRootOopClosure : public ZRootsIteratorClosure { return NativeAccess::oop_load(p); } - if (Concurrent) { - return NativeAccess::oop_load(p); - } - - return RawAccess<>::oop_load(p); + return NativeAccess::oop_load(p); } public: @@ -121,11 +119,6 @@ class ZHeapIteratorRootOopClosure : public ZRootsIteratorClosure { virtual void do_oop(narrowOop* p) { ShouldNotReachHere(); } - - virtual void do_thread(Thread* thread) { - CodeBlobToOopClosure code_cl(this, false /* fix_oop_relocations */); - thread->oops_do(this, &code_cl); - } }; template @@ -160,12 +153,6 @@ class ZHeapIteratorOopClosure : public ClaimMetadataVisitingOopIterateClosure { virtual void do_oop(narrowOop* p) { ShouldNotReachHere(); } - -#ifdef ASSERT - virtual bool should_verify_oops() { - return false; - } -#endif }; ZHeapIterator::ZHeapIterator(uint nworkers, bool visit_weaks) : @@ -175,7 +162,7 @@ ZHeapIterator::ZHeapIterator(uint nworkers, bool visit_weaks) : _bitmaps_lock(), _queues(nworkers), _array_queues(nworkers), - _concurrent_roots(), + _concurrent_roots(ClassLoaderData::_claim_other), _weak_roots(), _concurrent_weak_roots(), _terminator(nworkers, &_queues) { @@ -250,10 +237,83 @@ bool ZHeapIterator::mark_object(oop obj) { return bitmap->try_set_bit(index); } -template -void ZHeapIterator::push_roots(const ZHeapIteratorContext& context, RootsIterator& iter) { - ZHeapIteratorRootOopClosure cl(context); - iter.oops_do(&cl); +typedef ClaimingCLDToOopClosure ZHeapIteratorCLDCLosure; + +class ZHeapIteratorNMethodClosure : public NMethodClosure { +private: + OopClosure* const _cl; + BarrierSetNMethod* const _bs_nm; + +public: + ZHeapIteratorNMethodClosure(OopClosure* cl) : + _cl(cl), + _bs_nm(BarrierSet::barrier_set()->barrier_set_nmethod()) {} + + virtual void do_nmethod(nmethod* nm) { + assert(!ClassUnloading, "Only used if class unloading is turned off"); + + // ClassUnloading is turned off, all nmethods are considered strong, + // not only those on the call stacks. The heap iteration might happen + // before the concurrent processign of the code cache, make sure that + // all nmethods have been processed before visiting the oops. + _bs_nm->nmethod_entry_barrier(nm); + + ZNMethod::nmethod_oops_do(nm, _cl); + } +}; + +class ZHeapIteratorThreadClosure : public ThreadClosure { +private: + OopClosure* const _cl; + + class NMethodVisitor : public CodeBlobToOopClosure { + public: + NMethodVisitor(OopClosure* cl) : + CodeBlobToOopClosure(cl, false /* fix_oop_relocations */) {} + + void do_code_blob(CodeBlob* cb) { + assert(!cb->is_nmethod() || !ZNMethod::is_armed(cb->as_nmethod()), + "NMethods on stack should have been fixed and disarmed"); + + CodeBlobToOopClosure::do_code_blob(cb); + } + }; + +public: + ZHeapIteratorThreadClosure(OopClosure* cl) : _cl(cl) {} + + void do_thread(Thread* thread) { + NMethodVisitor code_cl(_cl); + thread->oops_do(_cl, &code_cl); + } +}; + +void ZHeapIterator::push_strong_roots(const ZHeapIteratorContext& context) { + ZHeapIteratorRootOopClosure cl(context); + ZHeapIteratorCLDCLosure cld_cl(&cl); + ZHeapIteratorNMethodClosure nm_cl(&cl); + ZHeapIteratorThreadClosure thread_cl(&cl); + + _concurrent_roots.apply(&cl, + &cld_cl, + &thread_cl, + &nm_cl); +} + +void ZHeapIterator::push_weak_roots(const ZHeapIteratorContext& context) { + ZHeapIteratorRootOopClosure cl(context); + _concurrent_weak_roots.apply(&cl); + + AlwaysTrueClosure is_alive; + _weak_roots.apply(&is_alive, &cl); +} + +template +void ZHeapIterator::push_roots(const ZHeapIteratorContext& context) { + push_strong_roots(context); + if (VisitWeaks) { + push_weak_roots(context); + } } template @@ -338,14 +398,9 @@ void ZHeapIterator::drain_and_steal(const ZHeapIteratorContext& context, ObjectC } template -void ZHeapIterator::object_iterate_inner(const ZHeapIteratorContext& context, ObjectClosure* cl) { - push_roots(context, _concurrent_roots); - if (VisitWeaks) { - push_roots(context, _weak_roots); - push_roots(context, _concurrent_weak_roots); - } - - drain_and_steal(context, cl); +void ZHeapIterator::object_iterate_inner(const ZHeapIteratorContext& context, ObjectClosure* object_cl) { + push_roots(context); + drain_and_steal(context, object_cl); } void ZHeapIterator::object_iterate(ObjectClosure* cl, uint worker_id) { diff --git a/src/hotspot/share/gc/z/zHeapIterator.hpp b/src/hotspot/share/gc/z/zHeapIterator.hpp index 598cb7d7c59..002e9ab949b 100644 --- a/src/hotspot/share/gc/z/zHeapIterator.hpp +++ b/src/hotspot/share/gc/z/zHeapIterator.hpp @@ -46,23 +46,26 @@ class ZHeapIterator : public ParallelObjectIterator { friend class ZHeapIteratorContext; private: - const bool _visit_weaks; - ZStatTimerDisable _timer_disable; - ZHeapIteratorBitMaps _bitmaps; - ZLock _bitmaps_lock; - ZHeapIteratorQueues _queues; - ZHeapIteratorArrayQueues _array_queues; - ZConcurrentRootsIteratorClaimOther _concurrent_roots; - ZWeakRootsIterator _weak_roots; - ZConcurrentWeakRootsIterator _concurrent_weak_roots; - TaskTerminator _terminator; + const bool _visit_weaks; + ZStatTimerDisable _timer_disable; + ZHeapIteratorBitMaps _bitmaps; + ZLock _bitmaps_lock; + ZHeapIteratorQueues _queues; + ZHeapIteratorArrayQueues _array_queues; + ZConcurrentRootsIterator _concurrent_roots; + ZWeakRootsIterator _weak_roots; + ZConcurrentWeakRootsIterator _concurrent_weak_roots; + TaskTerminator _terminator; ZHeapIteratorBitMap* object_bitmap(oop obj); bool mark_object(oop obj); - template - void push_roots(const ZHeapIteratorContext& context, RootsIterator& iter); + void push_strong_roots(const ZHeapIteratorContext& context); + void push_weak_roots(const ZHeapIteratorContext& context); + + template + void push_roots(const ZHeapIteratorContext& context); template void follow_object(const ZHeapIteratorContext& context, oop obj); diff --git a/src/hotspot/share/gc/z/zMark.cpp b/src/hotspot/share/gc/z/zMark.cpp index 421dc28b348..d4c4bbdfde5 100644 --- a/src/hotspot/share/gc/z/zMark.cpp +++ b/src/hotspot/share/gc/z/zMark.cpp @@ -23,12 +23,15 @@ #include "precompiled.hpp" #include "classfile/classLoaderDataGraph.hpp" +#include "code/nmethod.hpp" #include "gc/shared/suspendibleThreadSet.hpp" #include "gc/z/zBarrier.inline.hpp" +#include "gc/z/zLock.inline.hpp" #include "gc/z/zMark.inline.hpp" #include "gc/z/zMarkCache.inline.hpp" #include "gc/z/zMarkStack.inline.hpp" #include "gc/z/zMarkTerminate.inline.hpp" +#include "gc/z/zNMethod.hpp" #include "gc/z/zOopClosures.inline.hpp" #include "gc/z/zPage.hpp" #include "gc/z/zPageTable.inline.hpp" @@ -572,49 +575,79 @@ void ZMark::work(uint64_t timeout_in_micros) { stacks->free(&_allocator); } -class ZMarkConcurrentRootsIteratorClosure : public ZRootsIteratorClosure { -public: - ZMarkConcurrentRootsIteratorClosure() { - ZThreadLocalAllocBuffer::reset_statistics(); +class ZMarkOopClosure : public OopClosure { + virtual void do_oop(oop* p) { + ZBarrier::mark_barrier_on_oop_field(p, false /* finalizable */); } - ~ZMarkConcurrentRootsIteratorClosure() { - ZThreadLocalAllocBuffer::publish_statistics(); + virtual void do_oop(narrowOop* p) { + ShouldNotReachHere(); } +}; - virtual bool should_disarm_nmethods() const { - return true; - } +class ZMarkThreadClosure : public ThreadClosure { +private: + OopClosure* const _cl; +public: + ZMarkThreadClosure(OopClosure* cl) : + _cl(cl) { + ZThreadLocalAllocBuffer::reset_statistics(); + } + ~ZMarkThreadClosure() { + ZThreadLocalAllocBuffer::publish_statistics(); + } virtual void do_thread(Thread* thread) { JavaThread* const jt = thread->as_Java_thread(); - StackWatermarkSet::finish_processing(jt, this, StackWatermarkKind::gc); + StackWatermarkSet::finish_processing(jt, _cl, StackWatermarkKind::gc); ZThreadLocalAllocBuffer::update_stats(jt); } +}; - virtual void do_oop(oop* p) { - ZBarrier::mark_barrier_on_oop_field(p, false /* finalizable */); - } +class ZMarkNMethodClosure : public NMethodClosure { +private: + OopClosure* const _cl; - virtual void do_oop(narrowOop* p) { - ShouldNotReachHere(); +public: + ZMarkNMethodClosure(OopClosure* cl) : + _cl(cl) {} + + virtual void do_nmethod(nmethod* nm) { + ZLocker locker(ZNMethod::lock_for_nmethod(nm)); + if (!nm->is_alive()) { + return; + } + + if (ZNMethod::is_armed(nm)) { + ZNMethod::nmethod_oops_do_inner(nm, _cl); + ZNMethod::disarm(nm); + } } }; +typedef ClaimingCLDToOopClosure ZMarkCLDClosure; + class ZMarkConcurrentRootsTask : public ZTask { private: - ZMark* const _mark; - SuspendibleThreadSetJoiner _sts_joiner; - ZConcurrentRootsIteratorClaimStrong _roots; - ZMarkConcurrentRootsIteratorClosure _cl; + ZMark* const _mark; + SuspendibleThreadSetJoiner _sts_joiner; + ZConcurrentRootsIterator _roots; + + ZMarkOopClosure _cl; + ZMarkCLDClosure _cld_cl; + ZMarkThreadClosure _thread_cl; + ZMarkNMethodClosure _nm_cl; public: ZMarkConcurrentRootsTask(ZMark* mark) : ZTask("ZMarkConcurrentRootsTask"), _mark(mark), _sts_joiner(), - _roots(), - _cl() { + _roots(ClassLoaderData::_claim_strong), + _cl(), + _cld_cl(&_cl), + _thread_cl(&_cl), + _nm_cl(&_cl) { ClassLoaderDataGraph_lock->lock(); } @@ -623,7 +656,10 @@ class ZMarkConcurrentRootsTask : public ZTask { } virtual void work() { - _roots.oops_do(&_cl); + _roots.apply(&_cl, + &_cld_cl, + &_thread_cl, + &_nm_cl); // Flush and free worker stacks. Needed here since // the set of workers executing during root scanning diff --git a/src/hotspot/share/gc/z/zNMethod.cpp b/src/hotspot/share/gc/z/zNMethod.cpp index 16c0ef15d4e..ec3040e0f49 100644 --- a/src/hotspot/share/gc/z/zNMethod.cpp +++ b/src/hotspot/share/gc/z/zNMethod.cpp @@ -204,6 +204,15 @@ void ZNMethod::disarm(nmethod* nm) { } void ZNMethod::nmethod_oops_do(nmethod* nm, OopClosure* cl) { + ZLocker locker(ZNMethod::lock_for_nmethod(nm)); + if (!nm->is_alive()) { + return; + } + + ZNMethod::nmethod_oops_do_inner(nm, cl); +} + +void ZNMethod::nmethod_oops_do_inner(nmethod* nm, OopClosure* cl) { // Process oops table { oop* const begin = nm->oops_begin(); @@ -234,44 +243,16 @@ void ZNMethod::nmethod_oops_do(nmethod* nm, OopClosure* cl) { } } -class ZNMethodToOopsDoClosure : public NMethodClosure { -private: - OopClosure* const _cl; - const bool _should_disarm_nmethods; - -public: - ZNMethodToOopsDoClosure(OopClosure* cl, bool should_disarm_nmethods) : - _cl(cl), - _should_disarm_nmethods(should_disarm_nmethods) {} - - virtual void do_nmethod(nmethod* nm) { - ZLocker locker(ZNMethod::lock_for_nmethod(nm)); - if (!nm->is_alive()) { - return; - } - - if (_should_disarm_nmethods) { - if (ZNMethod::is_armed(nm)) { - ZNMethod::nmethod_oops_do(nm, _cl); - ZNMethod::disarm(nm); - } - } else { - ZNMethod::nmethod_oops_do(nm, _cl); - } - } -}; - -void ZNMethod::oops_do_begin() { +void ZNMethod::nmethods_do_begin() { ZNMethodTable::nmethods_do_begin(); } -void ZNMethod::oops_do_end() { +void ZNMethod::nmethods_do_end() { ZNMethodTable::nmethods_do_end(); } -void ZNMethod::oops_do(OopClosure* cl, bool should_disarm_nmethods) { - ZNMethodToOopsDoClosure nmethod_cl(cl, should_disarm_nmethods); - ZNMethodTable::nmethods_do(&nmethod_cl); +void ZNMethod::nmethods_do(NMethodClosure* cl) { + ZNMethodTable::nmethods_do(cl); } class ZNMethodUnlinkClosure : public NMethodClosure { diff --git a/src/hotspot/share/gc/z/zNMethod.hpp b/src/hotspot/share/gc/z/zNMethod.hpp index 1b6117b22c6..ec05389b7f4 100644 --- a/src/hotspot/share/gc/z/zNMethod.hpp +++ b/src/hotspot/share/gc/z/zNMethod.hpp @@ -27,7 +27,7 @@ #include "memory/allocation.hpp" class nmethod; -class OopClosure; +class NMethodClosure; class ZReentrantLock; class ZWorkers; @@ -49,10 +49,11 @@ class ZNMethod : public AllStatic { static void disarm(nmethod* nm); static void nmethod_oops_do(nmethod* nm, OopClosure* cl); + static void nmethod_oops_do_inner(nmethod* nm, OopClosure* cl); - static void oops_do_begin(); - static void oops_do_end(); - static void oops_do(OopClosure* cl, bool should_disarm_nmethods); + static void nmethods_do_begin(); + static void nmethods_do_end(); + static void nmethods_do(NMethodClosure* cl); static ZReentrantLock* lock_for_nmethod(nmethod* nm); diff --git a/src/hotspot/share/gc/z/zOopClosures.hpp b/src/hotspot/share/gc/z/zOopClosures.hpp index 2823f92f263..73201c339f5 100644 --- a/src/hotspot/share/gc/z/zOopClosures.hpp +++ b/src/hotspot/share/gc/z/zOopClosures.hpp @@ -31,12 +31,6 @@ class ZLoadBarrierOopClosure : public BasicOopIterateClosure { public: virtual void do_oop(oop* p); virtual void do_oop(narrowOop* p); - -#ifdef ASSERT - virtual bool should_verify_oops() { - return false; - } -#endif }; class ZNMethodOopClosure : public OopClosure { @@ -52,12 +46,6 @@ class ZMarkBarrierOopClosure : public ClaimMetadataVisitingOopIterateClosure { virtual void do_oop(oop* p); virtual void do_oop(narrowOop* p); - -#ifdef ASSERT - virtual bool should_verify_oops() { - return false; - } -#endif }; class ZPhantomIsAliveObjectClosure : public BoolObjectClosure { @@ -65,13 +53,12 @@ class ZPhantomIsAliveObjectClosure : public BoolObjectClosure { virtual bool do_object_b(oop o); }; -class ZPhantomKeepAliveOopClosure : public ZRootsIteratorClosure { +class ZPhantomKeepAliveOopClosure : public OopClosure { public: virtual void do_oop(oop* p); virtual void do_oop(narrowOop* p); }; - -class ZPhantomCleanOopClosure : public ZRootsIteratorClosure { +class ZPhantomCleanOopClosure : public OopClosure { public: virtual void do_oop(oop* p); virtual void do_oop(narrowOop* p); diff --git a/src/hotspot/share/gc/z/zPageAllocator.cpp b/src/hotspot/share/gc/z/zPageAllocator.cpp index ebf29596de2..371ee2ff75a 100644 --- a/src/hotspot/share/gc/z/zPageAllocator.cpp +++ b/src/hotspot/share/gc/z/zPageAllocator.cpp @@ -24,6 +24,7 @@ #include "precompiled.hpp" #include "gc/shared/gcLogPrecious.hpp" #include "gc/shared/suspendibleThreadSet.hpp" +#include "gc/z/zArray.inline.hpp" #include "gc/z/zCollectedHeap.hpp" #include "gc/z/zFuture.inline.hpp" #include "gc/z/zGlobals.hpp" @@ -748,6 +749,19 @@ void ZPageAllocator::free_page(ZPage* page, bool reclaimed) { satisfy_stalled(); } +void ZPageAllocator::free_pages(const ZArray* pages, bool reclaimed) { + ZLocker locker(&_lock); + + // Free pages + ZArrayIterator iter(pages); + for (ZPage* page; iter.next(&page);) { + free_page_inner(page, reclaimed); + } + + // Try satisfy stalled allocations + satisfy_stalled(); +} + size_t ZPageAllocator::uncommit(uint64_t* timeout) { // We need to join the suspendible thread set while manipulating capacity and // used, to make sure GC safepoints will have a consistent view. However, when diff --git a/src/hotspot/share/gc/z/zPageAllocator.hpp b/src/hotspot/share/gc/z/zPageAllocator.hpp index 800ef4d9875..9c970350732 100644 --- a/src/hotspot/share/gc/z/zPageAllocator.hpp +++ b/src/hotspot/share/gc/z/zPageAllocator.hpp @@ -25,6 +25,7 @@ #define SHARE_GC_Z_ZPAGEALLOCATOR_HPP #include "gc/z/zAllocationFlags.hpp" +#include "gc/z/zArray.hpp" #include "gc/z/zList.hpp" #include "gc/z/zLock.hpp" #include "gc/z/zPageCache.hpp" @@ -124,6 +125,7 @@ class ZPageAllocator { ZPage* alloc_page(uint8_t type, size_t size, ZAllocationFlags flags); void free_page(ZPage* page, bool reclaimed); + void free_pages(const ZArray* pages, bool reclaimed); void enable_deferred_delete() const; void disable_deferred_delete() const; diff --git a/src/hotspot/share/gc/z/zRelocate.cpp b/src/hotspot/share/gc/z/zRelocate.cpp index a8f8f74ef86..95c07cb2bc4 100644 --- a/src/hotspot/share/gc/z/zRelocate.cpp +++ b/src/hotspot/share/gc/z/zRelocate.cpp @@ -36,8 +36,10 @@ #include "gc/z/zThread.inline.hpp" #include "gc/z/zWorkers.hpp" #include "logging/log.hpp" +#include "prims/jvmtiTagMap.hpp" static const ZStatCounter ZCounterRelocationContention("Contention", "Relocation Contention", ZStatUnitOpsPerSecond); +static const ZStatSubPhase ZSubPhasePauseRootsJVMTITagMap("Pause Roots JVMTITagMap"); ZRelocate::ZRelocate(ZWorkers* workers) : _workers(workers) {} @@ -67,8 +69,10 @@ class ZRelocateRootsTask : public ZTask { assert(ZThread::worker_id() == 0, "No multi-thread support"); // During relocation we need to visit the JVMTI - // export weak roots to rehash the JVMTI tag map - ZRelocateRoots::oops_do(&_cl); + // tag map to rehash the entries with the new oop addresses. + ZStatTimer timer(ZSubPhasePauseRootsJVMTITagMap); + AlwaysTrueClosure always_alive; + JvmtiTagMap::weak_oops_do(&always_alive, &_cl); } }; diff --git a/src/hotspot/share/gc/z/zRelocationSet.cpp b/src/hotspot/share/gc/z/zRelocationSet.cpp index b7f566397ae..0591c2a711a 100644 --- a/src/hotspot/share/gc/z/zRelocationSet.cpp +++ b/src/hotspot/share/gc/z/zRelocationSet.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2020, 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 @@ -22,35 +22,108 @@ */ #include "precompiled.hpp" -#include "gc/z/zForwarding.hpp" +#include "gc/z/zArray.inline.hpp" +#include "gc/z/zForwarding.inline.hpp" +#include "gc/z/zForwardingAllocator.inline.hpp" #include "gc/z/zRelocationSet.hpp" -#include "memory/allocation.hpp" +#include "gc/z/zRelocationSetSelector.inline.hpp" +#include "gc/z/zStat.hpp" +#include "gc/z/zTask.hpp" +#include "gc/z/zWorkers.hpp" +#include "runtime/atomic.hpp" +#include "utilities/debug.hpp" -ZRelocationSet::ZRelocationSet() : - _forwardings(NULL), - _nforwardings(0) {} +class ZRelocationSetInstallTask : public ZTask { +private: + ZForwardingAllocator* const _allocator; + ZForwarding** _forwardings; + const size_t _nforwardings; + ZArrayParallelIterator _small_iter; + ZArrayParallelIterator _medium_iter; + volatile size_t _small_next; + volatile size_t _medium_next; + + void install(ZForwarding* forwarding, volatile size_t* next) { + const size_t index = Atomic::fetch_and_add(next, 1u); + assert(index < _nforwardings, "Invalid index"); + _forwardings[index] = forwarding; + } + + void install_small(ZForwarding* forwarding) { + install(forwarding, &_small_next); + } + + void install_medium(ZForwarding* forwarding) { + install(forwarding, &_medium_next); + } + +public: + ZRelocationSetInstallTask(ZForwardingAllocator* allocator, const ZRelocationSetSelector* selector) : + ZTask("ZRelocationSetInstallTask"), + _allocator(allocator), + _forwardings(NULL), + _nforwardings(selector->small()->length() + selector->medium()->length()), + _small_iter(selector->small()), + _medium_iter(selector->medium()), + _small_next(selector->medium()->length()), + _medium_next(0) { + + // Reset the allocator to have room for the relocation + // set, all forwardings, and all forwarding entries. + const size_t relocation_set_size = _nforwardings * sizeof(ZForwarding*); + const size_t forwardings_size = _nforwardings * sizeof(ZForwarding); + const size_t forwarding_entries_size = selector->forwarding_entries() * sizeof(ZForwardingEntry); + _allocator->reset(relocation_set_size + forwardings_size + forwarding_entries_size); + + // Allocate relocation set + _forwardings = new (_allocator->alloc(relocation_set_size)) ZForwarding*[_nforwardings]; + } + + ~ZRelocationSetInstallTask() { + assert(_allocator->is_full(), "Should be full"); + } -void ZRelocationSet::populate(ZPage* const* group0, size_t ngroup0, - ZPage* const* group1, size_t ngroup1) { - _nforwardings = ngroup0 + ngroup1; - _forwardings = REALLOC_C_HEAP_ARRAY(ZForwarding*, _forwardings, _nforwardings, mtGC); + virtual void work() { + // Allocate and install forwardings for small pages + for (ZPage* page; _small_iter.next(&page);) { + ZForwarding* const forwarding = ZForwarding::alloc(_allocator, page); + install_small(forwarding); + } - size_t j = 0; + // Allocate and install forwardings for medium pages + for (ZPage* page; _medium_iter.next(&page);) { + ZForwarding* const forwarding = ZForwarding::alloc(_allocator, page); + install_medium(forwarding); + } + } - // Populate group 0 - for (size_t i = 0; i < ngroup0; i++) { - _forwardings[j++] = ZForwarding::create(group0[i]); + ZForwarding** forwardings() const { + return _forwardings; } - // Populate group 1 - for (size_t i = 0; i < ngroup1; i++) { - _forwardings[j++] = ZForwarding::create(group1[i]); + size_t nforwardings() const { + return _nforwardings; } +}; + +ZRelocationSet::ZRelocationSet(ZWorkers* workers) : + _workers(workers), + _allocator(), + _forwardings(NULL), + _nforwardings(0) {} + +void ZRelocationSet::install(const ZRelocationSetSelector* selector) { + // Install relocation set + ZRelocationSetInstallTask task(&_allocator, selector); + _workers->run_concurrent(&task); + + _forwardings = task.forwardings(); + _nforwardings = task.nforwardings(); + + // Update statistics + ZStatRelocation::set_at_install_relocation_set(_allocator.size()); } void ZRelocationSet::reset() { - for (size_t i = 0; i < _nforwardings; i++) { - ZForwarding::destroy(_forwardings[i]); - _forwardings[i] = NULL; - } + _nforwardings = 0; } diff --git a/src/hotspot/share/gc/z/zRelocationSet.hpp b/src/hotspot/share/gc/z/zRelocationSet.hpp index 21dff8a16e9..5881055db99 100644 --- a/src/hotspot/share/gc/z/zRelocationSet.hpp +++ b/src/hotspot/share/gc/z/zRelocationSet.hpp @@ -25,23 +25,25 @@ #define SHARE_GC_Z_ZRELOCATIONSET_HPP #include "gc/z/zArray.hpp" -#include "memory/allocation.hpp" +#include "gc/z/zForwardingAllocator.hpp" class ZForwarding; -class ZPage; +class ZRelocationSetSelector; +class ZWorkers; class ZRelocationSet { template friend class ZRelocationSetIteratorImpl; private: - ZForwarding** _forwardings; - size_t _nforwardings; + ZWorkers* _workers; + ZForwardingAllocator _allocator; + ZForwarding** _forwardings; + size_t _nforwardings; public: - ZRelocationSet(); + ZRelocationSet(ZWorkers* workers); - void populate(ZPage* const* group0, size_t ngroup0, - ZPage* const* group1, size_t ngroup1); + void install(const ZRelocationSetSelector* selector); void reset(); }; diff --git a/src/hotspot/share/gc/z/zRelocationSetSelector.cpp b/src/hotspot/share/gc/z/zRelocationSetSelector.cpp index ac33451735e..3d80286a894 100644 --- a/src/hotspot/share/gc/z/zRelocationSetSelector.cpp +++ b/src/hotspot/share/gc/z/zRelocationSetSelector.cpp @@ -23,8 +23,8 @@ #include "precompiled.hpp" #include "gc/z/zArray.inline.hpp" +#include "gc/z/zForwarding.inline.hpp" #include "gc/z/zPage.inline.hpp" -#include "gc/z/zRelocationSet.hpp" #include "gc/z/zRelocationSetSelector.inline.hpp" #include "jfr/jfrEvents.hpp" #include "logging/log.hpp" @@ -51,39 +51,9 @@ ZRelocationSetSelectorGroup::ZRelocationSetSelectorGroup(const char* name, _object_size_limit(object_size_limit), _fragmentation_limit(page_size * (ZFragmentationLimit / 100)), _registered_pages(), - _sorted_pages(NULL), - _nselected(0), + _forwarding_entries(0), _stats() {} -ZRelocationSetSelectorGroup::~ZRelocationSetSelectorGroup() { - FREE_C_HEAP_ARRAY(ZPage*, _sorted_pages); -} - -void ZRelocationSetSelectorGroup::register_live_page(ZPage* page) { - const uint8_t type = page->type(); - const size_t size = page->size(); - const size_t live = page->live_bytes(); - const size_t garbage = size - live; - - if (garbage > _fragmentation_limit) { - _registered_pages.append(page); - } - - _stats._npages++; - _stats._total += size; - _stats._live += live; - _stats._garbage += garbage; -} - -void ZRelocationSetSelectorGroup::register_garbage_page(ZPage* page) { - const size_t size = page->size(); - - _stats._npages++; - _stats._total += size; - _stats._garbage += size; - _stats._empty += size; -} - bool ZRelocationSetSelectorGroup::is_disabled() { // Medium pages are disabled when their page size is zero return _page_type == ZPageTypeMedium && _page_size == 0; @@ -100,18 +70,11 @@ void ZRelocationSetSelectorGroup::semi_sort() { const size_t npartitions = (size_t)1 << npartitions_shift; const size_t partition_size = _page_size >> npartitions_shift; const size_t partition_size_shift = exact_log2(partition_size); - const size_t npages = _registered_pages.length(); // Partition slots/fingers - size_t partitions[npartitions]; - - // Allocate destination array - assert(_sorted_pages == NULL, "Already initialized"); - _sorted_pages = NEW_C_HEAP_ARRAY(ZPage*, npages, mtGC); - debug_only(memset(_sorted_pages, 0, npages * sizeof(ZPage*))); + int partitions[npartitions] = { /* zero initialize */ }; // Calculate partition slots - memset(partitions, 0, sizeof(partitions)); ZArrayIterator iter1(&_registered_pages); for (ZPage* page; iter1.next(&page);) { const size_t index = page->live_bytes() >> partition_size_shift; @@ -119,70 +82,83 @@ void ZRelocationSetSelectorGroup::semi_sort() { } // Calculate partition fingers - size_t finger = 0; + int finger = 0; for (size_t i = 0; i < npartitions; i++) { - const size_t slots = partitions[i]; + const int slots = partitions[i]; partitions[i] = finger; finger += slots; } + // Allocate destination array + const int npages = _registered_pages.length(); + ZArray sorted_pages(npages, npages, NULL); + // Sort pages into partitions ZArrayIterator iter2(&_registered_pages); for (ZPage* page; iter2.next(&page);) { const size_t index = page->live_bytes() >> partition_size_shift; - const size_t finger = partitions[index]++; - assert(_sorted_pages[finger] == NULL, "Invalid finger"); - _sorted_pages[finger] = page; + const int finger = partitions[index]++; + assert(sorted_pages.at(finger) == NULL, "Invalid finger"); + sorted_pages.at_put(finger, page); } + + _registered_pages.swap(&sorted_pages); } void ZRelocationSetSelectorGroup::select_inner() { // Calculate the number of pages to relocate by successively including pages in // a candidate relocation set and calculate the maximum space requirement for // their live objects. - const size_t npages = _registered_pages.length(); - size_t selected_from = 0; - size_t selected_to = 0; - size_t from_size = 0; + const int npages = _registered_pages.length(); + int selected_from = 0; + int selected_to = 0; + size_t selected_forwarding_entries = 0; + size_t from_live_bytes = 0; + size_t from_forwarding_entries = 0; semi_sort(); - for (size_t from = 1; from <= npages; from++) { + for (int from = 1; from <= npages; from++) { // Add page to the candidate relocation set - from_size += _sorted_pages[from - 1]->live_bytes(); + ZPage* const page = _registered_pages.at(from - 1); + from_live_bytes += page->live_bytes(); + from_forwarding_entries += ZForwarding::nentries(page); // Calculate the maximum number of pages needed by the candidate relocation set. // By subtracting the object size limit from the pages size we get the maximum // number of pages that the relocation set is guaranteed to fit in, regardless // of in which order the objects are relocated. - const size_t to = ceil((double)(from_size) / (double)(_page_size - _object_size_limit)); + const int to = ceil((double)(from_live_bytes) / (double)(_page_size - _object_size_limit)); // Calculate the relative difference in reclaimable space compared to our // currently selected final relocation set. If this number is larger than the // acceptable fragmentation limit, then the current candidate relocation set // becomes our new final relocation set. - const size_t diff_from = from - selected_from; - const size_t diff_to = to - selected_to; + const int diff_from = from - selected_from; + const int diff_to = to - selected_to; const double diff_reclaimable = 100 - percent_of(diff_to, diff_from); if (diff_reclaimable > ZFragmentationLimit) { selected_from = from; selected_to = to; + selected_forwarding_entries = from_forwarding_entries; } - log_trace(gc, reloc)("Candidate Relocation Set (%s Pages): " - SIZE_FORMAT "->" SIZE_FORMAT ", %.1f%% relative defragmentation, %s", - _name, from, to, diff_reclaimable, (selected_from == from) ? "Selected" : "Rejected"); + log_trace(gc, reloc)("Candidate Relocation Set (%s Pages): %d->%d, " + "%.1f%% relative defragmentation, " SIZE_FORMAT " forwarding entries, %s", + _name, from, to, diff_reclaimable, from_forwarding_entries, + (selected_from == from) ? "Selected" : "Rejected"); } // Finalize selection - _nselected = selected_from; + _registered_pages.trunc_to(selected_from); + _forwarding_entries = selected_forwarding_entries; // Update statistics _stats._compacting_from = selected_from * _page_size; _stats._compacting_to = selected_to * _page_size; - log_trace(gc, reloc)("Relocation Set (%s Pages): " SIZE_FORMAT "->" SIZE_FORMAT ", " SIZE_FORMAT " skipped", - _name, selected_from, selected_to, npages - _nselected); + log_trace(gc, reloc)("Relocation Set (%s Pages): %d->%d, %d skipped, " SIZE_FORMAT " forwarding entries", + _name, selected_from, selected_to, npages - selected_from, selected_forwarding_entries); } void ZRelocationSetSelectorGroup::select() { @@ -204,33 +180,10 @@ void ZRelocationSetSelectorGroup::select() { ZRelocationSetSelector::ZRelocationSetSelector() : _small("Small", ZPageTypeSmall, ZPageSizeSmall, ZObjectSizeLimitSmall), _medium("Medium", ZPageTypeMedium, ZPageSizeMedium, ZObjectSizeLimitMedium), - _large("Large", ZPageTypeLarge, 0 /* page_size */, 0 /* object_size_limit */) {} - -void ZRelocationSetSelector::register_live_page(ZPage* page) { - const uint8_t type = page->type(); - - if (type == ZPageTypeSmall) { - _small.register_live_page(page); - } else if (type == ZPageTypeMedium) { - _medium.register_live_page(page); - } else { - _large.register_live_page(page); - } -} - -void ZRelocationSetSelector::register_garbage_page(ZPage* page) { - const uint8_t type = page->type(); - - if (type == ZPageTypeSmall) { - _small.register_garbage_page(page); - } else if (type == ZPageTypeMedium) { - _medium.register_garbage_page(page); - } else { - _large.register_garbage_page(page); - } -} + _large("Large", ZPageTypeLarge, 0 /* page_size */, 0 /* object_size_limit */), + _garbage_pages() {} -void ZRelocationSetSelector::select(ZRelocationSet* relocation_set) { +void ZRelocationSetSelector::select() { // Select pages to relocate. The resulting relocation set will be // sorted such that medium pages comes first, followed by small // pages. Pages within each page group will be semi-sorted by live @@ -244,10 +197,6 @@ void ZRelocationSetSelector::select(ZRelocationSet* relocation_set) { _medium.select(); _small.select(); - // Populate relocation set - relocation_set->populate(_medium.selected(), _medium.nselected(), - _small.selected(), _small.nselected()); - // Send event event.commit(total(), empty(), compacting_from(), compacting_to()); } diff --git a/src/hotspot/share/gc/z/zRelocationSetSelector.hpp b/src/hotspot/share/gc/z/zRelocationSetSelector.hpp index 70900f814d8..164fcd628a0 100644 --- a/src/hotspot/share/gc/z/zRelocationSetSelector.hpp +++ b/src/hotspot/share/gc/z/zRelocationSetSelector.hpp @@ -28,7 +28,6 @@ #include "memory/allocation.hpp" class ZPage; -class ZRelocationSet; class ZRelocationSetSelectorGroupStats { friend class ZRelocationSetSelectorGroup; @@ -75,10 +74,8 @@ class ZRelocationSetSelectorGroup { const size_t _page_size; const size_t _object_size_limit; const size_t _fragmentation_limit; - ZArray _registered_pages; - ZPage** _sorted_pages; - size_t _nselected; + size_t _forwarding_entries; ZRelocationSetSelectorGroupStats _stats; bool is_disabled(); @@ -91,14 +88,13 @@ class ZRelocationSetSelectorGroup { uint8_t page_type, size_t page_size, size_t object_size_limit); - ~ZRelocationSetSelectorGroup(); void register_live_page(ZPage* page); void register_garbage_page(ZPage* page); void select(); - ZPage* const* selected() const; - size_t nselected() const; + const ZArray* selected() const; + size_t forwarding_entries() const; const ZRelocationSetSelectorGroupStats& stats() const; }; @@ -108,6 +104,7 @@ class ZRelocationSetSelector : public StackObj { ZRelocationSetSelectorGroup _small; ZRelocationSetSelectorGroup _medium; ZRelocationSetSelectorGroup _large; + ZArray _garbage_pages; size_t total() const; size_t empty() const; @@ -119,7 +116,16 @@ class ZRelocationSetSelector : public StackObj { void register_live_page(ZPage* page); void register_garbage_page(ZPage* page); - void select(ZRelocationSet* relocation_set); + + bool should_free_garbage_pages(int bulk) const; + const ZArray* garbage_pages() const; + void clear_garbage_pages(); + + void select(); + + const ZArray* small() const; + const ZArray* medium() const; + size_t forwarding_entries() const; ZRelocationSetSelectorStats stats() const; }; diff --git a/src/hotspot/share/gc/z/zRelocationSetSelector.inline.hpp b/src/hotspot/share/gc/z/zRelocationSetSelector.inline.hpp index 37b7839511d..11c48394fc9 100644 --- a/src/hotspot/share/gc/z/zRelocationSetSelector.inline.hpp +++ b/src/hotspot/share/gc/z/zRelocationSetSelector.inline.hpp @@ -24,6 +24,8 @@ #ifndef SHARE_GC_Z_ZRELOCATIONSETSELECTOR_INLINE_HPP #define SHARE_GC_Z_ZRELOCATIONSETSELECTOR_INLINE_HPP +#include "gc/z/zArray.inline.hpp" +#include "gc/z/zPage.inline.hpp" #include "gc/z/zRelocationSetSelector.hpp" inline size_t ZRelocationSetSelectorGroupStats::npages() const { @@ -66,18 +68,81 @@ inline const ZRelocationSetSelectorGroupStats& ZRelocationSetSelectorStats::larg return _large; } -inline ZPage* const* ZRelocationSetSelectorGroup::selected() const { - return _sorted_pages; +inline void ZRelocationSetSelectorGroup::register_live_page(ZPage* page) { + const uint8_t type = page->type(); + const size_t size = page->size(); + const size_t live = page->live_bytes(); + const size_t garbage = size - live; + + if (garbage > _fragmentation_limit) { + _registered_pages.append(page); + } + + _stats._npages++; + _stats._total += size; + _stats._live += live; + _stats._garbage += garbage; +} + +inline void ZRelocationSetSelectorGroup::register_garbage_page(ZPage* page) { + const size_t size = page->size(); + + _stats._npages++; + _stats._total += size; + _stats._garbage += size; + _stats._empty += size; +} + +inline const ZArray* ZRelocationSetSelectorGroup::selected() const { + return &_registered_pages; } -inline size_t ZRelocationSetSelectorGroup::nselected() const { - return _nselected; +inline size_t ZRelocationSetSelectorGroup::forwarding_entries() const { + return _forwarding_entries; } inline const ZRelocationSetSelectorGroupStats& ZRelocationSetSelectorGroup::stats() const { return _stats; } +inline void ZRelocationSetSelector::register_live_page(ZPage* page) { + const uint8_t type = page->type(); + + if (type == ZPageTypeSmall) { + _small.register_live_page(page); + } else if (type == ZPageTypeMedium) { + _medium.register_live_page(page); + } else { + _large.register_live_page(page); + } +} + +inline void ZRelocationSetSelector::register_garbage_page(ZPage* page) { + const uint8_t type = page->type(); + + if (type == ZPageTypeSmall) { + _small.register_garbage_page(page); + } else if (type == ZPageTypeMedium) { + _medium.register_garbage_page(page); + } else { + _large.register_garbage_page(page); + } + + _garbage_pages.append(page); +} + +inline bool ZRelocationSetSelector::should_free_garbage_pages(int bulk) const { + return _garbage_pages.length() >= bulk && _garbage_pages.is_nonempty(); +} + +inline const ZArray* ZRelocationSetSelector::garbage_pages() const { + return &_garbage_pages; +} + +inline void ZRelocationSetSelector::clear_garbage_pages() { + return _garbage_pages.clear(); +} + inline size_t ZRelocationSetSelector::total() const { return _small.stats().total() + _medium.stats().total() + _large.stats().total(); } @@ -94,4 +159,16 @@ inline size_t ZRelocationSetSelector::compacting_to() const { return _small.stats().compacting_to() + _medium.stats().compacting_to() + _large.stats().compacting_to(); } +inline const ZArray* ZRelocationSetSelector::small() const { + return _small.selected(); +} + +inline const ZArray* ZRelocationSetSelector::medium() const { + return _medium.selected(); +} + +inline size_t ZRelocationSetSelector::forwarding_entries() const { + return _small.forwarding_entries() + _medium.forwarding_entries(); +} + #endif // SHARE_GC_Z_ZRELOCATIONSETSELECTOR_INLINE_HPP diff --git a/src/hotspot/share/gc/z/zRootsIterator.cpp b/src/hotspot/share/gc/z/zRootsIterator.cpp index 5d5e7190c8a..ec1887e2de2 100644 --- a/src/hotspot/share/gc/z/zRootsIterator.cpp +++ b/src/hotspot/share/gc/z/zRootsIterator.cpp @@ -22,53 +22,57 @@ */ #include "precompiled.hpp" +#include "classfile/classLoaderDataGraph.hpp" #include "gc/shared/oopStorageSetParState.inline.hpp" #include "gc/z/zNMethod.hpp" #include "gc/z/zNMethodTable.hpp" #include "gc/z/zRootsIterator.hpp" #include "gc/z/zStat.hpp" #include "memory/resourceArea.hpp" -#include "prims/jvmtiExport.hpp" +#include "prims/jvmtiTagMap.hpp" #include "runtime/atomic.hpp" #include "runtime/globals.hpp" #include "runtime/safepoint.hpp" #include "utilities/debug.hpp" -static const ZStatSubPhase ZSubPhasePauseRootsJVMTIWeakExport("Pause Roots JVMTIWeakExport"); static const ZStatSubPhase ZSubPhaseConcurrentRootsOopStorageSet("Concurrent Roots OopStorageSet"); static const ZStatSubPhase ZSubPhaseConcurrentRootsClassLoaderDataGraph("Concurrent Roots ClassLoaderDataGraph"); static const ZStatSubPhase ZSubPhaseConcurrentRootsJavaThreads("Concurrent Roots JavaThreads"); static const ZStatSubPhase ZSubPhaseConcurrentRootsCodeCache("Concurrent Roots CodeCache"); -static const ZStatSubPhase ZSubPhasePauseWeakRootsJVMTIWeakExport("Pause Weak Roots JVMTIWeakExport"); +static const ZStatSubPhase ZSubPhasePauseWeakRootsJVMTITagMap("Pause Weak Roots JVMTITagMap"); static const ZStatSubPhase ZSubPhaseConcurrentWeakRootsOopStorageSet("Concurrent Weak Roots OopStorageSet"); -template -ZParallelOopsDo::ZParallelOopsDo(T* iter) : - _iter(iter), - _completed(false) {} - -template -void ZParallelOopsDo::oops_do(ZRootsIteratorClosure* cl) { +template +template +void ZParallelApply::apply(ClosureType* cl) { if (!Atomic::load(&_completed)) { - (_iter->*F)(cl); + _iter.apply(cl); if (!Atomic::load(&_completed)) { Atomic::store(&_completed, true); } } } -template -ZSerialWeakOopsDo::ZSerialWeakOopsDo(T* iter) : - _iter(iter), - _claimed(false) {} - -template -void ZSerialWeakOopsDo::weak_oops_do(BoolObjectClosure* is_alive, ZRootsIteratorClosure* cl) { +template +void ZSerialWeakApply::apply(BoolObjectClosure* is_alive, OopClosure* cl) { if (!Atomic::load(&_claimed) && Atomic::cmpxchg(&_claimed, false, true) == false) { - (_iter->*F)(is_alive, cl); + _iter.apply(is_alive, cl); } } +ZStrongOopStorageSetIterator::ZStrongOopStorageSetIterator() : + _iter() {} + +void ZStrongOopStorageSetIterator::apply(OopClosure* cl) { + ZStatTimer timer(ZSubPhaseConcurrentRootsOopStorageSet); + _iter.oops_do(cl); +} + +void ZStrongCLDsIterator::apply(CLDClosure* cl) { + ZStatTimer timer(ZSubPhaseConcurrentRootsClassLoaderDataGraph); + ClassLoaderDataGraph::always_strong_cld_do(cl); +} + ZJavaThreadsIterator::ZJavaThreadsIterator() : _threads(), _claimed(0) {} @@ -77,119 +81,84 @@ uint ZJavaThreadsIterator::claim() { return Atomic::fetch_and_add(&_claimed, 1u); } -void ZJavaThreadsIterator::threads_do(ThreadClosure* cl) { +void ZJavaThreadsIterator::apply(ThreadClosure* cl) { + ZStatTimer timer(ZSubPhaseConcurrentRootsJavaThreads); + + // The resource mark is needed because interpreter oop maps are + // not reused in concurrent mode. Instead, they are temporary and + // resource allocated. + ResourceMark _rm; + for (uint i = claim(); i < _threads.length(); i = claim()) { cl->do_thread(_threads.thread_at(i)); } } -void ZRelocateRoots::oops_do(OopClosure* cl) { - ZStatTimer timer(ZSubPhasePauseRootsJVMTIWeakExport); - AlwaysTrueClosure always_alive; - JvmtiExport::weak_oops_do(&always_alive, cl); -} - -ZConcurrentRootsIterator::ZConcurrentRootsIterator(int cld_claim) : - _oop_storage_set_iter(), - _java_threads_iter(), - _cld_claim(cld_claim), - _oop_storage_set(this), - _class_loader_data_graph(this), - _java_threads(this), - _code_cache(this) { - ClassLoaderDataGraph::clear_claimed_marks(cld_claim); +ZNMethodsIterator::ZNMethodsIterator() { if (!ClassUnloading) { - ZNMethodTable::nmethods_do_begin(); + ZNMethod::nmethods_do_begin(); } } -ZConcurrentRootsIterator::~ZConcurrentRootsIterator() { +ZNMethodsIterator::~ZNMethodsIterator() { if (!ClassUnloading) { - ZNMethodTable::nmethods_do_end(); + ZNMethod::nmethods_do_end(); } } -void ZConcurrentRootsIterator::do_oop_storage_set(ZRootsIteratorClosure* cl) { - ZStatTimer timer(ZSubPhaseConcurrentRootsOopStorageSet); - _oop_storage_set_iter.oops_do(cl); -} - -void ZConcurrentRootsIterator::do_class_loader_data_graph(ZRootsIteratorClosure* cl) { - ZStatTimer timer(ZSubPhaseConcurrentRootsClassLoaderDataGraph); - CLDToOopClosure cld_cl(cl, _cld_claim); - ClassLoaderDataGraph::always_strong_cld_do(&cld_cl); -} - -void ZConcurrentRootsIterator::do_code_cache(ZRootsIteratorClosure* cl) { +void ZNMethodsIterator::apply(NMethodClosure* cl) { ZStatTimer timer(ZSubPhaseConcurrentRootsCodeCache); - ZNMethod::oops_do(cl, cl->should_disarm_nmethods()); + ZNMethod::nmethods_do(cl); } -class ZConcurrentRootsIteratorThreadClosure : public ThreadClosure { -private: - // The resource mark is needed because interpreter oop maps are - // not reused in concurrent mode. Instead, they are temporary and - // resource allocated. - ResourceMark _rm; - ZRootsIteratorClosure* const _cl; - -public: - ZConcurrentRootsIteratorThreadClosure(ZRootsIteratorClosure* cl) : - _cl(cl) {} - - virtual void do_thread(Thread* thread) { - _cl->do_thread(thread); +ZConcurrentRootsIterator::ZConcurrentRootsIterator(int cld_claim) { + if (cld_claim != ClassLoaderData::_claim_none) { + ClassLoaderDataGraph::clear_claimed_marks(cld_claim); } -}; - -void ZConcurrentRootsIterator::do_java_threads(ZRootsIteratorClosure* cl) { - ZStatTimer timer(ZSubPhaseConcurrentRootsJavaThreads); - ZConcurrentRootsIteratorThreadClosure thread_cl(cl); - _java_threads_iter.threads_do(&thread_cl); } -void ZConcurrentRootsIterator::oops_do(ZRootsIteratorClosure* cl) { - _oop_storage_set.oops_do(cl); - _class_loader_data_graph.oops_do(cl); - _java_threads.oops_do(cl); +void ZConcurrentRootsIterator::apply(OopClosure* cl, + CLDClosure* cld_cl, + ThreadClosure* thread_cl, + NMethodClosure* nm_cl) { + _oop_storage_set.apply(cl); + _class_loader_data_graph.apply(cld_cl); + _java_threads.apply(thread_cl); if (!ClassUnloading) { - _code_cache.oops_do(cl); + _nmethods.apply(nm_cl); } } ZWeakRootsIterator::ZWeakRootsIterator() : - _jvmti_weak_export(this) { + _jvmti_tag_map() { assert(SafepointSynchronize::is_at_safepoint(), "Should be at safepoint"); } -void ZWeakRootsIterator::do_jvmti_weak_export(BoolObjectClosure* is_alive, ZRootsIteratorClosure* cl) { - ZStatTimer timer(ZSubPhasePauseWeakRootsJVMTIWeakExport); - JvmtiExport::weak_oops_do(is_alive, cl); +void ZWeakRootsIterator::apply(BoolObjectClosure* is_alive, OopClosure* cl) { + _jvmti_tag_map.apply(is_alive, cl); } -void ZWeakRootsIterator::weak_oops_do(BoolObjectClosure* is_alive, ZRootsIteratorClosure* cl) { - _jvmti_weak_export.weak_oops_do(is_alive, cl); +void ZJVMTITagMapIterator::apply(BoolObjectClosure* is_alive, OopClosure* cl) { + ZStatTimer timer(ZSubPhasePauseWeakRootsJVMTITagMap); + JvmtiTagMap::weak_oops_do(is_alive, cl); } -void ZWeakRootsIterator::oops_do(ZRootsIteratorClosure* cl) { - AlwaysTrueClosure always_alive; - weak_oops_do(&always_alive, cl); -} +ZWeakOopStorageSetIterator::ZWeakOopStorageSetIterator() : + _iter() {} -ZConcurrentWeakRootsIterator::ZConcurrentWeakRootsIterator() : - _oop_storage_set_iter(), - _oop_storage_set(this) { +void ZWeakOopStorageSetIterator::apply(OopClosure* cl) { + ZStatTimer timer(ZSubPhaseConcurrentWeakRootsOopStorageSet); + _iter.oops_do(cl); } -void ZConcurrentWeakRootsIterator::report_num_dead() { - _oop_storage_set_iter.report_num_dead(); +void ZWeakOopStorageSetIterator::report_num_dead() { + _iter.report_num_dead(); } -void ZConcurrentWeakRootsIterator::do_oop_storage_set(ZRootsIteratorClosure* cl) { - ZStatTimer timer(ZSubPhaseConcurrentWeakRootsOopStorageSet); - _oop_storage_set_iter.oops_do(cl); +void ZConcurrentWeakRootsIterator::report_num_dead() { + _oop_storage_set.iter().report_num_dead(); } -void ZConcurrentWeakRootsIterator::oops_do(ZRootsIteratorClosure* cl) { - _oop_storage_set.oops_do(cl); +void ZConcurrentWeakRootsIterator::apply(OopClosure* cl) { + _oop_storage_set.apply(cl); } diff --git a/src/hotspot/share/gc/z/zRootsIterator.hpp b/src/hotspot/share/gc/z/zRootsIterator.hpp index 87626b09ab1..57b7ce6372d 100644 --- a/src/hotspot/share/gc/z/zRootsIterator.hpp +++ b/src/hotspot/share/gc/z/zRootsIterator.hpp @@ -24,46 +24,56 @@ #ifndef SHARE_GC_Z_ZROOTSITERATOR_HPP #define SHARE_GC_Z_ZROOTSITERATOR_HPP -#include "classfile/classLoaderDataGraph.hpp" #include "gc/shared/oopStorageSetParState.hpp" -#include "memory/allocation.hpp" +#include "logging/log.hpp" #include "memory/iterator.hpp" #include "runtime/threadSMR.hpp" -class ZRootsIteratorClosure; - -typedef OopStorageSetStrongParState ZOopStorageSetStrongIterator; -typedef OopStorageSetWeakParState ZOopStorageSetWeakIterator; - -template -class ZParallelOopsDo { +template +class ZParallelApply { private: - T* const _iter; + Iterator _iter; volatile bool _completed; public: - ZParallelOopsDo(T* iter); - void oops_do(ZRootsIteratorClosure* cl); + ZParallelApply() : + _iter(), + _completed(false) {} + + template + void apply(ClosureType* cl); + + Iterator& iter() { + return _iter; + } }; -template -class ZSerialWeakOopsDo { +template +class ZSerialWeakApply { private: - T* const _iter; + Iterator _iter; volatile bool _claimed; public: - ZSerialWeakOopsDo(T* iter); - void weak_oops_do(BoolObjectClosure* is_alive, ZRootsIteratorClosure* cl); + ZSerialWeakApply() : + _iter(), + _claimed(false) {} + + void apply(BoolObjectClosure* is_alive, OopClosure* cl); }; -class ZRootsIteratorClosure : public OopClosure { +class ZStrongOopStorageSetIterator { + OopStorageSetStrongParState _iter; + public: - virtual void do_thread(Thread* thread) {} + ZStrongOopStorageSetIterator(); - virtual bool should_disarm_nmethods() const { - return false; - } + void apply(OopClosure* cl); +}; + +class ZStrongCLDsIterator { +public: + void apply(CLDClosure* cl); }; class ZJavaThreadsIterator { @@ -76,80 +86,66 @@ class ZJavaThreadsIterator { public: ZJavaThreadsIterator(); - void threads_do(ThreadClosure* cl); + void apply(ThreadClosure* cl); }; -class ZRelocateRoots : public AllStatic { +class ZNMethodsIterator { public: - static void oops_do(OopClosure* cl); + ZNMethodsIterator(); + ~ZNMethodsIterator(); + + void apply(NMethodClosure* cl); }; class ZConcurrentRootsIterator { private: - ZOopStorageSetStrongIterator _oop_storage_set_iter; - ZJavaThreadsIterator _java_threads_iter; - const int _cld_claim; - - void do_oop_storage_set(ZRootsIteratorClosure* cl); - void do_java_threads(ZRootsIteratorClosure* cl); - void do_class_loader_data_graph(ZRootsIteratorClosure* cl); - void do_code_cache(ZRootsIteratorClosure* cl); - - ZParallelOopsDo _oop_storage_set; - ZParallelOopsDo _class_loader_data_graph; - ZParallelOopsDo _java_threads; - ZParallelOopsDo _code_cache; + ZParallelApply _oop_storage_set; + ZParallelApply _class_loader_data_graph; + ZParallelApply _java_threads; + ZParallelApply _nmethods; public: ZConcurrentRootsIterator(int cld_claim); - ~ZConcurrentRootsIterator(); - void oops_do(ZRootsIteratorClosure* cl); + void apply(OopClosure* cl, + CLDClosure* cld_cl, + ThreadClosure* thread_cl, + NMethodClosure* nm_cl); }; -class ZConcurrentRootsIteratorClaimStrong : public ZConcurrentRootsIterator { -public: - ZConcurrentRootsIteratorClaimStrong() : - ZConcurrentRootsIterator(ClassLoaderData::_claim_strong) {} -}; +class ZWeakOopStorageSetIterator { +private: + OopStorageSetWeakParState _iter; -class ZConcurrentRootsIteratorClaimOther : public ZConcurrentRootsIterator { public: - ZConcurrentRootsIteratorClaimOther() : - ZConcurrentRootsIterator(ClassLoaderData::_claim_other) {} + ZWeakOopStorageSetIterator(); + + void apply(OopClosure* cl); + + void report_num_dead(); }; -class ZConcurrentRootsIteratorClaimNone : public ZConcurrentRootsIterator { +class ZJVMTITagMapIterator { public: - ZConcurrentRootsIteratorClaimNone() : - ZConcurrentRootsIterator(ClassLoaderData::_claim_none) {} + void apply(BoolObjectClosure* is_alive, OopClosure* cl); }; class ZWeakRootsIterator { private: - void do_jvmti_weak_export(BoolObjectClosure* is_alive, ZRootsIteratorClosure* cl); - - ZSerialWeakOopsDo _jvmti_weak_export; + ZSerialWeakApply _jvmti_tag_map; public: ZWeakRootsIterator(); - void weak_oops_do(BoolObjectClosure* is_alive, ZRootsIteratorClosure* cl); - void oops_do(ZRootsIteratorClosure* cl); + void apply(BoolObjectClosure* is_alive, OopClosure* cl); }; class ZConcurrentWeakRootsIterator { private: - ZOopStorageSetWeakIterator _oop_storage_set_iter; - - void do_oop_storage_set(ZRootsIteratorClosure* cl); - - ZParallelOopsDo _oop_storage_set; + ZParallelApply _oop_storage_set; public: - ZConcurrentWeakRootsIterator(); - - void oops_do(ZRootsIteratorClosure* cl); + void apply(OopClosure* cl); void report_num_dead(); }; diff --git a/src/hotspot/share/gc/z/zStat.cpp b/src/hotspot/share/gc/z/zStat.cpp index 73ee5494de0..5d2933289d2 100644 --- a/src/hotspot/share/gc/z/zStat.cpp +++ b/src/hotspot/share/gc/z/zStat.cpp @@ -1140,12 +1140,17 @@ void ZStatMark::print() { // Stat relocation // ZRelocationSetSelectorStats ZStatRelocation::_stats; +size_t ZStatRelocation::_forwarding_usage; bool ZStatRelocation::_success; void ZStatRelocation::set_at_select_relocation_set(const ZRelocationSetSelectorStats& stats) { _stats = stats; } +void ZStatRelocation::set_at_install_relocation_set(size_t forwarding_usage) { + _forwarding_usage = forwarding_usage; +} + void ZStatRelocation::set_at_relocate_end(bool success) { _success = success; } @@ -1169,6 +1174,7 @@ void ZStatRelocation::print() { } print("Large", _stats.large()); + log_info(gc, reloc)("Forwarding Usage: " SIZE_FORMAT "M", _forwarding_usage / M); log_info(gc, reloc)("Relocation: %s", _success ? "Successful" : "Incomplete"); } diff --git a/src/hotspot/share/gc/z/zStat.hpp b/src/hotspot/share/gc/z/zStat.hpp index 3faac3b8ea5..6d44c3c99c5 100644 --- a/src/hotspot/share/gc/z/zStat.hpp +++ b/src/hotspot/share/gc/z/zStat.hpp @@ -423,12 +423,14 @@ class ZStatMark : public AllStatic { class ZStatRelocation : public AllStatic { private: static ZRelocationSetSelectorStats _stats; + static size_t _forwarding_usage; static bool _success; static void print(const char* name, const ZRelocationSetSelectorGroupStats& group); public: static void set_at_select_relocation_set(const ZRelocationSetSelectorStats& stats); + static void set_at_install_relocation_set(size_t forwarding_usage); static void set_at_relocate_end(bool success); static void print(); diff --git a/src/hotspot/share/gc/z/zUnload.cpp b/src/hotspot/share/gc/z/zUnload.cpp index 6eb23088bf3..e4d2cfc6eec 100644 --- a/src/hotspot/share/gc/z/zUnload.cpp +++ b/src/hotspot/share/gc/z/zUnload.cpp @@ -72,7 +72,7 @@ class ZIsUnloadingBehaviour : public IsUnloadingBehaviour { ZReentrantLock* const lock = ZNMethod::lock_for_nmethod(nm); ZLocker locker(lock); ZIsUnloadingOopClosure cl; - ZNMethod::nmethod_oops_do(nm, &cl); + ZNMethod::nmethod_oops_do_inner(nm, &cl); return cl.is_unloading(); } }; diff --git a/src/hotspot/share/gc/z/zVerify.cpp b/src/hotspot/share/gc/z/zVerify.cpp index 6ca1ebc888f..1481a8576d5 100644 --- a/src/hotspot/share/gc/z/zVerify.cpp +++ b/src/hotspot/share/gc/z/zVerify.cpp @@ -25,6 +25,7 @@ #include "classfile/classLoaderData.hpp" #include "gc/z/zAddress.inline.hpp" #include "gc/z/zHeap.inline.hpp" +#include "gc/z/zNMethod.hpp" #include "gc/z/zOop.hpp" #include "gc/z/zPageAllocator.hpp" #include "gc/z/zResurrection.hpp" @@ -66,7 +67,7 @@ static void z_verify_possibly_weak_oop(oop* p) { } } -class ZVerifyRootClosure : public ZRootsIteratorClosure { +class ZVerifyRootClosure : public OopClosure { private: const bool _verify_fixed; @@ -89,8 +90,6 @@ class ZVerifyRootClosure : public ZRootsIteratorClosure { ShouldNotReachHere(); } - virtual void do_thread(Thread* thread); - bool verify_fixed() const { return _verify_fixed; } @@ -176,19 +175,7 @@ class ZVerifyStack : public OopClosure { } }; -void ZVerifyRootClosure::do_thread(Thread* thread) { - thread->oops_do_no_frames(this, NULL); - - JavaThread* const jt = thread->as_Java_thread(); - if (!jt->has_last_Java_frame()) { - return; - } - - ZVerifyStack verify_stack(this, jt); - verify_stack.verify_frames(); -} - -class ZVerifyOopClosure : public ClaimMetadataVisitingOopIterateClosure, public ZRootsIteratorClosure { +class ZVerifyOopClosure : public ClaimMetadataVisitingOopIterateClosure { private: const bool _verify_weaks; @@ -214,44 +201,92 @@ class ZVerifyOopClosure : public ClaimMetadataVisitingOopIterateClosure, public virtual ReferenceIterationMode reference_iteration_mode() { return _verify_weaks ? DO_FIELDS : DO_FIELDS_EXCEPT_REFERENT; } +}; -#ifdef ASSERT - // Verification handled by the closure itself - virtual bool should_verify_oops() { - return false; +typedef ClaimingCLDToOopClosure ZVerifyCLDClosure; + +class ZVerifyThreadClosure : public ThreadClosure { +private: + ZVerifyRootClosure* const _cl; + +public: + ZVerifyThreadClosure(ZVerifyRootClosure* cl) : + _cl(cl) {} + + virtual void do_thread(Thread* thread) { + thread->oops_do_no_frames(_cl, NULL); + + JavaThread* const jt = thread->as_Java_thread(); + if (!jt->has_last_Java_frame()) { + return; + } + + ZVerifyStack verify_stack(_cl, jt); + verify_stack.verify_frames(); } -#endif }; -template -void ZVerify::roots(bool verify_fixed) { - assert(SafepointSynchronize::is_at_safepoint(), "Must be at a safepoint"); - assert(!ZResurrection::is_blocked(), "Invalid phase"); +class ZVerifyNMethodClosure : public NMethodClosure { +private: + OopClosure* const _cl; + BarrierSetNMethod* const _bs_nm; + const bool _verify_fixed; + + bool trust_nmethod_state() const { + // The root iterator will visit non-processed + // nmethods class unloading is turned off. + return ClassUnloading || _verify_fixed; + } - if (ZVerifyRoots) { - ZVerifyRootClosure cl(verify_fixed); - RootsIterator iter; - iter.oops_do(&cl); +public: + ZVerifyNMethodClosure(OopClosure* cl, bool verify_fixed) : + _cl(cl), + _bs_nm(BarrierSet::barrier_set()->barrier_set_nmethod()), + _verify_fixed(verify_fixed) {} + + virtual void do_nmethod(nmethod* nm) { + assert(!trust_nmethod_state() || !_bs_nm->is_armed(nm), "Should not encounter any armed nmethods"); + + ZNMethod::nmethod_oops_do(nm, _cl); } -} +}; -void ZVerify::roots_weak() { - roots(true /* verify_fixed */); +void ZVerify::roots_concurrent_strong(bool verify_fixed) { + ZVerifyRootClosure cl(verify_fixed); + ZVerifyCLDClosure cld_cl(&cl); + ZVerifyThreadClosure thread_cl(&cl); + ZVerifyNMethodClosure nm_cl(&cl, verify_fixed); + + ZConcurrentRootsIterator iter(ClassLoaderData::_claim_none); + iter.apply(&cl, + &cld_cl, + &thread_cl, + &nm_cl); } -void ZVerify::roots_concurrent_strong(bool verify_fixed) { - roots(verify_fixed); +void ZVerify::roots_weak() { + AlwaysTrueClosure is_alive; + ZVerifyRootClosure cl(true /* verify_fixed */); + ZWeakRootsIterator iter; + iter.apply(&is_alive, &cl); } void ZVerify::roots_concurrent_weak() { - roots(true /* verify_fixed */); + ZVerifyRootClosure cl(true /* verify_fixed */); + ZConcurrentWeakRootsIterator iter; + iter.apply(&cl); } void ZVerify::roots(bool verify_concurrent_strong, bool verify_weaks) { - roots_concurrent_strong(verify_concurrent_strong); - if (verify_weaks) { - roots_weak(); - roots_concurrent_weak(); + assert(SafepointSynchronize::is_at_safepoint(), "Must be at a safepoint"); + assert(!ZResurrection::is_blocked(), "Invalid phase"); + + if (ZVerifyRoots) { + roots_concurrent_strong(verify_concurrent_strong); + if (verify_weaks) { + roots_weak(); + roots_concurrent_weak(); + } } } diff --git a/src/hotspot/share/gc/z/zVerify.hpp b/src/hotspot/share/gc/z/zVerify.hpp index 4d405b957bb..400fc05a589 100644 --- a/src/hotspot/share/gc/z/zVerify.hpp +++ b/src/hotspot/share/gc/z/zVerify.hpp @@ -31,10 +31,8 @@ class ZPageAllocator; class ZVerify : public AllStatic { private: - template static void roots(bool verify_fixed); - - static void roots_weak(); static void roots_concurrent_strong(bool verify_fixed); + static void roots_weak(); static void roots_concurrent_weak(); static void roots(bool verify_concurrent_strong, bool verify_weaks); diff --git a/src/hotspot/share/gc/z/zWeakRootsProcessor.cpp b/src/hotspot/share/gc/z/zWeakRootsProcessor.cpp index 0c22b3efff4..7c88523b37c 100644 --- a/src/hotspot/share/gc/z/zWeakRootsProcessor.cpp +++ b/src/hotspot/share/gc/z/zWeakRootsProcessor.cpp @@ -41,13 +41,13 @@ class ZProcessWeakRootsTask : public ZTask { virtual void work() { ZPhantomIsAliveObjectClosure is_alive; ZPhantomKeepAliveOopClosure keep_alive; - _weak_roots.weak_oops_do(&is_alive, &keep_alive); + _weak_roots.apply(&is_alive, &keep_alive); } }; void ZWeakRootsProcessor::process_weak_roots() { ZProcessWeakRootsTask task; - _workers->run_parallel(&task); + _workers->run_serial(&task); } class ZProcessConcurrentWeakRootsTask : public ZTask { @@ -65,7 +65,7 @@ class ZProcessConcurrentWeakRootsTask : public ZTask { virtual void work() { ZPhantomCleanOopClosure cl; - _concurrent_weak_roots.oops_do(&cl); + _concurrent_weak_roots.apply(&cl); } }; diff --git a/src/hotspot/share/interpreter/interpreterRuntime.cpp b/src/hotspot/share/interpreter/interpreterRuntime.cpp index 40c7d098009..07d3c0ea0b8 100644 --- a/src/hotspot/share/interpreter/interpreterRuntime.cpp +++ b/src/hotspot/share/interpreter/interpreterRuntime.cpp @@ -1172,10 +1172,7 @@ JRT_ENTRY(void, InterpreterRuntime::at_safepoint(JavaThread* thread)) } JRT_END -JRT_ENTRY(void, InterpreterRuntime::at_unwind(JavaThread* thread)) - // JRT_END does an implicit safepoint check, hence we are guaranteed to block - // if this is called during a safepoint - +JRT_LEAF(void, InterpreterRuntime::at_unwind(JavaThread* thread)) // This function is called by the interpreter when the return poll found a reason // to call the VM. The reason could be that we are returning into a not yet safe // to access frame. We handle that below. diff --git a/src/hotspot/share/interpreter/templateInterpreter.cpp b/src/hotspot/share/interpreter/templateInterpreter.cpp index 4bcd1333891..b65e1d57a8b 100644 --- a/src/hotspot/share/interpreter/templateInterpreter.cpp +++ b/src/hotspot/share/interpreter/templateInterpreter.cpp @@ -104,6 +104,19 @@ EntryPoint::EntryPoint(address bentry, address zentry, address centry, address s _entry[vtos] = ventry; } +EntryPoint::EntryPoint(address aentry, address ientry, address lentry, address fentry, address dentry, address ventry) { + assert(number_of_states == 10, "check the code below"); + _entry[btos] = ientry; + _entry[ztos] = ientry; + _entry[ctos] = ientry; + _entry[stos] = ientry; + _entry[atos] = aentry; + _entry[itos] = ientry; + _entry[ltos] = lentry; + _entry[ftos] = fentry; + _entry[dtos] = dentry; + _entry[vtos] = ventry; +} void EntryPoint::set_entry(TosState state, address entry) { assert(0 <= state && state < number_of_states, "state out of bounds"); diff --git a/src/hotspot/share/interpreter/templateInterpreter.hpp b/src/hotspot/share/interpreter/templateInterpreter.hpp index 2ff62e15d33..23a6a7f7007 100644 --- a/src/hotspot/share/interpreter/templateInterpreter.hpp +++ b/src/hotspot/share/interpreter/templateInterpreter.hpp @@ -48,7 +48,8 @@ class EntryPoint { // Construction EntryPoint(); EntryPoint(address bentry, address zentry, address centry, address sentry, address aentry, address ientry, address lentry, address fentry, address dentry, address ventry); - + // Will use the ientry for each of [bzcs]entry + EntryPoint(address aentry, address ientry, address lentry, address fentry, address dentry, address ventry); // Attributes address entry(TosState state) const; // return target address for a given tosca state void set_entry(TosState state, address entry); // set target address for a given tosca state diff --git a/src/hotspot/share/interpreter/templateInterpreterGenerator.cpp b/src/hotspot/share/interpreter/templateInterpreterGenerator.cpp index 51b95bbd76b..be26ef206bd 100644 --- a/src/hotspot/share/interpreter/templateInterpreterGenerator.cpp +++ b/src/hotspot/share/interpreter/templateInterpreterGenerator.cpp @@ -68,10 +68,6 @@ void TemplateInterpreterGenerator::generate_all() { CodeletMark cm(_masm, "bytecode tracing support"); Interpreter::_trace_code = EntryPoint( - generate_trace_code(btos), - generate_trace_code(ztos), - generate_trace_code(ctos), - generate_trace_code(stos), generate_trace_code(atos), generate_trace_code(itos), generate_trace_code(ltos), @@ -83,50 +79,54 @@ void TemplateInterpreterGenerator::generate_all() { #endif // !PRODUCT { CodeletMark cm(_masm, "return entry points"); - const int index_size = sizeof(u2); Interpreter::_return_entry[0] = EntryPoint(); for (int i = 1; i < Interpreter::number_of_return_entries; i++) { - address return_itos = generate_return_entry_for(itos, i, index_size); Interpreter::_return_entry[i] = EntryPoint( - return_itos, - return_itos, - return_itos, - return_itos, - generate_return_entry_for(atos, i, index_size), - return_itos, - generate_return_entry_for(ltos, i, index_size), - generate_return_entry_for(ftos, i, index_size), - generate_return_entry_for(dtos, i, index_size), - generate_return_entry_for(vtos, i, index_size) + generate_return_entry_for(atos, i, sizeof(u2)), + generate_return_entry_for(itos, i, sizeof(u2)), + generate_return_entry_for(ltos, i, sizeof(u2)), + generate_return_entry_for(ftos, i, sizeof(u2)), + generate_return_entry_for(dtos, i, sizeof(u2)), + generate_return_entry_for(vtos, i, sizeof(u2)) ); } } { CodeletMark cm(_masm, "invoke return entry points"); - // These states are in order specified in TosState, except btos/ztos/ctos/stos are - // really the same as itos since there is no top of stack optimization for these types - const TosState states[] = {itos, itos, itos, itos, itos, ltos, ftos, dtos, atos, vtos, ilgl}; + // These states are in order specified in TosState, except btos/ztos/ctos/stos which + // are the same as itos since there is no top of stack optimization for these types + const TosState states[] = {ilgl, ilgl, ilgl, ilgl, itos, ltos, ftos, dtos, atos, vtos, ilgl}; const int invoke_length = Bytecodes::length_for(Bytecodes::_invokestatic); const int invokeinterface_length = Bytecodes::length_for(Bytecodes::_invokeinterface); const int invokedynamic_length = Bytecodes::length_for(Bytecodes::_invokedynamic); - for (int i = 0; i < Interpreter::number_of_return_addrs; i++) { + assert(invoke_length >= 0 && invoke_length < Interpreter::number_of_return_entries, "invariant"); + assert(invokeinterface_length >= 0 && invokeinterface_length < Interpreter::number_of_return_entries, "invariant"); + + for (int i = itos; i < Interpreter::number_of_return_addrs; i++) { TosState state = states[i]; assert(state != ilgl, "states array is wrong above"); - Interpreter::_invoke_return_entry[i] = generate_return_entry_for(state, invoke_length, sizeof(u2)); - Interpreter::_invokeinterface_return_entry[i] = generate_return_entry_for(state, invokeinterface_length, sizeof(u2)); - Interpreter::_invokedynamic_return_entry[i] = generate_return_entry_for(state, invokedynamic_length, sizeof(u4)); + + // Reuse generated entry points + Interpreter::_invoke_return_entry[i] = Interpreter::_return_entry[invoke_length].entry(state); + Interpreter::_invokeinterface_return_entry[i] = Interpreter::_return_entry[invokeinterface_length].entry(state); + + Interpreter::_invokedynamic_return_entry[i] = generate_return_entry_for(state, invokedynamic_length, sizeof(u4)); + } + + // set itos entry points for btos/ztos/ctos/stos + for (int i = 0; i < itos; i++) { + Interpreter::_invoke_return_entry[i] = Interpreter::_invoke_return_entry[itos]; + Interpreter::_invokeinterface_return_entry[i] = Interpreter::_invokeinterface_return_entry[itos]; + Interpreter::_invokedynamic_return_entry[i] = Interpreter::_invokedynamic_return_entry[itos]; } } { CodeletMark cm(_masm, "earlyret entry points"); + address earlyret_entry_itos = generate_earlyret_entry_for(itos); Interpreter::_earlyret_entry = EntryPoint( - generate_earlyret_entry_for(btos), - generate_earlyret_entry_for(ztos), - generate_earlyret_entry_for(ctos), - generate_earlyret_entry_for(stos), generate_earlyret_entry_for(atos), generate_earlyret_entry_for(itos), generate_earlyret_entry_for(ltos), @@ -153,10 +153,6 @@ void TemplateInterpreterGenerator::generate_all() { { CodeletMark cm(_masm, "safepoint entry points"); Interpreter::_safept_entry = EntryPoint( - generate_safept_entry_for(btos, CAST_FROM_FN_PTR(address, InterpreterRuntime::at_safepoint)), - generate_safept_entry_for(ztos, CAST_FROM_FN_PTR(address, InterpreterRuntime::at_safepoint)), - generate_safept_entry_for(ctos, CAST_FROM_FN_PTR(address, InterpreterRuntime::at_safepoint)), - generate_safept_entry_for(stos, CAST_FROM_FN_PTR(address, InterpreterRuntime::at_safepoint)), generate_safept_entry_for(atos, CAST_FROM_FN_PTR(address, InterpreterRuntime::at_safepoint)), generate_safept_entry_for(itos, CAST_FROM_FN_PTR(address, InterpreterRuntime::at_safepoint)), generate_safept_entry_for(ltos, CAST_FROM_FN_PTR(address, InterpreterRuntime::at_safepoint)), @@ -242,12 +238,8 @@ void TemplateInterpreterGenerator::generate_all() { address deopt_itos = generate_deopt_entry_for(itos, i); Interpreter::_deopt_entry[i] = EntryPoint( - deopt_itos, /* btos */ - deopt_itos, /* ztos */ - deopt_itos, /* ctos */ - deopt_itos, /* stos */ generate_deopt_entry_for(atos, i), - deopt_itos, /* itos */ + generate_deopt_entry_for(itos, i), generate_deopt_entry_for(ltos, i), generate_deopt_entry_for(ftos, i), generate_deopt_entry_for(dtos, i), diff --git a/src/hotspot/share/jfr/leakprofiler/chains/bfsClosure.hpp b/src/hotspot/share/jfr/leakprofiler/chains/bfsClosure.hpp index b722cde50b7..4cc6a716427 100644 --- a/src/hotspot/share/jfr/leakprofiler/chains/bfsClosure.hpp +++ b/src/hotspot/share/jfr/leakprofiler/chains/bfsClosure.hpp @@ -64,7 +64,6 @@ class BFSClosure : public BasicOopIterateClosure { public: virtual ReferenceIterationMode reference_iteration_mode() { return DO_FIELDS_EXCEPT_REFERENT; } - virtual bool should_verify_oops() { return false; } BFSClosure(EdgeQueue* edge_queue, EdgeStore* edge_store, BitSet* mark_bits); void process(); diff --git a/src/hotspot/share/jfr/leakprofiler/chains/dfsClosure.hpp b/src/hotspot/share/jfr/leakprofiler/chains/dfsClosure.hpp index ba88b8dcd78..ad99f7d2320 100644 --- a/src/hotspot/share/jfr/leakprofiler/chains/dfsClosure.hpp +++ b/src/hotspot/share/jfr/leakprofiler/chains/dfsClosure.hpp @@ -54,7 +54,6 @@ class DFSClosure : public BasicOopIterateClosure { public: virtual ReferenceIterationMode reference_iteration_mode() { return DO_FIELDS_EXCEPT_REFERENT; } - virtual bool should_verify_oops() { return false; } static void find_leaks_from_edge(EdgeStore* edge_store, BitSet* mark_bits, const Edge* start_edge); static void find_leaks_from_root_set(EdgeStore* edge_store, BitSet* mark_bits); diff --git a/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp b/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp index 946ff0e5bb0..2070e631a21 100644 --- a/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp +++ b/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp @@ -285,7 +285,7 @@ TRACE_REQUEST_FUNC(ThreadContextSwitchRate) { Event ## eventType event; \ event.set_name(flag->name()); \ event.set_value(flag->get_ ## flagType()); \ - event.set_origin(flag->get_origin()); \ + event.set_origin(static_cast(flag->get_origin())); \ event.commit(); \ } \ } \ diff --git a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrType.cpp b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrType.cpp index b2b0e58cf9d..f867ce14226 100644 --- a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrType.cpp +++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrType.cpp @@ -122,27 +122,29 @@ void JfrThreadGroupConstant::serialize(JfrCheckpointWriter& writer) { JfrThreadGroup::serialize(writer); } -static const char* flag_value_origin_to_string(JVMFlag::Flags origin) { +static const char* flag_value_origin_to_string(JVMFlagOrigin origin) { switch (origin) { - case JVMFlag::DEFAULT: return "Default"; - case JVMFlag::COMMAND_LINE: return "Command line"; - case JVMFlag::ENVIRON_VAR: return "Environment variable"; - case JVMFlag::CONFIG_FILE: return "Config file"; - case JVMFlag::MANAGEMENT: return "Management"; - case JVMFlag::ERGONOMIC: return "Ergonomic"; - case JVMFlag::ATTACH_ON_DEMAND: return "Attach on demand"; - case JVMFlag::INTERNAL: return "Internal"; - case JVMFlag::JIMAGE_RESOURCE: return "JImage resource"; + case JVMFlagOrigin::DEFAULT: return "Default"; + case JVMFlagOrigin::COMMAND_LINE: return "Command line"; + case JVMFlagOrigin::ENVIRON_VAR: return "Environment variable"; + case JVMFlagOrigin::CONFIG_FILE: return "Config file"; + case JVMFlagOrigin::MANAGEMENT: return "Management"; + case JVMFlagOrigin::ERGONOMIC: return "Ergonomic"; + case JVMFlagOrigin::ATTACH_ON_DEMAND: return "Attach on demand"; + case JVMFlagOrigin::INTERNAL: return "Internal"; + case JVMFlagOrigin::JIMAGE_RESOURCE: return "JImage resource"; default: ShouldNotReachHere(); return ""; } } void FlagValueOriginConstant::serialize(JfrCheckpointWriter& writer) { - static const u4 nof_entries = JVMFlag::LAST_VALUE_ORIGIN + 1; - writer.write_count(nof_entries); - for (u4 i = 0; i < nof_entries; ++i) { - writer.write_key(i); - writer.write(flag_value_origin_to_string((JVMFlag::Flags)i)); + constexpr EnumRange range; + writer.write_count(static_cast(range.size())); + + for (EnumIterator it = range.begin(); it != range.end(); ++it) { + JVMFlagOrigin origin = *it; + writer.write_key(static_cast(origin)); + writer.write(flag_value_origin_to_string(origin)); } } diff --git a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp index 54f6c5c370e..60d8cf40cf2 100644 --- a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp +++ b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp @@ -1995,6 +1995,14 @@ C2V_VMENTRY_NULL(jobject, readFieldValue, (JNIEnv* env, jobject, jobject object, JVMCI_THROW_MSG_NULL(IllegalArgumentException, err_msg("Unexpected type: %s", JVMCIENV->klass_name(base))); } + + if (displacement == java_lang_Class::component_mirror_offset() && java_lang_Class::is_instance(obj()) && + !java_lang_Class::as_Klass(obj())->is_array_klass()) { + // Class.componentType for non-array classes can transiently contain an int[] that's + // used for locking so always return null to mimic Class.getComponentType() + return JVMCIENV->get_jobject(JVMCIENV->get_JavaConstant_NULL_POINTER()); + } + jlong value = 0; JVMCIObject kind; switch (constant_type) { @@ -2220,6 +2228,13 @@ C2V_VMENTRY_NULL(jobject, getObject, (JNIEnv* env, jobject, jobject x, long disp JVMCI_THROW_0(NullPointerException); } Handle xobj = JVMCIENV->asConstant(JVMCIENV->wrap(x), JVMCI_CHECK_0); + if (displacement == java_lang_Class::component_mirror_offset() && java_lang_Class::is_instance(xobj()) && + !java_lang_Class::as_Klass(xobj())->is_array_klass()) { + // Class.componentType for non-array classes can transiently contain an int[] that's + // used for locking so always return null to mimic Class.getComponentType() + return JVMCIENV->get_jobject(JVMCIENV->get_JavaConstant_NULL_POINTER()); + } + oop res = xobj->obj_field(displacement); JVMCIObject result = JVMCIENV->get_object_constant(res); return JVMCIENV->get_jobject(result); diff --git a/src/hotspot/share/jvmci/jvmciCompilerToVMInit.cpp b/src/hotspot/share/jvmci/jvmciCompilerToVMInit.cpp index fb52b9211e8..3d5cbc213a3 100644 --- a/src/hotspot/share/jvmci/jvmciCompilerToVMInit.cpp +++ b/src/hotspot/share/jvmci/jvmciCompilerToVMInit.cpp @@ -32,6 +32,7 @@ #include "memory/universe.hpp" #include "oops/compressedOops.hpp" #include "oops/klass.inline.hpp" +#include "runtime/flags/jvmFlag.hpp" #include "runtime/sharedRuntime.hpp" #include "utilities/resourceHash.hpp" diff --git a/src/hotspot/share/jvmci/jvmciRuntime.cpp b/src/hotspot/share/jvmci/jvmciRuntime.cpp index b6d5e37c482..ed9ad397aad 100644 --- a/src/hotspot/share/jvmci/jvmciRuntime.cpp +++ b/src/hotspot/share/jvmci/jvmciRuntime.cpp @@ -1328,29 +1328,23 @@ Method* JVMCIRuntime::lookup_method(InstanceKlass* accessor, // Accessibility checks are performed in JVMCIEnv::get_method_by_index_impl(). assert(check_klass_accessibility(accessor, holder), "holder not accessible"); - Method* dest_method; - LinkInfo link_info(holder, name, sig, accessor, LinkInfo::AccessCheck::required, LinkInfo::LoaderConstraintCheck::required, tag); + LinkInfo link_info(holder, name, sig, accessor, + LinkInfo::AccessCheck::required, + LinkInfo::LoaderConstraintCheck::required, + tag); switch (bc) { - case Bytecodes::_invokestatic: - dest_method = - LinkResolver::resolve_static_call_or_null(link_info); - break; - case Bytecodes::_invokespecial: - dest_method = - LinkResolver::resolve_special_call_or_null(link_info); - break; - case Bytecodes::_invokeinterface: - dest_method = - LinkResolver::linktime_resolve_interface_method_or_null(link_info); - break; - case Bytecodes::_invokevirtual: - dest_method = - LinkResolver::linktime_resolve_virtual_method_or_null(link_info); - break; - default: ShouldNotReachHere(); - } - - return dest_method; + case Bytecodes::_invokestatic: + return LinkResolver::resolve_static_call_or_null(link_info); + case Bytecodes::_invokespecial: + return LinkResolver::resolve_special_call_or_null(link_info); + case Bytecodes::_invokeinterface: + return LinkResolver::linktime_resolve_interface_method_or_null(link_info); + case Bytecodes::_invokevirtual: + return LinkResolver::linktime_resolve_virtual_method_or_null(link_info); + default: + fatal("Unhandled bytecode: %s", Bytecodes::name(bc)); + return NULL; // silence compiler warnings + } } diff --git a/src/hotspot/share/jvmci/jvmci_globals.cpp b/src/hotspot/share/jvmci/jvmci_globals.cpp index c9b3869f2f8..bbf3ec67b1b 100644 --- a/src/hotspot/share/jvmci/jvmci_globals.cpp +++ b/src/hotspot/share/jvmci/jvmci_globals.cpp @@ -158,7 +158,7 @@ bool JVMCIGlobals::check_jvmci_flags_are_consistent() { } // Convert JVMCI flags from experimental to product -bool JVMCIGlobals::enable_jvmci_product_mode(JVMFlag::Flags origin) { +bool JVMCIGlobals::enable_jvmci_product_mode(JVMFlagOrigin origin) { const char *JVMCIFlags[] = { "EnableJVMCI", "EnableJVMCIProduct", diff --git a/src/hotspot/share/jvmci/jvmci_globals.hpp b/src/hotspot/share/jvmci/jvmci_globals.hpp index dd1a375c732..5009b17db62 100644 --- a/src/hotspot/share/jvmci/jvmci_globals.hpp +++ b/src/hotspot/share/jvmci/jvmci_globals.hpp @@ -25,7 +25,7 @@ #ifndef SHARE_JVMCI_JVMCI_GLOBALS_HPP #define SHARE_JVMCI_JVMCI_GLOBALS_HPP -#include "runtime/flags/jvmFlag.hpp" +#include "utilities/vmEnums.hpp" class fileStream; @@ -153,7 +153,7 @@ class JVMCIGlobals { static bool check_jvmci_flags_are_consistent(); // Convert JVMCI experimental flags to product - static bool enable_jvmci_product_mode(JVMFlag::Flags); + static bool enable_jvmci_product_mode(JVMFlagOrigin); // Check and exit VM with error if selected GC is not supported by JVMCI. static void check_jvmci_supported_gc(); diff --git a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp index 6b4563ae558..4db20d040e9 100644 --- a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp +++ b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp @@ -33,6 +33,7 @@ #include "jvmci/vmStructs_jvmci.hpp" #include "oops/objArrayKlass.hpp" #include "runtime/deoptimization.hpp" +#include "runtime/flags/jvmFlag.hpp" #include "runtime/sharedRuntime.hpp" #if INCLUDE_G1GC #include "gc/g1/g1CardTable.hpp" diff --git a/src/hotspot/share/logging/logHandle.hpp b/src/hotspot/share/logging/logHandle.hpp index 3df30ac2900..fad63649b28 100644 --- a/src/hotspot/share/logging/logHandle.hpp +++ b/src/hotspot/share/logging/logHandle.hpp @@ -91,7 +91,9 @@ class LogTargetHandle { void print(const char* fmt, ...) ATTRIBUTE_PRINTF(2, 3) { va_list args; va_start(args, fmt); - _tagset->vwrite(_level, fmt, args); + if (is_enabled()) { + _tagset->vwrite(_level, fmt, args); + } va_end(args); } diff --git a/src/hotspot/share/logging/logTag.hpp b/src/hotspot/share/logging/logTag.hpp index 1ee9ddc556f..da0070d18af 100644 --- a/src/hotspot/share/logging/logTag.hpp +++ b/src/hotspot/share/logging/logTag.hpp @@ -77,9 +77,11 @@ LOG_TAG(free) \ LOG_TAG(freelist) \ LOG_TAG(gc) \ + NOT_PRODUCT(LOG_TAG(generate)) \ LOG_TAG(handshake) \ LOG_TAG(hashtables) \ LOG_TAG(heap) \ + NOT_PRODUCT(LOG_TAG(heapsampling)) \ LOG_TAG(humongous) \ LOG_TAG(ihop) \ LOG_TAG(iklass) \ diff --git a/src/hotspot/share/memory/archiveBuilder.cpp b/src/hotspot/share/memory/archiveBuilder.cpp index 861328195dd..d53ec907b41 100644 --- a/src/hotspot/share/memory/archiveBuilder.cpp +++ b/src/hotspot/share/memory/archiveBuilder.cpp @@ -38,6 +38,7 @@ #include "oops/instanceKlass.hpp" #include "oops/objArrayKlass.hpp" #include "oops/oopHandle.inline.hpp" +#include "runtime/sharedRuntime.hpp" #include "utilities/align.hpp" #include "utilities/bitMap.inline.hpp" #include "utilities/hashtable.inline.hpp" @@ -45,6 +46,27 @@ ArchiveBuilder* ArchiveBuilder::_singleton = NULL; intx ArchiveBuilder::_buffer_to_target_delta = 0; +class AdapterHandlerEntry; + +class MethodTrampolineInfo { + address _c2i_entry_trampoline; + AdapterHandlerEntry** _adapter_trampoline; +public: + address c2i_entry_trampoline() { return _c2i_entry_trampoline; } + AdapterHandlerEntry** adapter_trampoline() { return _adapter_trampoline; } + void set_c2i_entry_trampoline(address addr) { _c2i_entry_trampoline = addr; } + void set_adapter_trampoline(AdapterHandlerEntry** entry) { _adapter_trampoline = entry; } +}; + +class AdapterToTrampoline : public ResourceHashtable< + AdapterHandlerEntry*, MethodTrampolineInfo, + primitive_hash, + primitive_equals, + 941, // prime number + ResourceObj::C_HEAP> {}; + +static AdapterToTrampoline* _adapter_to_trampoline = NULL; + ArchiveBuilder::OtherROAllocMark::~OtherROAllocMark() { char* newtop = ArchiveBuilder::singleton()->_ro_region->top(); ArchiveBuilder::alloc_stats()->record_other_type(int(newtop - _oldtop), true); @@ -259,6 +281,8 @@ void ArchiveBuilder::gather_klasses_and_symbols() { // DynamicArchiveBuilder::sort_methods()). sort_symbols_and_fix_hash(); sort_klasses(); + allocate_method_trampoline_info(); + allocate_method_trampolines(); } } @@ -798,3 +822,89 @@ void ArchiveBuilder::clean_up_src_obj_table() { SrcObjTableCleaner cleaner; _src_obj_table.iterate(&cleaner); } + +void ArchiveBuilder::allocate_method_trampolines_for(InstanceKlass* ik) { + if (ik->methods() != NULL) { + for (int j = 0; j < ik->methods()->length(); j++) { + // Walk the methods in a deterministic order so that the trampolines are + // created in a deterministic order. + Method* m = ik->methods()->at(j); + AdapterHandlerEntry* ent = m->adapter(); // different methods can share the same AdapterHandlerEntry + MethodTrampolineInfo* info = _adapter_to_trampoline->get(ent); + if (info->c2i_entry_trampoline() == NULL) { + info->set_c2i_entry_trampoline( + (address)MetaspaceShared::misc_code_space_alloc(SharedRuntime::trampoline_size())); + info->set_adapter_trampoline( + (AdapterHandlerEntry**)MetaspaceShared::misc_code_space_alloc(sizeof(AdapterHandlerEntry*))); + } + } + } +} + +void ArchiveBuilder::allocate_method_trampolines() { + for (int i = 0; i < _klasses->length(); i++) { + Klass* k = _klasses->at(i); + if (k->is_instance_klass()) { + InstanceKlass* ik = InstanceKlass::cast(k); + allocate_method_trampolines_for(ik); + } + } +} + +// Allocate MethodTrampolineInfo for all Methods that will be archived. Also +// return the total number of bytes needed by the method trampolines in the MC +// region. +size_t ArchiveBuilder::allocate_method_trampoline_info() { + size_t total = 0; + size_t each_method_bytes = + align_up(SharedRuntime::trampoline_size(), BytesPerWord) + + align_up(sizeof(AdapterHandlerEntry*), BytesPerWord); + + if (_adapter_to_trampoline == NULL) { + _adapter_to_trampoline = new (ResourceObj::C_HEAP, mtClass)AdapterToTrampoline(); + } + int count = 0; + for (int i = 0; i < _klasses->length(); i++) { + Klass* k = _klasses->at(i); + if (k->is_instance_klass()) { + InstanceKlass* ik = InstanceKlass::cast(k); + if (ik->methods() != NULL) { + for (int j = 0; j < ik->methods()->length(); j++) { + Method* m = ik->methods()->at(j); + AdapterHandlerEntry* ent = m->adapter(); // different methods can share the same AdapterHandlerEntry + bool is_created = false; + MethodTrampolineInfo* info = _adapter_to_trampoline->put_if_absent(ent, &is_created); + if (is_created) { + count++; + } + } + } + } + } + if (count == 0) { + // We have nothing to archive, but let's avoid having an empty region. + total = SharedRuntime::trampoline_size(); + } else { + total = count * each_method_bytes; + } + return align_up(total, SharedSpaceObjectAlignment); +} + +void ArchiveBuilder::update_method_trampolines() { + for (int i = 0; i < klasses()->length(); i++) { + Klass* k = klasses()->at(i); + if (k->is_instance_klass()) { + InstanceKlass* ik = InstanceKlass::cast(k); + Array* methods = ik->methods(); + for (int j = 0; j < methods->length(); j++) { + Method* m = methods->at(j); + AdapterHandlerEntry* ent = m->adapter(); + MethodTrampolineInfo* info = _adapter_to_trampoline->get(ent); + // m is the "copy" of the original Method, but its adapter() field is still valid because + // we haven't called make_klasses_shareable() yet. + m->set_from_compiled_entry(info->c2i_entry_trampoline()); + m->set_adapter_trampoline(info->adapter_trampoline()); + } + } + } +} diff --git a/src/hotspot/share/memory/archiveBuilder.hpp b/src/hotspot/share/memory/archiveBuilder.hpp index 10704de6e3d..e39df1cd897 100644 --- a/src/hotspot/share/memory/archiveBuilder.hpp +++ b/src/hotspot/share/memory/archiveBuilder.hpp @@ -279,6 +279,13 @@ class ArchiveBuilder : public StackObj { void print_stats(int ro_all, int rw_all, int mc_all); static intx _buffer_to_target_delta; + + // Method trampolines related functions + void allocate_method_trampolines(); + void allocate_method_trampolines_for(InstanceKlass* ik); + size_t allocate_method_trampoline_info(); + void update_method_trampolines(); + }; #endif // SHARE_MEMORY_ARCHIVEBUILDER_HPP diff --git a/src/hotspot/share/memory/archiveUtils.cpp b/src/hotspot/share/memory/archiveUtils.cpp index 9b390d4a89f..dbf9960d99d 100644 --- a/src/hotspot/share/memory/archiveUtils.cpp +++ b/src/hotspot/share/memory/archiveUtils.cpp @@ -319,3 +319,12 @@ void ArchiveUtils::log_to_classlist(BootstrapInfo* bootstrap_specifier, TRAPS) { } } } + +void ArchiveUtils::check_for_oom(oop exception) { + assert(exception != nullptr, "Sanity check"); + if (exception->is_a(SystemDictionary::OutOfMemoryError_klass())) { + vm_exit_during_cds_dumping( + err_msg("Out of memory. Please run with a larger Java heap, current MaxHeapSize = " SIZE_FORMAT "M", + MaxHeapSize/M)); + } +} diff --git a/src/hotspot/share/memory/archiveUtils.hpp b/src/hotspot/share/memory/archiveUtils.hpp index 8e039c5a12c..4f2ae6f6276 100644 --- a/src/hotspot/share/memory/archiveUtils.hpp +++ b/src/hotspot/share/memory/archiveUtils.hpp @@ -243,6 +243,7 @@ class ReadClosure : public SerializeClosure { class ArchiveUtils { public: static void log_to_classlist(BootstrapInfo* bootstrap_specifier, TRAPS) NOT_CDS_RETURN; + static void check_for_oom(oop exception) NOT_CDS_RETURN; }; #endif // SHARE_MEMORY_ARCHIVEUTILS_HPP diff --git a/src/hotspot/share/memory/dynamicArchive.cpp b/src/hotspot/share/memory/dynamicArchive.cpp index 26c17a5faaa..5cb889f60cf 100644 --- a/src/hotspot/share/memory/dynamicArchive.cpp +++ b/src/hotspot/share/memory/dynamicArchive.cpp @@ -93,12 +93,10 @@ class DynamicArchiveBuilder : public ArchiveBuilder { size_t _estimated_trampoline_bytes; // method entry trampolines size_t estimate_archive_size(); - size_t estimate_trampoline_size(); size_t estimate_class_file_size(); address reserve_space_and_init_buffer_to_target_delta(); void init_header(address addr); void release_header(); - void make_trampolines(); void sort_methods(); void sort_methods(InstanceKlass* ik) const; void remark_pointers_for_instance_klass(InstanceKlass* k, bool should_mark) const; @@ -116,12 +114,6 @@ class DynamicArchiveBuilder : public ArchiveBuilder { _num_dump_regions_used = 1; } - void reserve_buffers_for_trampolines() { - size_t n = _estimated_trampoline_bytes; - assert(n >= SharedRuntime::trampoline_size(), "dont want to be empty"); - MetaspaceShared::misc_code_space_alloc(n); - } - public: DynamicArchiveBuilder() : ArchiveBuilder(MetaspaceShared::misc_code_dump_space(), MetaspaceShared::read_write_dump_space(), @@ -184,7 +176,7 @@ class DynamicArchiveBuilder : public ArchiveBuilder { CHeapBitMap ptrmap; ArchivePtrMarker::initialize(&ptrmap, (address*)reserved_bottom, (address*)current_dump_space()->top()); - reserve_buffers_for_trampolines(); + allocate_method_trampolines(); verify_estimate_size(_estimated_trampoline_bytes, "Trampolines"); gather_source_objs(); @@ -221,7 +213,7 @@ class DynamicArchiveBuilder : public ArchiveBuilder { verify_estimate_size(_estimated_hashtable_bytes, "Hashtables"); - make_trampolines(); + update_method_trampolines(); sort_methods(); log_info(cds)("Make classes shareable"); @@ -254,7 +246,7 @@ size_t DynamicArchiveBuilder::estimate_archive_size() { size_t dictionary_est = SystemDictionaryShared::estimate_size_for_archive(); _estimated_hashtable_bytes = symbol_table_est + dictionary_est; - _estimated_trampoline_bytes = estimate_trampoline_size(); + _estimated_trampoline_bytes = allocate_method_trampoline_info(); size_t total = 0; @@ -337,54 +329,6 @@ void DynamicArchiveBuilder::release_header() { _header = NULL; } -size_t DynamicArchiveBuilder::estimate_trampoline_size() { - size_t total = 0; - size_t each_method_bytes = - align_up(SharedRuntime::trampoline_size(), BytesPerWord) + - align_up(sizeof(AdapterHandlerEntry*), BytesPerWord); - - for (int i = 0; i < klasses()->length(); i++) { - Klass* k = klasses()->at(i); - if (k->is_instance_klass()) { - Array* methods = InstanceKlass::cast(k)->methods(); - total += each_method_bytes * methods->length(); - } - } - if (total == 0) { - // We have nothing to archive, but let's avoid having an empty region. - total = SharedRuntime::trampoline_size(); - } - return align_up(total, SharedSpaceObjectAlignment); -} - -void DynamicArchiveBuilder::make_trampolines() { - DumpRegion* mc_space = MetaspaceShared::misc_code_dump_space(); - char* p = mc_space->base(); - for (int i = 0; i < klasses()->length(); i++) { - Klass* k = klasses()->at(i); - if (!k->is_instance_klass()) { - continue; - } - InstanceKlass* ik = InstanceKlass::cast(k); - Array* methods = ik->methods(); - for (int j = 0; j < methods->length(); j++) { - Method* m = methods->at(j); - address c2i_entry_trampoline = (address)p; - p += SharedRuntime::trampoline_size(); - assert(p >= mc_space->base() && p <= mc_space->top(), "must be"); - m->set_from_compiled_entry(to_target(c2i_entry_trampoline)); - - AdapterHandlerEntry** adapter_trampoline =(AdapterHandlerEntry**)p; - p += sizeof(AdapterHandlerEntry*); - assert(p >= mc_space->base() && p <= mc_space->top(), "must be"); - *adapter_trampoline = NULL; - m->set_adapter_trampoline(to_target(adapter_trampoline)); - } - } - - guarantee(p <= mc_space->top(), "Estimate of trampoline size is insufficient"); -} - void DynamicArchiveBuilder::sort_methods() { InstanceKlass::disable_method_binary_search(); for (int i = 0; i < klasses()->length(); i++) { diff --git a/src/hotspot/share/memory/filemap.cpp b/src/hotspot/share/memory/filemap.cpp index de3ca7ad6cf..ab183ca623d 100644 --- a/src/hotspot/share/memory/filemap.cpp +++ b/src/hotspot/share/memory/filemap.cpp @@ -1737,7 +1737,7 @@ address FileMapInfo::decode_start_address(FileMapRegion* spc, bool with_current_ size_t offset = spc->mapping_offset(); narrowOop n = CompressedOops::narrow_oop_cast(offset); if (with_current_oop_encoding_mode) { - return cast_from_oop
(CompressedOops::decode_not_null(n)); + return cast_from_oop
(CompressedOops::decode_raw_not_null(n)); } else { return cast_from_oop
(HeapShared::decode_from_archive(n)); } diff --git a/src/hotspot/share/memory/heap.cpp b/src/hotspot/share/memory/heap.cpp index 3bcf3043cf3..d55bc07e2c0 100644 --- a/src/hotspot/share/memory/heap.cpp +++ b/src/hotspot/share/memory/heap.cpp @@ -770,7 +770,8 @@ int CodeHeap::segmap_hops(size_t beg, size_t end) { if (beg < end) { // setup _segmap pointers for faster indexing address p = (address)_segmap.low() + beg; - int hops_expected = (int)(((end-beg-1)+(free_sentinel-2))/(free_sentinel-1)); + int hops_expected + = checked_cast(((end-beg-1)+(free_sentinel-2))/(free_sentinel-1)); int nhops = 0; size_t ix = end-beg-1; while (p[ix] > 0) { diff --git a/src/hotspot/share/memory/heapShared.cpp b/src/hotspot/share/memory/heapShared.cpp index 1d9821300f4..fafbdaac527 100644 --- a/src/hotspot/share/memory/heapShared.cpp +++ b/src/hotspot/share/memory/heapShared.cpp @@ -259,15 +259,6 @@ void HeapShared::run_full_gc_in_vm_thread() { void HeapShared::archive_java_heap_objects(GrowableArray *closed, GrowableArray *open) { - if (!is_heap_object_archiving_allowed()) { - log_info(cds)( - "Archived java heap is not supported as UseG1GC, " - "UseCompressedOops and UseCompressedClassPointers are required." - "Current settings: UseG1GC=%s, UseCompressedOops=%s, UseCompressedClassPointers=%s.", - BOOL_TO_STR(UseG1GC), BOOL_TO_STR(UseCompressedOops), - BOOL_TO_STR(UseCompressedClassPointers)); - return; - } G1HeapVerifier::verify_ready_for_archiving(); @@ -1035,7 +1026,13 @@ void HeapShared::init_subgraph_entry_fields(ArchivableStaticFieldInfo fields[], TempNewSymbol field_name = SymbolTable::new_symbol(info->field_name); Klass* k = SystemDictionary::resolve_or_null(klass_name, THREAD); - assert(k != NULL && !HAS_PENDING_EXCEPTION, "class must exist"); + if (HAS_PENDING_EXCEPTION) { + ResourceMark rm(THREAD); + ArchiveUtils::check_for_oom(PENDING_EXCEPTION); // exit on OOM + log_info(cds)("%s: %s", PENDING_EXCEPTION->klass()->external_name(), + java_lang_String::as_utf8_string(java_lang_Throwable::message(PENDING_EXCEPTION))); + vm_exit_during_initialization("VM exits due to exception, use -Xlog:cds,exceptions=trace for detail"); + } InstanceKlass* ik = InstanceKlass::cast(k); assert(InstanceKlass::cast(ik)->is_shared_boot_class(), "Only support boot classes"); @@ -1052,8 +1049,8 @@ void HeapShared::init_subgraph_entry_fields(ArchivableStaticFieldInfo fields[], } void HeapShared::init_subgraph_entry_fields(Thread* THREAD) { + assert(is_heap_object_archiving_allowed(), "Sanity check"); _dump_time_subgraph_info_table = new (ResourceObj::C_HEAP, mtClass)DumpTimeKlassSubGraphInfoTable(); - init_subgraph_entry_fields(closed_archive_subgraph_entry_fields, num_closed_archive_subgraph_entry_fields, THREAD); @@ -1068,8 +1065,10 @@ void HeapShared::init_subgraph_entry_fields(Thread* THREAD) { } void HeapShared::init_for_dumping(Thread* THREAD) { - _dumped_interned_strings = new (ResourceObj::C_HEAP, mtClass)DumpedInternedStrings(); - init_subgraph_entry_fields(THREAD); + if (is_heap_object_archiving_allowed()) { + _dumped_interned_strings = new (ResourceObj::C_HEAP, mtClass)DumpedInternedStrings(); + init_subgraph_entry_fields(THREAD); + } } void HeapShared::archive_object_subgraphs(ArchivableStaticFieldInfo fields[], @@ -1150,9 +1149,6 @@ class FindEmbeddedNonNullPointers: public BasicOopIterateClosure { FindEmbeddedNonNullPointers(narrowOop* start, BitMap* oopmap) : _start(start), _oopmap(oopmap), _num_total_oops(0), _num_null_oops(0) {} - virtual bool should_verify_oops(void) { - return false; - } virtual void do_oop(narrowOop* p) { _num_total_oops ++; narrowOop v = *p; diff --git a/src/hotspot/share/memory/iterator.cpp b/src/hotspot/share/memory/iterator.cpp index b0692d5217a..51b223c53bb 100644 --- a/src/hotspot/share/memory/iterator.cpp +++ b/src/hotspot/share/memory/iterator.cpp @@ -23,6 +23,7 @@ */ #include "precompiled.hpp" +#include "classfile/classLoaderDataGraph.hpp" #include "code/nmethod.hpp" #include "memory/iterator.inline.hpp" #include "oops/oop.inline.hpp" diff --git a/src/hotspot/share/memory/iterator.hpp b/src/hotspot/share/memory/iterator.hpp index fb3a4c2ca34..a5b1d49836b 100644 --- a/src/hotspot/share/memory/iterator.hpp +++ b/src/hotspot/share/memory/iterator.hpp @@ -102,14 +102,6 @@ class OopIterateClosure : public OopClosure { virtual bool do_metadata() = 0; virtual void do_klass(Klass* k) = 0; virtual void do_cld(ClassLoaderData* cld) = 0; - -#ifdef ASSERT - // Default verification of each visited oop field. - template void verify(T* p); - - // Can be used by subclasses to turn off the default verification of oop fields. - virtual bool should_verify_oops() { return true; } -#endif }; // An OopIterateClosure that can be used when there's no need to visit the Metadata. @@ -151,6 +143,12 @@ class CLDToOopClosure : public CLDClosure { void do_cld(ClassLoaderData* cld); }; +template +class ClaimingCLDToOopClosure : public CLDToOopClosure { +public: + ClaimingCLDToOopClosure(OopClosure* cl) : CLDToOopClosure(cl, claim) {} +}; + class ClaimMetadataVisitingOopIterateClosure : public OopIterateClosure { protected: const int _claim; @@ -357,7 +355,6 @@ class CompareClosure : public Closure { // a concrete implementation, otherwise a virtual call is taken. class Devirtualizer { public: - template static void do_oop_no_verify(OopClosureType* closure, T* p); template static void do_oop(OopClosureType* closure, T* p); template static void do_klass(OopClosureType* closure, Klass* k); template static void do_cld(OopClosureType* closure, ClassLoaderData* cld); diff --git a/src/hotspot/share/memory/iterator.inline.hpp b/src/hotspot/share/memory/iterator.inline.hpp index 5d0300b6d3f..36ee100397d 100644 --- a/src/hotspot/share/memory/iterator.inline.hpp +++ b/src/hotspot/share/memory/iterator.inline.hpp @@ -27,7 +27,6 @@ #include "classfile/classLoaderData.hpp" #include "memory/iterator.hpp" -#include "memory/universe.hpp" #include "oops/access.inline.hpp" #include "oops/compressedOops.inline.hpp" #include "oops/klass.hpp" @@ -52,22 +51,6 @@ inline void ClaimMetadataVisitingOopIterateClosure::do_klass(Klass* k) { ClaimMetadataVisitingOopIterateClosure::do_cld(cld); } -#ifdef ASSERT -// This verification is applied to all visited oops. -// The closures can turn is off by overriding should_verify_oops(). -template -void OopIterateClosure::verify(T* p) { - if (should_verify_oops()) { - T heap_oop = RawAccess<>::oop_load(p); - if (!CompressedOops::is_null(heap_oop)) { - oop o = CompressedOops::decode_not_null(heap_oop); - assert(Universe::heap()->is_in(o), - "should be in closed *p " PTR_FORMAT " " PTR_FORMAT, p2i(p), p2i(o)); - } - } -} -#endif - // Implementation of the non-virtual do_oop dispatch. // // The same implementation is used for do_metadata, do_klass, and do_cld. @@ -123,16 +106,9 @@ call_do_oop(void (Receiver::*)(T*), void (Base::*)(T*), OopClosureType* closure, closure->OopClosureType::do_oop(p); } -template -inline void Devirtualizer::do_oop_no_verify(OopClosureType* closure, T* p) { - call_do_oop(&OopClosureType::do_oop, &OopClosure::do_oop, closure, p); -} - template inline void Devirtualizer::do_oop(OopClosureType* closure, T* p) { - debug_only(closure->verify(p)); - - do_oop_no_verify(closure, p); + call_do_oop(&OopClosureType::do_oop, &OopClosure::do_oop, closure, p); } // Implementation of the non-virtual do_metadata dispatch. diff --git a/src/hotspot/share/memory/metaspaceShared.cpp b/src/hotspot/share/memory/metaspaceShared.cpp index 0b9328961ff..59f488a6b66 100644 --- a/src/hotspot/share/memory/metaspaceShared.cpp +++ b/src/hotspot/share/memory/metaspaceShared.cpp @@ -770,6 +770,9 @@ void VM_PopulateDumpSharedSpace::doit() { builder.relocate_well_known_klasses(); + log_info(cds)("Update method trampolines"); + builder.update_method_trampolines(); + log_info(cds)("Make classes shareable"); builder.make_klasses_shareable(); @@ -1093,6 +1096,9 @@ int MetaspaceShared::preload_classes(const char* class_list_path, TRAPS) { int class_count = 0; while (parser.parse_one_line()) { + if (parser.lambda_form_line()) { + continue; + } Klass* klass = parser.load_current_class(THREAD); if (HAS_PENDING_EXCEPTION) { if (klass == NULL && @@ -1160,6 +1166,15 @@ bool MetaspaceShared::try_link_class(InstanceKlass* ik, TRAPS) { #if INCLUDE_CDS_JAVA_HEAP void VM_PopulateDumpSharedSpace::dump_java_heap_objects() { + if(!HeapShared::is_heap_object_archiving_allowed()) { + log_info(cds)( + "Archived java heap is not supported as UseG1GC, " + "UseCompressedOops and UseCompressedClassPointers are required." + "Current settings: UseG1GC=%s, UseCompressedOops=%s, UseCompressedClassPointers=%s.", + BOOL_TO_STR(UseG1GC), BOOL_TO_STR(UseCompressedOops), + BOOL_TO_STR(UseCompressedClassPointers)); + return; + } // Find all the interned strings that should be dumped. int i; for (i = 0; i < _global_klass_objects->length(); i++) { diff --git a/src/hotspot/share/memory/padded.hpp b/src/hotspot/share/memory/padded.hpp index 08003613609..feca46ac7c2 100644 --- a/src/hotspot/share/memory/padded.hpp +++ b/src/hotspot/share/memory/padded.hpp @@ -116,6 +116,7 @@ template class PaddedPrimitiveArray { public: static T* create_unfreeable(size_t length); + static T* create(size_t length, void** alloc_base); }; #endif // SHARE_MEMORY_PADDED_HPP diff --git a/src/hotspot/share/memory/padded.inline.hpp b/src/hotspot/share/memory/padded.inline.hpp index d698f5ee1b3..742db2fe3f8 100644 --- a/src/hotspot/share/memory/padded.inline.hpp +++ b/src/hotspot/share/memory/padded.inline.hpp @@ -82,11 +82,18 @@ T** Padded2DArray::create_unfreeable(uint rows, uint column template T* PaddedPrimitiveArray::create_unfreeable(size_t length) { + void* temp; + return create(length, &temp); +} + +template +T* PaddedPrimitiveArray::create(size_t length, void** alloc_base) { // Allocate a chunk of memory large enough to allow for some alignment. void* chunk = AllocateHeap(length * sizeof(T) + alignment, flags); memset(chunk, 0, length * sizeof(T) + alignment); + *alloc_base = chunk; return (T*)align_up(chunk, alignment); } diff --git a/src/hotspot/share/memory/virtualspace.cpp b/src/hotspot/share/memory/virtualspace.cpp index c67e9c1c78f..ab5849d6ac7 100644 --- a/src/hotspot/share/memory/virtualspace.cpp +++ b/src/hotspot/share/memory/virtualspace.cpp @@ -80,6 +80,30 @@ ReservedSpace::ReservedSpace(char* base, size_t size, size_t alignment, _executable = executable; } +// Helper method +static char* attempt_map_or_reserve_memory_at(char* base, size_t size, int fd) { + if (fd != -1) { + return os::attempt_map_memory_to_file_at(base, size, fd); + } + return os::attempt_reserve_memory_at(base, size); +} + +// Helper method +static char* map_or_reserve_memory(size_t size, int fd) { + if (fd != -1) { + return os::map_memory_to_file(size, fd); + } + return os::reserve_memory(size); +} + +// Helper method +static char* map_or_reserve_memory_aligned(size_t size, size_t alignment, int fd) { + if (fd != -1) { + return os::map_memory_to_file_aligned(size, alignment, fd); + } + return os::reserve_memory_aligned(size, alignment); +} + // Helper method static void unmap_or_release_memory(char* base, size_t size, bool is_file_mapped) { if (is_file_mapped) { @@ -188,13 +212,13 @@ void ReservedSpace::initialize(size_t size, size_t alignment, bool large, // important. If available space is not detected, return NULL. if (requested_address != 0) { - base = os::attempt_reserve_memory_at(requested_address, size, _fd_for_heap); + base = attempt_map_or_reserve_memory_at(requested_address, size, _fd_for_heap); if (failed_to_reserve_as_requested(base, requested_address, size, false, _fd_for_heap != -1)) { // OS ignored requested address. Try different address. base = NULL; } } else { - base = os::reserve_memory_with_fd(size, _fd_for_heap); + base = map_or_reserve_memory(size, _fd_for_heap); } if (base == NULL) return; @@ -206,7 +230,7 @@ void ReservedSpace::initialize(size_t size, size_t alignment, bool large, // Make sure that size is aligned size = align_up(size, alignment); - base = os::reserve_memory_aligned(size, alignment, _fd_for_heap); + base = map_or_reserve_memory_aligned(size, alignment, _fd_for_heap); if (requested_address != 0 && failed_to_reserve_as_requested(base, requested_address, size, false, _fd_for_heap != -1)) { @@ -372,13 +396,13 @@ void ReservedHeapSpace::try_reserve_heap(size_t size, } if (requested_address != 0) { - base = os::attempt_reserve_memory_at(requested_address, size, _fd_for_heap); + base = attempt_map_or_reserve_memory_at(requested_address, size, _fd_for_heap); } else { // Optimistically assume that the OSes returns an aligned base pointer. // When reserving a large address range, most OSes seem to align to at // least 64K. // If the returned memory is not aligned we will release and retry. - base = os::reserve_memory_with_fd(size, _fd_for_heap); + base = map_or_reserve_memory(size, _fd_for_heap); } } if (base == NULL) { return; } diff --git a/src/hotspot/share/oops/compressedOops.hpp b/src/hotspot/share/oops/compressedOops.hpp index 60f099c9be9..c12f6bd197b 100644 --- a/src/hotspot/share/oops/compressedOops.hpp +++ b/src/hotspot/share/oops/compressedOops.hpp @@ -119,6 +119,7 @@ class CompressedOops : public AllStatic { static bool is_null(oop v) { return v == NULL; } static bool is_null(narrowOop v) { return v == narrowOop::null; } + static inline oop decode_raw_not_null(narrowOop v); static inline oop decode_raw(narrowOop v); static inline oop decode_not_null(narrowOop v); static inline oop decode(narrowOop v); @@ -126,10 +127,10 @@ class CompressedOops : public AllStatic { static inline narrowOop encode(oop v); // No conversions needed for these overloads - static oop decode_not_null(oop v) { return v; } - static oop decode(oop v) { return v; } - static narrowOop encode_not_null(narrowOop v) { return v; } - static narrowOop encode(narrowOop v) { return v; } + static inline oop decode_not_null(oop v); + static inline oop decode(oop v); + static inline narrowOop encode_not_null(narrowOop v); + static inline narrowOop encode(narrowOop v); static inline uint32_t narrow_oop_value(oop o); static inline uint32_t narrow_oop_value(narrowOop o); diff --git a/src/hotspot/share/oops/compressedOops.inline.hpp b/src/hotspot/share/oops/compressedOops.inline.hpp index 8c8a922094d..920e87703b4 100644 --- a/src/hotspot/share/oops/compressedOops.inline.hpp +++ b/src/hotspot/share/oops/compressedOops.inline.hpp @@ -41,6 +41,11 @@ // offset from the heap base. Saving the check for null can save instructions // in inner GC loops so these are separated. +inline oop CompressedOops::decode_raw_not_null(narrowOop v) { + assert(!is_null(v), "narrow oop value can never be zero"); + return decode_raw(v); +} + inline oop CompressedOops::decode_raw(narrowOop v) { return (oop)(void*)((uintptr_t)base() + ((uintptr_t)v << shift())); } @@ -49,6 +54,7 @@ inline oop CompressedOops::decode_not_null(narrowOop v) { assert(!is_null(v), "narrow oop value can never be zero"); oop result = decode_raw(v); assert(is_object_aligned(result), "address not aligned: " INTPTR_FORMAT, p2i((void*) result)); + assert(Universe::heap()->is_in(result), "object not in heap " PTR_FORMAT, p2i((void*) result)); return result; } @@ -63,7 +69,7 @@ inline narrowOop CompressedOops::encode_not_null(oop v) { uint64_t pd = (uint64_t)(pointer_delta((void*)v, (void*)base(), 1)); assert(OopEncodingHeapMax > pd, "change encoding max if new encoding"); narrowOop result = narrow_oop_cast(pd >> shift()); - assert(decode(result) == v, "reversibility"); + assert(decode_raw(result) == v, "reversibility"); return result; } @@ -71,6 +77,24 @@ inline narrowOop CompressedOops::encode(oop v) { return is_null(v) ? narrowOop::null : encode_not_null(v); } +inline oop CompressedOops::decode_not_null(oop v) { + assert(Universe::heap()->is_in(v), "object not in heap " PTR_FORMAT, p2i((void*) v)); + return v; +} + +inline oop CompressedOops::decode(oop v) { + assert(Universe::heap()->is_in_or_null(v), "object not in heap " PTR_FORMAT, p2i((void*) v)); + return v; +} + +inline narrowOop CompressedOops::encode_not_null(narrowOop v) { + return v; +} + +inline narrowOop CompressedOops::encode(narrowOop v) { + return v; +} + inline uint32_t CompressedOops::narrow_oop_value(oop o) { return narrow_oop_value(encode(o)); } diff --git a/src/hotspot/share/oops/method.cpp b/src/hotspot/share/oops/method.cpp index 32e35546de5..c0c5c52feac 100644 --- a/src/hotspot/share/oops/method.cpp +++ b/src/hotspot/share/oops/method.cpp @@ -1107,17 +1107,9 @@ void Method::unlink_method() { _i2i_entry = Interpreter::entry_for_cds_method(methodHandle(Thread::current(), this)); _from_interpreted_entry = _i2i_entry; - if (DynamicDumpSharedSpaces) { - assert(_from_compiled_entry != NULL, "sanity"); - } else { - // TODO: Simplify the adapter trampoline allocation for static archiving. - // Remove the use of CDSAdapterHandlerEntry. - CDSAdapterHandlerEntry* cds_adapter = (CDSAdapterHandlerEntry*)adapter(); - constMethod()->set_adapter_trampoline(cds_adapter->get_adapter_trampoline()); - _from_compiled_entry = cds_adapter->get_c2i_entry_trampoline(); - assert(*((int*)_from_compiled_entry) == 0, - "must be NULL during dump time, to be initialized at run time"); - } + assert(_from_compiled_entry != NULL, "sanity"); + assert(*((int*)_from_compiled_entry) == 0, + "must be NULL during dump time, to be initialized at run time"); if (is_native()) { *native_function_addr() = NULL; diff --git a/src/hotspot/share/oops/methodData.cpp b/src/hotspot/share/oops/methodData.cpp index c7b34950cea..a1d71f273bc 100644 --- a/src/hotspot/share/oops/methodData.cpp +++ b/src/hotspot/share/oops/methodData.cpp @@ -1099,6 +1099,40 @@ ProfileData* MethodData::data_at(int data_index) const { return data_layout->data_in(); } +int DataLayout::cell_count() { + switch (tag()) { + case DataLayout::no_tag: + default: + ShouldNotReachHere(); + return 0; + case DataLayout::bit_data_tag: + return BitData::static_cell_count(); + case DataLayout::counter_data_tag: + return CounterData::static_cell_count(); + case DataLayout::jump_data_tag: + return JumpData::static_cell_count(); + case DataLayout::receiver_type_data_tag: + return ReceiverTypeData::static_cell_count(); + case DataLayout::virtual_call_data_tag: + return VirtualCallData::static_cell_count(); + case DataLayout::ret_data_tag: + return RetData::static_cell_count(); + case DataLayout::branch_data_tag: + return BranchData::static_cell_count(); + case DataLayout::multi_branch_data_tag: + return ((new MultiBranchData(this))->cell_count()); + case DataLayout::arg_info_data_tag: + return ((new ArgInfoData(this))->cell_count()); + case DataLayout::call_type_data_tag: + return ((new CallTypeData(this))->cell_count()); + case DataLayout::virtual_call_type_data_tag: + return ((new VirtualCallTypeData(this))->cell_count()); + case DataLayout::parameters_type_data_tag: + return ((new ParametersTypeData(this))->cell_count()); + case DataLayout::speculative_trap_data_tag: + return SpeculativeTrapData::static_cell_count(); + } +} ProfileData* DataLayout::data_in() { switch (tag()) { case DataLayout::no_tag: @@ -1142,6 +1176,16 @@ ProfileData* MethodData::next_data(ProfileData* current) const { return next; } +DataLayout* MethodData::next_data_layout(DataLayout* current) const { + int current_index = dp_to_di((address)current); + int next_index = current_index + current->size_in_bytes(); + if (out_of_bounds(next_index)) { + return NULL; + } + DataLayout* next = data_layout_at(next_index); + return next; +} + // Give each of the data entries a chance to perform specific // data initialization. void MethodData::post_initialize(BytecodeStream* stream) { @@ -1314,13 +1358,13 @@ bool MethodData::is_mature() const { // Translate a bci to its corresponding data index (di). address MethodData::bci_to_dp(int bci) { ResourceMark rm; - ProfileData* data = data_before(bci); - ProfileData* prev = NULL; - for ( ; is_valid(data); data = next_data(data)) { + DataLayout* data = data_layout_before(bci); + DataLayout* prev = NULL; + for ( ; is_valid(data); data = next_data_layout(data)) { if (data->bci() >= bci) { - if (data->bci() == bci) set_hint_di(dp_to_di(data->dp())); - else if (prev != NULL) set_hint_di(dp_to_di(prev->dp())); - return data->dp(); + if (data->bci() == bci) set_hint_di(dp_to_di((address)data)); + else if (prev != NULL) set_hint_di(dp_to_di((address)prev)); + return (address)data; } prev = data; } @@ -1329,11 +1373,11 @@ address MethodData::bci_to_dp(int bci) { // Translate a bci to its corresponding data, or NULL. ProfileData* MethodData::bci_to_data(int bci) { - ProfileData* data = data_before(bci); - for ( ; is_valid(data); data = next_data(data)) { + DataLayout* data = data_layout_before(bci); + for ( ; is_valid(data); data = next_data_layout(data)) { if (data->bci() == bci) { - set_hint_di(dp_to_di(data->dp())); - return data; + set_hint_di(dp_to_di((address)data)); + return data->data_in(); } else if (data->bci() > bci) { break; } @@ -1786,27 +1830,7 @@ void MethodData::clean_method_data(bool always_clean) { // methods out of MethodData for all methods. void MethodData::clean_weak_method_links() { ResourceMark rm; - for (ProfileData* data = first_data(); - is_valid(data); - data = next_data(data)) { - data->clean_weak_method_links(); - } - CleanExtraDataMethodClosure cl; clean_extra_data(&cl); verify_extra_data_clean(&cl); } - -#ifdef ASSERT -void MethodData::verify_clean_weak_method_links() { - ResourceMark rm; - for (ProfileData* data = first_data(); - is_valid(data); - data = next_data(data)) { - data->verify_clean_weak_method_links(); - } - - CleanExtraDataMethodClosure cl; - verify_extra_data_clean(&cl); -} -#endif // ASSERT diff --git a/src/hotspot/share/oops/methodData.hpp b/src/hotspot/share/oops/methodData.hpp index 4567b7d4c6c..bbac95b6122 100644 --- a/src/hotspot/share/oops/methodData.hpp +++ b/src/hotspot/share/oops/methodData.hpp @@ -236,12 +236,15 @@ class DataLayout { ProfileData* data_in(); + int size_in_bytes() { + int cells = cell_count(); + assert(cells >= 0, "invalid number of cells"); + return DataLayout::compute_size_in_bytes(cells); + } + int cell_count(); + // GC support void clean_weak_klass_links(bool always_clean); - - // Redefinition support - void clean_weak_method_links(); - DEBUG_ONLY(void verify_clean_weak_method_links();) }; @@ -455,10 +458,6 @@ class ProfileData : public ResourceObj { // GC support virtual void clean_weak_klass_links(bool always_clean) {} - // Redefinition support - virtual void clean_weak_method_links() {} - DEBUG_ONLY(virtual void verify_clean_weak_method_links() {}) - // CI translation: ProfileData can represent both MethodDataOop data // as well as CIMethodData data. This function is provided for translating // an oop in a ProfileData to the ci equivalent. Generally speaking, @@ -2061,14 +2060,15 @@ class MethodData : public Metadata { assert(!out_of_bounds(di), "hint_di out of bounds"); _hint_di = di; } - ProfileData* data_before(int bci) { + + DataLayout* data_layout_before(int bci) { // avoid SEGV on this edge case if (data_size() == 0) return NULL; - int hint = hint_di(); - if (data_layout_at(hint)->bci() <= bci) - return data_at(hint); - return first_data(); + DataLayout* layout = data_layout_at(hint_di()); + if (layout->bci() <= bci) + return layout; + return data_layout_at(first_di()); } // What is the index of the first data entry? @@ -2251,7 +2251,9 @@ class MethodData : public Metadata { // Walk through the data in order. ProfileData* first_data() const { return data_at(first_di()); } ProfileData* next_data(ProfileData* current) const; + DataLayout* next_data_layout(DataLayout* current) const; bool is_valid(ProfileData* current) const { return current != NULL; } + bool is_valid(DataLayout* current) const { return current != NULL; } // Convert a dp (data pointer) to a di (data index). int dp_to_di(address dp) const { @@ -2415,7 +2417,6 @@ class MethodData : public Metadata { void clean_method_data(bool always_clean); void clean_weak_method_links(); - DEBUG_ONLY(void verify_clean_weak_method_links();) Mutex* extra_data_lock() { return &_extra_data_lock; } }; diff --git a/src/hotspot/share/opto/callnode.hpp b/src/hotspot/share/opto/callnode.hpp index f318dd6a3db..4688b01d534 100644 --- a/src/hotspot/share/opto/callnode.hpp +++ b/src/hotspot/share/opto/callnode.hpp @@ -716,8 +716,6 @@ class CallStaticJavaNode : public CallJavaNode { init_flags(Flag_is_macro); C->add_macro_node(this); } - _is_scalar_replaceable = false; - _is_non_escaping = false; } CallStaticJavaNode(const TypeFunc* tf, address addr, const char* name, int bci, const TypePtr* adr_type) @@ -725,15 +723,9 @@ class CallStaticJavaNode : public CallJavaNode { init_class_id(Class_CallStaticJava); // This node calls a runtime stub, which often has narrow memory effects. _adr_type = adr_type; - _is_scalar_replaceable = false; - _is_non_escaping = false; _name = name; } - // Result of Escape Analysis - bool _is_scalar_replaceable; - bool _is_non_escaping; - // If this is an uncommon trap, return the request code, else zero. int uncommon_trap_request() const; static int extract_uncommon_trap_request(const Node* call); diff --git a/src/hotspot/share/opto/compile.cpp b/src/hotspot/share/opto/compile.cpp index f01687ebb2c..39a375f027a 100644 --- a/src/hotspot/share/opto/compile.cpp +++ b/src/hotspot/share/opto/compile.cpp @@ -929,8 +929,6 @@ void Compile::Init(int aliaslevel) { set_max_inline_size(MaxInlineSize); set_freq_inline_size(FreqInlineSize); set_do_scheduling(OptoScheduling); - set_do_count_invocations(false); - set_do_method_data_update(false); set_do_vector_loop(false); diff --git a/src/hotspot/share/opto/compile.hpp b/src/hotspot/share/opto/compile.hpp index 615279aa116..46c4dcfb9c6 100644 --- a/src/hotspot/share/opto/compile.hpp +++ b/src/hotspot/share/opto/compile.hpp @@ -282,8 +282,6 @@ class Compile : public Phase { bool _do_inlining; // True if we intend to do inlining bool _do_scheduling; // True if we intend to do scheduling bool _do_freq_based_layout; // True if we intend to do frequency based block layout - bool _do_count_invocations; // True if we generate code to count invocations - bool _do_method_data_update; // True if we generate code to update MethodData*s bool _do_vector_loop; // True if allowed to execute loop in parallel iterations bool _use_cmove; // True if CMove should be used without profitability analysis bool _age_code; // True if we need to profile code age (decrement the aging counter) @@ -571,10 +569,6 @@ class Compile : public Phase { void set_do_scheduling(bool z) { _do_scheduling = z; } bool do_freq_based_layout() const{ return _do_freq_based_layout; } void set_do_freq_based_layout(bool z){ _do_freq_based_layout = z; } - bool do_count_invocations() const{ return _do_count_invocations; } - void set_do_count_invocations(bool z){ _do_count_invocations = z; } - bool do_method_data_update() const { return _do_method_data_update; } - void set_do_method_data_update(bool z) { _do_method_data_update = z; } bool do_vector_loop() const { return _do_vector_loop; } void set_do_vector_loop(bool z) { _do_vector_loop = z; } bool use_cmove() const { return _use_cmove; } diff --git a/src/hotspot/share/opto/doCall.cpp b/src/hotspot/share/opto/doCall.cpp index 7dba7b65dff..13053bb6317 100644 --- a/src/hotspot/share/opto/doCall.cpp +++ b/src/hotspot/share/opto/doCall.cpp @@ -643,10 +643,6 @@ void Parse::do_call() { receiver = record_profiled_receiver_for_speculation(receiver); } - // Bump method data counters (We profile *before* the call is made - // because exceptions don't return to the call site.) - profile_call(receiver); - JVMState* new_jvms = cg->generate(jvms); if (new_jvms == NULL) { // When inlining attempt fails (e.g., too many arguments), diff --git a/src/hotspot/share/opto/escape.cpp b/src/hotspot/share/opto/escape.cpp index da5590bf0f0..5742f4e862b 100644 --- a/src/hotspot/share/opto/escape.cpp +++ b/src/hotspot/share/opto/escape.cpp @@ -246,9 +246,6 @@ bool ConnectionGraph::compute_escape() { if (n->is_Allocate()) { n->as_Allocate()->_is_non_escaping = noescape; } - if (n->is_CallStaticJava()) { - n->as_CallStaticJava()->_is_non_escaping = noescape; - } if (noescape && ptn->scalar_replaceable()) { adjust_scalar_replaceable_state(ptn); if (ptn->scalar_replaceable()) { @@ -3068,11 +3065,6 @@ void ConnectionGraph::split_unique_types(GrowableArray &alloc_worklist, // so it could be eliminated if it has no uses. alloc->as_Allocate()->_is_scalar_replaceable = true; } - if (alloc->is_CallStaticJava()) { - // Set the scalar_replaceable flag for boxing method - // so it could be eliminated if it has no uses. - alloc->as_CallStaticJava()->_is_scalar_replaceable = true; - } continue; } if (!n->is_CheckCastPP()) { // not unique CheckCastPP. @@ -3121,11 +3113,6 @@ void ConnectionGraph::split_unique_types(GrowableArray &alloc_worklist, // so it could be eliminated. alloc->as_Allocate()->_is_scalar_replaceable = true; } - if (alloc->is_CallStaticJava()) { - // Set the scalar_replaceable flag for boxing method - // so it could be eliminated. - alloc->as_CallStaticJava()->_is_scalar_replaceable = true; - } set_escape_state(ptnode_adr(n->_idx), es); // CheckCastPP escape state // in order for an object to be scalar-replaceable, it must be: // - a direct allocation (not a call returning an object) diff --git a/src/hotspot/share/opto/loopTransform.cpp b/src/hotspot/share/opto/loopTransform.cpp index 8a374d0d15d..8ab78ce620d 100644 --- a/src/hotspot/share/opto/loopTransform.cpp +++ b/src/hotspot/share/opto/loopTransform.cpp @@ -1045,16 +1045,6 @@ void IdealLoopTree::policy_unroll_slp_analysis(CountedLoopNode *cl, PhaseIdealLo } } -//------------------------------policy_align----------------------------------- -// Return TRUE or FALSE if the loop should be cache-line aligned. Gather the -// expression that does the alignment. Note that only one array base can be -// aligned in a loop (unless the VM guarantees mutual alignment). Note that -// if we vectorize short memory ops into longer memory ops, we may want to -// increase alignment. -bool IdealLoopTree::policy_align(PhaseIdealLoop *phase) const { - return false; -} - //------------------------------policy_range_check----------------------------- // Return TRUE or FALSE if the loop should be range-check-eliminated or not. // When TRUE, the estimated node budget is also requested. @@ -3341,9 +3331,8 @@ bool IdealLoopTree::iteration_split_impl(PhaseIdealLoop *phase, Node_List &old_n uint est_peeling = estimate_peeling(phase); bool should_peel = 0 < est_peeling; - // Counted loops may be peeled, may need some iterations run up - // front for RCE, and may want to align loop refs to a cache - // line. Thus we clone a full loop up front whose trip count is + // Counted loops may be peeled, or may need some iterations run up + // front for RCE. Thus we clone a full loop up front whose trip count is // at least 1 (if peeling), but may be several more. // The main loop will start cache-line aligned with at least 1 @@ -3355,27 +3344,25 @@ bool IdealLoopTree::iteration_split_impl(PhaseIdealLoop *phase, Node_List &old_n bool should_unroll = policy_unroll(phase); bool should_rce = policy_range_check(phase); - // TODO: Remove align -- not used. - bool should_align = policy_align(phase); - // If not RCE'ing (iteration splitting) or Aligning, then we do not need a - // pre-loop. We may still need to peel an initial iteration but we will not + // If not RCE'ing (iteration splitting), then we do not need a pre-loop. + // We may still need to peel an initial iteration but we will not // be needing an unknown number of pre-iterations. // - // Basically, if may_rce_align reports FALSE first time through, we will not - // be able to later do RCE or Aligning on this loop. - bool may_rce_align = !policy_peel_only(phase) || should_rce || should_align; + // Basically, if peel_only reports TRUE first time through, we will not + // be able to later do RCE on this loop. + bool peel_only = policy_peel_only(phase) && !should_rce; - // If we have any of these conditions (RCE, alignment, unrolling) met, then + // If we have any of these conditions (RCE, unrolling) met, then // we switch to the pre-/main-/post-loop model. This model also covers // peeling. - if (should_rce || should_align || should_unroll) { + if (should_rce || should_unroll) { if (cl->is_normal_loop()) { // Convert to 'pre/main/post' loops uint estimate = est_loop_clone_sz(3); if (!phase->may_require_nodes(estimate)) { return false; } - phase->insert_pre_post_loops(this, old_new, !may_rce_align); + phase->insert_pre_post_loops(this, old_new, peel_only); } // Adjust the pre- and main-loop limits to let the pre and post loops run // with full checks, but the main-loop with no checks. Remove said checks @@ -3406,11 +3393,6 @@ bool IdealLoopTree::iteration_split_impl(PhaseIdealLoop *phase, Node_List &old_n } phase->do_unroll(this, old_new, true); } - - // Adjust the pre-loop limits to align the main body iterations. - if (should_align) { - Unimplemented(); - } } else { // Else we have an unchanged counted loop if (should_peel) { // Might want to peel but do nothing else if (phase->may_require_nodes(est_peeling)) { diff --git a/src/hotspot/share/opto/loopnode.hpp b/src/hotspot/share/opto/loopnode.hpp index ab6f783978f..ac65ffc09ed 100644 --- a/src/hotspot/share/opto/loopnode.hpp +++ b/src/hotspot/share/opto/loopnode.hpp @@ -617,13 +617,6 @@ class IdealLoopTree : public ResourceObj { // also gather the end of the first split and the start of the 2nd split. bool policy_range_check( PhaseIdealLoop *phase ) const; - // Return TRUE or FALSE if the loop should be cache-line aligned. - // Gather the expression that does the alignment. Note that only - // one array base can be aligned in a loop (unless the VM guarantees - // mutual alignment). Note that if we vectorize short memory ops - // into longer memory ops, we may want to increase alignment. - bool policy_align( PhaseIdealLoop *phase ) const; - // Return TRUE if "iff" is a range check. bool is_range_check_if(IfNode *iff, PhaseIdealLoop *phase, Invariance& invar) const; diff --git a/src/hotspot/share/opto/memnode.cpp b/src/hotspot/share/opto/memnode.cpp index f288225c0ba..09bb0fcd2c0 100644 --- a/src/hotspot/share/opto/memnode.cpp +++ b/src/hotspot/share/opto/memnode.cpp @@ -1268,6 +1268,59 @@ Node* LoadNode::convert_to_signed_load(PhaseGVN& gvn) { is_unaligned_access(), is_mismatched_access()); } +bool LoadNode::has_reinterpret_variant(const Type* rt) { + BasicType bt = rt->basic_type(); + switch (Opcode()) { + case Op_LoadI: return (bt == T_FLOAT); + case Op_LoadL: return (bt == T_DOUBLE); + case Op_LoadF: return (bt == T_INT); + case Op_LoadD: return (bt == T_LONG); + + default: return false; + } +} + +Node* LoadNode::convert_to_reinterpret_load(PhaseGVN& gvn, const Type* rt) { + BasicType bt = rt->basic_type(); + assert(has_reinterpret_variant(rt), "no reinterpret variant: %s %s", Name(), type2name(bt)); + bool is_mismatched = is_mismatched_access(); + const TypeRawPtr* raw_type = gvn.type(in(MemNode::Memory))->isa_rawptr(); + if (raw_type == NULL) { + is_mismatched = true; // conservatively match all non-raw accesses as mismatched + } + return LoadNode::make(gvn, in(MemNode::Control), in(MemNode::Memory), in(MemNode::Address), + raw_adr_type(), rt, bt, _mo, _control_dependency, + is_unaligned_access(), is_mismatched); +} + +bool StoreNode::has_reinterpret_variant(const Type* vt) { + BasicType bt = vt->basic_type(); + switch (Opcode()) { + case Op_StoreI: return (bt == T_FLOAT); + case Op_StoreL: return (bt == T_DOUBLE); + case Op_StoreF: return (bt == T_INT); + case Op_StoreD: return (bt == T_LONG); + + default: return false; + } +} + +Node* StoreNode::convert_to_reinterpret_store(PhaseGVN& gvn, Node* val, const Type* vt) { + BasicType bt = vt->basic_type(); + assert(has_reinterpret_variant(vt), "no reinterpret variant: %s %s", Name(), type2name(bt)); + StoreNode* st = StoreNode::make(gvn, in(MemNode::Control), in(MemNode::Memory), in(MemNode::Address), raw_adr_type(), val, bt, _mo); + + bool is_mismatched = is_mismatched_access(); + const TypeRawPtr* raw_type = gvn.type(in(MemNode::Memory))->isa_rawptr(); + if (raw_type == NULL) { + is_mismatched = true; // conservatively match all non-raw accesses as mismatched + } + if (is_mismatched) { + st->set_mismatched_access(); + } + return st; +} + // We're loading from an object which has autobox behaviour. // If this object is result of a valueOf call we'll have a phi // merging a newly allocated object and a load from the cache. @@ -2548,6 +2601,7 @@ Node *StoreNode::Ideal(PhaseGVN *phase, bool can_reshape) { Node* mem = in(MemNode::Memory); Node* address = in(MemNode::Address); + Node* value = in(MemNode::ValueIn); // Back-to-back stores to same address? Fold em up. Generally // unsafe if I have intervening uses... Also disallowed for StoreCM // since they must follow each StoreP operation. Redundant StoreCMs @@ -2611,6 +2665,19 @@ Node *StoreNode::Ideal(PhaseGVN *phase, bool can_reshape) { } } + // Fold reinterpret cast into memory operation: + // StoreX mem (MoveY2X v) => StoreY mem v + if (value->is_Move()) { + const Type* vt = value->in(1)->bottom_type(); + if (has_reinterpret_variant(vt)) { + if (phase->C->post_loop_opts_phase()) { + return convert_to_reinterpret_store(*phase, value->in(1), vt); + } else { + phase->C->record_for_post_loop_opts_igvn(this); // attempt the transformation once loop opts are over + } + } + } + return NULL; // No further progress } diff --git a/src/hotspot/share/opto/memnode.hpp b/src/hotspot/share/opto/memnode.hpp index 413c64e7604..8899a8f48f6 100644 --- a/src/hotspot/share/opto/memnode.hpp +++ b/src/hotspot/share/opto/memnode.hpp @@ -282,6 +282,9 @@ class LoadNode : public MemNode { Node* convert_to_unsigned_load(PhaseGVN& gvn); Node* convert_to_signed_load(PhaseGVN& gvn); + bool has_reinterpret_variant(const Type* rt); + Node* convert_to_reinterpret_load(PhaseGVN& gvn, const Type* rt); + void pin() { _control_dependency = Pinned; } bool has_unknown_control_dependency() const { return _control_dependency == UnknownControl; } @@ -634,6 +637,9 @@ class StoreNode : public MemNode { // have all possible loads of the value stored been optimized away? bool value_never_loaded(PhaseTransform *phase) const; + bool has_reinterpret_variant(const Type* vt); + Node* convert_to_reinterpret_store(PhaseGVN& gvn, Node* val, const Type* vt); + MemBarNode* trailing_membar() const; }; diff --git a/src/hotspot/share/opto/movenode.cpp b/src/hotspot/share/opto/movenode.cpp index ad550a7b078..f5a001d6648 100644 --- a/src/hotspot/share/opto/movenode.cpp +++ b/src/hotspot/share/opto/movenode.cpp @@ -352,6 +352,36 @@ Node *CMoveDNode::Ideal(PhaseGVN *phase, bool can_reshape) { return abs; } +//------------------------------MoveNode------------------------------------------ + +Node* MoveNode::Ideal(PhaseGVN* phase, bool can_reshape) { + if (can_reshape) { + // Fold reinterpret cast into memory operation: + // MoveX2Y (LoadX mem) => LoadY mem + LoadNode* ld = in(1)->isa_Load(); + if (ld != NULL && (ld->outcnt() == 1)) { // replace only + const Type* rt = bottom_type(); + if (ld->has_reinterpret_variant(rt)) { + if (phase->C->post_loop_opts_phase()) { + return ld->convert_to_reinterpret_load(*phase, rt); + } else { + phase->C->record_for_post_loop_opts_igvn(this); // attempt the transformation once loop opts are over + } + } + } + } + return NULL; +} + +Node* MoveNode::Identity(PhaseGVN* phase) { + if (in(1)->is_Move()) { + // Back-to-back moves: MoveX2Y (MoveY2X v) => v + assert(bottom_type() == in(1)->in(1)->bottom_type(), "sanity"); + return in(1)->in(1); + } + return this; +} + //------------------------------Value------------------------------------------ const Type* MoveL2DNode::Value(PhaseGVN* phase) const { const Type *t = phase->type( in(1) ); diff --git a/src/hotspot/share/opto/movenode.hpp b/src/hotspot/share/opto/movenode.hpp index 323cd7cc5d1..1e8b1b2489b 100644 --- a/src/hotspot/share/opto/movenode.hpp +++ b/src/hotspot/share/opto/movenode.hpp @@ -98,41 +98,52 @@ class CMoveNNode : public CMoveNode { }; // -class MoveI2FNode : public Node { +class MoveNode : public Node { + protected: + MoveNode(Node* value) : Node(NULL, value) { + init_class_id(Class_Move); + } + + public: + virtual Node* Ideal(PhaseGVN* phase, bool can_reshape); + virtual Node* Identity(PhaseGVN* phase); +}; + +class MoveI2FNode : public MoveNode { public: - MoveI2FNode( Node *value ) : Node(0,value) {} + MoveI2FNode(Node* value) : MoveNode(value) {} virtual int Opcode() const; - virtual const Type *bottom_type() const { return Type::FLOAT; } + virtual const Type* bottom_type() const { return Type::FLOAT; } virtual uint ideal_reg() const { return Op_RegF; } virtual const Type* Value(PhaseGVN* phase) const; virtual Node* Identity(PhaseGVN* phase); }; -class MoveL2DNode : public Node { +class MoveL2DNode : public MoveNode { public: - MoveL2DNode( Node *value ) : Node(0,value) {} + MoveL2DNode(Node* value) : MoveNode(value) {} virtual int Opcode() const; - virtual const Type *bottom_type() const { return Type::DOUBLE; } + virtual const Type* bottom_type() const { return Type::DOUBLE; } virtual uint ideal_reg() const { return Op_RegD; } virtual const Type* Value(PhaseGVN* phase) const; virtual Node* Identity(PhaseGVN* phase); }; -class MoveF2INode : public Node { +class MoveF2INode : public MoveNode { public: - MoveF2INode( Node *value ) : Node(0,value) {} + MoveF2INode(Node* value) : MoveNode(value) {} virtual int Opcode() const; - virtual const Type *bottom_type() const { return TypeInt::INT; } + virtual const Type* bottom_type() const { return TypeInt::INT; } virtual uint ideal_reg() const { return Op_RegI; } virtual const Type* Value(PhaseGVN* phase) const; virtual Node* Identity(PhaseGVN* phase); }; -class MoveD2LNode : public Node { +class MoveD2LNode : public MoveNode { public: - MoveD2LNode( Node *value ) : Node(0,value) {} + MoveD2LNode(Node* value) : MoveNode(value) {} virtual int Opcode() const; - virtual const Type *bottom_type() const { return TypeLong::LONG; } + virtual const Type* bottom_type() const { return TypeLong::LONG; } virtual uint ideal_reg() const { return Op_RegL; } virtual const Type* Value(PhaseGVN* phase) const; virtual Node* Identity(PhaseGVN* phase); diff --git a/src/hotspot/share/opto/node.hpp b/src/hotspot/share/opto/node.hpp index fc2d7e81d41..7dc59465a5e 100644 --- a/src/hotspot/share/opto/node.hpp +++ b/src/hotspot/share/opto/node.hpp @@ -112,6 +112,7 @@ class MemBarNode; class MemBarStoreStoreNode; class MemNode; class MergeMemNode; +class MoveNode; class MulNode; class MultiNode; class MultiBranchNode; @@ -721,10 +722,11 @@ class Node { DEFINE_CLASS_ID(Vector, Node, 13) DEFINE_CLASS_ID(VectorMaskCmp, Vector, 0) DEFINE_CLASS_ID(ClearArray, Node, 14) - DEFINE_CLASS_ID(Halt, Node, 15) - DEFINE_CLASS_ID(Opaque1, Node, 16) + DEFINE_CLASS_ID(Halt, Node, 15) + DEFINE_CLASS_ID(Opaque1, Node, 16) + DEFINE_CLASS_ID(Move, Node, 17) - _max_classes = ClassMask_Opaque1 + _max_classes = ClassMask_Move }; #undef DEFINE_CLASS_ID @@ -870,6 +872,7 @@ class Node { DEFINE_CLASS_QUERY(MemBar) DEFINE_CLASS_QUERY(MemBarStoreStore) DEFINE_CLASS_QUERY(MergeMem) + DEFINE_CLASS_QUERY(Move) DEFINE_CLASS_QUERY(Mul) DEFINE_CLASS_QUERY(Multi) DEFINE_CLASS_QUERY(MultiBranch) diff --git a/src/hotspot/share/opto/parse.hpp b/src/hotspot/share/opto/parse.hpp index a6e7703796a..6166ede33cc 100644 --- a/src/hotspot/share/opto/parse.hpp +++ b/src/hotspot/share/opto/parse.hpp @@ -330,8 +330,6 @@ class Parse : public GraphKit { bool _wrote_volatile; // Did we write a volatile field? bool _wrote_stable; // Did we write a @Stable field? bool _wrote_fields; // Did we write any field? - bool _count_invocations; // update and test invocation counter - bool _method_data_update; // update method data oop Node* _alloc_with_final; // An allocation node with final field // Variables which track Java semantics during bytecode parsing: @@ -377,8 +375,6 @@ class Parse : public GraphKit { void set_wrote_stable(bool z) { _wrote_stable = z; } bool wrote_fields() const { return _wrote_fields; } void set_wrote_fields(bool z) { _wrote_fields = z; } - bool count_invocations() const { return _count_invocations; } - bool method_data_update() const { return _method_data_update; } Node* alloc_with_final() const { return _alloc_with_final; } void set_alloc_with_final(Node* n) { assert((_alloc_with_final == NULL) || (_alloc_with_final == n), "different init objects?"); @@ -500,9 +496,6 @@ class Parse : public GraphKit { // Helper function to uncommon-trap or bailout for non-compilable call-sites bool can_not_compile_call_site(ciMethod *dest_method, ciInstanceKlass *klass); - // Helper function to setup for type-profile based inlining - bool prepare_type_profile_inline(ciInstanceKlass* prof_klass, ciMethod* prof_method); - // Helper functions for type checking bytecodes: void do_checkcast(); void do_instanceof(); @@ -555,9 +548,9 @@ class Parse : public GraphKit { void maybe_add_predicate_after_if(Block* path); IfNode* jump_if_fork_int(Node* a, Node* b, BoolTest::mask mask, float prob, float cnt); Node* jump_if_join(Node* iffalse, Node* iftrue); - void jump_if_true_fork(IfNode *ifNode, int dest_bci_if_true, int prof_table_index, bool unc); - void jump_if_false_fork(IfNode *ifNode, int dest_bci_if_false, int prof_table_index, bool unc); - void jump_if_always_fork(int dest_bci_if_true, int prof_table_index, bool unc); + void jump_if_true_fork(IfNode *ifNode, int dest_bci_if_true, bool unc); + void jump_if_false_fork(IfNode *ifNode, int dest_bci_if_false, bool unc); + void jump_if_always_fork(int dest_bci_if_true, bool unc); friend class SwitchRange; void do_tableswitch(); @@ -567,23 +560,6 @@ class Parse : public GraphKit { void linear_search_switch_ranges(Node* key_val, SwitchRange*& lo, SwitchRange*& hi); void decrement_age(); - // helper functions for methodData style profiling - void test_counter_against_threshold(Node* cnt, int limit); - void increment_and_test_invocation_counter(int limit); - void test_for_osr_md_counter_at(ciMethodData* md, ciProfileData* data, ByteSize offset, int limit); - Node* method_data_addressing(ciMethodData* md, ciProfileData* data, ByteSize offset, Node* idx = NULL, uint stride = 0); - void increment_md_counter_at(ciMethodData* md, ciProfileData* data, ByteSize offset, Node* idx = NULL, uint stride = 0); - void set_md_flag_at(ciMethodData* md, ciProfileData* data, int flag_constant); - - void profile_method_entry(); - void profile_taken_branch(int target_bci, bool force_update = false); - void profile_not_taken_branch(bool force_update = false); - void profile_call(Node* receiver); - void profile_generic_call(); - void profile_receiver_type(Node* receiver); - void profile_ret(int target_bci); - void profile_null_checkcast(); - void profile_switch_case(int table_index); // helper function for call statistics void count_compiled_calls(bool at_method_entry, bool is_inline) PRODUCT_RETURN; diff --git a/src/hotspot/share/opto/parse1.cpp b/src/hotspot/share/opto/parse1.cpp index baf2bf9bacc..73f1c4ab000 100644 --- a/src/hotspot/share/opto/parse1.cpp +++ b/src/hotspot/share/opto/parse1.cpp @@ -483,9 +483,6 @@ Parse::Parse(JVMState* caller, ciMethod* parse_method, float expected_uses) // Accumulate total sum of decompilations, also. C->set_decompile_count(C->decompile_count() + md->decompile_count()); - _count_invocations = C->do_count_invocations(); - _method_data_update = C->do_method_data_update(); - if (log != NULL && method()->has_exception_handlers()) { log->elem("observe that='has_exception_handlers'"); } @@ -1228,10 +1225,6 @@ void Parse::do_method_entry() { // Feed profiling data for parameters to the type system so it can // propagate it as speculative types record_profiled_parameters_for_speculation(); - - if (depth() == 1) { - increment_and_test_invocation_counter(Tier2CompileThreshold); - } } //------------------------------init_blocks------------------------------------ diff --git a/src/hotspot/share/opto/parse2.cpp b/src/hotspot/share/opto/parse2.cpp index 59e9ce7a9dd..d39e0456388 100644 --- a/src/hotspot/share/opto/parse2.cpp +++ b/src/hotspot/share/opto/parse2.cpp @@ -232,7 +232,7 @@ Node* Parse::jump_if_join(Node* iffalse, Node* iftrue) { static const int never_reached = INT_MAX; //------------------------------helper for tableswitch------------------------- -void Parse::jump_if_true_fork(IfNode *iff, int dest_bci_if_true, int prof_table_index, bool unc) { +void Parse::jump_if_true_fork(IfNode *iff, int dest_bci_if_true, bool unc) { // True branch, use existing map info { PreserveJVMState pjvms(this); Node *iftrue = _gvn.transform( new IfTrueNode (iff) ); @@ -245,7 +245,6 @@ void Parse::jump_if_true_fork(IfNode *iff, int dest_bci_if_true, int prof_table_ "taken always"); } else { assert(dest_bci_if_true != never_reached, "inconsistent dest"); - profile_switch_case(prof_table_index); merge_new_path(dest_bci_if_true); } } @@ -255,7 +254,7 @@ void Parse::jump_if_true_fork(IfNode *iff, int dest_bci_if_true, int prof_table_ set_control( iffalse ); } -void Parse::jump_if_false_fork(IfNode *iff, int dest_bci_if_true, int prof_table_index, bool unc) { +void Parse::jump_if_false_fork(IfNode *iff, int dest_bci_if_true, bool unc) { // True branch, use existing map info { PreserveJVMState pjvms(this); Node *iffalse = _gvn.transform( new IfFalseNode (iff) ); @@ -268,7 +267,6 @@ void Parse::jump_if_false_fork(IfNode *iff, int dest_bci_if_true, int prof_table "taken never"); } else { assert(dest_bci_if_true != never_reached, "inconsistent dest"); - profile_switch_case(prof_table_index); merge_new_path(dest_bci_if_true); } } @@ -278,7 +276,7 @@ void Parse::jump_if_false_fork(IfNode *iff, int dest_bci_if_true, int prof_table set_control( iftrue ); } -void Parse::jump_if_always_fork(int dest_bci, int prof_table_index, bool unc) { +void Parse::jump_if_always_fork(int dest_bci, bool unc) { // False branch, use existing map and control() if (unc) { repush_if_args(); @@ -288,7 +286,6 @@ void Parse::jump_if_always_fork(int dest_bci, int prof_table_index, bool unc) { "taken never"); } else { assert(dest_bci != never_reached, "inconsistent dest"); - profile_switch_case(prof_table_index); merge_new_path(dest_bci); } } @@ -303,34 +300,28 @@ extern "C" { } -// Default value for methodData switch indexing. Must be a negative value to avoid -// conflict with any legal switch index. -#define NullTableIndex -1 - class SwitchRange : public StackObj { // a range of integers coupled with a bci destination jint _lo; // inclusive lower limit jint _hi; // inclusive upper limit int _dest; - int _table_index; // index into method data table float _cnt; // how many times this range was hit according to profiling public: jint lo() const { return _lo; } jint hi() const { return _hi; } int dest() const { return _dest; } - int table_index() const { return _table_index; } bool is_singleton() const { return _lo == _hi; } float cnt() const { return _cnt; } - void setRange(jint lo, jint hi, int dest, int table_index, float cnt) { + void setRange(jint lo, jint hi, int dest, float cnt) { assert(lo <= hi, "must be a non-empty range"); - _lo = lo, _hi = hi; _dest = dest; _table_index = table_index; _cnt = cnt; + _lo = lo, _hi = hi; _dest = dest; _cnt = cnt; assert(_cnt >= 0, ""); } - bool adjoinRange(jint lo, jint hi, int dest, int table_index, float cnt, bool trim_ranges) { + bool adjoinRange(jint lo, jint hi, int dest, float cnt, bool trim_ranges) { assert(lo <= hi, "must be a non-empty range"); - if (lo == _hi+1 && table_index == _table_index) { + if (lo == _hi+1) { // see merge_ranges() comment below if (trim_ranges) { if (cnt == 0) { @@ -360,14 +351,14 @@ class SwitchRange : public StackObj { return false; } - void set (jint value, int dest, int table_index, float cnt) { - setRange(value, value, dest, table_index, cnt); + void set (jint value, int dest, float cnt) { + setRange(value, value, dest, cnt); } - bool adjoin(jint value, int dest, int table_index, float cnt, bool trim_ranges) { - return adjoinRange(value, value, dest, table_index, cnt, trim_ranges); + bool adjoin(jint value, int dest, float cnt, bool trim_ranges) { + return adjoinRange(value, value, dest, cnt, trim_ranges); } bool adjoin(SwitchRange& other) { - return adjoinRange(other._lo, other._hi, other._dest, other._table_index, other._cnt, false); + return adjoinRange(other._lo, other._hi, other._dest, other._cnt, false); } void print() { @@ -418,7 +409,7 @@ static void merge_ranges(SwitchRange* ranges, int& rp) { for (int j = 0; j <= rp; j++) { SwitchRange& r = ranges[j]; if (r.cnt() == 0 && r.dest() != never_reached) { - r.setRange(r.lo(), r.hi(), never_reached, r.table_index(), r.cnt()); + r.setRange(r.lo(), r.hi(), never_reached, r.cnt()); } } } @@ -447,7 +438,7 @@ void Parse::do_tableswitch() { profile = (ciMultiBranchData*)data; } } - bool trim_ranges = !method_data_update() && !C->too_many_traps(method(), bci(), Deoptimization::Reason_unstable_if); + bool trim_ranges = !C->too_many_traps(method(), bci(), Deoptimization::Reason_unstable_if); // generate decision tree, using trichotomy when possible int rnum = len+2; @@ -459,19 +450,18 @@ void Parse::do_tableswitch() { if (profile != NULL) { cnt = profile->default_count() / (hi_index != max_jint ? 2 : 1); } - ranges[++rp].setRange(min_jint, lo_index-1, default_dest, NullTableIndex, cnt); + ranges[++rp].setRange(min_jint, lo_index-1, default_dest, cnt); } for (int j = 0; j < len; j++) { jint match_int = lo_index+j; int dest = iter().get_dest_table(j+3); makes_backward_branch |= (dest <= bci()); - int table_index = method_data_update() ? j : NullTableIndex; uint cnt = 1; if (profile != NULL) { cnt = profile->count_at(j); } - if (rp < 0 || !ranges[rp].adjoin(match_int, dest, table_index, cnt, trim_ranges)) { - ranges[++rp].set(match_int, dest, table_index, cnt); + if (rp < 0 || !ranges[rp].adjoin(match_int, dest, cnt, trim_ranges)) { + ranges[++rp].set(match_int, dest, cnt); } } jint highest = lo_index+(len-1); @@ -481,8 +471,8 @@ void Parse::do_tableswitch() { if (profile != NULL) { cnt = profile->default_count() / (lo_index != min_jint ? 2 : 1); } - if (!ranges[rp].adjoinRange(highest+1, max_jint, default_dest, NullTableIndex, cnt, trim_ranges)) { - ranges[++rp].setRange(highest+1, max_jint, default_dest, NullTableIndex, cnt); + if (!ranges[rp].adjoinRange(highest+1, max_jint, default_dest, cnt, trim_ranges)) { + ranges[++rp].setRange(highest+1, max_jint, default_dest, cnt); } } assert(rp < len+2, "not too many ranges"); @@ -520,7 +510,7 @@ void Parse::do_lookupswitch() { profile = (ciMultiBranchData*)data; } } - bool trim_ranges = !method_data_update() && !C->too_many_traps(method(), bci(), Deoptimization::Reason_unstable_if); + bool trim_ranges = !C->too_many_traps(method(), bci(), Deoptimization::Reason_unstable_if); // generate decision tree, using trichotomy when possible jint* table = NEW_RESOURCE_ARRAY(jint, len*3); @@ -560,23 +550,22 @@ void Parse::do_lookupswitch() { int dest = table[3*j+1]; int cnt = table[3*j+2]; int next_lo = rp < 0 ? min_jint : ranges[rp].hi()+1; - int table_index = method_data_update() ? j : NullTableIndex; makes_backward_branch |= (dest <= bci()); float c = default_cnt * ((float)match_int - next_lo); - if (match_int != next_lo && (rp < 0 || !ranges[rp].adjoinRange(next_lo, match_int-1, default_dest, NullTableIndex, c, trim_ranges))) { + if (match_int != next_lo && (rp < 0 || !ranges[rp].adjoinRange(next_lo, match_int-1, default_dest, c, trim_ranges))) { assert(default_dest != never_reached, "sentinel value for dead destinations"); - ranges[++rp].setRange(next_lo, match_int-1, default_dest, NullTableIndex, c); + ranges[++rp].setRange(next_lo, match_int-1, default_dest, c); } - if (rp < 0 || !ranges[rp].adjoin(match_int, dest, table_index, cnt, trim_ranges)) { + if (rp < 0 || !ranges[rp].adjoin(match_int, dest, cnt, trim_ranges)) { assert(dest != never_reached, "sentinel value for dead destinations"); - ranges[++rp].set(match_int, dest, table_index, cnt); + ranges[++rp].set(match_int, dest, cnt); } } jint highest = table[3*(len-1)]; assert(ranges[rp].hi() == highest, ""); if (highest != max_jint && - !ranges[rp].adjoinRange(highest+1, max_jint, default_dest, NullTableIndex, default_cnt * ((float)max_jint - highest), trim_ranges)) { - ranges[++rp].setRange(highest+1, max_jint, default_dest, NullTableIndex, default_cnt * ((float)max_jint - highest)); + !ranges[rp].adjoinRange(highest+1, max_jint, default_dest, default_cnt * ((float)max_jint - highest), trim_ranges)) { + ranges[++rp].setRange(highest+1, max_jint, default_dest, default_cnt * ((float)max_jint - highest)); } assert(rp < rnum, "not too many ranges"); @@ -735,7 +724,7 @@ void Parse::linear_search_switch_ranges(Node* key_val, SwitchRange*& lo, SwitchR shift++; if (i > 0 && i < nr-1) { SwitchRange prev = lo[i-1]; - prev.setRange(prev.lo(), sr->hi(), prev.dest(), prev.table_index(), prev.cnt()); + prev.setRange(prev.lo(), sr->hi(), prev.dest(), prev.cnt()); if (prev.adjoin(lo[i+1])) { shift++; i++; @@ -762,7 +751,7 @@ void Parse::linear_search_switch_ranges(Node* key_val, SwitchRange*& lo, SwitchR Node* cmp = _gvn.transform(new CmpUNode(val, _gvn.intcon(most_freq.hi() - most_freq.lo()))); Node* tst = _gvn.transform(new BoolNode(cmp, BoolTest::le)); IfNode* iff = create_and_map_if(control(), tst, if_prob(most_freq.cnt(), total_cnt), if_cnt(most_freq.cnt())); - jump_if_true_fork(iff, most_freq.dest(), most_freq.table_index(), false); + jump_if_true_fork(iff, most_freq.dest(), false); sub += most_freq.cnt() / total_cnt; extra += 1 - sub; @@ -778,9 +767,6 @@ bool Parse::create_jump_tables(Node* key_val, SwitchRange* lo, SwitchRange* hi) // Are jumptables supported if (!Matcher::has_match_rule(Op_Jump)) return false; - // Don't make jump table if profiling - if (method_data_update()) return false; - bool trim_ranges = !C->too_many_traps(method(), bci(), Deoptimization::Reason_unstable_if); // Decide if a guard is needed to lop off big ranges at either (or @@ -858,7 +844,7 @@ bool Parse::create_jump_tables(Node* key_val, SwitchRange* lo, SwitchRange* hi) Node* cmp = _gvn.transform(new CmpUNode(key_val, size)); Node* tst = _gvn.transform(new BoolNode(cmp, BoolTest::ge)); IfNode* iff = create_and_map_if(control(), tst, if_prob(trimmed_cnt, total), if_cnt(trimmed_cnt)); - jump_if_true_fork(iff, default_dest, NullTableIndex, trim_ranges && trimmed_cnt == 0); + jump_if_true_fork(iff, default_dest, trim_ranges && trimmed_cnt == 0); total -= trimmed_cnt; } @@ -918,7 +904,7 @@ bool Parse::create_jump_tables(Node* key_val, SwitchRange* lo, SwitchRange* hi) { PreserveJVMState pjvms(this); set_control(input); - jump_if_always_fork(r->dest(), r->table_index(), trim_ranges && r->cnt() == 0); + jump_if_always_fork(r->dest(), trim_ranges && r->cnt() == 0); } } } @@ -930,7 +916,7 @@ bool Parse::create_jump_tables(Node* key_val, SwitchRange* lo, SwitchRange* hi) //----------------------------jump_switch_ranges------------------------------- void Parse::jump_switch_ranges(Node* key_val, SwitchRange *lo, SwitchRange *hi, int switch_depth) { Block* switch_block = block(); - bool trim_ranges = !method_data_update() && !C->too_many_traps(method(), bci(), Deoptimization::Reason_unstable_if); + bool trim_ranges = !C->too_many_traps(method(), bci(), Deoptimization::Reason_unstable_if); if (switch_depth == 0) { // Do special processing for the top-level call. @@ -971,13 +957,13 @@ void Parse::jump_switch_ranges(Node* key_val, SwitchRange *lo, SwitchRange *hi, lo++; } if (lo->lo() < min_val) { - lo->setRange(min_val, lo->hi(), lo->dest(), lo->table_index(), lo->cnt()); + lo->setRange(min_val, lo->hi(), lo->dest(), lo->cnt()); } while (hi->lo() > max_val) { hi--; } if (hi->hi() > max_val) { - hi->setRange(hi->lo(), max_val, hi->dest(), hi->table_index(), hi->cnt()); + hi->setRange(hi->lo(), max_val, hi->dest(), hi->cnt()); } linear_search_switch_ranges(key_val, lo, hi); @@ -992,7 +978,7 @@ void Parse::jump_switch_ranges(Node* key_val, SwitchRange *lo, SwitchRange *hi, assert(lo <= hi, "must be a non-empty set of ranges"); if (lo == hi) { - jump_if_always_fork(lo->dest(), lo->table_index(), trim_ranges && lo->cnt() == 0); + jump_if_always_fork(lo->dest(), trim_ranges && lo->cnt() == 0); } else { assert(lo->hi() == (lo+1)->lo()-1, "contiguous ranges"); assert(hi->lo() == (hi-1)->hi()+1, "contiguous ranges"); @@ -1030,7 +1016,7 @@ void Parse::jump_switch_ranges(Node* key_val, SwitchRange *lo, SwitchRange *hi, if (mid->is_singleton()) { IfNode *iff_ne = jump_if_fork_int(key_val, test_val, BoolTest::ne, 1-if_prob(mid->cnt(), total_cnt), if_cnt(mid->cnt())); - jump_if_false_fork(iff_ne, mid->dest(), mid->table_index(), trim_ranges && mid->cnt() == 0); + jump_if_false_fork(iff_ne, mid->dest(), trim_ranges && mid->cnt() == 0); // Special Case: If there are exactly three ranges, and the high // and low range each go to the same place, omit the "gt" test, @@ -1059,7 +1045,7 @@ void Parse::jump_switch_ranges(Node* key_val, SwitchRange *lo, SwitchRange *hi, // if there is a higher range, test for it and process it: if (mid == hi) { - jump_if_true_fork(iff_ge, mid->dest(), mid->table_index(), trim_ranges && cnt == 0); + jump_if_true_fork(iff_ge, mid->dest(), trim_ranges && cnt == 0); } else { Node *iftrue = _gvn.transform( new IfTrueNode(iff_ge) ); Node *iffalse = _gvn.transform( new IfFalseNode(iff_ge) ); @@ -1076,7 +1062,7 @@ void Parse::jump_switch_ranges(Node* key_val, SwitchRange *lo, SwitchRange *hi, if (mid->is_singleton()) { jump_switch_ranges(key_val, lo+1, hi, switch_depth+1); } else { - jump_if_always_fork(lo->dest(), lo->table_index(), trim_ranges && lo->cnt() == 0); + jump_if_always_fork(lo->dest(), trim_ranges && lo->cnt() == 0); } } else { jump_switch_ranges(key_val, lo, mid-1, switch_depth+1); @@ -1211,9 +1197,6 @@ void Parse::do_jsr() { int return_bci = iter().next_bci(); int jsr_bci = (bc() == Bytecodes::_jsr) ? iter().get_dest() : iter().get_far_dest(); - // Update method data - profile_taken_branch(jsr_bci); - // The way we do things now, there is only one successor block // for the jsr, because the target code is cloned by ciTypeFlow. Block* target = successor_for_bci(jsr_bci); @@ -1235,7 +1218,6 @@ void Parse::do_ret() { assert(block()->num_successors() == 1, "a ret can only go one place now"); Block* target = block()->successor_at(0); assert(!target->is_ready(), "our arrival must be expected"); - profile_ret(target->flow()->start()); int pnum = target->next_path_num(); merge_common(target, pnum); } @@ -1447,11 +1429,6 @@ void Parse::do_ifnull(BoolTest::mask btest, Node *c) { tty->print_cr("Never-taken edge stops compilation at bci %d", bci()); } repush_if_args(); // to gather stats on loop - // We need to mark this branch as taken so that if we recompile we will - // see that it is possible. In the tiered system the interpreter doesn't - // do profiling and by the time we get to the lower tier from the interpreter - // the path may be cold again. Make sure it doesn't look untaken - profile_taken_branch(target_bci, !ProfileInterpreter); uncommon_trap(Deoptimization::Reason_unreached, Deoptimization::Action_reinterpret, NULL, "cold"); @@ -1485,8 +1462,6 @@ void Parse::do_ifnull(BoolTest::mask btest, Node *c) { branch_block->next_path_num(); } } else { // Path is live. - // Update method data - profile_taken_branch(target_bci); adjust_map_after_if(btest, c, prob, branch_block, next_block); if (!stopped()) { merge(target_bci); @@ -1505,8 +1480,6 @@ void Parse::do_ifnull(BoolTest::mask btest, Node *c) { next_block->next_path_num(); } } else { // Path is live. - // Update method data - profile_not_taken_branch(); adjust_map_after_if(BoolTest(btest).negate(), c, 1.0-prob, next_block, branch_block); } @@ -1528,11 +1501,6 @@ void Parse::do_if(BoolTest::mask btest, Node* c) { tty->print_cr("Never-taken edge stops compilation at bci %d", bci()); } repush_if_args(); // to gather stats on loop - // We need to mark this branch as taken so that if we recompile we will - // see that it is possible. In the tiered system the interpreter doesn't - // do profiling and by the time we get to the lower tier from the interpreter - // the path may be cold again. Make sure it doesn't look untaken - profile_taken_branch(target_bci, !ProfileInterpreter); uncommon_trap(Deoptimization::Reason_unreached, Deoptimization::Action_reinterpret, NULL, "cold"); @@ -1607,8 +1575,6 @@ void Parse::do_if(BoolTest::mask btest, Node* c) { branch_block->next_path_num(); } } else { - // Update method data - profile_taken_branch(target_bci); adjust_map_after_if(taken_btest, c, prob, branch_block, next_block); if (!stopped()) { merge(target_bci); @@ -1626,8 +1592,6 @@ void Parse::do_if(BoolTest::mask btest, Node* c) { next_block->next_path_num(); } } else { - // Update method data - profile_not_taken_branch(); adjust_map_after_if(untaken_btest, c, untaken_prob, next_block, branch_block); } @@ -2691,9 +2655,6 @@ void Parse::do_one_bytecode() { // If this is a backwards branch in the bytecodes, add Safepoint maybe_add_safepoint(target_bci); - // Update method data - profile_taken_branch(target_bci); - // Merge the current control into the target basic block merge(target_bci); diff --git a/src/hotspot/share/opto/parseHelper.cpp b/src/hotspot/share/opto/parseHelper.cpp index d214c2a97b3..c885f7806b1 100644 --- a/src/hotspot/share/opto/parseHelper.cpp +++ b/src/hotspot/share/opto/parseHelper.cpp @@ -86,9 +86,6 @@ void Parse::do_checkcast() { } null_assert(obj); assert( stopped() || _gvn.type(peek())->higher_equal(TypePtr::NULL_PTR), "what's left behind is null" ); - if (!stopped()) { - profile_null_checkcast(); - } return; } @@ -299,287 +296,3 @@ void Parse::dump_map_adr_mem() const { #endif - -//============================================================================= -// -// parser methods for profiling - - -//----------------------test_counter_against_threshold ------------------------ -void Parse::test_counter_against_threshold(Node* cnt, int limit) { - // Test the counter against the limit and uncommon trap if greater. - - // This code is largely copied from the range check code in - // array_addressing() - - // Test invocation count vs threshold - Node *threshold = makecon(TypeInt::make(limit)); - Node *chk = _gvn.transform( new CmpUNode( cnt, threshold) ); - BoolTest::mask btest = BoolTest::lt; - Node *tst = _gvn.transform( new BoolNode( chk, btest) ); - // Branch to failure if threshold exceeded - { BuildCutout unless(this, tst, PROB_ALWAYS); - uncommon_trap(Deoptimization::Reason_age, - Deoptimization::Action_maybe_recompile); - } -} - -//----------------------increment_and_test_invocation_counter------------------- -void Parse::increment_and_test_invocation_counter(int limit) { - if (!count_invocations()) return; - - // Get the Method* node. - ciMethod* m = method(); - MethodCounters* counters_adr = m->ensure_method_counters(); - if (counters_adr == NULL) { - C->record_failure("method counters allocation failed"); - return; - } - - Node* ctrl = control(); - const TypePtr* adr_type = TypeRawPtr::make((address) counters_adr); - Node *counters_node = makecon(adr_type); - Node* adr_iic_node = basic_plus_adr(counters_node, counters_node, - MethodCounters::interpreter_invocation_counter_offset_in_bytes()); - Node* cnt = make_load(ctrl, adr_iic_node, TypeInt::INT, T_INT, adr_type, MemNode::unordered); - - test_counter_against_threshold(cnt, limit); - - // Add one to the counter and store - Node* incr = _gvn.transform(new AddINode(cnt, _gvn.intcon(1))); - store_to_memory(ctrl, adr_iic_node, incr, T_INT, adr_type, MemNode::unordered); -} - -//----------------------------method_data_addressing--------------------------- -Node* Parse::method_data_addressing(ciMethodData* md, ciProfileData* data, ByteSize counter_offset, Node* idx, uint stride) { - // Get offset within MethodData* of the data array - ByteSize data_offset = MethodData::data_offset(); - - // Get cell offset of the ProfileData within data array - int cell_offset = md->dp_to_di(data->dp()); - - // Add in counter_offset, the # of bytes into the ProfileData of counter or flag - int offset = in_bytes(data_offset) + cell_offset + in_bytes(counter_offset); - - const TypePtr* adr_type = TypeMetadataPtr::make(md); - Node* mdo = makecon(adr_type); - Node* ptr = basic_plus_adr(mdo, mdo, offset); - - if (stride != 0) { - Node* str = _gvn.MakeConX(stride); - Node* scale = _gvn.transform( new MulXNode( idx, str ) ); - ptr = _gvn.transform( new AddPNode( mdo, ptr, scale ) ); - } - - return ptr; -} - -//--------------------------increment_md_counter_at---------------------------- -void Parse::increment_md_counter_at(ciMethodData* md, ciProfileData* data, ByteSize counter_offset, Node* idx, uint stride) { - Node* adr_node = method_data_addressing(md, data, counter_offset, idx, stride); - - const TypePtr* adr_type = _gvn.type(adr_node)->is_ptr(); - Node* cnt = make_load(NULL, adr_node, TypeInt::INT, T_INT, adr_type, MemNode::unordered); - Node* incr = _gvn.transform(new AddINode(cnt, _gvn.intcon(DataLayout::counter_increment))); - store_to_memory(NULL, adr_node, incr, T_INT, adr_type, MemNode::unordered); -} - -//--------------------------test_for_osr_md_counter_at------------------------- -void Parse::test_for_osr_md_counter_at(ciMethodData* md, ciProfileData* data, ByteSize counter_offset, int limit) { - Node* adr_node = method_data_addressing(md, data, counter_offset); - - const TypePtr* adr_type = _gvn.type(adr_node)->is_ptr(); - Node* cnt = make_load(NULL, adr_node, TypeInt::INT, T_INT, adr_type, MemNode::unordered); - - test_counter_against_threshold(cnt, limit); -} - -//-------------------------------set_md_flag_at-------------------------------- -void Parse::set_md_flag_at(ciMethodData* md, ciProfileData* data, int flag_constant) { - Node* adr_node = method_data_addressing(md, data, DataLayout::flags_offset()); - - const TypePtr* adr_type = _gvn.type(adr_node)->is_ptr(); - Node* flags = make_load(NULL, adr_node, TypeInt::INT, T_INT, adr_type, MemNode::unordered); - Node* incr = _gvn.transform(new OrINode(flags, _gvn.intcon(flag_constant))); - store_to_memory(NULL, adr_node, incr, T_INT, adr_type, MemNode::unordered); -} - -//----------------------------profile_taken_branch----------------------------- -void Parse::profile_taken_branch(int target_bci, bool force_update) { - // This is a potential osr_site if we have a backedge. - int cur_bci = bci(); - bool osr_site = - (target_bci <= cur_bci) && count_invocations() && UseOnStackReplacement; - - // If we are going to OSR, restart at the target bytecode. - set_bci(target_bci); - - // To do: factor out the the limit calculations below. These duplicate - // the similar limit calculations in the interpreter. - - if (method_data_update() || force_update) { - ciMethodData* md = method()->method_data(); - assert(md != NULL, "expected valid ciMethodData"); - ciProfileData* data = md->bci_to_data(cur_bci); - assert(data != NULL && data->is_JumpData(), "need JumpData for taken branch"); - increment_md_counter_at(md, data, JumpData::taken_offset()); - } - - // In the new tiered system this is all we need to do. In the old - // (c2 based) tiered sytem we must do the code below. -#ifndef TIERED - if (method_data_update()) { - ciMethodData* md = method()->method_data(); - if (osr_site) { - ciProfileData* data = md->bci_to_data(cur_bci); - assert(data != NULL && data->is_JumpData(), "need JumpData for taken branch"); - int limit = (int)((int64_t)CompileThreshold - * (OnStackReplacePercentage - InterpreterProfilePercentage) / 100); - test_for_osr_md_counter_at(md, data, JumpData::taken_offset(), limit); - } - } else { - // With method data update off, use the invocation counter to trigger an - // OSR compilation, as done in the interpreter. - if (osr_site) { - int limit = (int)((int64_t)CompileThreshold * OnStackReplacePercentage / 100); - increment_and_test_invocation_counter(limit); - } - } -#endif // TIERED - - // Restore the original bytecode. - set_bci(cur_bci); -} - -//--------------------------profile_not_taken_branch--------------------------- -void Parse::profile_not_taken_branch(bool force_update) { - - if (method_data_update() || force_update) { - ciMethodData* md = method()->method_data(); - assert(md != NULL, "expected valid ciMethodData"); - ciProfileData* data = md->bci_to_data(bci()); - assert(data != NULL && data->is_BranchData(), "need BranchData for not taken branch"); - increment_md_counter_at(md, data, BranchData::not_taken_offset()); - } - -} - -//---------------------------------profile_call-------------------------------- -void Parse::profile_call(Node* receiver) { - if (!method_data_update()) return; - - switch (bc()) { - case Bytecodes::_invokevirtual: - case Bytecodes::_invokeinterface: - profile_receiver_type(receiver); - break; - case Bytecodes::_invokestatic: - case Bytecodes::_invokedynamic: - case Bytecodes::_invokespecial: - profile_generic_call(); - break; - default: fatal("unexpected call bytecode"); - } -} - -//------------------------------profile_generic_call--------------------------- -void Parse::profile_generic_call() { - assert(method_data_update(), "must be generating profile code"); - - ciMethodData* md = method()->method_data(); - assert(md != NULL, "expected valid ciMethodData"); - ciProfileData* data = md->bci_to_data(bci()); - assert(data != NULL && data->is_CounterData(), "need CounterData for not taken branch"); - increment_md_counter_at(md, data, CounterData::count_offset()); -} - -//-----------------------------profile_receiver_type--------------------------- -void Parse::profile_receiver_type(Node* receiver) { - assert(method_data_update(), "must be generating profile code"); - - ciMethodData* md = method()->method_data(); - assert(md != NULL, "expected valid ciMethodData"); - ciProfileData* data = md->bci_to_data(bci()); - assert(data != NULL && data->is_ReceiverTypeData(), "need ReceiverTypeData here"); - - // Skip if we aren't tracking receivers - if (TypeProfileWidth < 1) { - increment_md_counter_at(md, data, CounterData::count_offset()); - return; - } - ciReceiverTypeData* rdata = (ciReceiverTypeData*)data->as_ReceiverTypeData(); - - Node* method_data = method_data_addressing(md, rdata, in_ByteSize(0)); - - // Using an adr_type of TypePtr::BOTTOM to work around anti-dep problems. - // A better solution might be to use TypeRawPtr::BOTTOM with RC_NARROW_MEM. - make_runtime_call(RC_LEAF, OptoRuntime::profile_receiver_type_Type(), - CAST_FROM_FN_PTR(address, - OptoRuntime::profile_receiver_type_C), - "profile_receiver_type_C", - TypePtr::BOTTOM, - method_data, receiver); -} - -//---------------------------------profile_ret--------------------------------- -void Parse::profile_ret(int target_bci) { - if (!method_data_update()) return; - - // Skip if we aren't tracking ret targets - if (TypeProfileWidth < 1) return; - - ciMethodData* md = method()->method_data(); - assert(md != NULL, "expected valid ciMethodData"); - ciProfileData* data = md->bci_to_data(bci()); - assert(data != NULL && data->is_RetData(), "need RetData for ret"); - ciRetData* ret_data = (ciRetData*)data->as_RetData(); - - // Look for the target_bci is already in the table - uint row; - bool table_full = true; - for (row = 0; row < ret_data->row_limit(); row++) { - int key = ret_data->bci(row); - table_full &= (key != RetData::no_bci); - if (key == target_bci) break; - } - - if (row >= ret_data->row_limit()) { - // The target_bci was not found in the table. - if (!table_full) { - // XXX: Make slow call to update RetData - } - return; - } - - // the target_bci is already in the table - increment_md_counter_at(md, data, RetData::bci_count_offset(row)); -} - -//--------------------------profile_null_checkcast---------------------------- -void Parse::profile_null_checkcast() { - // Set the null-seen flag, done in conjunction with the usual null check. We - // never unset the flag, so this is a one-way switch. - if (!method_data_update()) return; - - ciMethodData* md = method()->method_data(); - assert(md != NULL, "expected valid ciMethodData"); - ciProfileData* data = md->bci_to_data(bci()); - assert(data != NULL && data->is_BitData(), "need BitData for checkcast"); - set_md_flag_at(md, data, BitData::null_seen_byte_constant()); -} - -//-----------------------------profile_switch_case----------------------------- -void Parse::profile_switch_case(int table_index) { - if (!method_data_update()) return; - - ciMethodData* md = method()->method_data(); - assert(md != NULL, "expected valid ciMethodData"); - - ciProfileData* data = md->bci_to_data(bci()); - assert(data != NULL && data->is_MultiBranchData(), "need MultiBranchData for switch case"); - if (table_index >= 0) { - increment_md_counter_at(md, data, MultiBranchData::case_count_offset(table_index)); - } else { - increment_md_counter_at(md, data, MultiBranchData::default_count_offset()); - } -} diff --git a/src/hotspot/share/opto/runtime.cpp b/src/hotspot/share/opto/runtime.cpp index fb6ef4a154c..f38a3a205d6 100644 --- a/src/hotspot/share/opto/runtime.cpp +++ b/src/hotspot/share/opto/runtime.cpp @@ -1210,60 +1210,6 @@ const TypeFunc* OptoRuntime::osr_end_Type() { return TypeFunc::make(domain, range); } -//-------------- methodData update helpers - -const TypeFunc* OptoRuntime::profile_receiver_type_Type() { - // create input type (domain) - const Type **fields = TypeTuple::fields(2); - fields[TypeFunc::Parms+0] = TypeAryPtr::NOTNULL; // methodData pointer - fields[TypeFunc::Parms+1] = TypeInstPtr::BOTTOM; // receiver oop - const TypeTuple *domain = TypeTuple::make(TypeFunc::Parms+2, fields); - - // create result type - fields = TypeTuple::fields(1); - fields[TypeFunc::Parms+0] = NULL; // void - const TypeTuple *range = TypeTuple::make(TypeFunc::Parms, fields); - return TypeFunc::make(domain,range); -} - -JRT_LEAF(void, OptoRuntime::profile_receiver_type_C(DataLayout* data, oopDesc* receiver)) - if (receiver == NULL) return; - Klass* receiver_klass = receiver->klass(); - - intptr_t* mdp = ((intptr_t*)(data)) + DataLayout::header_size_in_cells(); - int empty_row = -1; // free row, if any is encountered - - // ReceiverTypeData* vc = new ReceiverTypeData(mdp); - for (uint row = 0; row < ReceiverTypeData::row_limit(); row++) { - // if (vc->receiver(row) == receiver_klass) - int receiver_off = ReceiverTypeData::receiver_cell_index(row); - intptr_t row_recv = *(mdp + receiver_off); - if (row_recv == (intptr_t) receiver_klass) { - // vc->set_receiver_count(row, vc->receiver_count(row) + DataLayout::counter_increment); - int count_off = ReceiverTypeData::receiver_count_cell_index(row); - *(mdp + count_off) += DataLayout::counter_increment; - return; - } else if (row_recv == 0) { - // else if (vc->receiver(row) == NULL) - empty_row = (int) row; - } - } - - if (empty_row != -1) { - int receiver_off = ReceiverTypeData::receiver_cell_index(empty_row); - // vc->set_receiver(empty_row, receiver_klass); - *(mdp + receiver_off) = (intptr_t) receiver_klass; - // vc->set_receiver_count(empty_row, DataLayout::counter_increment); - int count_off = ReceiverTypeData::receiver_count_cell_index(empty_row); - *(mdp + count_off) = DataLayout::counter_increment; - } else { - // Receiver did not match any saved receiver and there is no empty row for it. - // Increment total counter to indicate polymorphic case. - intptr_t* count_p = (intptr_t*)(((uint8_t*)(data)) + in_bytes(CounterData::count_offset())); - *count_p += DataLayout::counter_increment; - } -JRT_END - //------------------------------------------------------------------------------------- // register policy diff --git a/src/hotspot/share/opto/runtime.hpp b/src/hotspot/share/opto/runtime.hpp index ffd5280d762..8f07b71de33 100644 --- a/src/hotspot/share/opto/runtime.hpp +++ b/src/hotspot/share/opto/runtime.hpp @@ -229,9 +229,6 @@ class OptoRuntime : public AllStatic { static ExceptionBlob* exception_blob() { return _exception_blob; } - // Leaf routines helping with method data update - static void profile_receiver_type_C(DataLayout* data, oopDesc* receiver); - // Implicit exception support static void throw_div0_exception_C (JavaThread* thread); static void throw_stack_overflow_error_C(JavaThread* thread); @@ -304,9 +301,6 @@ class OptoRuntime : public AllStatic { // leaf on stack replacement interpreter accessor types static const TypeFunc* osr_end_Type(); - // leaf methodData routine types - static const TypeFunc* profile_receiver_type_Type(); - // leaf on stack replacement interpreter accessor types static const TypeFunc* fetch_int_Type(); static const TypeFunc* fetch_long_Type(); diff --git a/src/hotspot/share/opto/superword.cpp b/src/hotspot/share/opto/superword.cpp index b5685a36460..a7515d3603e 100644 --- a/src/hotspot/share/opto/superword.cpp +++ b/src/hotspot/share/opto/superword.cpp @@ -91,6 +91,8 @@ SuperWord::SuperWord(PhaseIdealLoop* phase) : #endif } +static const bool _do_vector_loop_experimental = false; // Experimental vectorization which uses data from loop unrolling. + //------------------------------transform_loop--------------------------- void SuperWord::transform_loop(IdealLoopTree* lpt, bool do_optimization) { assert(UseSuperWord, "should be"); @@ -470,7 +472,7 @@ void SuperWord::SLP_extract() { CountedLoopNode *cl = lpt()->_head->as_CountedLoop(); bool post_loop_allowed = (PostLoopMultiversioning && Matcher::has_predicated_vectors() && cl->is_post_loop()); if (cl->is_main_loop()) { - if (_do_vector_loop) { + if (_do_vector_loop_experimental) { if (mark_generations() != -1) { hoist_loads_in_graph(); // this only rebuild the graph; all basic structs need rebuild explicitly @@ -508,11 +510,13 @@ void SuperWord::SLP_extract() { extend_packlist(); - if (_do_vector_loop) { + if (_do_vector_loop_experimental) { if (_packset.length() == 0) { +#ifndef PRODUCT if (TraceSuperWord) { tty->print_cr("\nSuperWord::_do_vector_loop DFA could not build packset, now trying to build anyway"); } +#endif pack_parallel(); } } @@ -1723,7 +1727,14 @@ void SuperWord::construct_my_pack_map() { Node_List* p = _packset.at(i); for (uint j = 0; j < p->size(); j++) { Node* s = p->at(j); - assert(my_pack(s) == NULL, "only in one pack"); +#ifdef ASSERT + if (my_pack(s) != NULL) { + s->dump(1); + tty->print_cr("packs[%d]:", i); + print_pack(p); + assert(false, "only in one pack"); + } +#endif set_my_pack(s, p); } } @@ -1738,7 +1749,7 @@ void SuperWord::filter_packs() { bool impl = implemented(pk); if (!impl) { #ifndef PRODUCT - if (TraceSuperWord && Verbose) { + if ((TraceSuperWord && Verbose) || _vector_loop_debug) { tty->print_cr("Unimplemented"); pk->at(0)->dump(); } @@ -1762,7 +1773,7 @@ void SuperWord::filter_packs() { bool prof = profitable(pk); if (!prof) { #ifndef PRODUCT - if (TraceSuperWord && Verbose) { + if ((TraceSuperWord && Verbose) || _vector_loop_debug) { tty->print_cr("Unprofitable"); pk->at(0)->dump(); } @@ -3052,12 +3063,13 @@ bool SuperWord::construct_bb() { int ii_current = -1; unsigned int load_idx = (unsigned int)-1; - _ii_order.clear(); + // Build iterations order if needed + bool build_ii_order = _do_vector_loop_experimental && _ii_order.is_empty(); // Create real map of block indices for nodes for (int j = 0; j < _block.length(); j++) { Node* n = _block.at(j); set_bb_idx(n, j); - if (_do_vector_loop && n->is_Load()) { + if (build_ii_order && n->is_Load()) { if (ii_current == -1) { ii_current = _clone_map.gen(n->_idx); _ii_order.push(ii_current); @@ -4700,6 +4712,15 @@ bool SuperWord::pack_parallel() { _packset.clear(); + if (_ii_order.is_empty()) { +#ifndef PRODUCT + if (_vector_loop_debug) { + tty->print_cr("SuperWord::pack_parallel: EMPTY"); + } +#endif + return false; + } + for (int ii = 0; ii < _iteration_first.length(); ii++) { Node* nd = _iteration_first.at(ii); if (in_bb(nd) && (nd->is_Load() || nd->is_Store() || nd->is_Add() || nd->is_Mul())) { diff --git a/src/hotspot/share/opto/type.cpp b/src/hotspot/share/opto/type.cpp index 25281ea3847..ff26780f786 100644 --- a/src/hotspot/share/opto/type.cpp +++ b/src/hotspot/share/opto/type.cpp @@ -3046,9 +3046,11 @@ TypeOopPtr::TypeOopPtr(TYPES t, PTR ptr, ciKlass* k, bool xk, ciObject* o, int o } else if (klass() == ciEnv::current()->Class_klass() && _offset >= InstanceMirrorKlass::offset_of_static_fields()) { // Static fields - assert(o != NULL, "must be constant"); - ciInstanceKlass* k = o->as_instance()->java_lang_Class_klass()->as_instance_klass(); - ciField* field = k->get_field_by_offset(_offset, true); + ciField* field = NULL; + if (const_oop() != NULL) { + ciInstanceKlass* k = const_oop()->as_instance()->java_lang_Class_klass()->as_instance_klass(); + field = k->get_field_by_offset(_offset, true); + } if (field != NULL) { BasicType basic_elem_type = field->layout_type(); _is_ptr_to_narrowoop = UseCompressedOops && is_reference_type(basic_elem_type); diff --git a/src/hotspot/share/opto/vectorIntrinsics.cpp b/src/hotspot/share/opto/vectorIntrinsics.cpp index abf11d4a48b..d06c8348907 100644 --- a/src/hotspot/share/opto/vectorIntrinsics.cpp +++ b/src/hotspot/share/opto/vectorIntrinsics.cpp @@ -100,7 +100,10 @@ static bool is_vector_shuffle(ciKlass* klass) { } static bool is_klass_initialized(const TypeInstPtr* vec_klass) { - assert(vec_klass->const_oop()->as_instance()->java_lang_Class_klass(), "klass instance expected"); + if (vec_klass->const_oop() == NULL) { + return false; // uninitialized or some kind of unsafe access + } + assert(vec_klass->const_oop()->as_instance()->java_lang_Class_klass() != NULL, "klass instance expected"); ciInstanceKlass* klass = vec_klass->const_oop()->as_instance()->java_lang_Class_klass()->as_instance_klass(); return klass->is_initialized(); } diff --git a/src/hotspot/share/prims/jvm.cpp b/src/hotspot/share/prims/jvm.cpp index 19f2eac8417..2ac00310f37 100644 --- a/src/hotspot/share/prims/jvm.cpp +++ b/src/hotspot/share/prims/jvm.cpp @@ -25,6 +25,7 @@ #include "precompiled.hpp" #include "jvm.h" #include "classfile/classFileStream.hpp" +#include "classfile/classListParser.hpp" #include "classfile/classListWriter.hpp" #include "classfile/classLoader.hpp" #include "classfile/classLoaderData.hpp" @@ -32,7 +33,6 @@ #include "classfile/classLoadInfo.hpp" #include "classfile/javaAssertions.hpp" #include "classfile/javaClasses.inline.hpp" -#include "classfile/lambdaFormInvokers.hpp" #include "classfile/moduleEntry.hpp" #include "classfile/modules.hpp" #include "classfile/packageEntry.hpp" @@ -3883,7 +3883,7 @@ JVM_ENTRY(void, JVM_LogLambdaFormInvoker(JNIEnv *env, jstring line)) Handle h_line (THREAD, JNIHandles::resolve_non_null(line)); char* c_line = java_lang_String::as_utf8_string(h_line()); ClassListWriter w; - w.stream()->print_cr("%s %s", LambdaFormInvokers::lambda_form_invoker_tag(), c_line); + w.stream()->print_cr("%s %s", LAMBDA_FORM_TAG, c_line); } #endif // INCLUDE_CDS JVM_END diff --git a/src/hotspot/share/prims/jvmtiEnv.cpp b/src/hotspot/share/prims/jvmtiEnv.cpp index 7cab2f2411f..85dfd406622 100644 --- a/src/hotspot/share/prims/jvmtiEnv.cpp +++ b/src/hotspot/share/prims/jvmtiEnv.cpp @@ -1653,17 +1653,9 @@ JvmtiEnv::PopFrame(JavaThread* java_thread) { // Eagerly reallocate scalar replaced objects. JavaThread* current_thread = JavaThread::current(); EscapeBarrier eb(true, current_thread, java_thread); - if (eb.barrier_active()) { - if (java_thread->frames_to_pop_failed_realloc() > 0) { - // VM is in the process of popping the top frame because it has scalar replaced objects which - // could not be reallocated on the heap. - // Return JVMTI_ERROR_OUT_OF_MEMORY to avoid interfering with the VM. - return JVMTI_ERROR_OUT_OF_MEMORY; - } - if (!eb.deoptimize_objects(1)) { - // Reallocation of scalar replaced objects failed -> return with error - return JVMTI_ERROR_OUT_OF_MEMORY; - } + if (!eb.deoptimize_objects(1)) { + // Reallocation of scalar replaced objects failed -> return with error + return JVMTI_ERROR_OUT_OF_MEMORY; } MutexLocker mu(JvmtiThreadState_lock); diff --git a/src/hotspot/share/prims/jvmtiEnvBase.cpp b/src/hotspot/share/prims/jvmtiEnvBase.cpp index b0d96f94aba..2065aa68f8c 100644 --- a/src/hotspot/share/prims/jvmtiEnvBase.cpp +++ b/src/hotspot/share/prims/jvmtiEnvBase.cpp @@ -1378,17 +1378,9 @@ JvmtiEnvBase::force_early_return(JavaThread* java_thread, jvalue value, TosState // Eagerly reallocate scalar replaced objects. JavaThread* current_thread = JavaThread::current(); EscapeBarrier eb(true, current_thread, java_thread); - if (eb.barrier_active()) { - if (java_thread->frames_to_pop_failed_realloc() > 0) { - // VM is in the process of popping the top frame because it has scalar replaced objects - // which could not be reallocated on the heap. - // Return JVMTI_ERROR_OUT_OF_MEMORY to avoid interfering with the VM. - return JVMTI_ERROR_OUT_OF_MEMORY; - } - if (!eb.deoptimize_objects(0)) { - // Reallocation of scalar replaced objects failed -> return with error - return JVMTI_ERROR_OUT_OF_MEMORY; - } + if (!eb.deoptimize_objects(0)) { + // Reallocation of scalar replaced objects failed -> return with error + return JVMTI_ERROR_OUT_OF_MEMORY; } SetForceEarlyReturn op(state, value, tos); diff --git a/src/hotspot/share/prims/jvmtiImpl.cpp b/src/hotspot/share/prims/jvmtiImpl.cpp index bb8875140ca..1617db70a8d 100644 --- a/src/hotspot/share/prims/jvmtiImpl.cpp +++ b/src/hotspot/share/prims/jvmtiImpl.cpp @@ -628,58 +628,12 @@ static bool can_be_deoptimized(vframe* vf) { return (vf->is_compiled_frame() && vf->fr().can_be_deoptimized()); } -// Revert optimizations based on escape analysis if this is an access to a local object -bool VM_GetOrSetLocal::deoptimize_objects(javaVFrame* jvf) { -#if COMPILER2_OR_JVMCI - assert(_type == T_OBJECT, "EscapeBarrier should not be active if _type != T_OBJECT"); - if (_depth < _thread->frames_to_pop_failed_realloc()) { - // cannot access frame with failed reallocations +bool VM_GetOrSetLocal::doit_prologue() { + if (!_eb.deoptimize_objects(_depth, _depth)) { + // The target frame is affected by a reallocation failure. _result = JVMTI_ERROR_OUT_OF_MEMORY; return false; } - if (can_be_deoptimized(jvf)) { - compiledVFrame* cf = compiledVFrame::cast(jvf); - if (cf->has_ea_local_in_scope() && !_eb.deoptimize_objects(cf->fr().id())) { - // reallocation of scalar replaced objects failed because heap is exhausted - _result = JVMTI_ERROR_OUT_OF_MEMORY; - return false; - } - } - - // With this access the object could escape the thread changing its escape state from ArgEscape, - // to GlobalEscape so we must deoptimize callers which could have optimized on the escape state. - vframe* vf = jvf; - do { - // move to next physical frame - while(!vf->is_top()) { - vf = vf->sender(); - } - vf = vf->sender(); - - if (vf != NULL && vf->is_compiled_frame()) { - compiledVFrame* cvf = compiledVFrame::cast(vf); - // Deoptimize objects if arg escape is being passed down the stack. - // Note that deoptimizing the frame is not enough because objects need to be relocked - if (cvf->arg_escape() && !_eb.deoptimize_objects(cvf->fr().id())) { - // reallocation of scalar replaced objects failed because heap is exhausted - _result = JVMTI_ERROR_OUT_OF_MEMORY; - return false; - } - } - } while(vf != NULL && !vf->is_entry_frame()); -#endif // COMPILER2_OR_JVMCI - return true; -} - -bool VM_GetOrSetLocal::doit_prologue() { - if (_eb.barrier_active()) { - _jvf = get_java_vframe(); - NULL_CHECK(_jvf, false); - - if (!deoptimize_objects(_jvf)) { - return false; - } - } return true; } diff --git a/src/hotspot/share/prims/jvmtiImpl.hpp b/src/hotspot/share/prims/jvmtiImpl.hpp index 7a3a2197b68..1895f9ab8e6 100644 --- a/src/hotspot/share/prims/jvmtiImpl.hpp +++ b/src/hotspot/share/prims/jvmtiImpl.hpp @@ -334,7 +334,6 @@ class VM_GetOrSetLocal : public VM_Operation { javaVFrame* get_java_vframe(); bool check_slot_type_lvt(javaVFrame* vf); bool check_slot_type_no_lvt(javaVFrame* vf); - bool deoptimize_objects(javaVFrame* vf); public: // Constructor for non-object getter diff --git a/src/hotspot/share/prims/whitebox.cpp b/src/hotspot/share/prims/whitebox.cpp index 901361052e7..223154ccc06 100644 --- a/src/hotspot/share/prims/whitebox.cpp +++ b/src/hotspot/share/prims/whitebox.cpp @@ -1245,7 +1245,7 @@ static bool SetVMFlag(JavaThread* thread, JNIEnv* env, jstring name, T* value) { const char* flag_name = env->GetStringUTFChars(name, NULL); CHECK_JNI_EXCEPTION_(env, false); JVMFlag* flag = JVMFlag::find_flag(flag_name); - JVMFlag::Error result = JVMFlagAccess::set(flag, value, JVMFlag::INTERNAL); + JVMFlag::Error result = JVMFlagAccess::set(flag, value, JVMFlagOrigin::INTERNAL); env->ReleaseStringUTFChars(name, flag_name); return (result == JVMFlag::SUCCESS); } diff --git a/src/hotspot/share/runtime/arguments.cpp b/src/hotspot/share/runtime/arguments.cpp index 43a505d7676..088fbe2885e 100644 --- a/src/hotspot/share/runtime/arguments.cpp +++ b/src/hotspot/share/runtime/arguments.cpp @@ -877,7 +877,7 @@ void Arguments::describe_range_error(ArgsRange errcode) { } } -static bool set_bool_flag(JVMFlag* flag, bool value, JVMFlag::Flags origin) { +static bool set_bool_flag(JVMFlag* flag, bool value, JVMFlagOrigin origin) { if (JVMFlagAccess::boolAtPut(flag, &value, origin) == JVMFlag::SUCCESS) { return true; } else { @@ -885,7 +885,7 @@ static bool set_bool_flag(JVMFlag* flag, bool value, JVMFlag::Flags origin) { } } -static bool set_fp_numeric_flag(JVMFlag* flag, char* value, JVMFlag::Flags origin) { +static bool set_fp_numeric_flag(JVMFlag* flag, char* value, JVMFlagOrigin origin) { char* end; errno = 0; double v = strtod(value, &end); @@ -899,7 +899,7 @@ static bool set_fp_numeric_flag(JVMFlag* flag, char* value, JVMFlag::Flags origi return false; } -static bool set_numeric_flag(JVMFlag* flag, char* value, JVMFlag::Flags origin) { +static bool set_numeric_flag(JVMFlag* flag, char* value, JVMFlagOrigin origin) { julong v; int int_v; intx intx_v; @@ -952,14 +952,14 @@ static bool set_numeric_flag(JVMFlag* flag, char* value, JVMFlag::Flags origin) } } -static bool set_string_flag(JVMFlag* flag, const char* value, JVMFlag::Flags origin) { +static bool set_string_flag(JVMFlag* flag, const char* value, JVMFlagOrigin origin) { if (JVMFlagAccess::ccstrAtPut(flag, &value, origin) != JVMFlag::SUCCESS) return false; // Contract: JVMFlag always returns a pointer that needs freeing. FREE_C_HEAP_ARRAY(char, value); return true; } -static bool append_to_string_flag(JVMFlag* flag, const char* new_value, JVMFlag::Flags origin) { +static bool append_to_string_flag(JVMFlag* flag, const char* new_value, JVMFlagOrigin origin) { const char* old_value = ""; if (JVMFlagAccess::ccstrAt(flag, &old_value) != JVMFlag::SUCCESS) return false; size_t old_len = old_value != NULL ? strlen(old_value) : 0; @@ -1060,7 +1060,7 @@ AliasedLoggingFlag Arguments::catch_logging_aliases(const char* name, bool on){ return a; } -bool Arguments::parse_argument(const char* arg, JVMFlag::Flags origin) { +bool Arguments::parse_argument(const char* arg, JVMFlagOrigin origin) { // range of acceptable characters spelled out for portability reasons #define NAME_RANGE "[abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_]" @@ -1275,7 +1275,7 @@ void Arguments::print_jvm_args_on(outputStream* st) { bool Arguments::process_argument(const char* arg, jboolean ignore_unrecognized, - JVMFlag::Flags origin) { + JVMFlagOrigin origin) { JDK_Version since = JDK_Version(); if (parse_argument(arg, origin)) { @@ -1404,7 +1404,7 @@ bool Arguments::process_settings_file(const char* file_name, bool should_exist, // this allows a way to include spaces in string-valued options token[pos] = '\0'; logOption(token); - result &= process_argument(token, ignore_unrecognized, JVMFlag::CONFIG_FILE); + result &= process_argument(token, ignore_unrecognized, JVMFlagOrigin::CONFIG_FILE); build_jvm_flags(token); pos = 0; in_white_space = true; @@ -1422,7 +1422,7 @@ bool Arguments::process_settings_file(const char* file_name, bool should_exist, } if (pos > 0) { token[pos] = '\0'; - result &= process_argument(token, ignore_unrecognized, JVMFlag::CONFIG_FILE); + result &= process_argument(token, ignore_unrecognized, JVMFlagOrigin::CONFIG_FILE); build_jvm_flags(token); } fclose(stream); @@ -1659,10 +1659,6 @@ void set_object_alignment() { // Oop encoding heap max OopEncodingHeapMax = (uint64_t(max_juint) + 1) << LogMinObjAlignmentInBytes; - - if (SurvivorAlignmentInBytes == 0) { - SurvivorAlignmentInBytes = ObjectAlignmentInBytes; - } } size_t Arguments::max_heap_for_compressed_oops() { @@ -2292,27 +2288,27 @@ jint Arguments::parse_vm_init_args(const JavaVMInitArgs *vm_options_args, set_mode_flags(_mixed); // Parse args structure generated from java.base vm options resource - jint result = parse_each_vm_init_arg(vm_options_args, &patch_mod_javabase, JVMFlag::JIMAGE_RESOURCE); + jint result = parse_each_vm_init_arg(vm_options_args, &patch_mod_javabase, JVMFlagOrigin::JIMAGE_RESOURCE); if (result != JNI_OK) { return result; } // Parse args structure generated from JAVA_TOOL_OPTIONS environment // variable (if present). - result = parse_each_vm_init_arg(java_tool_options_args, &patch_mod_javabase, JVMFlag::ENVIRON_VAR); + result = parse_each_vm_init_arg(java_tool_options_args, &patch_mod_javabase, JVMFlagOrigin::ENVIRON_VAR); if (result != JNI_OK) { return result; } // Parse args structure generated from the command line flags. - result = parse_each_vm_init_arg(cmd_line_args, &patch_mod_javabase, JVMFlag::COMMAND_LINE); + result = parse_each_vm_init_arg(cmd_line_args, &patch_mod_javabase, JVMFlagOrigin::COMMAND_LINE); if (result != JNI_OK) { return result; } // Parse args structure generated from the _JAVA_OPTIONS environment // variable (if present) (mimics classic VM) - result = parse_each_vm_init_arg(java_options_args, &patch_mod_javabase, JVMFlag::ENVIRON_VAR); + result = parse_each_vm_init_arg(java_options_args, &patch_mod_javabase, JVMFlagOrigin::ENVIRON_VAR); if (result != JNI_OK) { return result; } @@ -2456,7 +2452,7 @@ jint Arguments::parse_xss(const JavaVMOption* option, const char* tail, intx* ou return JNI_OK; } -jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, bool* patch_mod_javabase, JVMFlag::Flags origin) { +jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, bool* patch_mod_javabase, JVMFlagOrigin origin) { // For match_option to return remaining or value part of option string const char* tail; diff --git a/src/hotspot/share/runtime/arguments.hpp b/src/hotspot/share/runtime/arguments.hpp index 1a77eb3d302..eb3312dc588 100644 --- a/src/hotspot/share/runtime/arguments.hpp +++ b/src/hotspot/share/runtime/arguments.hpp @@ -28,11 +28,11 @@ #include "logging/logLevel.hpp" #include "logging/logTag.hpp" #include "memory/allocation.hpp" -#include "runtime/flags/jvmFlag.hpp" #include "runtime/java.hpp" #include "runtime/os.hpp" #include "runtime/perfData.hpp" #include "utilities/debug.hpp" +#include "utilities/vmEnums.hpp" // Arguments parses the command line and recognizes options @@ -408,8 +408,8 @@ class Arguments : AllStatic { static jint set_aggressive_heap_flags(); // Argument parsing - static bool parse_argument(const char* arg, JVMFlag::Flags origin); - static bool process_argument(const char* arg, jboolean ignore_unrecognized, JVMFlag::Flags origin); + static bool parse_argument(const char* arg, JVMFlagOrigin origin); + static bool process_argument(const char* arg, jboolean ignore_unrecognized, JVMFlagOrigin origin); static void process_java_launcher_argument(const char*, void*); static void process_java_compiler_argument(const char* arg); static jint parse_options_environment_variable(const char* name, ScopedVMInitArgs* vm_args); @@ -436,7 +436,7 @@ class Arguments : AllStatic { const JavaVMInitArgs *java_tool_options_args, const JavaVMInitArgs *java_options_args, const JavaVMInitArgs *cmd_line_args); - static jint parse_each_vm_init_arg(const JavaVMInitArgs* args, bool* patch_mod_javabase, JVMFlag::Flags origin); + static jint parse_each_vm_init_arg(const JavaVMInitArgs* args, bool* patch_mod_javabase, JVMFlagOrigin origin); static jint finalize_vm_init_args(bool patch_mod_javabase); static bool is_bad_option(const JavaVMOption* option, jboolean ignore, const char* option_type); diff --git a/src/hotspot/share/runtime/deoptimization.cpp b/src/hotspot/share/runtime/deoptimization.cpp index 1d9b6880202..6c89b3c773f 100644 --- a/src/hotspot/share/runtime/deoptimization.cpp +++ b/src/hotspot/share/runtime/deoptimization.cpp @@ -218,11 +218,6 @@ static bool eliminate_allocations(JavaThread* thread, int exec_mode, CompiledMet Thread* THREAD = thread; // Clear pending OOM if reallocation fails and return true indicating allocation failure realloc_failures = Deoptimization::realloc_objects(thread, &deoptee, &map, objects, CHECK_AND_CLEAR_(true)); - // Make sure the deoptee frame gets processed after a potential safepoint during - // object reallocation. This is necessary because (a) deoptee_thread can be - // different from the current thread and (b) the deoptee frame does not need to be - // the top frame. - StackWatermarkSet::finish_processing(deoptee_thread, NULL /* context */, StackWatermarkKind::gc); deoptimized_objects = true; } else { JRT_BLOCK diff --git a/src/hotspot/share/runtime/escapeBarrier.cpp b/src/hotspot/share/runtime/escapeBarrier.cpp index b6870e2209b..cc101d86b3e 100644 --- a/src/hotspot/share/runtime/escapeBarrier.cpp +++ b/src/hotspot/share/runtime/escapeBarrier.cpp @@ -33,6 +33,7 @@ #include "runtime/handles.hpp" #include "runtime/handshake.hpp" #include "runtime/interfaceSupport.inline.hpp" +#include "runtime/keepStackGCProcessed.hpp" #include "runtime/mutexLocker.hpp" #include "runtime/registerMap.hpp" #include "runtime/stackValue.hpp" @@ -62,29 +63,37 @@ bool EscapeBarrier::objs_are_deoptimized(JavaThread* thread, intptr_t* fr_id) { return result; } -// Object references of frames up to the given depth are about to be -// accessed. Frames with optimizations based on escape state that is potentially -// changed by the accesses need to be deoptimized and the referenced objects -// need to be reallocated and relocked. Up to depth this is done for frames -// with not escaping objects in scope. For deeper frames it is done only if -// they pass not escaping objects as arguments because they potentially escape -// from callee frames within the given depth. -// The search for deeper frames is ended if an entry frame is found because -// arguments to native methods are considered to escape globally. -bool EscapeBarrier::deoptimize_objects(int depth) { - if (barrier_active() && deoptee_thread()->has_last_Java_frame()) { +// Deoptimize objects of frames of the target thread at depth >= d1 and depth <= d2. +// Deoptimize objects of caller frames if they passed references to ArgEscape objects as arguments. +// Return false in the case of a reallocation failure and true otherwise. +bool EscapeBarrier::deoptimize_objects(int d1, int d2) { + if (!barrier_active()) return true; + if (d1 < deoptee_thread()->frames_to_pop_failed_realloc()) { + // The deoptee thread has frames with reallocation failures on top of its stack. + // These frames are about to be removed. We must not interfere with that and signal failure. + return false; + } + if (deoptee_thread()->has_last_Java_frame()) { assert(calling_thread() == Thread::current(), "should be"); + KeepStackGCProcessedMark ksgcpm(deoptee_thread()); ResourceMark rm(calling_thread()); HandleMark hm(calling_thread()); RegisterMap reg_map(deoptee_thread(), false /* update_map */, false /* process_frames */); vframe* vf = deoptee_thread()->last_java_vframe(®_map); int cur_depth = 0; - while (vf != NULL && ((cur_depth <= depth) || !vf->is_entry_frame())) { + + // Skip frames at depth < d1 + while (vf != NULL && cur_depth < d1) { + cur_depth++; + vf = vf->sender(); + } + + while (vf != NULL && ((cur_depth <= d2) || !vf->is_entry_frame())) { if (vf->is_compiled_frame()) { compiledVFrame* cvf = compiledVFrame::cast(vf); // Deoptimize frame and local objects if any exist. // If cvf is deeper than depth, then we deoptimize iff local objects are passed as args. - bool should_deopt = cur_depth <= depth ? cvf->has_ea_local_in_scope() : cvf->arg_escape(); + bool should_deopt = cur_depth <= d2 ? cvf->has_ea_local_in_scope() : cvf->arg_escape(); if (should_deopt && !deoptimize_objects(cvf->fr().id())) { // reallocation of scalar replaced objects failed because heap is exhausted return false; @@ -109,7 +118,13 @@ bool EscapeBarrier::deoptimize_objects_all_threads() { if (!barrier_active()) return true; ResourceMark rm(calling_thread()); for (JavaThreadIteratorWithHandle jtiwh; JavaThread *jt = jtiwh.next(); ) { + if (jt->frames_to_pop_failed_realloc() > 0) { + // The deoptee thread jt has frames with reallocation failures on top of its stack. + // These frames are about to be removed. We must not interfere with that and signal failure. + return false; + } if (jt->has_last_Java_frame()) { + KeepStackGCProcessedMark ksgcpm(jt); RegisterMap reg_map(jt, false /* update_map */, false /* process_frames */); vframe* vf = jt->last_java_vframe(®_map); assert(jt->frame_anchor()->walkable(), @@ -297,7 +312,7 @@ static void set_objs_are_deoptimized(JavaThread* thread, intptr_t* fr_id) { // frame is replaced with interpreter frames. Returns false iff at least one // reallocation failed. bool EscapeBarrier::deoptimize_objects_internal(JavaThread* deoptee, intptr_t* fr_id) { - if (!barrier_active()) return true; + assert(barrier_active(), "should not call"); JavaThread* ct = calling_thread(); bool realloc_failures = false; @@ -307,11 +322,7 @@ bool EscapeBarrier::deoptimize_objects_internal(JavaThread* deoptee, intptr_t* f compiledVFrame* last_cvf; bool fr_is_deoptimized; do { - if (!self_deopt()) { - // Process stack of deoptee thread as we will access oops during object deoptimization. - StackWatermarkSet::start_processing(deoptee, StackWatermarkKind::gc); - } - StackFrameStream fst(deoptee, true /* update */, true /* process_frames */); + StackFrameStream fst(deoptee, true /* update */, false /* process_frames */); while (fst.current()->id() != fr_id && !fst.is_done()) { fst.next(); } diff --git a/src/hotspot/share/runtime/escapeBarrier.hpp b/src/hotspot/share/runtime/escapeBarrier.hpp index 57230cbdb25..96df2827783 100644 --- a/src/hotspot/share/runtime/escapeBarrier.hpp +++ b/src/hotspot/share/runtime/escapeBarrier.hpp @@ -61,6 +61,12 @@ class EscapeBarrier : StackObj { // Deoptimize the given frame and deoptimize objects with optimizations based on escape analysis. bool deoptimize_objects_internal(JavaThread* deoptee, intptr_t* fr_id); + // Deoptimize objects, i.e. reallocate and relock them. The target frames are deoptimized. + // The methods return false iff at least one reallocation failed. + bool deoptimize_objects(intptr_t* fr_id) { + return deoptimize_objects_internal(deoptee_thread(), fr_id); + } + public: // Revert ea based optimizations for given deoptee thread EscapeBarrier(bool barrier_active, JavaThread* calling_thread, JavaThread* deoptee_thread) @@ -89,13 +95,17 @@ class EscapeBarrier : StackObj { bool barrier_active() const { return false; } #endif // COMPILER2_OR_JVMCI - // Deoptimize objects, i.e. reallocate and relock them. The target frames are deoptimized. - // The methods return false iff at least one reallocation failed. - bool deoptimize_objects(intptr_t* fr_id) { - return true COMPILER2_OR_JVMCI_PRESENT(&& deoptimize_objects_internal(deoptee_thread(), fr_id)); + // Deoptimize objects of frames of the target thread up to the given depth. + // Deoptimize objects of caller frames if they passed references to ArgEscape objects as arguments. + // Return false in the case of a reallocation failure and true otherwise. + bool deoptimize_objects(int depth) { + return deoptimize_objects(0, depth); } - bool deoptimize_objects(int depth) NOT_COMPILER2_OR_JVMCI_RETURN_(true); + // Deoptimize objects of frames of the target thread at depth >= d1 and depth <= d2. + // Deoptimize objects of caller frames if they passed references to ArgEscape objects as arguments. + // Return false in the case of a reallocation failure and true otherwise. + bool deoptimize_objects(int d1, int d2) NOT_COMPILER2_OR_JVMCI_RETURN_(true); // Find and deoptimize non escaping objects and the holding frames on all stacks. bool deoptimize_objects_all_threads() NOT_COMPILER2_OR_JVMCI_RETURN_(true); diff --git a/src/hotspot/share/runtime/flags/jvmFlag.cpp b/src/hotspot/share/runtime/flags/jvmFlag.cpp index d90a134d0b5..464f4a75f96 100644 --- a/src/hotspot/share/runtime/flags/jvmFlag.cpp +++ b/src/hotspot/share/runtime/flags/jvmFlag.cpp @@ -41,10 +41,15 @@ static bool is_product_build() { #endif } -void JVMFlag::set_origin(Flags origin) { +void JVMFlag::set_origin(JVMFlagOrigin new_origin) { + int old_flags = _flags; + int origin = static_cast(new_origin); assert((origin & VALUE_ORIGIN_MASK) == origin, "sanity"); - Flags new_origin = Flags((origin == COMMAND_LINE) ? Flags(origin | ORIG_COMMAND_LINE) : origin); - _flags = Flags((_flags & ~VALUE_ORIGIN_MASK) | new_origin); + int was_in_cmdline = (new_origin == JVMFlagOrigin::COMMAND_LINE) ? WAS_SET_ON_COMMAND_LINE : 0; + _flags = Flags((_flags & ~VALUE_ORIGIN_MASK) | origin | was_in_cmdline); + if ((old_flags & WAS_SET_ON_COMMAND_LINE) != 0) { + assert((_flags & WAS_SET_ON_COMMAND_LINE) != 0, "once initialized, should never change"); + } } /** @@ -376,29 +381,28 @@ void JVMFlag::print_kind(outputStream* st, unsigned int width) const { } void JVMFlag::print_origin(outputStream* st, unsigned int width) const { - int origin = _flags & VALUE_ORIGIN_MASK; st->print("{"); - switch(origin) { - case DEFAULT: + switch(get_origin()) { + case JVMFlagOrigin::DEFAULT: st->print("default"); break; - case COMMAND_LINE: + case JVMFlagOrigin::COMMAND_LINE: st->print("command line"); break; - case ENVIRON_VAR: + case JVMFlagOrigin::ENVIRON_VAR: st->print("environment"); break; - case CONFIG_FILE: + case JVMFlagOrigin::CONFIG_FILE: st->print("config file"); break; - case MANAGEMENT: + case JVMFlagOrigin::MANAGEMENT: st->print("management"); break; - case ERGONOMIC: - if (_flags & ORIG_COMMAND_LINE) { + case JVMFlagOrigin::ERGONOMIC: + if (_flags & WAS_SET_ON_COMMAND_LINE) { st->print("command line, "); } st->print("ergonomic"); break; - case ATTACH_ON_DEMAND: + case JVMFlagOrigin::ATTACH_ON_DEMAND: st->print("attach"); break; - case INTERNAL: + case JVMFlagOrigin::INTERNAL: st->print("internal"); break; - case JIMAGE_RESOURCE: + case JVMFlagOrigin::JIMAGE_RESOURCE: st->print("jimage"); break; } st->print("}"); @@ -495,7 +499,7 @@ static constexpr int flag_group(int flag_enum) { constexpr JVMFlag::JVMFlag(int flag_enum, FlagType type, const char* name, void* addr, int flags, int extra_flags, const char* doc) : _addr(addr), _name(name), _flags(), _type(type) NOT_PRODUCT(COMMA _doc(doc)) { - flags = flags | extra_flags | JVMFlag::DEFAULT | flag_group(flag_enum); + flags = flags | extra_flags | static_cast(JVMFlagOrigin::DEFAULT) | flag_group(flag_enum); if ((flags & JVMFlag::KIND_PRODUCT) != 0) { if (flags & (JVMFlag::KIND_DIAGNOSTIC | JVMFlag::KIND_MANAGEABLE | JVMFlag::KIND_EXPERIMENTAL)) { // Backwards compatibility. This will be relaxed in JDK-7123237. @@ -653,7 +657,7 @@ void JVMFlag::printSetFlags(outputStream* out) { // Print for (size_t i = 0; i < length; i++) { - if (array[i]->get_origin() /* naked field! */) { + if (array[i]->get_origin() != JVMFlagOrigin::DEFAULT) { array[i]->print_as_flag(out); out->print(" "); } diff --git a/src/hotspot/share/runtime/flags/jvmFlag.hpp b/src/hotspot/share/runtime/flags/jvmFlag.hpp index 9704ddd42f3..d4beb7d85e3 100644 --- a/src/hotspot/share/runtime/flags/jvmFlag.hpp +++ b/src/hotspot/share/runtime/flags/jvmFlag.hpp @@ -26,27 +26,34 @@ #define SHARE_RUNTIME_FLAGS_JVMFLAG_HPP #include "utilities/globalDefinitions.hpp" +#include "utilities/enumIterator.hpp" #include "utilities/macros.hpp" #include "utilities/vmEnums.hpp" class outputStream; +enum class JVMFlagOrigin : int { + // This is the value returned by JVMFlag::get_origin(). It records who + // has most recently changed the value of a JVMFlag. DEFAULT means that the + // flag was never changed, or was most recently changed by FLAG_SET_DEFAULT. + DEFAULT = 0, + COMMAND_LINE = 1, + ENVIRON_VAR = 2, + CONFIG_FILE = 3, + MANAGEMENT = 4, + ERGONOMIC = 5, + ATTACH_ON_DEMAND = 6, + INTERNAL = 7, + JIMAGE_RESOURCE = 8, +}; + +ENUMERATOR_RANGE(JVMFlagOrigin, JVMFlagOrigin::DEFAULT, JVMFlagOrigin::JIMAGE_RESOURCE) + class JVMFlag { friend class VMStructs; + public: enum Flags : int { - // latest value origin - DEFAULT = 0, - COMMAND_LINE = 1, - ENVIRON_VAR = 2, - CONFIG_FILE = 3, - MANAGEMENT = 4, - ERGONOMIC = 5, - ATTACH_ON_DEMAND = 6, - INTERNAL = 7, - JIMAGE_RESOURCE = 8, - - LAST_VALUE_ORIGIN = JIMAGE_RESOURCE, VALUE_ORIGIN_BITS = 4, VALUE_ORIGIN_MASK = right_n_bits(VALUE_ORIGIN_BITS), @@ -64,10 +71,15 @@ class JVMFlag { KIND_LP64_PRODUCT = 1 << 14, KIND_JVMCI = 1 << 15, - // set this bit if the flag was set on the command line - ORIG_COMMAND_LINE = 1 << 17, + // Note the difference: + // f->get_origin() == COMMAND_LINE + // f was mostly recently set by the command-line + // f->_flags & WAS_SET_ON_COMMAND_LINE + // f was specified on the command-line (but may have since been updated by + // someone else like FLAG_SET_ERGO) + WAS_SET_ON_COMMAND_LINE = 1 << 17, - KIND_MASK = ~(VALUE_ORIGIN_MASK | ORIG_COMMAND_LINE) + KIND_MASK = ~(VALUE_ORIGIN_MASK | WAS_SET_ON_COMMAND_LINE) }; enum Error { @@ -232,20 +244,20 @@ class JVMFlag { *static_cast(_addr) = value; } - Flags get_origin() const { return Flags(_flags & VALUE_ORIGIN_MASK); } - void set_origin(Flags origin); - - bool is_default() const { return (get_origin() == DEFAULT); } - bool is_ergonomic() const { return (get_origin() == ERGONOMIC); } - bool is_command_line() const { return (_flags & ORIG_COMMAND_LINE) != 0; } - void set_command_line() { _flags = Flags(_flags | ORIG_COMMAND_LINE); } - bool is_jimage_resource() const { return (get_origin() == JIMAGE_RESOURCE); } - bool is_product() const { return (_flags & KIND_PRODUCT) != 0; } - bool is_manageable() const { return (_flags & KIND_MANAGEABLE) != 0; } - bool is_diagnostic() const { return (_flags & KIND_DIAGNOSTIC) != 0; } - bool is_experimental() const { return (_flags & KIND_EXPERIMENTAL) != 0; } - bool is_notproduct() const { return (_flags & KIND_NOT_PRODUCT) != 0; } - bool is_develop() const { return (_flags & KIND_DEVELOP) != 0; } + JVMFlagOrigin get_origin() const { return JVMFlagOrigin(_flags & VALUE_ORIGIN_MASK); } + void set_origin(JVMFlagOrigin origin); + + bool is_default() const { return (get_origin() == JVMFlagOrigin::DEFAULT); } + bool is_ergonomic() const { return (get_origin() == JVMFlagOrigin::ERGONOMIC); } + bool is_command_line() const { return (_flags & WAS_SET_ON_COMMAND_LINE) != 0; } + void set_command_line() { _flags = Flags(_flags | WAS_SET_ON_COMMAND_LINE); } + bool is_jimage_resource() const { return (get_origin() == JVMFlagOrigin::JIMAGE_RESOURCE); } + bool is_product() const { return (_flags & KIND_PRODUCT) != 0; } + bool is_manageable() const { return (_flags & KIND_MANAGEABLE) != 0; } + bool is_diagnostic() const { return (_flags & KIND_DIAGNOSTIC) != 0; } + bool is_experimental() const { return (_flags & KIND_EXPERIMENTAL) != 0; } + bool is_notproduct() const { return (_flags & KIND_NOT_PRODUCT) != 0; } + bool is_develop() const { return (_flags & KIND_DEVELOP) != 0; } bool is_constant_in_binary() const; diff --git a/src/hotspot/share/runtime/flags/jvmFlagAccess.cpp b/src/hotspot/share/runtime/flags/jvmFlagAccess.cpp index 07ff6b1546e..51aeb086081 100644 --- a/src/hotspot/share/runtime/flags/jvmFlagAccess.cpp +++ b/src/hotspot/share/runtime/flags/jvmFlagAccess.cpp @@ -33,22 +33,22 @@ #include "utilities/ostream.hpp" template -static void trace_flag_changed(JVMFlag* flag, const T old_value, const T new_value, const JVMFlag::Flags origin) { +static void trace_flag_changed(JVMFlag* flag, const T old_value, const T new_value, const JVMFlagOrigin origin) { EVENT e; e.set_name(flag->name()); e.set_oldValue(old_value); e.set_newValue(new_value); - e.set_origin(origin); + e.set_origin(static_cast(origin)); e.commit(); } class FlagAccessImpl { public: - JVMFlag::Error set(JVMFlag* flag, void* value, JVMFlag::Flags origin) const { + JVMFlag::Error set(JVMFlag* flag, void* value, JVMFlagOrigin origin) const { return set_impl(flag, value, origin); } - virtual JVMFlag::Error set_impl(JVMFlag* flag, void* value, JVMFlag::Flags origin) const = 0; + virtual JVMFlag::Error set_impl(JVMFlag* flag, void* value, JVMFlagOrigin origin) const = 0; virtual JVMFlag::Error check_range(const JVMFlag* flag, bool verbose) const { return JVMFlag::SUCCESS; } virtual void print_range(outputStream* st, const JVMFlagLimit* range) const { ShouldNotReachHere(); } virtual void print_default_range(outputStream* st) const { ShouldNotReachHere(); } @@ -59,7 +59,7 @@ template class TypedFlagAccessImpl : public FlagAccessImpl { public: - JVMFlag::Error check_constraint_and_set(JVMFlag* flag, void* value_addr, JVMFlag::Flags origin, bool verbose) const { + JVMFlag::Error check_constraint_and_set(JVMFlag* flag, void* value_addr, JVMFlagOrigin origin, bool verbose) const { T value = *((T*)value_addr); const JVMTypedFlagLimit* constraint = (const JVMTypedFlagLimit*)JVMFlagLimit::get_constraint(flag); if (constraint != NULL && constraint->phase() <= static_cast(JVMFlagLimit::validating_phase())) { @@ -87,7 +87,7 @@ class TypedFlagAccessImpl : public FlagAccessImpl { class FlagAccessImpl_bool : public TypedFlagAccessImpl { public: - JVMFlag::Error set_impl(JVMFlag* flag, void* value_addr, JVMFlag::Flags origin) const { + JVMFlag::Error set_impl(JVMFlag* flag, void* value_addr, JVMFlagOrigin origin) const { bool verbose = JVMFlagLimit::verbose_checks_needed(); return TypedFlagAccessImpl ::check_constraint_and_set(flag, value_addr, origin, verbose); @@ -101,7 +101,7 @@ class FlagAccessImpl_bool : public TypedFlagAccessImpl class RangedFlagAccessImpl : public TypedFlagAccessImpl { public: - virtual JVMFlag::Error set_impl(JVMFlag* flag, void* value_addr, JVMFlag::Flags origin) const { + virtual JVMFlag::Error set_impl(JVMFlag* flag, void* value_addr, JVMFlagOrigin origin) const { T value = *((T*)value_addr); bool verbose = JVMFlagLimit::verbose_checks_needed(); @@ -292,7 +292,7 @@ inline const FlagAccessImpl* JVMFlagAccess::access_impl(const JVMFlag* flag) { } // This is called by JVMFlagAccess::*AtPut() and JVMFlagAccess::set<...>(JVMFlag* flag, ...) -JVMFlag::Error JVMFlagAccess::set_impl(JVMFlag* flag, int type_enum, void* value, JVMFlag::Flags origin) { +JVMFlag::Error JVMFlagAccess::set_impl(JVMFlag* flag, int type_enum, void* value, JVMFlagOrigin origin) { if (type_enum == JVMFlag::TYPE_ccstr || type_enum == JVMFlag::TYPE_ccstrlist) { return ccstrAtPut(flag, (ccstr*)value, origin); } @@ -306,7 +306,7 @@ JVMFlag::Error JVMFlagAccess::set_impl(JVMFlag* flag, int type_enum, void* value return access_impl(flag)->set(flag, value, origin); } -JVMFlag::Error JVMFlagAccess::ccstrAtPut(JVMFlag* flag, ccstr* value, JVMFlag::Flags origin) { +JVMFlag::Error JVMFlagAccess::ccstrAtPut(JVMFlag* flag, ccstr* value, JVMFlagOrigin origin) { if (flag == NULL) return JVMFlag::INVALID_FLAG; if (!flag->is_ccstr()) return JVMFlag::WRONG_FORMAT; ccstr old_value = flag->get_ccstr(); @@ -326,7 +326,7 @@ JVMFlag::Error JVMFlagAccess::ccstrAtPut(JVMFlag* flag, ccstr* value, JVMFlag::F } // This is called by the FLAG_SET_XXX macros. -JVMFlag::Error JVMFlagAccess::set_impl(JVMFlagsEnum flag_enum, int type_enum, void* value, JVMFlag::Flags origin) { +JVMFlag::Error JVMFlagAccess::set_impl(JVMFlagsEnum flag_enum, int type_enum, void* value, JVMFlagOrigin origin) { if (type_enum == JVMFlag::TYPE_ccstr || type_enum == JVMFlag::TYPE_ccstrlist) { return ccstrAtPut((JVMFlagsEnum)flag_enum, *((ccstr*)value), origin); } @@ -337,7 +337,7 @@ JVMFlag::Error JVMFlagAccess::set_impl(JVMFlagsEnum flag_enum, int type_enum, vo } // This is called by the FLAG_SET_XXX macros. -JVMFlag::Error JVMFlagAccess::ccstrAtPut(JVMFlagsEnum flag, ccstr value, JVMFlag::Flags origin) { +JVMFlag::Error JVMFlagAccess::ccstrAtPut(JVMFlagsEnum flag, ccstr value, JVMFlagOrigin origin) { JVMFlag* faddr = JVMFlag::flag_from_enum(flag); assert(faddr->is_ccstr(), "wrong flag type"); ccstr old_value = faddr->get_ccstr(); diff --git a/src/hotspot/share/runtime/flags/jvmFlagAccess.hpp b/src/hotspot/share/runtime/flags/jvmFlagAccess.hpp index ce5dff42e87..91e41ded3da 100644 --- a/src/hotspot/share/runtime/flags/jvmFlagAccess.hpp +++ b/src/hotspot/share/runtime/flags/jvmFlagAccess.hpp @@ -52,9 +52,9 @@ class outputStream; // of setters are provided. See notes below on which one to use. class JVMFlagAccess : AllStatic { inline static const FlagAccessImpl* access_impl(const JVMFlag* flag); - static JVMFlag::Error set_impl(JVMFlagsEnum flag_enum, int type_enum, void* value, JVMFlag::Flags origin); - static JVMFlag::Error set_impl(JVMFlag* flag, int type_enum, void* value, JVMFlag::Flags origin); - static JVMFlag::Error ccstrAtPut(JVMFlagsEnum flag, ccstr value, JVMFlag::Flags origin); + static JVMFlag::Error set_impl(JVMFlagsEnum flag_enum, int type_enum, void* value, JVMFlagOrigin origin); + static JVMFlag::Error set_impl(JVMFlag* flag, int type_enum, void* value, JVMFlagOrigin origin); + static JVMFlag::Error ccstrAtPut(JVMFlagsEnum flag, ccstr value, JVMFlagOrigin origin); public: static JVMFlag::Error check_range(const JVMFlag* flag, bool verbose); @@ -85,7 +85,7 @@ class JVMFlagAccess : AllStatic { // It's used to set a specific flag whose type is statically known. A mismatched // type_enum will result in an assert. template - static JVMFlag::Error set(JVMFlagsEnum flag_enum, T value, JVMFlag::Flags origin) { + static JVMFlag::Error set(JVMFlagsEnum flag_enum, T value, JVMFlagOrigin origin) { return set_impl(flag_enum, type_enum, &value, origin); } @@ -95,23 +95,23 @@ class JVMFlagAccess : AllStatic { // Examples callers are arguments.cpp, writeableFlags.cpp, and WB_SetXxxVMFlag functions. // A mismatched type_enum would result in a JVMFlag::WRONG_FORMAT code. template - static JVMFlag::Error set(JVMFlag* flag, T* value, JVMFlag::Flags origin) { + static JVMFlag::Error set(JVMFlag* flag, T* value, JVMFlagOrigin origin) { return set_impl(flag, type_enum, (void*)value, origin); } - static JVMFlag::Error boolAtPut (JVMFlag* f, bool* v, JVMFlag::Flags origin) { return set (f, v, origin); } - static JVMFlag::Error intAtPut (JVMFlag* f, int* v, JVMFlag::Flags origin) { return set (f, v, origin); } - static JVMFlag::Error uintAtPut (JVMFlag* f, uint* v, JVMFlag::Flags origin) { return set (f, v, origin); } - static JVMFlag::Error intxAtPut (JVMFlag* f, intx* v, JVMFlag::Flags origin) { return set (f, v, origin); } - static JVMFlag::Error uintxAtPut (JVMFlag* f, uintx* v, JVMFlag::Flags origin) { return set (f, v, origin); } - static JVMFlag::Error uint64_tAtPut(JVMFlag* f, uint64_t* v, JVMFlag::Flags origin) { return set(f, v, origin); } - static JVMFlag::Error size_tAtPut (JVMFlag* f, size_t* v, JVMFlag::Flags origin) { return set (f, v, origin); } - static JVMFlag::Error doubleAtPut (JVMFlag* f, double* v, JVMFlag::Flags origin) { return set (f, v, origin); } + static JVMFlag::Error boolAtPut (JVMFlag* f, bool* v, JVMFlagOrigin origin) { return set (f, v, origin); } + static JVMFlag::Error intAtPut (JVMFlag* f, int* v, JVMFlagOrigin origin) { return set (f, v, origin); } + static JVMFlag::Error uintAtPut (JVMFlag* f, uint* v, JVMFlagOrigin origin) { return set (f, v, origin); } + static JVMFlag::Error intxAtPut (JVMFlag* f, intx* v, JVMFlagOrigin origin) { return set (f, v, origin); } + static JVMFlag::Error uintxAtPut (JVMFlag* f, uintx* v, JVMFlagOrigin origin) { return set (f, v, origin); } + static JVMFlag::Error uint64_tAtPut(JVMFlag* f, uint64_t* v, JVMFlagOrigin origin) { return set(f, v, origin); } + static JVMFlag::Error size_tAtPut (JVMFlag* f, size_t* v, JVMFlagOrigin origin) { return set (f, v, origin); } + static JVMFlag::Error doubleAtPut (JVMFlag* f, double* v, JVMFlagOrigin origin) { return set (f, v, origin); } // Special handling needed for ccstr // Contract: JVMFlag will make private copy of the incoming value. // Outgoing value is always malloc-ed, and caller MUST call free. - static JVMFlag::Error ccstrAtPut(JVMFlag* flag, ccstr* value, JVMFlag::Flags origin); + static JVMFlag::Error ccstrAtPut(JVMFlag* flag, ccstr* value, JVMFlagOrigin origin); // Handy aliases static JVMFlag::Error ccstrAt(const JVMFlag* flag, ccstr* value) { diff --git a/src/hotspot/share/runtime/globals.hpp b/src/hotspot/share/runtime/globals.hpp index 4b77de98941..6ae94f95a5c 100644 --- a/src/hotspot/share/runtime/globals.hpp +++ b/src/hotspot/share/runtime/globals.hpp @@ -2393,11 +2393,6 @@ const intx ObjectAlignmentInBytes = 8; product(bool, WhiteBoxAPI, false, DIAGNOSTIC, \ "Enable internal testing APIs") \ \ - product(intx, SurvivorAlignmentInBytes, 0, EXPERIMENTAL, \ - "Default survivor space alignment in bytes") \ - range(8, 256) \ - constraint(SurvivorAlignmentInBytesConstraintFunc,AfterErgo) \ - \ product(ccstr, DumpLoadedClassList, NULL, \ "Dump the names all loaded classes, that could be stored into " \ "the CDS archive, in the specified file") \ diff --git a/src/hotspot/share/runtime/globals_extension.hpp b/src/hotspot/share/runtime/globals_extension.hpp index e5a7750e3d6..ceb5413b212 100644 --- a/src/hotspot/share/runtime/globals_extension.hpp +++ b/src/hotspot/share/runtime/globals_extension.hpp @@ -53,7 +53,7 @@ enum JVMFlagsEnum : int { #define FLAG_MEMBER_SETTER(name) Flag_##name##_set #define FLAG_MEMBER_SETTER_(type, name) \ - inline JVMFlag::Error FLAG_MEMBER_SETTER(name)(type value, JVMFlag::Flags origin) { \ + inline JVMFlag::Error FLAG_MEMBER_SETTER(name)(type value, JVMFlagOrigin origin) { \ return JVMFlagAccess::set(FLAG_MEMBER_ENUM(name), value, origin); \ } @@ -75,9 +75,9 @@ ALL_FLAGS(DEFINE_FLAG_MEMBER_SETTER, #define FLAG_SET_DEFAULT(name, value) ((name) = (value)) #define FLAG_SET_CMDLINE(name, value) (JVMFlag::setOnCmdLine(FLAG_MEMBER_ENUM(name)), \ - FLAG_MEMBER_SETTER(name)((value), JVMFlag::COMMAND_LINE)) -#define FLAG_SET_ERGO(name, value) (FLAG_MEMBER_SETTER(name)((value), JVMFlag::ERGONOMIC)) -#define FLAG_SET_MGMT(name, value) (FLAG_MEMBER_SETTER(name)((value), JVMFlag::MANAGEMENT)) + FLAG_MEMBER_SETTER(name)((value), JVMFlagOrigin::COMMAND_LINE)) +#define FLAG_SET_ERGO(name, value) (FLAG_MEMBER_SETTER(name)((value), JVMFlagOrigin::ERGONOMIC)) +#define FLAG_SET_MGMT(name, value) (FLAG_MEMBER_SETTER(name)((value), JVMFlagOrigin::MANAGEMENT)) #define FLAG_SET_ERGO_IF_DEFAULT(name, value) \ do { \ diff --git a/src/hotspot/share/runtime/java.cpp b/src/hotspot/share/runtime/java.cpp index be27009fb83..3e0a274a247 100644 --- a/src/hotspot/share/runtime/java.cpp +++ b/src/hotspot/share/runtime/java.cpp @@ -688,6 +688,7 @@ void vm_shutdown_during_initialization(const char* error, const char* message) { } JDK_Version JDK_Version::_current; +const char* JDK_Version::_java_version; const char* JDK_Version::_runtime_name; const char* JDK_Version::_runtime_version; const char* JDK_Version::_runtime_vendor_version; diff --git a/src/hotspot/share/runtime/java.hpp b/src/hotspot/share/runtime/java.hpp index 66a93c4f4cc..c24b2619c6e 100644 --- a/src/hotspot/share/runtime/java.hpp +++ b/src/hotspot/share/runtime/java.hpp @@ -65,6 +65,7 @@ class JDK_Version { private: static JDK_Version _current; + static const char* _java_version; static const char* _runtime_name; static const char* _runtime_version; static const char* _runtime_vendor_version; @@ -130,6 +131,13 @@ class JDK_Version { void to_string(char* buffer, size_t buflen) const; + static const char* java_version() { + return _java_version; + } + static void set_java_version(const char* version) { + _java_version = version; + } + static const char* runtime_name() { return _runtime_name; } diff --git a/src/hotspot/share/runtime/keepStackGCProcessed.cpp b/src/hotspot/share/runtime/keepStackGCProcessed.cpp new file mode 100644 index 00000000000..df851b9f1cc --- /dev/null +++ b/src/hotspot/share/runtime/keepStackGCProcessed.cpp @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "runtime/safepoint.hpp" +#include "runtime/stackWatermark.inline.hpp" +#include "runtime/stackWatermarkSet.inline.hpp" +#include "runtime/keepStackGCProcessed.hpp" + +KeepStackGCProcessedMark::KeepStackGCProcessedMark(JavaThread* jt) : + _active(true), + _jt(jt) { + finish_processing(); + if (!Thread::current()->is_Java_thread()) { + assert(SafepointSynchronize::is_at_safepoint() && Thread::current()->is_VM_thread(), + "must be either Java thread or VM thread in a safepoint"); + _active = false; + return; + } + StackWatermark* our_watermark = StackWatermarkSet::get(JavaThread::current(), StackWatermarkKind::gc); + if (our_watermark == NULL) { + _active = false; + return; + } + StackWatermark* their_watermark = StackWatermarkSet::get(jt, StackWatermarkKind::gc); + our_watermark->link_watermark(their_watermark); +} + +KeepStackGCProcessedMark::~KeepStackGCProcessedMark() { + if (!_active) { + return; + } + StackWatermark* our_watermark = StackWatermarkSet::get(JavaThread::current(), StackWatermarkKind::gc); + our_watermark->link_watermark(NULL); +} + +void KeepStackGCProcessedMark::finish_processing() { + StackWatermarkSet::finish_processing(_jt, NULL /* context */, StackWatermarkKind::gc); +} diff --git a/src/hotspot/share/runtime/keepStackGCProcessed.hpp b/src/hotspot/share/runtime/keepStackGCProcessed.hpp new file mode 100644 index 00000000000..2c36991fe28 --- /dev/null +++ b/src/hotspot/share/runtime/keepStackGCProcessed.hpp @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_RUNTIME_KEEPSTACKGCPROCESSED_HPP +#define SHARE_RUNTIME_KEEPSTACKGCPROCESSED_HPP + +#include "memory/allocation.hpp" +#include "runtime/stackWatermark.hpp" +#include "runtime/stackWatermarkKind.hpp" +#include "runtime/stackWatermarkSet.hpp" + +// Use this class to mark a remote thread you are currently interested +// in examining the entire stack, without it slipping into an unprocessed +// state at safepoint polls. +class KeepStackGCProcessedMark : public StackObj { + friend class StackWatermark; + bool _active; + JavaThread* _jt; + + void finish_processing(); + +public: + KeepStackGCProcessedMark(JavaThread* jt); + ~KeepStackGCProcessedMark(); +}; + + +#endif // SHARE_RUNTIME_KEEPSTACKGCPROCESSED_HPP diff --git a/src/hotspot/share/runtime/mutex.cpp b/src/hotspot/share/runtime/mutex.cpp index e8eb720e2a6..b9e1b0578dc 100644 --- a/src/hotspot/share/runtime/mutex.cpp +++ b/src/hotspot/share/runtime/mutex.cpp @@ -50,8 +50,8 @@ void Mutex::check_safepoint_state(Thread* thread) { // If the JavaThread checks for safepoint, verify that the lock wasn't created with safepoint_check_never. if (thread->is_active_Java_thread()) { assert(_safepoint_check_required != _safepoint_check_never, - "This lock should %s have a safepoint check for Java threads: %s", - _safepoint_check_required ? "always" : "never", name()); + "This lock should never have a safepoint check for Java threads: %s", + name()); // Also check NoSafepointVerifier, and thread state is _thread_in_vm thread->check_for_valid_safepoint_state(); @@ -65,8 +65,8 @@ void Mutex::check_safepoint_state(Thread* thread) { void Mutex::check_no_safepoint_state(Thread* thread) { check_block_state(thread); assert(!thread->is_active_Java_thread() || _safepoint_check_required != _safepoint_check_always, - "This lock should %s have a safepoint check for Java threads: %s", - _safepoint_check_required ? "always" : "never", name()); + "This lock should always have a safepoint check for Java threads: %s", + name()); } #endif // ASSERT diff --git a/src/hotspot/share/runtime/mutex.hpp b/src/hotspot/share/runtime/mutex.hpp index ee4cd68cd51..1ab0832edab 100644 --- a/src/hotspot/share/runtime/mutex.hpp +++ b/src/hotspot/share/runtime/mutex.hpp @@ -99,10 +99,8 @@ class Mutex : public CHeapObj { void no_safepoint_verifier (Thread* thread, bool enable) NOT_DEBUG_RETURN; public: - enum { - _allow_vm_block_flag = true, - _as_suspend_equivalent_flag = true - }; + static const bool _allow_vm_block_flag = true; + static const bool _as_suspend_equivalent_flag = true; // Locks can be acquired with or without a safepoint check. NonJavaThreads do not follow // the safepoint protocol when acquiring locks. @@ -124,12 +122,17 @@ class Mutex : public CHeapObj { // deadlock can occur. We should check this by noting which // locks are shared, and walk held locks during safepoint checking. - enum SafepointCheckFlag { + enum class SafepointCheckFlag { _safepoint_check_flag, _no_safepoint_check_flag }; + // Bring the enumerator names into class scope. + static const SafepointCheckFlag _safepoint_check_flag = + SafepointCheckFlag::_safepoint_check_flag; + static const SafepointCheckFlag _no_safepoint_check_flag = + SafepointCheckFlag::_no_safepoint_check_flag; - enum SafepointCheckRequired { + enum class SafepointCheckRequired { _safepoint_check_never, // Mutexes with this value will cause errors // when acquired by a JavaThread with a safepoint check. _safepoint_check_sometimes, // A couple of special locks are acquired by JavaThreads sometimes @@ -138,6 +141,13 @@ class Mutex : public CHeapObj { _safepoint_check_always // Mutexes with this value will cause errors // when acquired by a JavaThread without a safepoint check. }; + // Bring the enumerator names into class scope. + static const SafepointCheckRequired _safepoint_check_never = + SafepointCheckRequired::_safepoint_check_never; + static const SafepointCheckRequired _safepoint_check_sometimes = + SafepointCheckRequired::_safepoint_check_sometimes; + static const SafepointCheckRequired _safepoint_check_always = + SafepointCheckRequired::_safepoint_check_always; NOT_PRODUCT(SafepointCheckRequired _safepoint_check_required;) diff --git a/src/hotspot/share/runtime/mutexLocker.hpp b/src/hotspot/share/runtime/mutexLocker.hpp index 07d33964713..41d3c0910e9 100644 --- a/src/hotspot/share/runtime/mutexLocker.hpp +++ b/src/hotspot/share/runtime/mutexLocker.hpp @@ -298,7 +298,7 @@ class MutexUnlocker: StackObj { public: MutexUnlocker(Mutex* mutex, Mutex::SafepointCheckFlag flag = Mutex::_safepoint_check_flag) : _mutex(mutex), - _no_safepoint_check(flag) { + _no_safepoint_check(flag == Mutex::_no_safepoint_check_flag) { _mutex->unlock(); } diff --git a/src/hotspot/share/runtime/os.cpp b/src/hotspot/share/runtime/os.cpp index 9a7e50f2946..433818c8d24 100644 --- a/src/hotspot/share/runtime/os.cpp +++ b/src/hotspot/share/runtime/os.cpp @@ -1658,38 +1658,10 @@ char* os::reserve_memory(size_t bytes, MEMFLAGS flags) { return result; } -char* os::reserve_memory_with_fd(size_t bytes, int file_desc) { - char* result; - - if (file_desc != -1) { - // Could have called pd_reserve_memory() followed by replace_existing_mapping_with_file_mapping(), - // but AIX may use SHM in which case its more trouble to detach the segment and remap memory to the file. - result = os::map_memory_to_file(NULL /* addr */, bytes, file_desc); - if (result != NULL) { - MemTracker::record_virtual_memory_reserve_and_commit(result, bytes, CALLER_PC); - } - } else { - result = pd_reserve_memory(bytes); - if (result != NULL) { - MemTracker::record_virtual_memory_reserve(result, bytes, CALLER_PC); - } - } - - return result; -} - -char* os::attempt_reserve_memory_at(char* addr, size_t bytes, int file_desc) { - char* result = NULL; - if (file_desc != -1) { - result = pd_attempt_reserve_memory_at(addr, bytes, file_desc); - if (result != NULL) { - MemTracker::record_virtual_memory_reserve_and_commit((address)result, bytes, CALLER_PC); - } - } else { - result = pd_attempt_reserve_memory_at(addr, bytes); - if (result != NULL) { - MemTracker::record_virtual_memory_reserve((address)result, bytes, CALLER_PC); - } +char* os::attempt_reserve_memory_at(char* addr, size_t bytes) { + char* result = pd_attempt_reserve_memory_at(addr, bytes); + if (result != NULL) { + MemTracker::record_virtual_memory_reserve((address)result, bytes, CALLER_PC); } return result; } @@ -1758,6 +1730,25 @@ void os::pretouch_memory(void* start, void* end, size_t page_size) { } } +char* os::map_memory_to_file(size_t bytes, int file_desc) { + // Could have called pd_reserve_memory() followed by replace_existing_mapping_with_file_mapping(), + // but AIX may use SHM in which case its more trouble to detach the segment and remap memory to the file. + // On all current implementations NULL is interpreted as any available address. + char* result = os::map_memory_to_file(NULL /* addr */, bytes, file_desc); + if (result != NULL) { + MemTracker::record_virtual_memory_reserve_and_commit(result, bytes, CALLER_PC); + } + return result; +} + +char* os::attempt_map_memory_to_file_at(char* addr, size_t bytes, int file_desc) { + char* result = pd_attempt_map_memory_to_file_at(addr, bytes, file_desc); + if (result != NULL) { + MemTracker::record_virtual_memory_reserve_and_commit((address)result, bytes, CALLER_PC); + } + return result; +} + char* os::map_memory(int fd, const char* file_name, size_t file_offset, char *addr, size_t bytes, bool read_only, bool allow_exec, MEMFLAGS flags) { diff --git a/src/hotspot/share/runtime/os.hpp b/src/hotspot/share/runtime/os.hpp index eb51d771105..d91b9f561ca 100644 --- a/src/hotspot/share/runtime/os.hpp +++ b/src/hotspot/share/runtime/os.hpp @@ -116,7 +116,6 @@ class os: AllStatic { static char* pd_reserve_memory(size_t bytes); static char* pd_attempt_reserve_memory_at(char* addr, size_t bytes); - static char* pd_attempt_reserve_memory_at(char* addr, size_t bytes, int file_desc); static bool pd_commit_memory(char* addr, size_t bytes, bool executable); static bool pd_commit_memory(char* addr, size_t size, size_t alignment_hint, @@ -131,6 +130,8 @@ class os: AllStatic { static bool pd_uncommit_memory(char* addr, size_t bytes); static bool pd_release_memory(char* addr, size_t bytes); + static char* pd_attempt_map_memory_to_file_at(char* addr, size_t bytes, int file_desc); + static char* pd_map_memory(int fd, const char* file_name, size_t file_offset, char *addr, size_t bytes, bool read_only = false, bool allow_exec = false); @@ -313,19 +314,14 @@ class os: AllStatic { static int vm_allocation_granularity(); // Reserves virtual memory. - // alignment_hint - currently only used by AIX static char* reserve_memory(size_t bytes, MEMFLAGS flags = mtOther); - // Reserves virtual memory. - // if file_desc != -1, also attaches the memory to the file. - static char* reserve_memory_with_fd(size_t bytes, int file_desc); - // Reserves virtual memory that starts at an address that is aligned to 'alignment'. - static char* reserve_memory_aligned(size_t size, size_t alignment, int file_desc = -1); + static char* reserve_memory_aligned(size_t size, size_t alignment); // Attempts to reserve the virtual memory at [addr, addr + bytes). // Does not overwrite existing mappings. - static char* attempt_reserve_memory_at(char* addr, size_t bytes, int file_desc = -1); + static char* attempt_reserve_memory_at(char* addr, size_t bytes); // Split a reserved memory region [base, base+size) into two regions [base, base+split) and // [base+split, base+size). @@ -370,7 +366,10 @@ class os: AllStatic { static int create_file_for_heap(const char* dir); // Map memory to the file referred by fd. This function is slightly different from map_memory() // and is added to be used for implementation of -XX:AllocateHeapAt + static char* map_memory_to_file(size_t size, int fd); + static char* map_memory_to_file_aligned(size_t size, size_t alignment, int fd); static char* map_memory_to_file(char* base, size_t size, int fd); + static char* attempt_map_memory_to_file_at(char* base, size_t size, int fd); // Replace existing reserved memory with file mapping static char* replace_existing_mapping_with_file_mapping(char* base, size_t size, int fd); diff --git a/src/hotspot/share/runtime/safepointMechanism.cpp b/src/hotspot/share/runtime/safepointMechanism.cpp index 2218b527d16..bb10694b000 100644 --- a/src/hotspot/share/runtime/safepointMechanism.cpp +++ b/src/hotspot/share/runtime/safepointMechanism.cpp @@ -83,13 +83,13 @@ void SafepointMechanism::process(JavaThread *thread) { SafepointSynchronize::block(thread); // Recursive } - // The call to start_processing fixes the thread's oops and the first few frames. + // The call to on_safepoint fixes the thread's oops and the first few frames. // // The call has been carefully placed here to cater for a few situations: // 1) After we exit from block after a global poll // 2) After a thread races with the disarming of the global poll and transitions from native/blocked // 3) Before the handshake code is run - StackWatermarkSet::start_processing(thread, StackWatermarkKind::gc); + StackWatermarkSet::on_safepoint(thread); if (thread->handshake_state()->should_process()) { thread->handshake_state()->process_by_self(); diff --git a/src/hotspot/share/runtime/sharedRuntime.cpp b/src/hotspot/share/runtime/sharedRuntime.cpp index ccedbdaddb4..95369e6272e 100644 --- a/src/hotspot/share/runtime/sharedRuntime.cpp +++ b/src/hotspot/share/runtime/sharedRuntime.cpp @@ -2454,15 +2454,12 @@ class AdapterHandlerTable : public BasicHashtable { public: AdapterHandlerTable() - : BasicHashtable(293, (DumpSharedSpaces ? sizeof(CDSAdapterHandlerEntry) : sizeof(AdapterHandlerEntry))) { } + : BasicHashtable(293, (sizeof(AdapterHandlerEntry))) { } // Create a new entry suitable for insertion in the table AdapterHandlerEntry* new_entry(AdapterFingerPrint* fingerprint, address i2c_entry, address c2i_entry, address c2i_unverified_entry, address c2i_no_clinit_check_entry) { AdapterHandlerEntry* entry = (AdapterHandlerEntry*)BasicHashtable::new_entry(fingerprint->compute_hash()); entry->init(fingerprint, i2c_entry, c2i_entry, c2i_unverified_entry, c2i_no_clinit_check_entry); - if (DumpSharedSpaces) { - ((CDSAdapterHandlerEntry*)entry)->init(); - } return entry; } @@ -3130,17 +3127,6 @@ void AdapterHandlerEntry::print_adapter_on(outputStream* st) const { st->cr(); } -#if INCLUDE_CDS - -void CDSAdapterHandlerEntry::init() { - assert(DumpSharedSpaces, "used during dump time only"); - _c2i_entry_trampoline = (address)MetaspaceShared::misc_code_space_alloc(SharedRuntime::trampoline_size()); - _adapter_trampoline = (AdapterHandlerEntry**)MetaspaceShared::misc_code_space_alloc(sizeof(AdapterHandlerEntry*)); -}; - -#endif // INCLUDE_CDS - - #ifndef PRODUCT void AdapterHandlerLibrary::print_statistics() { diff --git a/src/hotspot/share/runtime/sharedRuntime.hpp b/src/hotspot/share/runtime/sharedRuntime.hpp index 32b9786f0cb..1dc5294c1d9 100644 --- a/src/hotspot/share/runtime/sharedRuntime.hpp +++ b/src/hotspot/share/runtime/sharedRuntime.hpp @@ -679,20 +679,6 @@ class AdapterHandlerEntry : public BasicHashtableEntry { void print_adapter_on(outputStream* st) const; }; -// This class is used only with DumpSharedSpaces==true. It holds extra information -// that's used only during CDS dump time. -// For details, see comments around Method::link_method() -class CDSAdapterHandlerEntry: public AdapterHandlerEntry { - address _c2i_entry_trampoline; // allocated from shared spaces "MC" region - AdapterHandlerEntry** _adapter_trampoline; // allocated from shared spaces "MD" region - -public: - address get_c2i_entry_trampoline() const { return _c2i_entry_trampoline; } - AdapterHandlerEntry** get_adapter_trampoline() const { return _adapter_trampoline; } - void init() NOT_CDS_RETURN; -}; - - class AdapterHandlerLibrary: public AllStatic { private: static BufferBlob* _buffer; // the temporary code buffer in CodeCache diff --git a/src/hotspot/share/runtime/stackOverflow.hpp b/src/hotspot/share/runtime/stackOverflow.hpp index 45a2314f022..c8e4249ab25 100644 --- a/src/hotspot/share/runtime/stackOverflow.hpp +++ b/src/hotspot/share/runtime/stackOverflow.hpp @@ -137,12 +137,15 @@ class StackOverflow { return _stack_red_zone_size; } + // Returns base of red zone (one-beyond the highest red zone address, so + // itself outside red zone and the highest address of the yellow zone). address stack_red_zone_base() const { return (address)(stack_end() + stack_red_zone_size()); } + // Returns true if address points into the red zone. bool in_stack_red_zone(address a) const { - return a <= stack_red_zone_base() && a >= stack_end(); + return a < stack_red_zone_base() && a >= stack_end(); } static size_t stack_yellow_zone_size() { @@ -155,20 +158,25 @@ class StackOverflow { return _stack_reserved_zone_size; } + // Returns base of the reserved zone (one-beyond the highest reserved zone address). address stack_reserved_zone_base() const { return (address)(stack_end() + (stack_red_zone_size() + stack_yellow_zone_size() + stack_reserved_zone_size())); } + + // Returns true if address points into the reserved zone. bool in_stack_reserved_zone(address a) const { - return (a <= stack_reserved_zone_base()) && + return (a < stack_reserved_zone_base()) && (a >= (address)((intptr_t)stack_reserved_zone_base() - stack_reserved_zone_size())); } static size_t stack_yellow_reserved_zone_size() { return _stack_yellow_zone_size + _stack_reserved_zone_size; } + + // Returns true if a points into either yellow or reserved zone. bool in_stack_yellow_reserved_zone(address a) const { - return (a <= stack_reserved_zone_base()) && (a >= stack_red_zone_base()); + return (a < stack_reserved_zone_base()) && (a >= stack_red_zone_base()); } // Size of red + yellow + reserved zones. diff --git a/src/hotspot/share/runtime/stackValue.cpp b/src/hotspot/share/runtime/stackValue.cpp index 43828d621d4..91ca8fe5850 100644 --- a/src/hotspot/share/runtime/stackValue.cpp +++ b/src/hotspot/share/runtime/stackValue.cpp @@ -33,7 +33,7 @@ #include "gc/z/zBarrier.inline.hpp" #endif #if INCLUDE_SHENANDOAHGC -#include "gc/shenandoah/shenandoahBarrierSet.hpp" +#include "gc/shenandoah/shenandoahBarrierSet.inline.hpp" #endif StackValue* StackValue::create_stack_value(const frame* fr, const RegisterMap* reg_map, ScopeValue* sv) { diff --git a/src/hotspot/share/runtime/stackWatermark.cpp b/src/hotspot/share/runtime/stackWatermark.cpp index 1dbd3f8c860..2d6722f2e8c 100644 --- a/src/hotspot/share/runtime/stackWatermark.cpp +++ b/src/hotspot/share/runtime/stackWatermark.cpp @@ -163,7 +163,8 @@ StackWatermark::StackWatermark(JavaThread* jt, StackWatermarkKind kind, uint32_t _jt(jt), _iterator(NULL), _lock(Mutex::tty - 1, "stack_watermark_lock", true, Mutex::_safepoint_check_never), - _kind(kind) { + _kind(kind), + _linked_watermark(NULL) { } StackWatermark::~StackWatermark() { @@ -247,6 +248,11 @@ void StackWatermark::process_one() { } } +void StackWatermark::link_watermark(StackWatermark* watermark) { + assert(watermark == NULL || _linked_watermark == NULL, "nesting not supported"); + _linked_watermark = watermark; +} + uintptr_t StackWatermark::watermark() { return Atomic::load_acquire(&_watermark); } @@ -280,6 +286,14 @@ bool StackWatermark::processing_completed_acquire() const { return processing_completed(Atomic::load_acquire(&_state)); } +void StackWatermark::on_safepoint() { + start_processing(); + StackWatermark* linked_watermark = _linked_watermark; + if (linked_watermark != NULL) { + linked_watermark->finish_processing(NULL /* context */); + } +} + void StackWatermark::start_processing() { if (!processing_started_acquire()) { MutexLocker ml(&_lock, Mutex::_no_safepoint_check_flag); diff --git a/src/hotspot/share/runtime/stackWatermark.hpp b/src/hotspot/share/runtime/stackWatermark.hpp index df0c13840b9..342bbd15613 100644 --- a/src/hotspot/share/runtime/stackWatermark.hpp +++ b/src/hotspot/share/runtime/stackWatermark.hpp @@ -26,6 +26,7 @@ #define SHARE_RUNTIME_STACKWATERMARK_HPP #include "memory/allocation.hpp" +#include "runtime/mutex.hpp" #include "runtime/stackWatermarkKind.hpp" class frame; @@ -92,6 +93,7 @@ class StackWatermark : public CHeapObj { StackWatermarkFramesIterator* _iterator; Mutex _lock; StackWatermarkKind _kind; + StackWatermark* _linked_watermark; void process_one(); @@ -127,6 +129,8 @@ class StackWatermark : public CHeapObj { StackWatermark* next() const { return _next; } void set_next(StackWatermark* n) { _next = n; } + void link_watermark(StackWatermark* watermark); + uintptr_t watermark(); uintptr_t last_processed(); @@ -139,6 +143,7 @@ class StackWatermark : public CHeapObj { void after_unwind(); void on_iteration(const frame& f); + void on_safepoint(); void start_processing(); void finish_processing(void* context); }; diff --git a/src/hotspot/share/runtime/stackWatermark.inline.hpp b/src/hotspot/share/runtime/stackWatermark.inline.hpp index 161c7687e83..93c92234457 100644 --- a/src/hotspot/share/runtime/stackWatermark.inline.hpp +++ b/src/hotspot/share/runtime/stackWatermark.inline.hpp @@ -25,6 +25,7 @@ #ifndef SHARE_RUNTIME_STACKWATERMARK_INLINE_HPP #define SHARE_RUNTIME_STACKWATERMARK_INLINE_HPP +#include "code/nmethod.hpp" #include "runtime/stackWatermark.hpp" #include "runtime/thread.hpp" diff --git a/src/hotspot/share/runtime/stackWatermarkSet.cpp b/src/hotspot/share/runtime/stackWatermarkSet.cpp index 617e3b38448..e2836797120 100644 --- a/src/hotspot/share/runtime/stackWatermarkSet.cpp +++ b/src/hotspot/share/runtime/stackWatermarkSet.cpp @@ -109,6 +109,13 @@ void StackWatermarkSet::on_iteration(JavaThread* jt, const frame& fr) { // calling this might not be Thread::current(). } +void StackWatermarkSet::on_safepoint(JavaThread* jt) { + StackWatermark* watermark = get(jt, StackWatermarkKind::gc); + if (watermark != NULL) { + watermark->on_safepoint(); + } +} + void StackWatermarkSet::start_processing(JavaThread* jt, StackWatermarkKind kind) { verify_processing_context(); assert(!jt->is_terminated(), "Poll after termination is a bug"); diff --git a/src/hotspot/share/runtime/stackWatermarkSet.hpp b/src/hotspot/share/runtime/stackWatermarkSet.hpp index ee3af3ceff4..78cfc7f2827 100644 --- a/src/hotspot/share/runtime/stackWatermarkSet.hpp +++ b/src/hotspot/share/runtime/stackWatermarkSet.hpp @@ -73,6 +73,9 @@ class StackWatermarkSet : public AllStatic { // Called by stack walkers when walking into a frame static void on_iteration(JavaThread* jt, const frame& fr); + // Called to ensure that processing of the thread is started when waking up from safepoint + static void on_safepoint(JavaThread* jt); + // Called to ensure that processing of the thread is started static void start_processing(JavaThread* jt, StackWatermarkKind kind); diff --git a/src/hotspot/share/runtime/statSampler.cpp b/src/hotspot/share/runtime/statSampler.cpp index 65229be6d30..471e9577a0f 100644 --- a/src/hotspot/share/runtime/statSampler.cpp +++ b/src/hotspot/share/runtime/statSampler.cpp @@ -173,15 +173,15 @@ void StatSampler::collect_sample() { } /* - * method to upcall into Java to return the value of the specified - * property as a utf8 string, or NULL if does not exist. The caller - * is responsible for setting a ResourceMark for proper cleanup of - * the utf8 strings. + * Call into java.lang.System.getProperty to check that the value of the + * specified property matches */ -const char* StatSampler::get_system_property(const char* name, TRAPS) { +void StatSampler::assert_system_property(const char* name, const char* value, TRAPS) { +#ifdef ASSERT + ResourceMark rm(THREAD); // setup the arguments to getProperty - Handle key_str = java_lang_String::create_from_str(name, CHECK_NULL); + Handle key_str = java_lang_String::create_from_str(name, CHECK); // return value JavaValue result(T_OBJECT); @@ -192,100 +192,73 @@ const char* StatSampler::get_system_property(const char* name, TRAPS) { vmSymbols::getProperty_name(), vmSymbols::string_string_signature(), key_str, - CHECK_NULL); + CHECK); oop value_oop = (oop)result.get_jobject(); - if (value_oop == NULL) { - return NULL; - } + assert(value_oop != NULL, "property must have a value"); // convert Java String to utf8 string - char* value = java_lang_String::as_utf8_string(value_oop); + char* system_value = java_lang_String::as_utf8_string(value_oop); - return value; + assert(strcmp(value, system_value) == 0, "property value mustn't differ from System.getProperty"); +#endif // ASSERT } /* - * The list of System Properties that have corresponding PerfData - * string instrumentation created by retrieving the named property's - * value from System.getProperty() and unconditionally creating a - * PerfStringConstant object initialized to the retrieved value. This - * is not an exhaustive list of Java properties with corresponding string - * instrumentation as the create_system_property_instrumentation() method - * creates other property based instrumentation conditionally. + * Adds a constant counter of the given property. Asserts the value does not + * differ from the value retrievable from System.getProperty(name) */ +void StatSampler::add_property_constant(CounterNS name_space, const char* name, const char* value, TRAPS) { + // the property must exist + assert(value != NULL, "property name should be have a value: %s", name); + assert_system_property(name, value, CHECK); + if (value != NULL) { + // create the property counter + PerfDataManager::create_string_constant(name_space, name, value, CHECK); + } +} -// stable interface, supported counters -static const char* property_counters_ss[] = { - "java.vm.specification.version", - "java.vm.specification.name", - "java.vm.specification.vendor", - "java.vm.version", - "java.vm.name", - "java.vm.vendor", - "java.vm.info", - "jdk.debug", - "java.library.path", - "java.class.path", - "java.version", - "java.home", - NULL -}; - -// unstable interface, supported counters -static const char* property_counters_us[] = { - NULL -}; - -// unstable interface, unsupported counters -static const char* property_counters_uu[] = { - "sun.boot.library.path", - NULL -}; - -typedef struct { - const char** property_list; - CounterNS name_space; -} PropertyCounters; - -static PropertyCounters property_counters[] = { - { property_counters_ss, JAVA_PROPERTY }, - { property_counters_us, COM_PROPERTY }, - { property_counters_uu, SUN_PROPERTY }, - { NULL, SUN_PROPERTY } -}; - +/* + * Adds a string constant of the given property. Retrieves the value via + * Arguments::get_property() and asserts the value for the does not differ from + * the value retrievable from System.getProperty() + */ +void StatSampler::add_property_constant(CounterNS name_space, const char* name, TRAPS) { + add_property_constant(name_space, name, Arguments::get_property(name), CHECK); +} /* - * Method to create PerfData string instruments that contain the values - * of various system properties. String instruments are created for each - * property specified in the property lists provided in property_counters[]. + * Method to create PerfStringConstants containing the values of various + * system properties. Constants are created from information known to HotSpot, + * but are initialized as-if getting the values from System.getProperty() + * during bootstrap. + * * Property counters have a counter name space prefix prepended to the - * property name as indicated in property_counters[]. + * property name. */ void StatSampler::create_system_property_instrumentation(TRAPS) { - ResourceMark rm; - - for (int i = 0; property_counters[i].property_list != NULL; i++) { - - for (int j = 0; property_counters[i].property_list[j] != NULL; j++) { - - const char* property_name = property_counters[i].property_list[j]; - assert(property_name != NULL, "property name should not be NULL"); - - const char* value = get_system_property(property_name, CHECK); - - // the property must exist - assert(value != NULL, "property name should be valid"); - - if (value != NULL) { - // create the property counter - PerfDataManager::create_string_constant(property_counters[i].name_space, - property_name, value, CHECK); - } - } - } + // Non-writeable, constant properties + add_property_constant(JAVA_PROPERTY, "java.vm.specification.name", "Java Virtual Machine Specification", CHECK); + add_property_constant(JAVA_PROPERTY, "java.version", JDK_Version::java_version(), CHECK); + add_property_constant(JAVA_PROPERTY, "java.vm.version", VM_Version::vm_release(), CHECK); + add_property_constant(JAVA_PROPERTY, "java.vm.name", VM_Version::vm_name(), CHECK); + add_property_constant(JAVA_PROPERTY, "java.vm.vendor", VM_Version::vm_vendor(), CHECK); + add_property_constant(JAVA_PROPERTY, "jdk.debug", VM_Version::jdk_debug_level(), CHECK); + + // Get remaining property constants via Arguments::get_property, + // which does a linear search over the internal system properties list. + + // SUN_PROPERTY properties + add_property_constant(SUN_PROPERTY, "sun.boot.library.path", CHECK); + + // JAVA_PROPERTY properties + add_property_constant(JAVA_PROPERTY, "java.vm.specification.version", CHECK); + add_property_constant(JAVA_PROPERTY, "java.vm.specification.vendor", CHECK); + add_property_constant(JAVA_PROPERTY, "java.vm.info", CHECK); + add_property_constant(JAVA_PROPERTY, "java.library.path", CHECK); + add_property_constant(JAVA_PROPERTY, "java.class.path", CHECK); + add_property_constant(JAVA_PROPERTY, "java.home", CHECK); } /* diff --git a/src/hotspot/share/runtime/statSampler.hpp b/src/hotspot/share/runtime/statSampler.hpp index fb620fbc75c..4590f85302c 100644 --- a/src/hotspot/share/runtime/statSampler.hpp +++ b/src/hotspot/share/runtime/statSampler.hpp @@ -51,7 +51,9 @@ class StatSampler : AllStatic { static void create_misc_perfdata(); static void create_sampled_perfdata(); static void sample_data(PerfDataList* list); - static const char* get_system_property(const char* name, TRAPS); + static void assert_system_property(const char* name, const char* value, TRAPS); + static void add_property_constant(CounterNS name_space, const char* name, TRAPS); + static void add_property_constant(CounterNS name_space, const char* name, const char* value, TRAPS); static void create_system_property_instrumentation(TRAPS); public: diff --git a/src/hotspot/share/runtime/thread.cpp b/src/hotspot/share/runtime/thread.cpp index 980be2c79c9..7bc6272d3d3 100644 --- a/src/hotspot/share/runtime/thread.cpp +++ b/src/hotspot/share/runtime/thread.cpp @@ -894,11 +894,34 @@ static void create_initial_thread(Handle thread_group, JavaThread* thread, java_lang_Thread::RUNNABLE); } +char java_version[64] = ""; char java_runtime_name[128] = ""; char java_runtime_version[128] = ""; char java_runtime_vendor_version[128] = ""; char java_runtime_vendor_vm_bug_url[128] = ""; +// extract the JRE version string from java.lang.VersionProps.java_version +static const char* get_java_version(TRAPS) { + Klass* k = SystemDictionary::find(vmSymbols::java_lang_VersionProps(), + Handle(), Handle(), CHECK_AND_CLEAR_NULL); + fieldDescriptor fd; + bool found = k != NULL && + InstanceKlass::cast(k)->find_local_field(vmSymbols::java_version_name(), + vmSymbols::string_signature(), &fd); + if (found) { + oop name_oop = k->java_mirror()->obj_field(fd.offset()); + if (name_oop == NULL) { + return NULL; + } + const char* name = java_lang_String::as_utf8_string(name_oop, + java_version, + sizeof(java_version)); + return name; + } else { + return NULL; + } +} + // extract the JRE name from java.lang.VersionProps.java_runtime_name static const char* get_java_runtime_name(TRAPS) { Klass* k = SystemDictionary::find(vmSymbols::java_lang_VersionProps(), @@ -3383,6 +3406,7 @@ void Threads::initialize_java_lang_classes(JavaThread* main_thread, TRAPS) { call_initPhase1(CHECK); // get the Java runtime name, version, and vendor info after java.lang.System is initialized + JDK_Version::set_java_version(get_java_version(THREAD)); JDK_Version::set_runtime_name(get_java_runtime_name(THREAD)); JDK_Version::set_runtime_version(get_java_runtime_version(THREAD)); JDK_Version::set_runtime_vendor_version(get_java_runtime_vendor_version(THREAD)); diff --git a/src/hotspot/share/runtime/threadHeapSampler.cpp b/src/hotspot/share/runtime/threadHeapSampler.cpp index 68f02f0d2fe..21f57c9f055 100644 --- a/src/hotspot/share/runtime/threadHeapSampler.cpp +++ b/src/hotspot/share/runtime/threadHeapSampler.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2018, Google and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -24,6 +24,8 @@ */ #include "precompiled.hpp" +#include "logging/log.hpp" +#include "logging/logTag.hpp" #include "runtime/atomic.hpp" #include "runtime/handles.inline.hpp" #include "runtime/sharedRuntime.hpp" @@ -34,19 +36,305 @@ uint64_t ThreadHeapSampler::_rnd; // Default is 512kb. volatile int ThreadHeapSampler::_sampling_interval = 512 * 1024; -// Ordering here is important: _log_table first, _log_table_initialized second. -double ThreadHeapSampler::_log_table[1 << ThreadHeapSampler::FastLogNumBits] = {}; +// Statics for the fast log +static const int FastLogNumBits = 10; +static const int FastLogCount = 1 << FastLogNumBits; +static const int FastLogMask = FastLogCount - 1; +static const double log_table[FastLogCount] = { + 0.000704269011247, 0.002111776479852, 0.003517912108602, 0.004922678569045, + 0.006326078524934, 0.007728114632254, 0.009128789539256, 0.010528105886485, + 0.011926066306808, 0.013322673425448, 0.014717929860010, 0.016111838220512, + 0.017504401109415, 0.018895621121649, 0.020285500844648, 0.021674042858370, + 0.023061249735335, 0.024447124040647, 0.025831668332026, 0.027214885159835, + 0.028596777067108, 0.029977346589579, 0.031356596255709, 0.032734528586714, + 0.034111146096593, 0.035486451292154, 0.036860446673046, 0.038233134731779, + 0.039604517953758, 0.040974598817306, 0.042343379793691, 0.043710863347156, + 0.045077051934941, 0.046441948007312, 0.047805554007589, 0.049167872372170, + 0.050528905530555, 0.051888655905378, 0.053247125912426, 0.054604317960672, + 0.055960234452294, 0.057314877782703, 0.058668250340571, 0.060020354507853, + 0.061371192659811, 0.062720767165044, 0.064069080385509, 0.065416134676548, + 0.066761932386908, 0.068106475858773, 0.069449767427783, 0.070791809423061, + 0.072132604167234, 0.073472153976460, 0.074810461160454, 0.076147528022505, + 0.077483356859507, 0.078817949961979, 0.080151309614087, 0.081483438093674, + 0.082814337672274, 0.084144010615144, 0.085472459181283, 0.086799685623453, + 0.088125692188207, 0.089450481115907, 0.090774054640751, 0.092096414990791, + 0.093417564387961, 0.094737505048093, 0.096056239180946, 0.097373768990222, + 0.098690096673594, 0.100005224422721, 0.101319154423276, 0.102631888854968, + 0.103943429891557, 0.105253779700883, 0.106562940444883, 0.107870914279614, + 0.109177703355275, 0.110483309816226, 0.111787735801012, 0.113090983442381, + 0.114393054867307, 0.115693952197011, 0.116993677546981, 0.118292233026990, + 0.119589620741122, 0.120885842787790, 0.122180901259752, 0.123474798244141, + 0.124767535822473, 0.126059116070680, 0.127349541059119, 0.128638812852598, + 0.129926933510393, 0.131213905086272, 0.132499729628509, 0.133784409179907, + 0.135067945777817, 0.136350341454156, 0.137631598235428, 0.138911718142743, + 0.140190703191836, 0.141468555393084, 0.142745276751529, 0.144020869266892, + 0.145295334933597, 0.146568675740786, 0.147840893672337, 0.149111990706888, + 0.150381968817848, 0.151650829973421, 0.152918576136622, 0.154185209265297, + 0.155450731312137, 0.156715144224702, 0.157978449945432, 0.159240650411673, + 0.160501747555687, 0.161761743304675, 0.163020639580794, 0.164278438301170, + 0.165535141377924, 0.166790750718180, 0.168045268224090, 0.169298695792846, + 0.170551035316700, 0.171802288682983, 0.173052457774115, 0.174301544467631, + 0.175549550636190, 0.176796478147599, 0.178042328864822, 0.179287104646004, + 0.180530807344482, 0.181773438808808, 0.183015000882756, 0.184255495405349, + 0.185494924210866, 0.186733289128866, 0.187970591984199, 0.189206834597024, + 0.190442018782825, 0.191676146352428, 0.192909219112013, 0.194141238863136, + 0.195372207402739, 0.196602126523170, 0.197830998012197, 0.199058823653021, + 0.200285605224298, 0.201511344500146, 0.202736043250167, 0.203959703239463, + 0.205182326228643, 0.206403913973847, 0.207624468226758, 0.208843990734615, + 0.210062483240231, 0.211279947482008, 0.212496385193948, 0.213711798105673, + 0.214926187942435, 0.216139556425135, 0.217351905270334, 0.218563236190271, + 0.219773550892874, 0.220982851081777, 0.222191138456332, 0.223398414711628, + 0.224604681538499, 0.225809940623543, 0.227014193649133, 0.228217442293435, + 0.229419688230416, 0.230620933129866, 0.231821178657404, 0.233020426474497, + 0.234218678238471, 0.235415935602526, 0.236612200215751, 0.237807473723136, + 0.239001757765583, 0.240195053979925, 0.241387363998937, 0.242578689451346, + 0.243769031961852, 0.244958393151134, 0.246146774635865, 0.247334178028729, + 0.248520604938429, 0.249706056969705, 0.250890535723341, 0.252074042796184, + 0.253256579781154, 0.254438148267256, 0.255618749839596, 0.256798386079390, + 0.257977058563978, 0.259154768866840, 0.260331518557602, 0.261507309202055, + 0.262682142362165, 0.263856019596082, 0.265028942458160, 0.266200912498961, + 0.267371931265274, 0.268542000300123, 0.269711121142782, 0.270879295328784, + 0.272046524389938, 0.273212809854334, 0.274378153246363, 0.275542556086722, + 0.276706019892431, 0.277868546176841, 0.279030136449649, 0.280190792216907, + 0.281350514981036, 0.282509306240837, 0.283667167491501, 0.284824100224623, + 0.285980105928212, 0.287135186086704, 0.288289342180970, 0.289442575688332, + 0.290594888082571, 0.291746280833939, 0.292896755409173, 0.294046313271500, + 0.295194955880655, 0.296342684692889, 0.297489501160979, 0.298635406734241, + 0.299780402858540, 0.300924490976300, 0.302067672526519, 0.303209948944775, + 0.304351321663238, 0.305491792110684, 0.306631361712501, 0.307770031890703, + 0.308907804063939, 0.310044679647506, 0.311180660053355, 0.312315746690106, + 0.313449940963058, 0.314583244274195, 0.315715658022202, 0.316847183602472, + 0.317977822407119, 0.319107575824984, 0.320236445241649, 0.321364432039446, + 0.322491537597468, 0.323617763291577, 0.324743110494416, 0.325867580575418, + 0.326991174900817, 0.328113894833656, 0.329235741733800, 0.330356716957943, + 0.331476821859620, 0.332596057789214, 0.333714426093970, 0.334831928118000, + 0.335948565202297, 0.337064338684741, 0.338179249900111, 0.339293300180094, + 0.340406490853295, 0.341518823245243, 0.342630298678407, 0.343740918472201, + 0.344850683942991, 0.345959596404112, 0.347067657165871, 0.348174867535556, + 0.349281228817452, 0.350386742312842, 0.351491409320021, 0.352595231134304, + 0.353698209048035, 0.354800344350596, 0.355901638328417, 0.357002092264984, + 0.358101707440847, 0.359200485133632, 0.360298426618046, 0.361395533165889, + 0.362491806046063, 0.363587246524577, 0.364681855864560, 0.365775635326268, + 0.366868586167093, 0.367960709641570, 0.369052007001388, 0.370142479495399, + 0.371232128369622, 0.372320954867259, 0.373408960228696, 0.374496145691516, + 0.375582512490507, 0.376668061857668, 0.377752795022220, 0.378836713210614, + 0.379919817646538, 0.381002109550926, 0.382083590141966, 0.383164260635110, + 0.384244122243078, 0.385323176175872, 0.386401423640778, 0.387478865842379, + 0.388555503982561, 0.389631339260521, 0.390706372872775, 0.391780606013166, + 0.392854039872873, 0.393926675640417, 0.394998514501672, 0.396069557639868, + 0.397139806235604, 0.398209261466852, 0.399277924508967, 0.400345796534695, + 0.401412878714178, 0.402479172214964, 0.403544678202014, 0.404609397837712, + 0.405673332281866, 0.406736482691724, 0.407798850221975, 0.408860436024760, + 0.409921241249679, 0.410981267043796, 0.412040514551651, 0.413098984915263, + 0.414156679274141, 0.415213598765286, 0.416269744523207, 0.417325117679919, + 0.418379719364956, 0.419433550705378, 0.420486612825775, 0.421538906848277, + 0.422590433892561, 0.423641195075856, 0.424691191512953, 0.425740424316211, + 0.426788894595561, 0.427836603458520, 0.428883552010191, 0.429929741353273, + 0.430975172588069, 0.432019846812492, 0.433063765122069, 0.434106928609955, + 0.435149338366930, 0.436190995481417, 0.437231901039479, 0.438272056124831, + 0.439311461818846, 0.440350119200562, 0.441388029346687, 0.442425193331607, + 0.443461612227394, 0.444497287103809, 0.445532219028312, 0.446566409066067, + 0.447599858279950, 0.448632567730552, 0.449664538476192, 0.450695771572915, + 0.451726268074506, 0.452756029032494, 0.453785055496155, 0.454813348512524, + 0.455840909126398, 0.456867738380343, 0.457893837314700, 0.458919206967592, + 0.459943848374931, 0.460967762570422, 0.461990950585571, 0.463013413449693, + 0.464035152189912, 0.465056167831175, 0.466076461396253, 0.467096033905747, + 0.468114886378099, 0.469133019829591, 0.470150435274359, 0.471167133724392, + 0.472183116189541, 0.473198383677527, 0.474212937193944, 0.475226777742266, + 0.476239906323851, 0.477252323937953, 0.478264031581720, 0.479275030250205, + 0.480285320936372, 0.481294904631098, 0.482303782323183, 0.483311954999353, + 0.484319423644267, 0.485326189240524, 0.486332252768664, 0.487337615207182, + 0.488342277532524, 0.489346240719100, 0.490349505739287, 0.491352073563435, + 0.492353945159870, 0.493355121494907, 0.494355603532845, 0.495355392235982, + 0.496354488564616, 0.497352893477049, 0.498350607929600, 0.499347632876599, + 0.500343969270403, 0.501339618061397, 0.502334580197997, 0.503328856626662, + 0.504322448291891, 0.505315356136237, 0.506307581100306, 0.507299124122766, + 0.508289986140348, 0.509280168087859, 0.510269670898178, 0.511258495502268, + 0.512246642829179, 0.513234113806053, 0.514220909358129, 0.515207030408751, + 0.516192477879367, 0.517177252689541, 0.518161355756956, 0.519144787997414, + 0.520127550324851, 0.521109643651332, 0.522091068887064, 0.523071826940395, + 0.524051918717823, 0.525031345124000, 0.526010107061737, 0.526988205432007, + 0.527965641133954, 0.528942415064895, 0.529918528120324, 0.530893981193921, + 0.531868775177554, 0.532842910961282, 0.533816389433366, 0.534789211480267, + 0.535761377986656, 0.536732889835414, 0.537703747907644, 0.538673953082668, + 0.539643506238036, 0.540612408249530, 0.541580659991169, 0.542548262335212, + 0.543515216152167, 0.544481522310791, 0.545447181678094, 0.546412195119352, + 0.547376563498101, 0.548340287676148, 0.549303368513575, 0.550265806868740, + 0.551227603598288, 0.552188759557150, 0.553149275598548, 0.554109152574003, + 0.555068391333337, 0.556026992724677, 0.556984957594463, 0.557942286787447, + 0.558898981146702, 0.559855041513625, 0.560810468727941, 0.561765263627707, + 0.562719427049319, 0.563672959827513, 0.564625862795372, 0.565578136784329, + 0.566529782624171, 0.567480801143044, 0.568431193167460, 0.569380959522294, + 0.570330101030798, 0.571278618514596, 0.572226512793695, 0.573173784686486, + 0.574120435009748, 0.575066464578656, 0.576011874206780, 0.576956664706092, + 0.577900836886970, 0.578844391558203, 0.579787329526992, 0.580729651598958, + 0.581671358578144, 0.582612451267020, 0.583552930466485, 0.584492796975875, + 0.585432051592962, 0.586370695113965, 0.587308728333545, 0.588246152044817, + 0.589182967039351, 0.590119174107175, 0.591054774036780, 0.591989767615125, + 0.592924155627638, 0.593857938858223, 0.594791118089265, 0.595723694101627, + 0.596655667674663, 0.597587039586216, 0.598517810612622, 0.599447981528719, + 0.600377553107844, 0.601306526121841, 0.602234901341064, 0.603162679534382, + 0.604089861469180, 0.605016447911364, 0.605942439625368, 0.606867837374152, + 0.607792641919210, 0.608716854020573, 0.609640474436812, 0.610563503925040, + 0.611485943240922, 0.612407793138670, 0.613329054371054, 0.614249727689401, + 0.615169813843603, 0.616089313582115, 0.617008227651965, 0.617926556798751, + 0.618844301766652, 0.619761463298424, 0.620678042135410, 0.621594039017540, + 0.622509454683335, 0.623424289869911, 0.624338545312985, 0.625252221746873, + 0.626165319904499, 0.627077840517394, 0.627989784315704, 0.628901152028190, + 0.629811944382234, 0.630722162103839, 0.631631805917638, 0.632540876546891, + 0.633449374713493, 0.634357301137976, 0.635264656539513, 0.636171441635921, + 0.637077657143663, 0.637983303777853, 0.638888382252261, 0.639792893279312, + 0.640696837570094, 0.641600215834357, 0.642503028780520, 0.643405277115674, + 0.644306961545581, 0.645208082774684, 0.646108641506103, 0.647008638441647, + 0.647908074281808, 0.648806949725770, 0.649705265471412, 0.650603022215310, + 0.651500220652738, 0.652396861477678, 0.653292945382815, 0.654188473059545, + 0.655083445197979, 0.655977862486942, 0.656871725613981, 0.657765035265364, + 0.658657792126085, 0.659549996879870, 0.660441650209173, 0.661332752795187, + 0.662223305317840, 0.663113308455806, 0.664002762886501, 0.664891669286088, + 0.665780028329483, 0.666667840690356, 0.667555107041132, 0.668441828052998, + 0.669328004395903, 0.670213636738564, 0.671098725748465, 0.671983272091864, + 0.672867276433793, 0.673750739438063, 0.674633661767266, 0.675516044082778, + 0.676397887044763, 0.677279191312175, 0.678159957542760, 0.679040186393061, + 0.679919878518420, 0.680799034572981, 0.681677655209692, 0.682555741080310, + 0.683433292835402, 0.684310311124349, 0.685186796595348, 0.686062749895414, + 0.686938171670387, 0.687813062564931, 0.688687423222536, 0.689561254285525, + 0.690434556395054, 0.691307330191115, 0.692179576312539, 0.693051295396999, + 0.693922488081015, 0.694793154999950, 0.695663296788022, 0.696532914078300, + 0.697402007502708, 0.698270577692031, 0.699138625275914, 0.700006150882866, + 0.700873155140263, 0.701739638674351, 0.702605602110248, 0.703471046071947, + 0.704335971182319, 0.705200378063116, 0.706064267334970, 0.706927639617403, + 0.707790495528823, 0.708652835686530, 0.709514660706716, 0.710375971204471, + 0.711236767793784, 0.712097051087546, 0.712956821697550, 0.713816080234498, + 0.714674827308002, 0.715533063526583, 0.716390789497679, 0.717248005827646, + 0.718104713121757, 0.718960911984210, 0.719816603018127, 0.720671786825556, + 0.721526464007477, 0.722380635163802, 0.723234300893377, 0.724087461793988, + 0.724940118462359, 0.725792271494157, 0.726643921483994, 0.727495069025431, + 0.728345714710977, 0.729195859132094, 0.730045502879201, 0.730894646541672, + 0.731743290707842, 0.732591435965008, 0.733439082899433, 0.734286232096346, + 0.735132884139946, 0.735979039613404, 0.736824699098865, 0.737669863177453, + 0.738514532429268, 0.739358707433394, 0.740202388767900, 0.741045577009838, + 0.741888272735251, 0.742730476519174, 0.743572188935634, 0.744413410557655, + 0.745254141957257, 0.746094383705463, 0.746934136372297, 0.747773400526791, + 0.748612176736981, 0.749450465569916, 0.750288267591654, 0.751125583367269, + 0.751962413460854, 0.752798758435516, 0.753634618853387, 0.754469995275621, + 0.755304888262399, 0.756139298372928, 0.756973226165448, 0.757806672197228, + 0.758639637024576, 0.759472121202833, 0.760304125286382, 0.761135649828646, + 0.761966695382092, 0.762797262498232, 0.763627351727628, 0.764456963619890, + 0.765286098723682, 0.766114757586723, 0.766942940755785, 0.767770648776705, + 0.768597882194375, 0.769424641552754, 0.770250927394865, 0.771076740262799, + 0.771902080697716, 0.772726949239850, 0.773551346428504, 0.774375272802063, + 0.775198728897986, 0.776021715252813, 0.776844232402167, 0.777666280880755, + 0.778487861222371, 0.779308973959898, 0.780129619625307, 0.780949798749665, + 0.781769511863131, 0.782588759494964, 0.783407542173518, 0.784225860426252, + 0.785043714779724, 0.785861105759600, 0.786678033890652, 0.787494499696761, + 0.788310503700919, 0.789126046425230, 0.789941128390916, 0.790755750118313, + 0.791569912126878, 0.792383614935189, 0.793196859060945, 0.794009645020972, + 0.794821973331222, 0.795633844506778, 0.796445259061850, 0.797256217509785, + 0.798066720363063, 0.798876768133299, 0.799686361331250, 0.800495500466812, + 0.801304186049023, 0.802112418586066, 0.802920198585270, 0.803727526553114, + 0.804534402995225, 0.805340828416384, 0.806146803320525, 0.806952328210736, + 0.807757403589267, 0.808562029957525, 0.809366207816078, 0.810169937664658, + 0.810973220002164, 0.811776055326660, 0.812578444135380, 0.813380386924727, + 0.814181884190280, 0.814982936426790, 0.815783544128185, 0.816583707787570, + 0.817383427897233, 0.818182704948640, 0.818981539432443, 0.819779931838480, + 0.820577882655774, 0.821375392372539, 0.822172461476178, 0.822969090453287, + 0.823765279789659, 0.824561029970280, 0.825356341479334, 0.826151214800207, + 0.826945650415485, 0.827739648806957, 0.828533210455617, 0.829326335841667, + 0.830119025444515, 0.830911279742782, 0.831703099214300, 0.832494484336112, + 0.833285435584481, 0.834075953434884, 0.834866038362018, 0.835655690839800, + 0.836444911341368, 0.837233700339087, 0.838022058304546, 0.838809985708559, + 0.839597483021174, 0.840384550711666, 0.841171189248543, 0.841957399099547, + 0.842743180731658, 0.843528534611089, 0.844313461203296, 0.845097960972975, + 0.845882034384061, 0.846665681899738, 0.847448903982432, 0.848231701093818, + 0.849014073694819, 0.849796022245609, 0.850577547205614, 0.851358649033513, + 0.852139328187243, 0.852919585123995, 0.853699420300221, 0.854478834171630, + 0.855257827193196, 0.856036399819156, 0.856814552503010, 0.857592285697526, + 0.858369599854740, 0.859146495425959, 0.859922972861758, 0.860699032611988, + 0.861474675125773, 0.862249900851513, 0.863024710236886, 0.863799103728850, + 0.864573081773641, 0.865346644816780, 0.866119793303070, 0.866892527676600, + 0.867664848380745, 0.868436755858169, 0.869208250550826, 0.869979332899962, + 0.870750003346114, 0.871520262329114, 0.872290110288090, 0.873059547661470, + 0.873828574886976, 0.874597192401634, 0.875365400641771, 0.876133200043017, + 0.876900591040306, 0.877667574067881, 0.878434149559290, 0.879200317947393, + 0.879966079664357, 0.880731435141664, 0.881496384810110, 0.882260929099804, + 0.883025068440173, 0.883788803259962, 0.884552133987234, 0.885315061049376, + 0.886077584873094, 0.886839705884419, 0.887601424508708, 0.888362741170644, + 0.889123656294237, 0.889884170302829, 0.890644283619089, 0.891403996665022, + 0.892163309861966, 0.892922223630591, 0.893680738390908, 0.894438854562262, + 0.895196572563340, 0.895953892812168, 0.896710815726115, 0.897467341721893, + 0.898223471215558, 0.898979204622514, 0.899734542357511, 0.900489484834649, + 0.901244032467376, 0.901998185668496, 0.902751944850161, 0.903505310423880, + 0.904258282800518, 0.905010862390296, 0.905763049602793, 0.906514844846950, + 0.907266248531065, 0.908017261062803, 0.908767882849189, 0.909518114296615, + 0.910267955810839, 0.911017407796985, 0.911766470659550, 0.912515144802397, + 0.913263430628762, 0.914011328541254, 0.914758838941858, 0.915505962231931, + 0.916252698812210, 0.916999049082807, 0.917745013443216, 0.918490592292311, + 0.919235786028347, 0.919980595048962, 0.920725019751180, 0.921469060531410, + 0.922212717785448, 0.922955991908478, 0.923698883295072, 0.924441392339197, + 0.925183519434208, 0.925925264972856, 0.926666629347283, 0.927407612949032, + 0.928148216169037, 0.928888439397636, 0.929628283024562, 0.930367747438952, + 0.931106833029342, 0.931845540183673, 0.932583869289291, 0.933321820732945, + 0.934059394900794, 0.934796592178403, 0.935533412950747, 0.936269857602210, + 0.937005926516589, 0.937741620077096, 0.938476938666352, 0.939211882666397, + 0.939946452458687, 0.940680648424094, 0.941414470942911, 0.942147920394849, + 0.942880997159041, 0.943613701614043, 0.944346034137834, 0.945077995107817, + 0.945809584900821, 0.946540803893103, 0.947271652460349, 0.948002130977671, + 0.948732239819614, 0.949461979360154, 0.950191349972701, 0.950920352030097, + 0.951648985904620, 0.952377251967984, 0.953105150591341, 0.953832682145281, + 0.954559846999833, 0.955286645524468, 0.956013078088099, 0.956739145059080, + 0.957464846805211, 0.958190183693738, 0.958915156091350, 0.959639764364186, + 0.960364008877834, 0.961087889997331, 0.961811408087163, 0.962534563511272, + 0.963257356633048, 0.963979787815339, 0.964701857420447, 0.965423565810129, + 0.966144913345602, 0.966865900387539, 0.967586527296073, 0.968306794430798, + 0.969026702150771, 0.969746250814509, 0.970465440779995, 0.971184272404677, + 0.971902746045467, 0.972620862058745, 0.973338620800360, 0.974056022625630, + 0.974773067889342, 0.975489756945754, 0.976206090148598, 0.976922067851080, + 0.977637690405876, 0.978352958165143, 0.979067871480510, 0.979782430703087, + 0.980496636183459, 0.981210488271695, 0.981923987317340, 0.982637133669424, + 0.983349927676458, 0.984062369686437, 0.984774460046841, 0.985486199104635, + 0.986197587206273, 0.986908624697693, 0.987619311924326, 0.988329649231088, + 0.989039636962390, 0.989749275462133, 0.990458565073711, 0.991167506140010, + 0.991876099003415, 0.992584344005802, 0.993292241488548, 0.993999791792523, + 0.994706995258101, 0.995413852225151, 0.996120363033046, 0.996826528020659, + 0.997532347526366, 0.998237821888046, 0.998942951443085, 0.999647736528371, +}; -// Force initialization of the log_table. -bool ThreadHeapSampler::_log_table_initialized = init_log_table(); +#ifndef PRODUCT +static double log_table_value(int i) { + return (log(1.0 + static_cast(i + 0.5) / FastLogCount) / log(2.0)); +} + +// Ensure initialization checks only happen once during bootstrap +static volatile bool log_table_checked = false; -bool ThreadHeapSampler::init_log_table() { - for (int i = 0; i < (1 << FastLogNumBits); i++) { - _log_table[i] = (log(1.0 + static_cast(i+0.5) / (1 << FastLogNumBits)) - / log(2.0)); +// Sanity check all log_table values or print it out if running +// -Xlog:heapsampling+generate::none +static void verify_or_generate_log_table() { + log_table_checked = true; + assert(is_power_of_2(FastLogCount) && FastLogCount >= 4, "table size should be power of two and at least 4"); + if (log_is_enabled(Info,heapsampling,generate)) { + log_info(heapsampling,generate)("FastLogCount = %d", FastLogCount); + log_info(heapsampling,generate)("static const double log_table[FastLogCount] = {"); + int i = 0; + for (; i < FastLogCount; i += 4) { + double v1 = log_table_value(i); + double v2 = log_table_value(i + 1); + double v3 = log_table_value(i + 2); + double v4 = log_table_value(i + 3); + log_info(heapsampling,generate)(" %.15f, %.15f, %.15f, %.15f,", v1, v2, v3, v4); + } + log_info(heapsampling,generate)("};"); + assert(i == FastLogCount, "post-loop invariant"); + } else { + // sanity check log_table - disabled when generating + for (int i = 0; i < FastLogCount; i++) { + assert(abs(log_table_value(i) - log_table[i]) < 0.0001, + "log_table deviates too much at index: %d %.15f %.15f", + i, log_table_value(i), log_table[i]); + } } - return true; } +#endif // Returns the next prng value. // pRNG is: aX+b mod c with a = 0x5DEECE66D, b = 0xB, c = 1<<48 @@ -71,9 +359,7 @@ double ThreadHeapSampler::fast_log2(const double& d) { assert(FastLogNumBits <= 20, "FastLogNumBits should be less than 20."); const uint32_t y = x_high >> (20 - FastLogNumBits) & FastLogMask; const int32_t exponent = ((x_high >> 20) & 0x7FF) - 1023; - - assert(_log_table_initialized, "log table should be initialized"); - return exponent + _log_table[y]; + return exponent + log_table[y]; } // Generates a geometric variable with the specified mean (512K by default). @@ -113,6 +399,11 @@ void ThreadHeapSampler::pick_next_geometric_sample() { } void ThreadHeapSampler::pick_next_sample(size_t overflowed_bytes) { +#ifndef PRODUCT + if (!log_table_checked) { + verify_or_generate_log_table(); + } +#endif // Explicitly test if the sampling interval is 0, return 0 to sample every // allocation. if (get_sampling_interval() == 0) { diff --git a/src/hotspot/share/runtime/threadHeapSampler.hpp b/src/hotspot/share/runtime/threadHeapSampler.hpp index 95dd83d0acd..220998c26f7 100644 --- a/src/hotspot/share/runtime/threadHeapSampler.hpp +++ b/src/hotspot/share/runtime/threadHeapSampler.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2018, Google and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -30,23 +30,16 @@ class ThreadHeapSampler { private: - // Statics for the fast log - static const int FastLogNumBits = 10; - static const int FastLogMask = (1 << FastLogNumBits) - 1; - size_t _bytes_until_sample; // Cheap random number generator static uint64_t _rnd; - static bool _log_table_initialized; - static double _log_table[1< KlassHashtableEntry; /******************************/ \ /* -XX flags (value origin) */ \ /******************************/ \ - declare_constant(JVMFlag::DEFAULT) \ - declare_constant(JVMFlag::COMMAND_LINE) \ - declare_constant(JVMFlag::ENVIRON_VAR) \ - declare_constant(JVMFlag::CONFIG_FILE) \ - declare_constant(JVMFlag::MANAGEMENT) \ - declare_constant(JVMFlag::ERGONOMIC) \ - declare_constant(JVMFlag::ATTACH_ON_DEMAND) \ - declare_constant(JVMFlag::INTERNAL) \ - declare_constant(JVMFlag::JIMAGE_RESOURCE) \ + declare_constant(JVMFlagOrigin::DEFAULT) \ + declare_constant(JVMFlagOrigin::COMMAND_LINE) \ + declare_constant(JVMFlagOrigin::ENVIRON_VAR) \ + declare_constant(JVMFlagOrigin::CONFIG_FILE) \ + declare_constant(JVMFlagOrigin::MANAGEMENT) \ + declare_constant(JVMFlagOrigin::ERGONOMIC) \ + declare_constant(JVMFlagOrigin::ATTACH_ON_DEMAND) \ + declare_constant(JVMFlagOrigin::INTERNAL) \ + declare_constant(JVMFlagOrigin::JIMAGE_RESOURCE) \ declare_constant(JVMFlag::VALUE_ORIGIN_MASK) \ - declare_constant(JVMFlag::ORIG_COMMAND_LINE) + declare_constant(JVMFlag::WAS_SET_ON_COMMAND_LINE) //-------------------------------------------------------------------------------- // VM_LONG_CONSTANTS diff --git a/src/hotspot/share/services/attachListener.cpp b/src/hotspot/share/services/attachListener.cpp index d8ab4dbcd9c..7a2d1024893 100644 --- a/src/hotspot/share/services/attachListener.cpp +++ b/src/hotspot/share/services/attachListener.cpp @@ -303,7 +303,7 @@ static jint set_flag(AttachOperation* op, outputStream* out) { FormatBuffer<80> err_msg("%s", ""); - int ret = WriteableFlags::set_flag(op->arg(0), op->arg(1), JVMFlag::ATTACH_ON_DEMAND, err_msg); + int ret = WriteableFlags::set_flag(op->arg(0), op->arg(1), JVMFlagOrigin::ATTACH_ON_DEMAND, err_msg); if (ret != JVMFlag::SUCCESS) { if (ret == JVMFlag::NON_WRITABLE) { // if the flag is not manageable try to change it through diff --git a/src/hotspot/share/services/diagnosticCommand.cpp b/src/hotspot/share/services/diagnosticCommand.cpp index e884a3f3580..8511156b08b 100644 --- a/src/hotspot/share/services/diagnosticCommand.cpp +++ b/src/hotspot/share/services/diagnosticCommand.cpp @@ -276,7 +276,7 @@ void SetVMFlagDCmd::execute(DCmdSource source, TRAPS) { } FormatBuffer<80> err_msg("%s", ""); - int ret = WriteableFlags::set_flag(_flag.value(), val, JVMFlag::MANAGEMENT, err_msg); + int ret = WriteableFlags::set_flag(_flag.value(), val, JVMFlagOrigin::MANAGEMENT, err_msg); if (ret != JVMFlag::SUCCESS) { output()->print_cr("%s", err_msg.buffer()); diff --git a/src/hotspot/share/services/management.cpp b/src/hotspot/share/services/management.cpp index 92f086619d4..65a8481ad53 100644 --- a/src/hotspot/share/services/management.cpp +++ b/src/hotspot/share/services/management.cpp @@ -1474,25 +1474,25 @@ bool add_global_entry(Handle name, jmmVMGlobal *global, JVMFlag *flag, TRAPS) { global->writeable = flag->is_writeable(); global->external = flag->is_external(); switch (flag->get_origin()) { - case JVMFlag::DEFAULT: + case JVMFlagOrigin::DEFAULT: global->origin = JMM_VMGLOBAL_ORIGIN_DEFAULT; break; - case JVMFlag::COMMAND_LINE: + case JVMFlagOrigin::COMMAND_LINE: global->origin = JMM_VMGLOBAL_ORIGIN_COMMAND_LINE; break; - case JVMFlag::ENVIRON_VAR: + case JVMFlagOrigin::ENVIRON_VAR: global->origin = JMM_VMGLOBAL_ORIGIN_ENVIRON_VAR; break; - case JVMFlag::CONFIG_FILE: + case JVMFlagOrigin::CONFIG_FILE: global->origin = JMM_VMGLOBAL_ORIGIN_CONFIG_FILE; break; - case JVMFlag::MANAGEMENT: + case JVMFlagOrigin::MANAGEMENT: global->origin = JMM_VMGLOBAL_ORIGIN_MANAGEMENT; break; - case JVMFlag::ERGONOMIC: + case JVMFlagOrigin::ERGONOMIC: global->origin = JMM_VMGLOBAL_ORIGIN_ERGONOMIC; break; - case JVMFlag::ATTACH_ON_DEMAND: + case JVMFlagOrigin::ATTACH_ON_DEMAND: global->origin = JMM_VMGLOBAL_ORIGIN_ATTACH_ON_DEMAND; break; default: @@ -1584,7 +1584,7 @@ JVM_ENTRY(void, jmm_SetVMGlobal(JNIEnv *env, jstring flag_name, jvalue new_value char* name = java_lang_String::as_utf8_string(fn); FormatBuffer<80> error_msg("%s", ""); - int succeed = WriteableFlags::set_flag(name, new_value, JVMFlag::MANAGEMENT, error_msg); + int succeed = WriteableFlags::set_flag(name, new_value, JVMFlagOrigin::MANAGEMENT, error_msg); if (succeed != JVMFlag::SUCCESS) { if (succeed == JVMFlag::MISSING_VALUE) { diff --git a/src/hotspot/share/services/writeableFlags.cpp b/src/hotspot/share/services/writeableFlags.cpp index e9d0e929ab5..dc5f62b4bf8 100644 --- a/src/hotspot/share/services/writeableFlags.cpp +++ b/src/hotspot/share/services/writeableFlags.cpp @@ -97,7 +97,7 @@ static void print_flag_error_message_if_needed(JVMFlag::Error error, const JVMFl } // set a boolean global flag -JVMFlag::Error WriteableFlags::set_bool_flag(const char* name, const char* arg, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) { +JVMFlag::Error WriteableFlags::set_bool_flag(const char* name, const char* arg, JVMFlagOrigin origin, FormatBuffer<80>& err_msg) { if ((strcasecmp(arg, "true") == 0) || (*arg == '1' && *(arg + 1) == 0)) { return set_bool_flag(name, true, origin, err_msg); } else if ((strcasecmp(arg, "false") == 0) || (*arg == '0' && *(arg + 1) == 0)) { @@ -107,7 +107,7 @@ JVMFlag::Error WriteableFlags::set_bool_flag(const char* name, const char* arg, return JVMFlag::WRONG_FORMAT; } -JVMFlag::Error WriteableFlags::set_bool_flag(const char* name, bool value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) { +JVMFlag::Error WriteableFlags::set_bool_flag(const char* name, bool value, JVMFlagOrigin origin, FormatBuffer<80>& err_msg) { JVMFlag* flag = JVMFlag::find_flag(name); JVMFlag::Error err = JVMFlagAccess::boolAtPut(flag, &value, origin); print_flag_error_message_if_needed(err, flag, err_msg); @@ -115,7 +115,7 @@ JVMFlag::Error WriteableFlags::set_bool_flag(const char* name, bool value, JVMFl } // set a int global flag -JVMFlag::Error WriteableFlags::set_int_flag(const char* name, const char* arg, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) { +JVMFlag::Error WriteableFlags::set_int_flag(const char* name, const char* arg, JVMFlagOrigin origin, FormatBuffer<80>& err_msg) { int value; if (sscanf(arg, "%d", &value) == 1) { @@ -125,7 +125,7 @@ JVMFlag::Error WriteableFlags::set_int_flag(const char* name, const char* arg, J return JVMFlag::WRONG_FORMAT; } -JVMFlag::Error WriteableFlags::set_int_flag(const char* name, int value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) { +JVMFlag::Error WriteableFlags::set_int_flag(const char* name, int value, JVMFlagOrigin origin, FormatBuffer<80>& err_msg) { JVMFlag* flag = JVMFlag::find_flag(name); JVMFlag::Error err = JVMFlagAccess::intAtPut(flag, &value, origin); print_flag_error_message_if_needed(err, flag, err_msg); @@ -133,7 +133,7 @@ JVMFlag::Error WriteableFlags::set_int_flag(const char* name, int value, JVMFlag } // set a uint global flag -JVMFlag::Error WriteableFlags::set_uint_flag(const char* name, const char* arg, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) { +JVMFlag::Error WriteableFlags::set_uint_flag(const char* name, const char* arg, JVMFlagOrigin origin, FormatBuffer<80>& err_msg) { uint value; if (sscanf(arg, "%u", &value) == 1) { @@ -143,7 +143,7 @@ JVMFlag::Error WriteableFlags::set_uint_flag(const char* name, const char* arg, return JVMFlag::WRONG_FORMAT; } -JVMFlag::Error WriteableFlags::set_uint_flag(const char* name, uint value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) { +JVMFlag::Error WriteableFlags::set_uint_flag(const char* name, uint value, JVMFlagOrigin origin, FormatBuffer<80>& err_msg) { JVMFlag* flag = JVMFlag::find_flag(name); JVMFlag::Error err = JVMFlagAccess::uintAtPut(flag, &value, origin); print_flag_error_message_if_needed(err, flag, err_msg); @@ -151,7 +151,7 @@ JVMFlag::Error WriteableFlags::set_uint_flag(const char* name, uint value, JVMFl } // set a intx global flag -JVMFlag::Error WriteableFlags::set_intx_flag(const char* name, const char* arg, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) { +JVMFlag::Error WriteableFlags::set_intx_flag(const char* name, const char* arg, JVMFlagOrigin origin, FormatBuffer<80>& err_msg) { intx value; if (sscanf(arg, INTX_FORMAT, &value) == 1) { @@ -161,7 +161,7 @@ JVMFlag::Error WriteableFlags::set_intx_flag(const char* name, const char* arg, return JVMFlag::WRONG_FORMAT; } -JVMFlag::Error WriteableFlags::set_intx_flag(const char* name, intx value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) { +JVMFlag::Error WriteableFlags::set_intx_flag(const char* name, intx value, JVMFlagOrigin origin, FormatBuffer<80>& err_msg) { JVMFlag* flag = JVMFlag::find_flag(name); JVMFlag::Error err = JVMFlagAccess::intxAtPut(flag, &value, origin); print_flag_error_message_if_needed(err, flag, err_msg); @@ -169,7 +169,7 @@ JVMFlag::Error WriteableFlags::set_intx_flag(const char* name, intx value, JVMFl } // set a uintx global flag -JVMFlag::Error WriteableFlags::set_uintx_flag(const char* name, const char* arg, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) { +JVMFlag::Error WriteableFlags::set_uintx_flag(const char* name, const char* arg, JVMFlagOrigin origin, FormatBuffer<80>& err_msg) { uintx value; if (sscanf(arg, UINTX_FORMAT, &value) == 1) { @@ -179,7 +179,7 @@ JVMFlag::Error WriteableFlags::set_uintx_flag(const char* name, const char* arg, return JVMFlag::WRONG_FORMAT; } -JVMFlag::Error WriteableFlags::set_uintx_flag(const char* name, uintx value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) { +JVMFlag::Error WriteableFlags::set_uintx_flag(const char* name, uintx value, JVMFlagOrigin origin, FormatBuffer<80>& err_msg) { JVMFlag* flag = JVMFlag::find_flag(name); JVMFlag::Error err = JVMFlagAccess::uintxAtPut(flag, &value, origin); print_flag_error_message_if_needed(err, flag, err_msg); @@ -187,7 +187,7 @@ JVMFlag::Error WriteableFlags::set_uintx_flag(const char* name, uintx value, JVM } // set a uint64_t global flag -JVMFlag::Error WriteableFlags::set_uint64_t_flag(const char* name, const char* arg, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) { +JVMFlag::Error WriteableFlags::set_uint64_t_flag(const char* name, const char* arg, JVMFlagOrigin origin, FormatBuffer<80>& err_msg) { uint64_t value; if (sscanf(arg, UINT64_FORMAT, &value) == 1) { @@ -197,7 +197,7 @@ JVMFlag::Error WriteableFlags::set_uint64_t_flag(const char* name, const char* a return JVMFlag::WRONG_FORMAT; } -JVMFlag::Error WriteableFlags::set_uint64_t_flag(const char* name, uint64_t value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) { +JVMFlag::Error WriteableFlags::set_uint64_t_flag(const char* name, uint64_t value, JVMFlagOrigin origin, FormatBuffer<80>& err_msg) { JVMFlag* flag = JVMFlag::find_flag(name); JVMFlag::Error err = JVMFlagAccess::uint64_tAtPut(flag, &value, origin); print_flag_error_message_if_needed(err, flag, err_msg); @@ -205,7 +205,7 @@ JVMFlag::Error WriteableFlags::set_uint64_t_flag(const char* name, uint64_t valu } // set a size_t global flag -JVMFlag::Error WriteableFlags::set_size_t_flag(const char* name, const char* arg, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) { +JVMFlag::Error WriteableFlags::set_size_t_flag(const char* name, const char* arg, JVMFlagOrigin origin, FormatBuffer<80>& err_msg) { size_t value; if (sscanf(arg, SIZE_FORMAT, &value) == 1) { @@ -215,7 +215,7 @@ JVMFlag::Error WriteableFlags::set_size_t_flag(const char* name, const char* arg return JVMFlag::WRONG_FORMAT; } -JVMFlag::Error WriteableFlags::set_size_t_flag(const char* name, size_t value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) { +JVMFlag::Error WriteableFlags::set_size_t_flag(const char* name, size_t value, JVMFlagOrigin origin, FormatBuffer<80>& err_msg) { JVMFlag* flag = JVMFlag::find_flag(name); JVMFlag::Error err = JVMFlagAccess::size_tAtPut(flag, &value, origin); print_flag_error_message_if_needed(err, flag, err_msg); @@ -223,7 +223,7 @@ JVMFlag::Error WriteableFlags::set_size_t_flag(const char* name, size_t value, J } // set a double global flag -JVMFlag::Error WriteableFlags::set_double_flag(const char* name, const char* arg, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) { +JVMFlag::Error WriteableFlags::set_double_flag(const char* name, const char* arg, JVMFlagOrigin origin, FormatBuffer<80>& err_msg) { double value; if (sscanf(arg, "%lf", &value) == 1) { @@ -233,7 +233,7 @@ JVMFlag::Error WriteableFlags::set_double_flag(const char* name, const char* arg return JVMFlag::WRONG_FORMAT; } -JVMFlag::Error WriteableFlags::set_double_flag(const char* name, double value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) { +JVMFlag::Error WriteableFlags::set_double_flag(const char* name, double value, JVMFlagOrigin origin, FormatBuffer<80>& err_msg) { JVMFlag* flag = JVMFlag::find_flag(name); JVMFlag::Error err = JVMFlagAccess::doubleAtPut(flag, &value, origin); print_flag_error_message_if_needed(err, flag, err_msg); @@ -241,7 +241,7 @@ JVMFlag::Error WriteableFlags::set_double_flag(const char* name, double value, J } // set a string global flag using value from AttachOperation -JVMFlag::Error WriteableFlags::set_ccstr_flag(const char* name, const char* value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) { +JVMFlag::Error WriteableFlags::set_ccstr_flag(const char* name, const char* value, JVMFlagOrigin origin, FormatBuffer<80>& err_msg) { JVMFlag* flag = JVMFlag::find_flag(name); JVMFlag::Error err = JVMFlagAccess::ccstrAtPut(flag, &value, origin); print_flag_error_message_if_needed(err, flag, err_msg); @@ -253,7 +253,7 @@ JVMFlag::Error WriteableFlags::set_ccstr_flag(const char* name, const char* valu * - return status is one of the WriteableFlags::err enum values * - an eventual error message will be generated to the provided err_msg buffer */ -JVMFlag::Error WriteableFlags::set_flag(const char* flag_name, const char* flag_value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) { +JVMFlag::Error WriteableFlags::set_flag(const char* flag_name, const char* flag_value, JVMFlagOrigin origin, FormatBuffer<80>& err_msg) { return set_flag(flag_name, &flag_value, set_flag_from_char, origin, err_msg); } @@ -262,12 +262,12 @@ JVMFlag::Error WriteableFlags::set_flag(const char* flag_name, const char* flag_ * - return status is one of the WriteableFlags::err enum values * - an eventual error message will be generated to the provided err_msg buffer */ -JVMFlag::Error WriteableFlags::set_flag(const char* flag_name, jvalue flag_value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) { +JVMFlag::Error WriteableFlags::set_flag(const char* flag_name, jvalue flag_value, JVMFlagOrigin origin, FormatBuffer<80>& err_msg) { return set_flag(flag_name, &flag_value, set_flag_from_jvalue, origin, err_msg); } // a writeable flag setter accepting either 'jvalue' or 'char *' values -JVMFlag::Error WriteableFlags::set_flag(const char* name, const void* value, JVMFlag::Error(*setter)(JVMFlag*,const void*,JVMFlag::Flags,FormatBuffer<80>&), JVMFlag::Flags origin, FormatBuffer<80>& err_msg) { +JVMFlag::Error WriteableFlags::set_flag(const char* name, const void* value, JVMFlag::Error(*setter)(JVMFlag*,const void*,JVMFlagOrigin,FormatBuffer<80>&), JVMFlagOrigin origin, FormatBuffer<80>& err_msg) { if (name == NULL) { err_msg.print("flag name is missing"); return JVMFlag::MISSING_NAME; @@ -293,7 +293,7 @@ JVMFlag::Error WriteableFlags::set_flag(const char* name, const void* value, JVM } // a writeable flag setter accepting 'char *' values -JVMFlag::Error WriteableFlags::set_flag_from_char(JVMFlag* f, const void* value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg) { +JVMFlag::Error WriteableFlags::set_flag_from_char(JVMFlag* f, const void* value, JVMFlagOrigin origin, FormatBuffer<80>& err_msg) { char* flag_value = *(char**)value; if (flag_value == NULL) { err_msg.print("flag value is missing"); @@ -324,7 +324,7 @@ JVMFlag::Error WriteableFlags::set_flag_from_char(JVMFlag* f, const void* value, } // a writeable flag setter accepting 'jvalue' values -JVMFlag::Error WriteableFlags::set_flag_from_jvalue(JVMFlag* f, const void* value, JVMFlag::Flags origin, +JVMFlag::Error WriteableFlags::set_flag_from_jvalue(JVMFlag* f, const void* value, JVMFlagOrigin origin, FormatBuffer<80>& err_msg) { jvalue new_value = *(jvalue*)value; if (f->is_bool()) { diff --git a/src/hotspot/share/services/writeableFlags.hpp b/src/hotspot/share/services/writeableFlags.hpp index a49fde390fe..1488d1c7cfd 100644 --- a/src/hotspot/share/services/writeableFlags.hpp +++ b/src/hotspot/share/services/writeableFlags.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2020, 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,46 +32,46 @@ class WriteableFlags : AllStatic { private: // a writeable flag setter accepting either 'jvalue' or 'char *' values - static JVMFlag::Error set_flag(const char* name, const void* value, JVMFlag::Error(*setter)(JVMFlag*, const void*, JVMFlag::Flags, FormatBuffer<80>&), JVMFlag::Flags origin, FormatBuffer<80>& err_msg); + static JVMFlag::Error set_flag(const char* name, const void* value, JVMFlag::Error(*setter)(JVMFlag*, const void*, JVMFlagOrigin, FormatBuffer<80>&), JVMFlagOrigin origin, FormatBuffer<80>& err_msg); // a writeable flag setter accepting 'char *' values - static JVMFlag::Error set_flag_from_char(JVMFlag* f, const void* value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg); + static JVMFlag::Error set_flag_from_char(JVMFlag* f, const void* value, JVMFlagOrigin origin, FormatBuffer<80>& err_msg); // a writeable flag setter accepting 'jvalue' values - static JVMFlag::Error set_flag_from_jvalue(JVMFlag* f, const void* value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg); + static JVMFlag::Error set_flag_from_jvalue(JVMFlag* f, const void* value, JVMFlagOrigin origin, FormatBuffer<80>& err_msg); // set a boolean global flag - static JVMFlag::Error set_bool_flag(const char* name, const char* value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg); + static JVMFlag::Error set_bool_flag(const char* name, const char* value, JVMFlagOrigin origin, FormatBuffer<80>& err_msg); // set a int global flag - static JVMFlag::Error set_int_flag(const char* name, const char* value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg); + static JVMFlag::Error set_int_flag(const char* name, const char* value, JVMFlagOrigin origin, FormatBuffer<80>& err_msg); // set a uint global flag - static JVMFlag::Error set_uint_flag(const char* name, const char* value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg); + static JVMFlag::Error set_uint_flag(const char* name, const char* value, JVMFlagOrigin origin, FormatBuffer<80>& err_msg); // set a intx global flag - static JVMFlag::Error set_intx_flag(const char* name, const char* value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg); + static JVMFlag::Error set_intx_flag(const char* name, const char* value, JVMFlagOrigin origin, FormatBuffer<80>& err_msg); // set a uintx global flag - static JVMFlag::Error set_uintx_flag(const char* name, const char* value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg); + static JVMFlag::Error set_uintx_flag(const char* name, const char* value, JVMFlagOrigin origin, FormatBuffer<80>& err_msg); // set a uint64_t global flag - static JVMFlag::Error set_uint64_t_flag(const char* name, const char* value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg); + static JVMFlag::Error set_uint64_t_flag(const char* name, const char* value, JVMFlagOrigin origin, FormatBuffer<80>& err_msg); // set a size_t global flag using value from AttachOperation - static JVMFlag::Error set_size_t_flag(const char* name, const char* value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg); + static JVMFlag::Error set_size_t_flag(const char* name, const char* value, JVMFlagOrigin origin, FormatBuffer<80>& err_msg); // set a double global flag using value from AttachOperation - static JVMFlag::Error set_double_flag(const char* name, const char* value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg); + static JVMFlag::Error set_double_flag(const char* name, const char* value, JVMFlagOrigin origin, FormatBuffer<80>& err_msg); // set a boolean global flag - static JVMFlag::Error set_bool_flag(const char* name, bool value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg); + static JVMFlag::Error set_bool_flag(const char* name, bool value, JVMFlagOrigin origin, FormatBuffer<80>& err_msg); // set a int global flag - static JVMFlag::Error set_int_flag(const char* name, int value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg); + static JVMFlag::Error set_int_flag(const char* name, int value, JVMFlagOrigin origin, FormatBuffer<80>& err_msg); // set a uint global flag - static JVMFlag::Error set_uint_flag(const char* name, uint value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg); + static JVMFlag::Error set_uint_flag(const char* name, uint value, JVMFlagOrigin origin, FormatBuffer<80>& err_msg); // set a intx global flag - static JVMFlag::Error set_intx_flag(const char* name, intx value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg); + static JVMFlag::Error set_intx_flag(const char* name, intx value, JVMFlagOrigin origin, FormatBuffer<80>& err_msg); // set a uintx global flag - static JVMFlag::Error set_uintx_flag(const char* name, uintx value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg); + static JVMFlag::Error set_uintx_flag(const char* name, uintx value, JVMFlagOrigin origin, FormatBuffer<80>& err_msg); // set a uint64_t global flag - static JVMFlag::Error set_uint64_t_flag(const char* name, uint64_t value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg); + static JVMFlag::Error set_uint64_t_flag(const char* name, uint64_t value, JVMFlagOrigin origin, FormatBuffer<80>& err_msg); // set a size_t global flag using value from AttachOperation - static JVMFlag::Error set_size_t_flag(const char* name, size_t value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg); + static JVMFlag::Error set_size_t_flag(const char* name, size_t value, JVMFlagOrigin origin, FormatBuffer<80>& err_msg); // set a double global flag using value from AttachOperation - static JVMFlag::Error set_double_flag(const char* name, double value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg); + static JVMFlag::Error set_double_flag(const char* name, double value, JVMFlagOrigin origin, FormatBuffer<80>& err_msg); // set a string global flag - static JVMFlag::Error set_ccstr_flag(const char* name, const char* value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg); + static JVMFlag::Error set_ccstr_flag(const char* name, const char* value, JVMFlagOrigin origin, FormatBuffer<80>& err_msg); public: /* sets a writeable flag to the provided value @@ -79,14 +79,14 @@ class WriteableFlags : AllStatic { * - return status is one of the WriteableFlags::err enum values * - an eventual error message will be generated to the provided err_msg buffer */ - static JVMFlag::Error set_flag(const char* flag_name, const char* flag_value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg); + static JVMFlag::Error set_flag(const char* flag_name, const char* flag_value, JVMFlagOrigin origin, FormatBuffer<80>& err_msg); /* sets a writeable flag to the provided value * * - return status is one of the WriteableFlags::err enum values * - an eventual error message will be generated to the provided err_msg buffer */ - static JVMFlag::Error set_flag(const char* flag_name, jvalue flag_value, JVMFlag::Flags origin, FormatBuffer<80>& err_msg); + static JVMFlag::Error set_flag(const char* flag_name, jvalue flag_value, JVMFlagOrigin origin, FormatBuffer<80>& err_msg); }; #endif // SHARE_SERVICES_WRITEABLEFLAGS_HPP diff --git a/src/hotspot/share/utilities/concurrentHashTable.hpp b/src/hotspot/share/utilities/concurrentHashTable.hpp index bec1661d4ce..154672ece92 100644 --- a/src/hotspot/share/utilities/concurrentHashTable.hpp +++ b/src/hotspot/share/utilities/concurrentHashTable.hpp @@ -191,13 +191,6 @@ class ConcurrentHashTable : public CHeapObj { Bucket* get_bucket(size_t idx) { return &_buckets[idx]; } }; - // Used as default functor when no functor supplied for some methods. - struct NoOp { - void operator()(VALUE*) {} - const VALUE& operator()() {} - void operator()(bool, VALUE*) {} - } noOp; - // For materializing a supplied value. class LazyValueRetrieve { private: @@ -429,7 +422,10 @@ class ConcurrentHashTable : public CHeapObj { // Same without DELETE_FUNC. template bool remove(Thread* thread, LOOKUP_FUNC& lookup_f) { - return internal_remove(thread, lookup_f, noOp); + struct { + void operator()(VALUE*) {} + } ignore_del_f; + return internal_remove(thread, lookup_f, ignore_del_f); } // Visit all items with SCAN_FUNC if no concurrent resize. Takes the resize diff --git a/src/hotspot/share/utilities/enumIterator.hpp b/src/hotspot/share/utilities/enumIterator.hpp index b876531207e..45a1a0fe082 100644 --- a/src/hotspot/share/utilities/enumIterator.hpp +++ b/src/hotspot/share/utilities/enumIterator.hpp @@ -210,6 +210,10 @@ class EnumRange { constexpr Iterator end() const { return Iterator(static_cast(_end)); } + + constexpr size_t size() const { + return static_cast(_end - _start); // _end is exclusive + } }; #endif // SHARE_UTILITIES_ENUMITERATOR_HPP diff --git a/src/hotspot/share/utilities/globalDefinitions.hpp b/src/hotspot/share/utilities/globalDefinitions.hpp index 831ed3716df..c8f98f4065d 100644 --- a/src/hotspot/share/utilities/globalDefinitions.hpp +++ b/src/hotspot/share/utilities/globalDefinitions.hpp @@ -446,6 +446,21 @@ inline size_t pointer_delta(const MetaWord* left, const MetaWord* right) { #define CAST_TO_FN_PTR(func_type, value) (reinterpret_cast(value)) #define CAST_FROM_FN_PTR(new_type, func_ptr) ((new_type)((address_word)(func_ptr))) +// In many places we've added C-style casts to silence compiler +// warnings, for example when truncating a size_t to an int when we +// know the size_t is a small struct. Such casts are risky because +// they effectively disable useful compiler warnings. We can make our +// lives safer with this function, which ensures that any cast is +// reversible without loss of information. It doesn't check +// everything: it isn't intended to make sure that pointer types are +// compatible, for example. +template +T2 checked_cast(T1 thing) { + T2 result = static_cast(thing); + assert(static_cast(result) == thing, "must be"); + return result; +} + // Need the correct linkage to call qsort without warnings extern "C" { typedef int (*_sort_Fn)(const void *, const void *); diff --git a/src/hotspot/share/utilities/vmEnums.hpp b/src/hotspot/share/utilities/vmEnums.hpp index 2430c37af8d..bc044e675e8 100644 --- a/src/hotspot/share/utilities/vmEnums.hpp +++ b/src/hotspot/share/utilities/vmEnums.hpp @@ -29,6 +29,7 @@ // you don't use their members directly. This way you don't need to include the // complex header files that have the full definitions of these enums. +enum class JVMFlagOrigin : int; enum JVMFlagsEnum : int; enum class vmSymbolID : int; diff --git a/src/java.base/share/classes/java/lang/AbstractStringBuilder.java b/src/java.base/share/classes/java/lang/AbstractStringBuilder.java index 115f5257907..759848063cb 100644 --- a/src/java.base/share/classes/java/lang/AbstractStringBuilder.java +++ b/src/java.base/share/classes/java/lang/AbstractStringBuilder.java @@ -1028,12 +1028,12 @@ public String substring(int start) { *

An invocation of this method of the form * *

{@code
-     * sb.subSequence(begin, end)}
+ * sb.subSequence(begin, end)} * * behaves in exactly the same way as the invocation * *
{@code
-     * sb.substring(begin, end)}
+ * sb.substring(begin, end)} * * This method is provided so that this class can * implement the {@link CharSequence} interface. diff --git a/src/java.base/share/classes/java/lang/Class.java b/src/java.base/share/classes/java/lang/Class.java index 54a69b1bb84..b0a687a56a5 100644 --- a/src/java.base/share/classes/java/lang/Class.java +++ b/src/java.base/share/classes/java/lang/Class.java @@ -2338,13 +2338,6 @@ public Field[] getDeclaredFields() throws SecurityException { } /** - * {@preview Associated with records, a preview feature of the Java language. - * - * This method is associated with records, a preview - * feature of the Java language. Preview features - * may be removed in a future release, or upgraded to permanent - * features of the Java language.} - * * Returns an array of {@code RecordComponent} objects representing all the * record components of this record class, or {@code null} if this class is * not a record class. @@ -2381,11 +2374,8 @@ public Field[] getDeclaredFields() throws SecurityException { * * * @jls 8.10 Record Types - * @since 14 + * @since 16 */ - @jdk.internal.PreviewFeature(feature=jdk.internal.PreviewFeature.Feature.RECORDS, - essentialAPI=false) - @SuppressWarnings("preview") @CallerSensitive public RecordComponent[] getRecordComponents() { SecurityManager sm = System.getSecurityManager(); @@ -3682,13 +3672,6 @@ private static Class javaLangRecordClass() { } /** - * {@preview Associated with records, a preview feature of the Java language. - * - * This method is associated with records, a preview - * feature of the Java language. Preview features - * may be removed in a future release, or upgraded to permanent - * features of the Java language.} - * * Returns {@code true} if and only if this class is a record class. * *

The {@linkplain #getSuperclass() direct superclass} of a record @@ -3701,10 +3684,8 @@ private static Class javaLangRecordClass() { * * @return true if and only if this class is a record class, otherwise false * @jls 8.10 Record Types - * @since 14 + * @since 16 */ - @jdk.internal.PreviewFeature(feature=jdk.internal.PreviewFeature.Feature.RECORDS, - essentialAPI=false) public boolean isRecord() { return getSuperclass() == JAVA_LANG_RECORD_CLASS && isRecord0(); } diff --git a/src/java.base/share/classes/java/lang/Record.java b/src/java.base/share/classes/java/lang/Record.java index 4d568e8baa0..121fc7ce73c 100644 --- a/src/java.base/share/classes/java/lang/Record.java +++ b/src/java.base/share/classes/java/lang/Record.java @@ -25,14 +25,6 @@ package java.lang; /** - * {@preview Associated with records, a preview feature of the Java language. - * - * This class is associated with records, a preview - * feature of the Java language. Programs can only use this - * class when preview features are enabled. Preview features - * may be removed in a future release, or upgraded to permanent - * features of the Java language.} - * * This is the common base class of all Java language record classes. * *

More information about records, including descriptions of the @@ -86,10 +78,8 @@ * record serialization. * * @jls 8.10 Record Types - * @since 14 + * @since 16 */ -@jdk.internal.PreviewFeature(feature=jdk.internal.PreviewFeature.Feature.RECORDS, - essentialAPI=true) public abstract class Record { /** * Constructor for record classes to call. diff --git a/src/java.base/share/classes/java/lang/VersionProps.java.template b/src/java.base/share/classes/java/lang/VersionProps.java.template index 4f29c2d5fc3..6037c61b3be 100644 --- a/src/java.base/share/classes/java/lang/VersionProps.java.template +++ b/src/java.base/share/classes/java/lang/VersionProps.java.template @@ -36,6 +36,7 @@ class VersionProps { private static final String launcher_name = "@@LAUNCHER_NAME@@"; + // This field is read by HotSpot private static final String java_version = "@@VERSION_SHORT@@"; diff --git a/src/java.base/share/classes/java/lang/annotation/ElementType.java b/src/java.base/share/classes/java/lang/annotation/ElementType.java index 15182f2a87b..db4e65a2b45 100644 --- a/src/java.base/share/classes/java/lang/annotation/ElementType.java +++ b/src/java.base/share/classes/java/lang/annotation/ElementType.java @@ -118,22 +118,12 @@ public enum ElementType { MODULE, /** - * {@preview Associated with records, a preview feature of the Java language. - * - * This constant is associated with records, a preview - * feature of the Java language. Programs can only use this - * constant when preview features are enabled. Preview features - * may be removed in a future release, or upgraded to permanent - * features of the Java language.} - * * Record component * * @jls 8.10.3 Record Members * @jls 9.7.4 Where Annotations May Appear * - * @since 14 + * @since 16 */ - @jdk.internal.PreviewFeature(feature=jdk.internal.PreviewFeature.Feature.RECORDS, - essentialAPI=true) RECORD_COMPONENT; } diff --git a/src/java.base/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java b/src/java.base/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java index 2bf096a3b06..5454eeca025 100644 --- a/src/java.base/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java +++ b/src/java.base/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java @@ -28,6 +28,7 @@ import jdk.internal.misc.CDS; import jdk.internal.org.objectweb.asm.*; import sun.invoke.util.BytecodeDescriptor; +import sun.invoke.util.VerifyAccess; import sun.security.action.GetPropertyAction; import sun.security.action.GetBooleanAction; @@ -66,7 +67,6 @@ private static final String DESCR_METHOD_WRITE_REPLACE = "()Ljava/lang/Object;"; private static final String DESCR_METHOD_WRITE_OBJECT = "(Ljava/io/ObjectOutputStream;)V"; private static final String DESCR_METHOD_READ_OBJECT = "(Ljava/io/ObjectInputStream;)V"; - private static final String DESCR_SET_IMPL_METHOD = "(Ljava/lang/invoke/MethodHandle;)V"; private static final String NAME_METHOD_WRITE_REPLACE = "writeReplace"; private static final String NAME_METHOD_READ_OBJECT = "readObject"; @@ -87,7 +87,7 @@ private static final String[] EMPTY_STRING_ARRAY = new String[0]; // Used to ensure that each spun class name is unique - private static final AtomicInteger counter = new AtomicInteger(0); + private static final AtomicInteger counter = new AtomicInteger(); // For dumping generated classes to disk, for debugging purposes private static final ProxyClassesDumper dumper; @@ -169,8 +169,8 @@ public InnerClassLambdaMetafactory(MethodHandles.Lookup caller, implMethodDesc = implInfo.getMethodType().toMethodDescriptorString(); constructorType = invokedType.changeReturnType(Void.TYPE); lambdaClassName = lambdaClassName(targetClass); - useImplMethodHandle = !implClass.getPackageName().equals(implInfo.getDeclaringClass().getPackageName()) - && !Modifier.isPublic(implInfo.getModifiers()); + useImplMethodHandle = !Modifier.isPublic(implInfo.getModifiers()) && + !VerifyAccess.isSamePackage(implClass, implInfo.getDeclaringClass()); cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); int parameterCount = invokedType.parameterCount(); if (parameterCount > 0) { diff --git a/src/java.base/share/classes/java/lang/invoke/MethodHandles.java b/src/java.base/share/classes/java/lang/invoke/MethodHandles.java index 79c59ab1d6c..64698d94a00 100644 --- a/src/java.base/share/classes/java/lang/invoke/MethodHandles.java +++ b/src/java.base/share/classes/java/lang/invoke/MethodHandles.java @@ -4739,23 +4739,24 @@ static boolean permuteArgumentChecks(int[] reorder, MethodType newType, MethodTy if (newType.returnType() != oldType.returnType()) throw newIllegalArgumentException("return types do not match", oldType, newType); - if (reorder.length == oldType.parameterCount()) { - int limit = newType.parameterCount(); - boolean bad = false; - for (int j = 0; j < reorder.length; j++) { - int i = reorder[j]; - if (i < 0 || i >= limit) { - bad = true; break; - } - Class src = newType.parameterType(i); - Class dst = oldType.parameterType(j); - if (src != dst) - throw newIllegalArgumentException("parameter types do not match after reorder", - oldType, newType); + if (reorder.length != oldType.parameterCount()) + throw newIllegalArgumentException("old type parameter count and reorder array length do not match", + oldType, Arrays.toString(reorder)); + + int limit = newType.parameterCount(); + for (int j = 0; j < reorder.length; j++) { + int i = reorder[j]; + if (i < 0 || i >= limit) { + throw newIllegalArgumentException("index is out of bounds for new type", + i, newType); } - if (!bad) return true; + Class src = newType.parameterType(i); + Class dst = oldType.parameterType(j); + if (src != dst) + throw newIllegalArgumentException("parameter types do not match after reorder", + oldType, newType); } - throw newIllegalArgumentException("bad reorder array: "+Arrays.toString(reorder)); + return true; } /** diff --git a/src/java.base/share/classes/java/lang/module/package-info.java b/src/java.base/share/classes/java/lang/module/package-info.java index 3bf75431bd2..3deaf3ad0a1 100644 --- a/src/java.base/share/classes/java/lang/module/package-info.java +++ b/src/java.base/share/classes/java/lang/module/package-info.java @@ -147,7 +147,7 @@ *

Otherwise, resolution succeeds, and the result of resolution is the * readability graph. * - *

Root modules

+ *

Root modules

* *

The set of root modules at compile-time is usually the set of modules * being compiled. At run-time, the set of root modules is usually the diff --git a/src/java.base/share/classes/java/lang/reflect/RecordComponent.java b/src/java.base/share/classes/java/lang/reflect/RecordComponent.java index 225a0999f17..7079f3d28f7 100644 --- a/src/java.base/share/classes/java/lang/reflect/RecordComponent.java +++ b/src/java.base/share/classes/java/lang/reflect/RecordComponent.java @@ -38,23 +38,14 @@ import java.util.Objects; /** - * {@preview Associated with records, a preview feature of the Java language. - * - * This class is associated with records, a preview - * feature of the Java language. Preview features - * may be removed in a future release, or upgraded to permanent - * features of the Java language.} - * * A {@code RecordComponent} provides information about, and dynamic access to, a * component of a record class. * * @see Class#getRecordComponents() * @see java.lang.Record * @jls 8.10 Record Types - * @since 14 + * @since 16 */ -@jdk.internal.PreviewFeature(feature=jdk.internal.PreviewFeature.Feature.RECORDS, - essentialAPI=false) public final class RecordComponent implements AnnotatedElement { // declaring class private Class clazz; diff --git a/src/java.base/share/classes/java/lang/runtime/ObjectMethods.java b/src/java.base/share/classes/java/lang/runtime/ObjectMethods.java index f1115b6c36d..ad50a002f71 100644 --- a/src/java.base/share/classes/java/lang/runtime/ObjectMethods.java +++ b/src/java.base/share/classes/java/lang/runtime/ObjectMethods.java @@ -38,23 +38,14 @@ import java.util.Objects; /** - * {@preview Associated with records, a preview feature of the Java language. - * - * This class is associated with records, a preview - * feature of the Java language. Preview features - * may be removed in a future release, or upgraded to permanent - * features of the Java language.} - * * Bootstrap methods for state-driven implementations of core methods, * including {@link Object#equals(Object)}, {@link Object#hashCode()}, and * {@link Object#toString()}. These methods may be used, for example, by * Java compiler implementations to implement the bodies of {@link Object} * methods for record classes. * - * @since 14 + * @since 16 */ -@jdk.internal.PreviewFeature(feature=jdk.internal.PreviewFeature.Feature.RECORDS, - essentialAPI=false) public class ObjectMethods { private ObjectMethods() { } diff --git a/src/java.base/share/classes/java/net/NetPermission.java b/src/java.base/share/classes/java/net/NetPermission.java index d4f4dfd4d17..23055e5b8d2 100644 --- a/src/java.base/share/classes/java/net/NetPermission.java +++ b/src/java.base/share/classes/java/net/NetPermission.java @@ -66,6 +66,16 @@ * * * + * accessUnixDomainSocket + * The ability to accept, bind, connect or get the local address + * of a Unix Domain socket. + * + * Malicious code could connect to local processes using Unix domain sockets + * or impersonate local processes, by binding to the same pathnames (assuming they + * have the required Operating System permissions. + * + * + * * getCookieHandler * The ability to get the cookie handler that processes highly * security sensitive cookie information for an Http session. diff --git a/src/java.base/share/classes/java/net/StandardProtocolFamily.java b/src/java.base/share/classes/java/net/StandardProtocolFamily.java index 25aaed4c81c..c90a3fcf012 100644 --- a/src/java.base/share/classes/java/net/StandardProtocolFamily.java +++ b/src/java.base/share/classes/java/net/StandardProtocolFamily.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2009, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2020, 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,5 +41,11 @@ public enum StandardProtocolFamily implements ProtocolFamily { /** * Internet Protocol Version 6 (IPv6) */ - INET6 + INET6, + + /** + * Unix domain (Local) interprocess communication. + * @since 16 + */ + UNIX } diff --git a/src/java.base/share/classes/java/net/UnixDomainSocketAddress.java b/src/java.base/share/classes/java/net/UnixDomainSocketAddress.java new file mode 100644 index 00000000000..d1d718fe1a1 --- /dev/null +++ b/src/java.base/share/classes/java/net/UnixDomainSocketAddress.java @@ -0,0 +1,211 @@ +/* + * Copyright (c) 2020, 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.net; + +import java.io.ObjectStreamException; +import java.io.Serializable; +import java.net.SocketAddress; +import java.nio.channels.SocketChannel; +import java.nio.file.FileSystem; +import java.nio.file.FileSystems; +import java.nio.file.InvalidPathException; +import java.nio.file.Path; + +/** + * A Unix domain socket address. + * A Unix domain socket address encapsulates a file-system path that Unix domain sockets + * bind or connect to. + * + *

An unnamed {@code UnixDomainSocketAddress} has + * an empty path. The local address of a {@link SocketChannel} to a Unix domain socket + * that is automatically or implicitly bound will be unnamed. + * + *

{@link Path} objects used to create instances of this class must be obtained + * from the {@linkplain FileSystems#getDefault system-default} file system. + * + * @see java.nio.channels.SocketChannel + * @see java.nio.channels.ServerSocketChannel + * @since 16 + */ +public final class UnixDomainSocketAddress extends SocketAddress { + @java.io.Serial + static final long serialVersionUID = 92902496589351288L; + + private final transient Path path; + + /** + * A serial proxy for all {@link UnixDomainSocketAddress} instances. + * It captures the file path name and reconstructs using the public static + * {@link #of(String) factory}. + * + * @serial include + */ + private static final class Ser implements Serializable { + @java.io.Serial + static final long serialVersionUID = -7955684448513979814L; + + /** + * The path name. + * @serial + */ + private final String pathname; + + Ser(String pathname) { + this.pathname = pathname; + } + + /** + * Creates a {@link UnixDomainSocketAddress} instance, by an invocation + * of the {@link #of(String) factory} method passing the path name. + * @return a UnixDomainSocketAddress + */ + @java.io.Serial + private Object readResolve() { + return UnixDomainSocketAddress.of(pathname); + } + } + + /** + * Returns a + * + * Ser containing the path name of this instance. + * + * @return a {@link Ser} + * representing the path name of this instance + */ + @java.io.Serial + private Object writeReplace() throws ObjectStreamException { + return new Ser(path.toString()); + } + + /** + * Throws InvalidObjectException, always. + * @param s the stream + * @throws java.io.InvalidObjectException always + */ + @java.io.Serial + private void readObject(java.io.ObjectInputStream s) + throws java.io.InvalidObjectException + { + throw new java.io.InvalidObjectException("Proxy required"); + } + + /** + * Throws InvalidObjectException, always. + * @throws java.io.InvalidObjectException always + */ + @java.io.Serial + private void readObjectNoData() + throws java.io.InvalidObjectException + { + throw new java.io.InvalidObjectException("Proxy required"); + } + + private UnixDomainSocketAddress(Path path) { + this.path = path; + } + + /** + * Creates a UnixDomainSocketAddress from the given path string. + * + * @param pathname + * The path string, which can be empty + * + * @return A UnixDomainSocketAddress + * + * @throws InvalidPathException + * If the path cannot be converted to a Path + * + * @throws NullPointerException if pathname is {@code null} + */ + public static UnixDomainSocketAddress of(String pathname) { + return of(Path.of(pathname)); + } + + /** + * Creates a UnixDomainSocketAddress for the given path. + * + * @param path + * The path to the socket, which can be empty + * + * @return A UnixDomainSocketAddress + * + * @throws IllegalArgumentException + * If the path is not associated with the default file system + * + * @throws NullPointerException if path is {@code null} + */ + public static UnixDomainSocketAddress of(Path path) { + FileSystem fs = path.getFileSystem(); + if (fs != FileSystems.getDefault()) { + throw new IllegalArgumentException(); + } + if (fs.getClass().getModule() != Object.class.getModule()) { + throw new IllegalArgumentException(); + } + return new UnixDomainSocketAddress(path); + } + + /** + * Returns this address's path. + * + * @return this address's path + */ + public Path getPath() { + return path; + } + + /** + * Returns the hash code of this {@code UnixDomainSocketAddress} + */ + @Override + public int hashCode() { + return path.hashCode(); + } + + /** + * Compares this address with another object. + * + * @return true if the path fields are equal + */ + @Override + public boolean equals(Object o) { + if (!(o instanceof UnixDomainSocketAddress)) + return false; + UnixDomainSocketAddress that = (UnixDomainSocketAddress)o; + return this.path.equals(that.path); + } + + /** + * Returns a string representation of this {@code UnixDomainSocketAddress}. + * + * @return this address's path which may be empty for an unnamed address + */ + @Override + public String toString() { + return path.toString(); + } +} diff --git a/src/java.base/share/classes/java/nio/channels/DatagramChannel.java b/src/java.base/share/classes/java/nio/channels/DatagramChannel.java index 2838bce939b..18dac3f4b3d 100644 --- a/src/java.base/share/classes/java/nio/channels/DatagramChannel.java +++ b/src/java.base/share/classes/java/nio/channels/DatagramChannel.java @@ -150,6 +150,9 @@ protected DatagramChannel(SelectorProvider provider) { * * @throws IOException * If an I/O error occurs + * + * @see + * java.net.preferIPv4Stack system property */ public static DatagramChannel open() throws IOException { return SelectorProvider.provider().openDatagramChannel(); @@ -169,6 +172,9 @@ public static DatagramChannel open() throws IOException { * java.nio.channels.spi.SelectorProvider} object. The channel will not be * connected. * + * @apiNote Unix domain sockets + * are not supported by DatagramChannel. + * * @param family * The protocol family * @@ -182,6 +188,9 @@ public static DatagramChannel open() throws IOException { * @throws IOException * If an I/O error occurs * + * @see + * java.net.preferIPv4Stack system property + * * @since 1.7 */ public static DatagramChannel open(ProtocolFamily family) throws IOException { @@ -629,5 +638,4 @@ public final long write(ByteBuffer[] srcs) throws IOException { */ @Override public abstract SocketAddress getLocalAddress() throws IOException; - } diff --git a/src/java.base/share/classes/java/nio/channels/ServerSocketChannel.java b/src/java.base/share/classes/java/nio/channels/ServerSocketChannel.java index 8beecb3ebaf..c3b541f536e 100644 --- a/src/java.base/share/classes/java/nio/channels/ServerSocketChannel.java +++ b/src/java.base/share/classes/java/nio/channels/ServerSocketChannel.java @@ -26,10 +26,12 @@ package java.nio.channels; import java.io.IOException; +import java.net.NetPermission; import java.net.ProtocolFamily; import java.net.ServerSocket; import java.net.SocketOption; import java.net.SocketAddress; +import java.net.UnixDomainSocketAddress; import java.nio.channels.spi.AbstractSelectableChannel; import java.nio.channels.spi.SelectorProvider; import static java.util.Objects.requireNonNull; @@ -37,16 +39,20 @@ /** * A selectable channel for stream-oriented listening sockets. * - *

A server-socket channel is created by invoking the {@link #open() open} - * method of this class. It is not possible to create a channel for an arbitrary, - * pre-existing {@link ServerSocket}. A newly-created server-socket channel is - * open but not yet bound. An attempt to invoke the {@link #accept() accept} - * method of an unbound server-socket channel will cause a {@link NotYetBoundException} + *

A server-socket channel is created by invoking one of the {@code open} + * methods of this class. The no-arg {@link #open() open} method opens a server-socket + * channel for an Internet protocol socket. The {@link #open(ProtocolFamily)} + * method is used to open a server-socket channel for a socket of a specified + * protocol family. It is not possible to create a channel for an arbitrary, + * pre-existing socket. A newly-created server-socket channel is open but not yet + * bound. An attempt to invoke the {@link #accept() accept} method of an + * unbound server-socket channel will cause a {@link NotYetBoundException} * to be thrown. A server-socket channel can be bound by invoking one of the - * {@link #bind(java.net.SocketAddress,int) bind} methods defined by this class. + * {@link #bind(java.net.SocketAddress, int) bind} methods defined by this class. * *

Socket options are configured using the {@link #setOption(SocketOption,Object) - * setOption} method. Server-socket channels support the following options: + * setOption} method. Server-socket channels for Internet protocol sockets + * support the following options: *

* * @@ -68,7 +74,27 @@ * *
Socket options
*
- * Additional (implementation specific) options may also be supported. + * + *

Server-socket channels for Unix domain sockets support: + *

+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Socket options
Option NameDescription
{@link java.net.StandardSocketOptions#SO_RCVBUF SO_RCVBUF} The size of the socket receive buffer
+ *
+ * + *

Additional (implementation specific) options may also be supported. * *

Server-socket channels are safe for use by multiple concurrent threads. *

@@ -94,7 +120,7 @@ protected ServerSocketChannel(SelectorProvider provider) { } /** - * Opens a server-socket channel. + * Opens a server-socket channel for an Internet protocol socket. * *

The new channel is created by invoking the {@link * java.nio.channels.spi.SelectorProvider#openServerSocketChannel @@ -110,13 +136,16 @@ protected ServerSocketChannel(SelectorProvider provider) { * * @throws IOException * If an I/O error occurs + * + * @see + * java.net.preferIPv4Stack system property */ public static ServerSocketChannel open() throws IOException { return SelectorProvider.provider().openServerSocketChannel(); } /** - * Opens a server-socket channel.The {@code family} parameter specifies the + * Opens a server-socket channel. The {@code family} parameter specifies the * {@link ProtocolFamily protocol family} of the channel's socket. * *

The new channel is created by invoking the {@link @@ -137,6 +166,9 @@ public static ServerSocketChannel open() throws IOException { * @throws IOException * If an I/O error occurs * + * @see + * java.net.preferIPv4Stack system property + * * @since 15 */ public static ServerSocketChannel open(ProtocolFamily family) throws IOException { @@ -180,8 +212,7 @@ public final int validOps() { * @throws ClosedChannelException {@inheritDoc} * @throws IOException {@inheritDoc} * @throws SecurityException - * If a security manager has been installed and its {@link - * SecurityManager#checkListen checkListen} method denies the + * If a security manager has been installed and it denies the * operation * * @since 1.7 @@ -197,8 +228,8 @@ public final ServerSocketChannel bind(SocketAddress local) * listen for connections. * *

This method is used to establish an association between the socket and - * a local address. Once an association is established then the socket remains - * bound until the channel is closed. + * a local address. For Internet protocol sockets, once an association + * is established then the socket remains bound until the channel is closed. * *

The {@code backlog} parameter is the maximum number of pending * connections on the socket. Its exact semantics are implementation specific. @@ -207,9 +238,25 @@ public final ServerSocketChannel bind(SocketAddress local) * the value {@code 0}, or a negative value, then an implementation specific * default is used. * + * @apiNote + * Binding a server socket channel for a Unix Domain socket, creates a + * file corresponding to the file path in the {@link UnixDomainSocketAddress}. + * This file persists after the channel is closed, and must be removed before + * another socket can bind to the same name. Binding to a {@code null} address + * causes the socket to be automatically bound to some unique file + * in a system temporary location. The associated socket file also persists + * after the channel is closed. Its name can be obtained from the channel's + * local socket address. + * + * @implNote + * Each platform enforces an implementation specific, maximum length for the + * name of a Unix Domain socket. This limitation is enforced when a + * channel is bound. The maximum length is typically close to and generally + * not less than 100 bytes. + * * @param local - * The address to bind the socket, or {@code null} to bind to an - * automatically assigned socket address + * The address to bind the socket, or {@code null} to bind to + * an automatically assigned socket address * @param backlog * The maximum number of pending connections * @@ -225,8 +272,10 @@ public final ServerSocketChannel bind(SocketAddress local) * If some other I/O error occurs * @throws SecurityException * If a security manager has been installed and its {@link - * SecurityManager#checkListen checkListen} method denies the - * operation + * SecurityManager#checkListen checkListen} method denies + * the operation for an Internet protocol socket address, + * or for a Unix domain socket address if it denies + * {@link NetPermission}{@code("accessUnixDomainSocket")}. * * @since 1.7 */ @@ -251,6 +300,9 @@ public abstract ServerSocketChannel setOption(SocketOption name, T value) * declared in the {@link java.net.ServerSocket} class.

* * @return A server socket associated with this channel + * + * @throws UnsupportedOperationException + * If the channel's socket is not an Internet protocol socket */ public abstract ServerSocket socket(); @@ -265,13 +317,15 @@ public abstract ServerSocketChannel setOption(SocketOption name, T value) *

The socket channel returned by this method, if any, will be in * blocking mode regardless of the blocking mode of this channel. * - *

This method performs exactly the same security checks as the {@link - * java.net.ServerSocket#accept accept} method of the {@link - * java.net.ServerSocket} class. That is, if a security manager has been - * installed then for each new connection this method verifies that the - * address and port number of the connection's remote endpoint are - * permitted by the security manager's {@link - * java.lang.SecurityManager#checkAccept checkAccept} method.

+ *

If bound to an Internet protocol socket address, this method + * performs exactly the same security checks as the {@link + * java.net.ServerSocket#accept accept} method of the {@link java.net.ServerSocket} + * class. That is, if a security manager has been installed then for each + * new connection this method verifies that the address and port number + * of the connection's remote endpoint are permitted by the security + * manager's {@link java.lang.SecurityManager#checkAccept checkAccept} + * method. If bound to a Unix Domain socket address, this method checks + * {@link NetPermission}{@code ("accessUnixDomainSocket")}. * * @return The socket channel for the new connection, * or {@code null} if this channel is in non-blocking mode @@ -305,7 +359,7 @@ public abstract ServerSocketChannel setOption(SocketOption name, T value) /** * {@inheritDoc} - *

+ * * If there is a security manager set, its {@code checkConnect} method is * called with the local address and {@code -1} as its arguments to see * if the operation is allowed. If the operation is not allowed, @@ -313,9 +367,16 @@ public abstract ServerSocketChannel setOption(SocketOption name, T value) * {@link java.net.InetAddress#getLoopbackAddress loopback} address and the * local port of the channel's socket is returned. * + *

Where the channel is bound to a Unix Domain socket address, the socket + * address is a {@link UnixDomainSocketAddress}. If there is a security manager + * set, its {@link SecurityManager#checkPermission(java.security.Permission) + * checkPermission} method is called with {@link NetPermission}{@code + * ("accessUnixDomainSocket")}. If the operation is not allowed an unnamed + * {@link UnixDomainSocketAddress} is returned. + * * @return The {@code SocketAddress} that the socket is bound to, or the - * {@code SocketAddress} representing the loopback address if - * denied by the security manager, or {@code null} if the + * {@code SocketAddress} representing the loopback address or empty + * path if denied by the security manager, or {@code null} if the * channel's socket is not bound * * @throws ClosedChannelException {@inheritDoc} @@ -323,5 +384,4 @@ public abstract ServerSocketChannel setOption(SocketOption name, T value) */ @Override public abstract SocketAddress getLocalAddress() throws IOException; - } diff --git a/src/java.base/share/classes/java/nio/channels/SocketChannel.java b/src/java.base/share/classes/java/nio/channels/SocketChannel.java index d97ebc681c7..560440744f6 100644 --- a/src/java.base/share/classes/java/nio/channels/SocketChannel.java +++ b/src/java.base/share/classes/java/nio/channels/SocketChannel.java @@ -26,10 +26,14 @@ package java.nio.channels; import java.io.IOException; +import java.net.InetSocketAddress; +import java.net.NetPermission; import java.net.ProtocolFamily; +import java.net.StandardProtocolFamily; import java.net.Socket; import java.net.SocketOption; import java.net.SocketAddress; +import java.net.UnixDomainSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.spi.AbstractSelectableChannel; import java.nio.channels.spi.SelectorProvider; @@ -38,15 +42,18 @@ /** * A selectable channel for stream-oriented connecting sockets. * - *

A socket channel is created by invoking one of the {@link #open open} - * methods of this class. It is not possible to create a channel for an arbitrary, - * pre-existing socket. A newly-created socket channel is open but not yet - * connected. An attempt to invoke an I/O operation upon an unconnected - * channel will cause a {@link NotYetConnectedException} to be thrown. A - * socket channel can be connected by invoking its {@link #connect connect} - * method; once connected, a socket channel remains connected until it is - * closed. Whether or not a socket channel is connected may be determined by - * invoking its {@link #isConnected isConnected} method. + *

A socket channel is created by invoking one of the {@code open} methods of + * this class. The no-arg {@link #open() open} method opens a socket channel + * for an Internet protocol socket. The {@link #open(ProtocolFamily)} + * method is used to open a socket channel for a socket of a specified protocol + * family. It is not possible to create a channel for an arbitrary, pre-existing + * socket. A newly-created socket channel is open but not yet connected. An + * attempt to invoke an I/O operation upon an unconnected channel will cause a + * {@link NotYetConnectedException} to be thrown. A socket channel can be + * connected by invoking its {@link #connect connect} method; once connected, + * a socket channel remains connected until it is closed. Whether or not a + * socket channel is connected may be determined by invoking its {@link #isConnected() + * isConnected} method. * *

Socket channels support non-blocking connection: A socket * channel may be created and the process of establishing the link to the @@ -55,7 +62,7 @@ * Whether or not a connection operation is in progress may be determined by * invoking the {@link #isConnectionPending isConnectionPending} method. * - *

Socket channels support asynchronous shutdown, which is similar + *

Socket channels support asynchronous shutdown, which is similar * to the asynchronous close operation specified in the {@link Channel} class. * If the input side of a socket is shut down by one thread while another * thread is blocked in a read operation on the socket's channel, then the read @@ -66,7 +73,8 @@ * AsynchronousCloseException}. * *

Socket options are configured using the {@link #setOption(SocketOption,Object) - * setOption} method. Socket channels support the following options: + * setOption} method. Socket channels for Internet protocol sockets support + * following options: *

* * @@ -105,7 +113,36 @@ * *
Socket options
*
- * Additional (implementation specific) options may also be supported. + * + *

Socket channels for Unix domain sockets support: + *

+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Socket options
Option NameDescription
{@link java.net.StandardSocketOptions#SO_SNDBUF SO_SNDBUF} The size of the socket send buffer
{@link java.net.StandardSocketOptions#SO_RCVBUF SO_RCVBUF} The size of the socket receive buffer
{@link java.net.StandardSocketOptions#SO_LINGER SO_LINGER} Linger on close if data is present (when configured in blocking mode + * only)
+ *
+ * + *

Additional (implementation specific) options may also be supported. * *

Socket channels are safe for use by multiple concurrent threads. They * support concurrent reading and writing, though at most one thread may be @@ -136,7 +173,7 @@ protected SocketChannel(SelectorProvider provider) { } /** - * Opens a socket channel. + * Opens a socket channel for an Internet protocol socket. * *

The new channel is created by invoking the {@link * java.nio.channels.spi.SelectorProvider#openSocketChannel @@ -147,6 +184,9 @@ protected SocketChannel(SelectorProvider provider) { * * @throws IOException * If an I/O error occurs + * + * @see + * java.net.preferIPv4Stack system property */ public static SocketChannel open() throws IOException { return SelectorProvider.provider().openSocketChannel(); @@ -174,6 +214,9 @@ public static SocketChannel open() throws IOException { * @throws IOException * If an I/O error occurs * + * @see + * java.net.preferIPv4Stack system property + * * @since 15 */ public static SocketChannel open(ProtocolFamily family) throws IOException { @@ -183,10 +226,16 @@ public static SocketChannel open(ProtocolFamily family) throws IOException { /** * Opens a socket channel and connects it to a remote address. * - *

This convenience method works as if by invoking the {@link #open()} - * method, invoking the {@link #connect(SocketAddress) connect} method upon - * the resulting socket channel, passing it {@code remote}, and then - * returning that channel.

+ *

If the remote address is an {@link InetSocketAddress} then this + * method works as if by invoking the {@link #open()} method, invoking the + * {@link #connect(SocketAddress) connect} method upon the resulting socket + * channel, passing it {@code remote}, and then returning that channel. + * + *

If the remote address is a {@link UnixDomainSocketAddress} then this + * works by invoking the {@link #open(ProtocolFamily)} method with {@link + * StandardProtocolFamily#UNIX} as parameter, invoking the {@link + * #connect(SocketAddress) connect} method upon the resulting socket channel, + * passing it {@code remote}, then returning that channel.

* * @param remote * The remote address to which the new channel is to be connected @@ -204,7 +253,8 @@ public static SocketChannel open(ProtocolFamily family) throws IOException { * interrupt status * * @throws UnresolvedAddressException - * If the given remote address is not fully resolved + * If the given remote address is an InetSocketAddress that is not fully + * resolved * * @throws UnsupportedAddressTypeException * If the type of the given remote address is not supported @@ -215,11 +265,22 @@ public static SocketChannel open(ProtocolFamily family) throws IOException { * * @throws IOException * If some other I/O error occurs + * + * @see + * java.net.preferIPv4Stack system property */ public static SocketChannel open(SocketAddress remote) throws IOException { - SocketChannel sc = open(); + SocketChannel sc; + requireNonNull(remote); + if (remote instanceof InetSocketAddress) + sc = open(); + else if (remote instanceof UnixDomainSocketAddress) + sc = open(StandardProtocolFamily.UNIX); + else + throw new UnsupportedAddressTypeException(); + try { sc.connect(remote); } catch (Throwable x) { @@ -255,6 +316,38 @@ public final int validOps() { // -- Socket-specific operations -- /** + * Binds the channel's socket to a local address. + * + *

This method is used to establish an association between the socket + * and a local address. For Internet Protocol sockets, once an + * association is established then the socket remains bound until the + * channel is closed. If the {@code local} parameter has the value {@code + * null} then the socket will be bound to an address that is assigned + * automatically. + * + * @apiNote + * Binding a socket channel to a Unix Domain socket creates a file + * corresponding to the file path in the {@link UnixDomainSocketAddress}. This + * file persists after the channel is closed, and must be removed before + * another socket can bind to the same name. If a socket channel to a Unix + * Domain socket is implicitly bound by connecting it without calling + * bind first, then its socket is + * unnamed + * with no corresponding socket file in the file-system. If a socket channel + * to a Unix Domain socket is automatically bound by calling {@code + * bind(null)} this results in an unnamed socket also. + * + * @implNote + * Each platform enforces an implementation specific maximum length for the + * name of a Unix Domain socket. This limitation is enforced when a + * channel is bound. The maximum length is typically close to and generally + * not less than 100 bytes. + * + * @param local The address to bind the socket, or {@code null} to bind + * the socket to an automatically assigned socket address + * + * @return This channel + * * @throws ConnectionPendingException * If a non-blocking connect operation is already in progress on * this channel @@ -263,9 +356,11 @@ public final int validOps() { * @throws ClosedChannelException {@inheritDoc} * @throws IOException {@inheritDoc} * @throws SecurityException - * If a security manager has been installed and its - * {@link SecurityManager#checkListen checkListen} method denies - * the operation + * If a security manager has been installed and its {@link + * SecurityManager#checkListen checkListen} method denies + * the operation for an Internet protocol socket address, + * or for a Unix domain socket address if it denies + * {@link NetPermission}{@code("accessUnixDomainSocket")}. * * @since 1.7 */ @@ -329,10 +424,10 @@ public abstract SocketChannel setOption(SocketOption name, T value) /** * Retrieves a socket associated with this channel. * - *

The returned object will not declare any public methods that are not - * declared in the {@link java.net.Socket} class.

- * * @return A socket associated with this channel + * + * @throws UnsupportedOperationException + * If the channel's socket is not an Internet protocol socket */ public abstract Socket socket(); @@ -368,12 +463,19 @@ public abstract SocketChannel setOption(SocketOption name, T value) * method will block until the connection is established or an I/O error * occurs. * - *

This method performs exactly the same security checks as the {@link - * java.net.Socket} class. That is, if a security manager has been + *

For channels to Internet protocol sockets, this method performs + * exactly the same security checks as the {@link java.net.Socket} class. + * That is, if a security manager has been * installed then this method verifies that its {@link * java.lang.SecurityManager#checkConnect checkConnect} method permits * connecting to the address and port number of the given remote endpoint. * + *

For channels to Unix Domain sockets, this method checks + * {@link java.net.NetPermission NetPermission}{@code + * ("accessUnixDomainSocket")} with the security manager's {@link + * SecurityManager#checkPermission(java.security.Permission) + * checkPermission} method. + * *

This method may be invoked at any time. If a read or write * operation upon this channel is invoked while an invocation of this * method is in progress then that operation will first block until this @@ -409,7 +511,7 @@ public abstract SocketChannel setOption(SocketOption name, T value) * interrupt status * * @throws UnresolvedAddressException - * If the given remote address is not fully resolved + * If the given remote address is an InetSocketAddress that is not fully resolved * * @throws UnsupportedAddressTypeException * If the type of the given remote address is not supported @@ -477,9 +579,12 @@ public abstract SocketChannel setOption(SocketOption name, T value) /** * Returns the remote address to which this channel's socket is connected. * - *

Where the channel is bound and connected to an Internet Protocol - * socket address then the return value from this method is of type {@link - * java.net.InetSocketAddress}. + *

Where the channel's socket is bound and connected to an Internet + * Protocol socket address then the return value is of type + * {@link java.net.InetSocketAddress}. + * + *

Where the channel's socket is bound and connected to a Unix Domain + * socket address, the returned address is a {@link UnixDomainSocketAddress}. * * @return The remote address; {@code null} if the channel's socket is not * connected @@ -539,7 +644,7 @@ public final long write(ByteBuffer[] srcs) throws IOException { /** * {@inheritDoc} - *

+ * * If there is a security manager set, its {@code checkConnect} method is * called with the local address and {@code -1} as its arguments to see * if the operation is allowed. If the operation is not allowed, @@ -547,9 +652,16 @@ public final long write(ByteBuffer[] srcs) throws IOException { * {@link java.net.InetAddress#getLoopbackAddress loopback} address and the * local port of the channel's socket is returned. * + *

Where the channel is bound to a Unix Domain socket address, the socket + * address is a {@link UnixDomainSocketAddress}. If there is a security manager + * set, its {@link SecurityManager#checkPermission(java.security.Permission) + * checkPermission} method is called with {@link NetPermission}{@code + * ("accessUnixDomainSocket")}. If the operation is not allowed an unnamed + * {@link UnixDomainSocketAddress} is returned. + * * @return The {@code SocketAddress} that the socket is bound to, or the - * {@code SocketAddress} representing the loopback address if - * denied by the security manager, or {@code null} if the + * {@code SocketAddress} representing the loopback address or empty + * path if denied by the security manager, or {@code null} if the * channel's socket is not bound * * @throws ClosedChannelException {@inheritDoc} @@ -557,5 +669,4 @@ public final long write(ByteBuffer[] srcs) throws IOException { */ @Override public abstract SocketAddress getLocalAddress() throws IOException; - } diff --git a/src/java.base/share/classes/java/nio/channels/package-info.java b/src/java.base/share/classes/java/nio/channels/package-info.java index 0dc410ddd76..ed9565d8172 100644 --- a/src/java.base/share/classes/java/nio/channels/package-info.java +++ b/src/java.base/share/classes/java/nio/channels/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2020, 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 @@ -241,6 +241,28 @@ * If a channel needs an associated socket then a socket will be created as a side * effect of this operation. * + *

{@link java.nio.channels.DatagramChannel}, + * {@link java.nio.channels.SocketChannel} and + * {@link java.nio.channels.ServerSocketChannel}s can be created + * with different {@link java.net.ProtocolFamily protocol families}. The standard + * family types are specified in {@link java.net.StandardProtocolFamily}. + * + *

Channels for Internet Protocol sockets are created using the + * {@link java.net.StandardProtocolFamily#INET INET} or {@link + * java.net.StandardProtocolFamily#INET6 INET6} protocol families. Internet + * Protocol sockets support network communication using TCP and UDP and are + * addressed using {@link java.net.InetSocketAddress}es which encapsulate an IP + * address and port number. Internet Protocol sockets are also the default + * type created, when a protocol family is not specified in the channel factory + * creation method. + * + *

Channels for Unix Domain sockets are created + * using the {@link java.net.StandardProtocolFamily#UNIX UNIX} protocol family. + * Unix Domain sockets support local inter-process + * communication on the same host, and are addressed using {@link + * java.net.UnixDomainSocketAddress}es which encapsulate a filesystem pathname + * on the local system. + * *

The implementation of selectors, selectable channels, and selection keys * can be replaced by "plugging in" an alternative definition or instance of the * {@link java.nio.channels.spi.SelectorProvider} class defined in the {@link diff --git a/src/java.base/share/classes/java/nio/channels/spi/SelectorProvider.java b/src/java.base/share/classes/java/nio/channels/spi/SelectorProvider.java index e59533a0148..3b3277469b8 100644 --- a/src/java.base/share/classes/java/nio/channels/spi/SelectorProvider.java +++ b/src/java.base/share/classes/java/nio/channels/spi/SelectorProvider.java @@ -268,34 +268,38 @@ public abstract SocketChannel openSocketChannel() * associated network port. In this example, the process that is started, * inherits a channel representing a network socket. * - *

In cases where the inherited channel represents a network socket - * then the {@link java.nio.channels.Channel Channel} type returned + *

In cases where the inherited channel is for an Internet protocol + * socket then the {@link Channel Channel} type returned * by this method is determined as follows: * *

    * - *
  • If the inherited channel represents a stream-oriented connected - * socket then a {@link java.nio.channels.SocketChannel SocketChannel} is - * returned. The socket channel is, at least initially, in blocking - * mode, bound to a socket address, and connected to a peer. + *

  • If the inherited channel is for a stream-oriented connected + * socket then a {@link SocketChannel SocketChannel} is returned. The + * socket channel is, at least initially, in blocking mode, bound + * to a socket address, and connected to a peer. *

  • * - *
  • If the inherited channel represents a stream-oriented listening - * socket then a {@link java.nio.channels.ServerSocketChannel - * ServerSocketChannel} is returned. The server-socket channel is, at - * least initially, in blocking mode, and bound to a socket address. + *

  • If the inherited channel is for a stream-oriented listening + * socket then a {@link ServerSocketChannel ServerSocketChannel} is returned. + * The server-socket channel is, at least initially, in blocking mode, + * and bound to a socket address. *

  • * - *
  • If the inherited channel is a datagram-oriented socket - * then a {@link java.nio.channels.DatagramChannel DatagramChannel} is - * returned. The datagram channel is, at least initially, in blocking - * mode, and bound to a socket address. + *

  • If the inherited channel is a datagram-oriented socket then a + * {@link DatagramChannel DatagramChannel} is returned. The datagram channel + * is, at least initially, in blocking mode, and bound to a socket address. *

  • * *
* - *

In addition to the network-oriented channels described, this method - * may return other kinds of channels in the future. + *

In cases where the inherited channel is for a Unix domain + * socket then the {@link Channel} type returned is the same as for + * Internet protocol sockets as described above, except that + * datagram-oriented sockets are not supported. + * + *

In addition to the two types of socket just described, this method + * may return other types in the future. * *

The first invocation of this method creates the channel that is * returned. Subsequent invocations of this method return the same diff --git a/src/java.base/share/classes/java/nio/file/TempFileHelper.java b/src/java.base/share/classes/java/nio/file/TempFileHelper.java index cccc14f880e..860838751bf 100644 --- a/src/java.base/share/classes/java/nio/file/TempFileHelper.java +++ b/src/java.base/share/classes/java/nio/file/TempFileHelper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2020, 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,8 +33,7 @@ import java.nio.file.attribute.PosixFilePermission; import java.nio.file.attribute.PosixFilePermissions; import static java.nio.file.attribute.PosixFilePermission.*; -import sun.security.action.GetPropertyAction; - +import jdk.internal.util.StaticProperty; /** * Helper class to support creation of temporary files and directories with @@ -45,8 +44,7 @@ class TempFileHelper { private TempFileHelper() { } // temporary directory location - private static final Path tmpdir = - Path.of(GetPropertyAction.privilegedGetProperty("java.io.tmpdir")); + private static final Path tmpdir = Path.of(StaticProperty.javaIoTmpDir()); private static final boolean isPosix = FileSystems.getDefault().supportedFileAttributeViews().contains("posix"); diff --git a/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java b/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java index c7a09e56232..521eca47fd4 100644 --- a/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java +++ b/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java @@ -1556,11 +1556,11 @@ public DateTimeFormatterBuilder appendOptional(DateTimeFormatter formatter) { * GGGGG 5 appendText(ChronoField.ERA, TextStyle.NARROW) * * u 1 appendValue(ChronoField.YEAR, 1, 19, SignStyle.NORMAL) - * uu 2 appendValueReduced(ChronoField.YEAR, 2, 2000) + * uu 2 appendValueReduced(ChronoField.YEAR, 2, 2, 2000) * uuu 3 appendValue(ChronoField.YEAR, 3, 19, SignStyle.NORMAL) * u..u 4..n appendValue(ChronoField.YEAR, n, 19, SignStyle.EXCEEDS_PAD) * y 1 appendValue(ChronoField.YEAR_OF_ERA, 1, 19, SignStyle.NORMAL) - * yy 2 appendValueReduced(ChronoField.YEAR_OF_ERA, 2, 2000) + * yy 2 appendValueReduced(ChronoField.YEAR_OF_ERA, 2, 2, 2000) * yyy 3 appendValue(ChronoField.YEAR_OF_ERA, 3, 19, SignStyle.NORMAL) * y..y 4..n appendValue(ChronoField.YEAR_OF_ERA, n, 19, SignStyle.EXCEEDS_PAD) * Y 1 append special localized WeekFields element for numeric week-based-year diff --git a/src/java.base/share/classes/java/util/Timer.java b/src/java.base/share/classes/java/util/Timer.java index 7c47d0c7135..95577f29b8d 100644 --- a/src/java.base/share/classes/java/util/Timer.java +++ b/src/java.base/share/classes/java/util/Timer.java @@ -120,7 +120,7 @@ protected void finalize() throws Throwable { /** * This ID is used to generate thread names. */ - private static final AtomicInteger nextSerialNumber = new AtomicInteger(0); + private static final AtomicInteger nextSerialNumber = new AtomicInteger(); private static int serialNumber() { return nextSerialNumber.getAndIncrement(); } diff --git a/src/java.base/share/classes/java/util/stream/AbstractShortCircuitTask.java b/src/java.base/share/classes/java/util/stream/AbstractShortCircuitTask.java index bbf09f03b14..d59fcfa600c 100644 --- a/src/java.base/share/classes/java/util/stream/AbstractShortCircuitTask.java +++ b/src/java.base/share/classes/java/util/stream/AbstractShortCircuitTask.java @@ -68,7 +68,7 @@ abstract class AbstractShortCircuitTask helper, Spliterator spliterator) { super(helper, spliterator); - sharedResult = new AtomicReference<>(null); + sharedResult = new AtomicReference<>(); } /** diff --git a/src/java.base/share/classes/java/util/zip/ZipFile.java b/src/java.base/share/classes/java/util/zip/ZipFile.java index 2a2e3534e18..4c53855abfe 100644 --- a/src/java.base/share/classes/java/util/zip/ZipFile.java +++ b/src/java.base/share/classes/java/util/zip/ZipFile.java @@ -1335,18 +1335,6 @@ private final void checkEncoding(ZipCoder zc, byte[] a, int pos, int nlen) throw } } - private static final int hashN(byte[] a, int off, int len) { - int h = 1; - while (len-- > 0) { - h = 31 * h + a[off++]; - } - return h; - } - - private static final int hash_append(int hash, byte b) { - return hash * 31 + b; - } - private static class End { int centot; // 4 bytes long cenlen; // 4 bytes diff --git a/src/java.base/share/classes/jdk/internal/PreviewFeature.java b/src/java.base/share/classes/jdk/internal/PreviewFeature.java index 2f62a9c48a6..5624ead42d9 100644 --- a/src/java.base/share/classes/jdk/internal/PreviewFeature.java +++ b/src/java.base/share/classes/jdk/internal/PreviewFeature.java @@ -62,6 +62,11 @@ public enum Feature { // JDK 15. Since the JDK 14 codebase uses the enum constant, it is // necessary for PreviewFeature in JDK 15 to declare the enum constant. TEXT_BLOCKS, + // The RECORDS enum constant is not used in the JDK 16 codebase, but + // exists to support the bootcycle build of JDK 16. The bootcycle build + // of JDK 16 is performed with JDK 15 and the PreviewFeature type from + // JDK 16. Since the JDK 15 codebase uses the enum constant, it is + // necessary for PreviewFeature in JDK 16 to declare the enum constant. RECORDS, SEALED_CLASSES, ; diff --git a/src/java.base/share/classes/jdk/internal/icu/text/BidiBase.java b/src/java.base/share/classes/jdk/internal/icu/text/BidiBase.java index 600fca59b6f..33dd332d18c 100644 --- a/src/java.base/share/classes/jdk/internal/icu/text/BidiBase.java +++ b/src/java.base/share/classes/jdk/internal/icu/text/BidiBase.java @@ -4541,7 +4541,8 @@ public static boolean requiresBidi(char[] text, if (0 > start || start > limit || limit > text.length) { throw new IllegalArgumentException("Value start " + start + - " is out of range 0 to " + limit); + " is out of range 0 to " + limit + ", or limit " + limit + + " is beyond the text length " + text.length); } for (int i = start; i < limit; ++i) { @@ -4589,13 +4590,13 @@ public static void reorderVisually(byte[] levels, } if (0 > objectStart || objects.length <= objectStart) { throw new IllegalArgumentException("Value objectStart " + - levelStart + " is out of range 0 to " + + objectStart + " is out of range 0 to " + (objects.length-1)); } if (0 > count || objects.length < (objectStart+count)) { throw new IllegalArgumentException("Value count " + - levelStart + " is out of range 0 to " + - (objects.length - objectStart)); + count + " is less than zero, or objectStart + count" + + " is beyond objects length " + objects.length); } byte[] reorderLevels = new byte[count]; diff --git a/src/java.base/share/classes/jdk/internal/util/StaticProperty.java b/src/java.base/share/classes/jdk/internal/util/StaticProperty.java index 4c167ff98f0..d493f6653b2 100644 --- a/src/java.base/share/classes/jdk/internal/util/StaticProperty.java +++ b/src/java.base/share/classes/jdk/internal/util/StaticProperty.java @@ -47,6 +47,7 @@ public final class StaticProperty { private static final String JAVA_LIBRARY_PATH; private static final String SUN_BOOT_LIBRARY_PATH; private static final String JDK_SERIAL_FILTER; + private static final String JAVA_IO_TMPDIR; private StaticProperty() {} @@ -56,6 +57,7 @@ private StaticProperty() {} USER_HOME = getProperty(props, "user.home"); USER_DIR = getProperty(props, "user.dir"); USER_NAME = getProperty(props, "user.name"); + JAVA_IO_TMPDIR = getProperty(props, "java.io.tmpdir"); JAVA_LIBRARY_PATH = getProperty(props, "java.library.path", ""); SUN_BOOT_LIBRARY_PATH = getProperty(props, "sun.boot.library.path", ""); JDK_SERIAL_FILTER = getProperty(props, "jdk.serialFilter", null); @@ -140,6 +142,19 @@ public static String javaLibraryPath() { return JAVA_LIBRARY_PATH; } + /** + * Return the {@code java.io.tmpdir} system property. + * + * {@link SecurityManager#checkPropertyAccess} is NOT checked + * in this method. The caller of this method should take care to ensure + * that the returned property is not made accessible to untrusted code. + * + * @return the {@code java.io.tmpdir} system property + */ + public static String javaIoTmpDir() { + return JAVA_IO_TMPDIR; + } + /** * Return the {@code sun.boot.library.path} system property. * diff --git a/src/java.base/share/classes/module-info.java b/src/java.base/share/classes/module-info.java index d04134969c2..12ea481767e 100644 --- a/src/java.base/share/classes/module-info.java +++ b/src/java.base/share/classes/module-info.java @@ -270,6 +270,8 @@ jdk.incubator.foreign; exports sun.nio.cs to jdk.charsets; + exports sun.nio.fs to + jdk.net; exports sun.reflect.annotation to jdk.compiler; exports sun.reflect.generics.reflectiveObjects to diff --git a/src/java.base/share/classes/sun/net/ResourceManager.java b/src/java.base/share/classes/sun/net/ResourceManager.java index fb19671578b..abc09680ba2 100644 --- a/src/java.base/share/classes/sun/net/ResourceManager.java +++ b/src/java.base/share/classes/sun/net/ResourceManager.java @@ -62,7 +62,7 @@ public class ResourceManager { } } catch (NumberFormatException e) {} maxSockets = defmax; - numSockets = new AtomicInteger(0); + numSockets = new AtomicInteger(); } public static void beforeUdpCreate() throws SocketException { diff --git a/src/java.base/share/classes/sun/net/ext/ExtendedSocketOptions.java b/src/java.base/share/classes/sun/net/ext/ExtendedSocketOptions.java index ee77c758fe8..cdde3507929 100644 --- a/src/java.base/share/classes/sun/net/ext/ExtendedSocketOptions.java +++ b/src/java.base/share/classes/sun/net/ext/ExtendedSocketOptions.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2020, 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,6 +48,7 @@ public abstract class ExtendedSocketOptions { private final Set> datagramOptions; private final Set> clientStreamOptions; private final Set> serverStreamOptions; + private final Set> unixDomainClientOptions; /** Tells whether or not the option is supported. */ public final boolean isOptionSupported(SocketOption option) { @@ -73,6 +74,19 @@ public static Set> clientSocketOptions() { return getInstance().options0(SOCK_STREAM, false); } + /** + * Return the, possibly empty, set of extended socket options available for + * Unix domain client sockets. Note, there are no extended + * Unix domain server options. + */ + private final Set> unixDomainClientOptions() { + return unixDomainClientOptions; + } + + public static Set> unixDomainSocketOptions() { + return getInstance().unixDomainClientOptions(); + } + /** * Returns the (possibly empty) set of extended socket options for * datagram-oriented sockets. @@ -82,14 +96,22 @@ public static Set> datagramSocketOptions() { } private static boolean isDatagramOption(SocketOption option) { - return !option.name().startsWith("TCP_"); + if (option.name().startsWith("TCP_") || isUnixDomainOption(option)) { + return false; + } else { + return true; + } + } + + private static boolean isUnixDomainOption(SocketOption option) { + return option.name().equals("SO_PEERCRED"); } private static boolean isStreamOption(SocketOption option, boolean server) { - if (server && "SO_FLOW_SLA".equals(option.name())) { + if (option.name().startsWith("UDP_") || isUnixDomainOption(option)) { return false; } else { - return !option.name().startsWith("UDP_"); + return true; } } @@ -122,6 +144,7 @@ protected ExtendedSocketOptions(Set> options) { var datagramOptions = new HashSet>(); var serverStreamOptions = new HashSet>(); var clientStreamOptions = new HashSet>(); + var unixDomainClientOptions = new HashSet>(); for (var option : options) { if (isDatagramOption(option)) { datagramOptions.add(option); @@ -132,10 +155,14 @@ protected ExtendedSocketOptions(Set> options) { if (isStreamOption(option, false)) { clientStreamOptions.add(option); } + if (isUnixDomainOption(option)) { + unixDomainClientOptions.add(option); + } } this.datagramOptions = Set.copyOf(datagramOptions); this.serverStreamOptions = Set.copyOf(serverStreamOptions); this.clientStreamOptions = Set.copyOf(clientStreamOptions); + this.unixDomainClientOptions = Set.copyOf(unixDomainClientOptions); } private static volatile ExtendedSocketOptions instance; diff --git a/src/java.base/share/classes/sun/net/ftp/impl/FtpClient.java b/src/java.base/share/classes/sun/net/ftp/impl/FtpClient.java index 5cf7f30d7cf..442860138c5 100644 --- a/src/java.base/share/classes/sun/net/ftp/impl/FtpClient.java +++ b/src/java.base/share/classes/sun/net/ftp/impl/FtpClient.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2020, 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,15 +29,16 @@ import java.security.AccessController; import java.security.PrivilegedAction; import java.text.DateFormat; -import java.text.ParseException; -import java.text.SimpleDateFormat; +import java.time.ZoneOffset; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeParseException; import java.util.ArrayList; import java.util.Base64; import java.util.Calendar; import java.util.Date; import java.util.Iterator; import java.util.List; -import java.util.TimeZone; import java.util.Vector; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -289,9 +290,6 @@ public FtpDirEntry parseLine(String line) { } private class MLSxParser implements FtpDirParser { - - private SimpleDateFormat df = new SimpleDateFormat("yyyyMMddhhmmss"); - public FtpDirEntry parseLine(String line) { String name = null; int i = line.lastIndexOf(';'); @@ -326,22 +324,14 @@ public FtpDirEntry parseLine(String line) { } s = file.getFact("Modify"); if (s != null) { - Date d = null; - try { - d = df.parse(s); - } catch (ParseException ex) { - } + Date d = parseRfc3659TimeValue(s); if (d != null) { file.setLastModified(d); } } s = file.getFact("Create"); if (s != null) { - Date d = null; - try { - d = df.parse(s); - } catch (ParseException ex) { - } + Date d = parseRfc3659TimeValue(s); if (d != null) { file.setCreated(d); } @@ -1749,18 +1739,9 @@ public long getSize(String path) throws sun.net.ftp.FtpProtocolException, IOExce } return -1; } - private static String[] MDTMformats = { - "yyyyMMddHHmmss.SSS", - "yyyyMMddHHmmss" - }; - private static SimpleDateFormat[] dateFormats = new SimpleDateFormat[MDTMformats.length]; - static { - for (int i = 0; i < MDTMformats.length; i++) { - dateFormats[i] = new SimpleDateFormat(MDTMformats[i]); - dateFormats[i].setTimeZone(TimeZone.getTimeZone("GMT")); - } - } + private static final DateTimeFormatter RFC3659_DATETIME_FORMAT = DateTimeFormatter.ofPattern("yyyyMMddHHmmss[.SSS]") + .withZone(ZoneOffset.UTC); /** * Issues the MDTM [path] command to the server to get the modification @@ -1777,21 +1758,22 @@ public long getSize(String path) throws sun.net.ftp.FtpProtocolException, IOExce public Date getLastModified(String path) throws sun.net.ftp.FtpProtocolException, IOException { issueCommandCheck("MDTM " + path); if (lastReplyCode == FtpReplyCode.FILE_STATUS) { - String s = getResponseString().substring(4); - Date d = null; - for (SimpleDateFormat dateFormat : dateFormats) { - try { - d = dateFormat.parse(s); - } catch (ParseException ex) { - } - if (d != null) { - return d; - } - } + String s = getResponseString(); + return parseRfc3659TimeValue(s.substring(4, s.length() - 1)); } return null; } + private static Date parseRfc3659TimeValue(String s) { + Date result = null; + try { + var d = ZonedDateTime.parse(s, RFC3659_DATETIME_FORMAT); + result = Date.from(d.toInstant()); + } catch (DateTimeParseException ex) { + } + return result; + } + /** * Sets the parser used to handle the directory output to the specified * one. By default the parser is set to one that can handle most FTP diff --git a/src/java.base/share/classes/sun/net/util/SocketExceptions.java b/src/java.base/share/classes/sun/net/util/SocketExceptions.java index 24f6d8e9bad..17cb5b3bfbe 100644 --- a/src/java.base/share/classes/sun/net/util/SocketExceptions.java +++ b/src/java.base/share/classes/sun/net/util/SocketExceptions.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,6 +28,8 @@ import java.io.IOException; import java.lang.reflect.Constructor; import java.net.InetSocketAddress; +import java.net.UnixDomainSocketAddress; +import java.net.SocketAddress; import java.security.AccessController; import java.security.PrivilegedAction; @@ -51,11 +53,22 @@ private SocketExceptions() {} * * Only specific IOException subtypes are supported. */ - public static IOException of(IOException e, InetSocketAddress address) { - if (!enhancedExceptionText || address == null) + public static IOException of(IOException e, SocketAddress addr) { + if (!enhancedExceptionText || addr == null) { return e; - int port = address.getPort(); - String host = address.getHostString(); + } + if (addr instanceof UnixDomainSocketAddress) { + return ofUnixDomain(e, (UnixDomainSocketAddress)addr); + } else if (addr instanceof InetSocketAddress) { + return ofInet(e, (InetSocketAddress)addr); + } else { + return e; + } + } + + private static IOException ofInet(IOException e, InetSocketAddress addr) { + int port = addr.getPort(); + String host = addr.getHostString(); StringBuilder sb = new StringBuilder(); sb.append(e.getMessage()); sb.append(": "); @@ -66,6 +79,16 @@ public static IOException of(IOException e, InetSocketAddress address) { return create(e, enhancedMsg); } + private static IOException ofUnixDomain(IOException e, UnixDomainSocketAddress addr) { + String path = addr.getPath().toString(); + StringBuilder sb = new StringBuilder(); + sb.append(e.getMessage()); + sb.append(": "); + sb.append(path); + String enhancedMsg = sb.toString(); + return create(e, enhancedMsg); + } + // return a new instance of the same type with the given detail // msg, or if the type doesn't support detail msgs, return given // instance. diff --git a/src/java.base/share/classes/sun/nio/ch/Net.java b/src/java.base/share/classes/sun/nio/ch/Net.java index 1a796dff453..62bc3c9395b 100644 --- a/src/java.base/share/classes/sun/nio/ch/Net.java +++ b/src/java.base/share/classes/sun/nio/ch/Net.java @@ -226,29 +226,31 @@ static void translateException(Exception x) /** * Returns the local address after performing a SecurityManager#checkConnect. */ - static InetSocketAddress getRevealedLocalAddress(InetSocketAddress addr) { + static InetSocketAddress getRevealedLocalAddress(SocketAddress sa) { + InetSocketAddress isa = (InetSocketAddress) sa; SecurityManager sm = System.getSecurityManager(); - if (addr == null || sm == null) - return addr; - - try{ - sm.checkConnect(addr.getAddress().getHostAddress(), -1); - // Security check passed - } catch (SecurityException e) { - // Return loopback address only if security check fails - addr = getLoopbackAddress(addr.getPort()); + if (isa != null && sm != null) { + try { + sm.checkConnect(isa.getAddress().getHostAddress(), -1); + } catch (SecurityException e) { + // Return loopback address only if security check fails + isa = getLoopbackAddress(isa.getPort()); + } } - return addr; + return isa; } - static String getRevealedLocalAddressAsString(InetSocketAddress addr) { - return System.getSecurityManager() == null ? addr.toString() : - getLoopbackAddress(addr.getPort()).toString(); + static String getRevealedLocalAddressAsString(SocketAddress sa) { + InetSocketAddress isa = (InetSocketAddress) sa; + if (System.getSecurityManager() == null) { + return isa.toString(); + } else { + return getLoopbackAddress(isa.getPort()).toString(); + } } private static InetSocketAddress getLoopbackAddress(int port) { - return new InetSocketAddress(InetAddress.getLoopbackAddress(), - port); + return new InetSocketAddress(InetAddress.getLoopbackAddress(), port); } private static final InetAddress anyLocalInet4Address; @@ -574,6 +576,13 @@ static int connect(ProtocolFamily family, FileDescriptor fd, InetAddress remote, return connect0(preferIPv6, fd, remote, remotePort); } + static int connect(ProtocolFamily family, FileDescriptor fd, SocketAddress remote) + throws IOException + { + InetSocketAddress isa = (InetSocketAddress) remote; + return connect(family, fd, isa.getAddress(), isa.getPort()); + } + private static native int connect0(boolean preferIPv6, FileDescriptor fd, InetAddress remote, diff --git a/src/java.base/share/classes/sun/nio/ch/SelectorProviderImpl.java b/src/java.base/share/classes/sun/nio/ch/SelectorProviderImpl.java index 2fd6a984140..fc327295ed6 100644 --- a/src/java.base/share/classes/sun/nio/ch/SelectorProviderImpl.java +++ b/src/java.base/share/classes/sun/nio/ch/SelectorProviderImpl.java @@ -33,6 +33,10 @@ import java.nio.channels.SocketChannel; import java.nio.channels.spi.AbstractSelector; import java.nio.channels.spi.SelectorProvider; +import java.util.Objects; +import static java.net.StandardProtocolFamily.INET; +import static java.net.StandardProtocolFamily.INET6; +import static java.net.StandardProtocolFamily.UNIX; public abstract class SelectorProviderImpl extends SelectorProvider @@ -75,11 +79,29 @@ public SocketChannel openSocketChannel() throws IOException { @Override public SocketChannel openSocketChannel(ProtocolFamily family) throws IOException { - return new SocketChannelImpl(this, family); + Objects.requireNonNull(family, "'family' is null"); + if (family == INET6 && !Net.isIPv6Available()) { + throw new UnsupportedOperationException("IPv6 not available"); + } else if (family == INET || family == INET6) { + return new SocketChannelImpl(this, family); + } else if (family == UNIX && UnixDomainSockets.isSupported()) { + return new SocketChannelImpl(this, family); + } else { + throw new UnsupportedOperationException("Protocol family not supported"); + } } @Override - public ServerSocketChannel openServerSocketChannel(ProtocolFamily family) { - return new ServerSocketChannelImpl(this, family); + public ServerSocketChannel openServerSocketChannel(ProtocolFamily family) throws IOException { + Objects.requireNonNull(family, "'family' is null"); + if (family == INET6 && !Net.isIPv6Available()) { + throw new UnsupportedOperationException("IPv6 not available"); + } else if (family == INET || family == INET6) { + return new ServerSocketChannelImpl(this, family); + } else if (family == UNIX && UnixDomainSockets.isSupported()) { + return new ServerSocketChannelImpl(this, family); + } else { + throw new UnsupportedOperationException("Protocol family not supported"); + } } } diff --git a/src/java.base/share/classes/sun/nio/ch/ServerSocketAdaptor.java b/src/java.base/share/classes/sun/nio/ch/ServerSocketAdaptor.java index ab0e5a85a3c..6b475027ca7 100644 --- a/src/java.base/share/classes/sun/nio/ch/ServerSocketAdaptor.java +++ b/src/java.base/share/classes/sun/nio/ch/ServerSocketAdaptor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2020, 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 @@ -93,7 +93,7 @@ public void bind(SocketAddress local, int backlog) throws IOException { @Override public InetAddress getInetAddress() { - InetSocketAddress local = ssc.localAddress(); + SocketAddress local = ssc.localAddress(); if (local == null) { return null; } else { @@ -103,7 +103,7 @@ public InetAddress getInetAddress() { @Override public int getLocalPort() { - InetSocketAddress local = ssc.localAddress(); + InetSocketAddress local = (InetSocketAddress) ssc.localAddress(); if (local == null) { return -1; } else { diff --git a/src/java.base/share/classes/sun/nio/ch/ServerSocketChannelImpl.java b/src/java.base/share/classes/sun/nio/ch/ServerSocketChannelImpl.java index 06915cb6cc5..fddfca1bbcb 100644 --- a/src/java.base/share/classes/sun/nio/ch/ServerSocketChannelImpl.java +++ b/src/java.base/share/classes/sun/nio/ch/ServerSocketChannelImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2020, 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,14 +27,15 @@ import java.io.FileDescriptor; import java.io.IOException; +import java.net.BindException; import java.net.InetSocketAddress; import java.net.ProtocolFamily; import java.net.ServerSocket; import java.net.SocketAddress; import java.net.SocketOption; import java.net.SocketTimeoutException; -import java.net.StandardProtocolFamily; import java.net.StandardSocketOptions; +import java.net.UnixDomainSocketAddress; import java.nio.channels.AlreadyBoundException; import java.nio.channels.AsynchronousCloseException; import java.nio.channels.ClosedChannelException; @@ -44,11 +45,15 @@ import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; import java.nio.channels.spi.SelectorProvider; +import java.nio.file.Path; import java.util.Collections; import java.util.HashSet; -import java.util.Objects; import java.util.Set; +import java.util.Objects; import java.util.concurrent.locks.ReentrantLock; +import static java.net.StandardProtocolFamily.INET; +import static java.net.StandardProtocolFamily.INET6; +import static java.net.StandardProtocolFamily.UNIX; import sun.net.NetHooks; import sun.net.ext.ExtendedSocketOptions; @@ -90,7 +95,7 @@ class ServerSocketChannelImpl private long thread; // Binding - private InetSocketAddress localAddress; // null => unbound + private SocketAddress localAddress; // null => unbound // set true when exclusive binding is on and SO_REUSEADDR is emulated private boolean isReuseAddress; @@ -100,47 +105,72 @@ class ServerSocketChannelImpl // -- End of fields protected by stateLock - ServerSocketChannelImpl(SelectorProvider sp) { - this(sp, Net.isIPv6Available() - ? StandardProtocolFamily.INET6 - : StandardProtocolFamily.INET); + ServerSocketChannelImpl(SelectorProvider sp) throws IOException { + this(sp, Net.isIPv6Available() ? INET6 : INET); } - ServerSocketChannelImpl(SelectorProvider sp, ProtocolFamily family) { + ServerSocketChannelImpl(SelectorProvider sp, ProtocolFamily family) + throws IOException + { super(sp); Objects.requireNonNull(family, "'family' is null"); - - if ((family != StandardProtocolFamily.INET) && - (family != StandardProtocolFamily.INET6)) { + if ((family != INET) && (family != INET6) && (family != UNIX)) { throw new UnsupportedOperationException("Protocol family not supported"); } - if (family == StandardProtocolFamily.INET6 && !Net.isIPv6Available()) { + if (family == INET6 && !Net.isIPv6Available()) { throw new UnsupportedOperationException("IPv6 not available"); } this.family = family; - this.fd = Net.serverSocket(family, true); + if (family == UNIX) { + this.fd = UnixDomainSockets.socket(); + } else { + this.fd = Net.serverSocket(family, true); + } this.fdVal = IOUtil.fdVal(fd); } - ServerSocketChannelImpl(SelectorProvider sp, FileDescriptor fd, boolean bound) + ServerSocketChannelImpl(SelectorProvider sp, + ProtocolFamily family, + FileDescriptor fd, + boolean bound) throws IOException { super(sp); - this.family = Net.isIPv6Available() - ? StandardProtocolFamily.INET6 - : StandardProtocolFamily.INET; - this.fd = fd; + if (family == UNIX) { + this.family = UNIX; + } else { + this.family = Net.isIPv6Available() ? INET6 : INET; + } + this.fd = fd; this.fdVal = IOUtil.fdVal(fd); if (bound) { synchronized (stateLock) { - localAddress = Net.localAddress(fd); + if (family == UNIX) { + localAddress = UnixDomainSockets.localAddress(fd); + } else { + localAddress = Net.localAddress(fd); + } } } } + /** + * Returns true if this channel is to a INET or INET6 socket. + */ + private boolean isNetSocket() { + return (family == INET) || (family == INET6); + } + + /** + * Returns true if this channel is to a UNIX socket. + */ + boolean isUnixSocket() { + return (family == UNIX); + } + // @throws ClosedChannelException if channel is closed private void ensureOpen() throws ClosedChannelException { if (!isOpen()) @@ -150,8 +180,13 @@ private void ensureOpen() throws ClosedChannelException { @Override public ServerSocket socket() { synchronized (stateLock) { - if (socket == null) - socket = ServerSocketAdaptor.create(this); + if (socket == null) { + if (isNetSocket()) { + socket = ServerSocketAdaptor.create(this); + } else { + throw new UnsupportedOperationException("Not supported"); + } + } return socket; } } @@ -160,9 +195,11 @@ public ServerSocket socket() { public SocketAddress getLocalAddress() throws IOException { synchronized (stateLock) { ensureOpen(); - return (localAddress == null) - ? null - : Net.getRevealedLocalAddress(localAddress); + if (isUnixSocket()) { + return UnixDomainSockets.getRevealedLocalAddress(localAddress); + } else { + return Net.getRevealedLocalAddress(localAddress); + } } } @@ -178,10 +215,11 @@ public ServerSocketChannel setOption(SocketOption name, T value) synchronized (stateLock) { ensureOpen(); - - if (name == StandardSocketOptions.SO_REUSEADDR && Net.useExclusiveBind()) { + if (isNetSocket() + && name == StandardSocketOptions.SO_REUSEADDR + && Net.useExclusiveBind()) { // SO_REUSEADDR emulated when using exclusive bind - isReuseAddress = (Boolean)value; + isReuseAddress = (Boolean) value; } else { // no options that require special handling Net.setSocketOption(fd, Net.UNSPEC, name, value); @@ -201,19 +239,23 @@ public T getOption(SocketOption name) synchronized (stateLock) { ensureOpen(); - if (name == StandardSocketOptions.SO_REUSEADDR && Net.useExclusiveBind()) { + if (isNetSocket() + && name == StandardSocketOptions.SO_REUSEADDR + && Net.useExclusiveBind()) { // SO_REUSEADDR emulated when using exclusive bind - return (T)Boolean.valueOf(isReuseAddress); + return (T) Boolean.valueOf(isReuseAddress); + } else { + // no options that require special handling + return (T) Net.getSocketOption(fd, Net.UNSPEC, name); } - // no options that require special handling - return (T) Net.getSocketOption(fd, Net.UNSPEC, name); } } private static class DefaultOptionsHolder { - static final Set> defaultOptions = defaultOptions(); + static final Set> defaultInetOptions = defaultInetOptions(); + static final Set> defaultUnixDomainOptions = defaultUnixDomainOptions(); - private static Set> defaultOptions() { + private static Set> defaultInetOptions() { HashSet> set = new HashSet<>(); set.add(StandardSocketOptions.SO_RCVBUF); set.add(StandardSocketOptions.SO_REUSEADDR); @@ -223,11 +265,21 @@ private static Set> defaultOptions() { set.addAll(ExtendedSocketOptions.serverSocketOptions()); return Collections.unmodifiableSet(set); } + + private static Set> defaultUnixDomainOptions() { + HashSet> set = new HashSet<>(); + set.add(StandardSocketOptions.SO_RCVBUF); + return Collections.unmodifiableSet(set); + } } @Override public final Set> supportedOptions() { - return DefaultOptionsHolder.defaultOptions; + if (isUnixSocket()) { + return DefaultOptionsHolder.defaultUnixDomainOptions; + } else { + return DefaultOptionsHolder.defaultInetOptions; + } } @Override @@ -236,23 +288,56 @@ public ServerSocketChannel bind(SocketAddress local, int backlog) throws IOExcep ensureOpen(); if (localAddress != null) throw new AlreadyBoundException(); - InetSocketAddress isa; - if (local == null) { - isa = new InetSocketAddress(Net.anyLocalAddress(family), 0); + if (isUnixSocket()) { + localAddress = unixBind(local, backlog); } else { - isa = Net.checkAddress(local, family); + localAddress = netBind(local, backlog); } - SecurityManager sm = System.getSecurityManager(); - if (sm != null) - sm.checkListen(isa.getPort()); - NetHooks.beforeTcpBind(fd, isa.getAddress(), isa.getPort()); - Net.bind(family, fd, isa.getAddress(), isa.getPort()); - Net.listen(fd, backlog < 1 ? 50 : backlog); - localAddress = Net.localAddress(fd); } return this; } + private SocketAddress unixBind(SocketAddress local, int backlog) throws IOException { + UnixDomainSockets.checkPermission(); + if (local == null) { + // Attempt up to 10 times to find an unused name in temp directory. + // If local address supplied then bind called only once + boolean bound = false; + int attempts = 0; + while (attempts < 10 && !bound) { + try { + Path path = UnixDomainSockets.generateTempName().getPath(); + UnixDomainSockets.bind(fd, path); + bound = true; + } catch (BindException e) { } + attempts++; + } + if (!bound) + throw new BindException("Could not bind to temporary name"); + } else { + Path path = UnixDomainSockets.checkAddress(local).getPath(); + UnixDomainSockets.bind(fd, path); + } + Net.listen(fd, backlog < 1 ? 50 : backlog); + return UnixDomainSockets.localAddress(fd); + } + + private SocketAddress netBind(SocketAddress local, int backlog) throws IOException { + InetSocketAddress isa; + if (local == null) { + isa = new InetSocketAddress(Net.anyLocalAddress(family), 0); + } else { + isa = Net.checkAddress(local, family); + } + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkListen(isa.getPort()); + NetHooks.beforeTcpBind(fd, isa.getAddress(), isa.getPort()); + Net.bind(family, fd, isa.getAddress(), isa.getPort()); + Net.listen(fd, backlog < 1 ? 50 : backlog); + return Net.localAddress(fd); + } + /** * Marks the beginning of an I/O operation that might block. * @@ -295,18 +380,18 @@ private void end(boolean blocking, boolean completed) public SocketChannel accept() throws IOException { int n = 0; FileDescriptor newfd = new FileDescriptor(); - InetSocketAddress[] isaa = new InetSocketAddress[1]; + SocketAddress[] saa = new SocketAddress[1]; acceptLock.lock(); try { boolean blocking = isBlocking(); try { begin(blocking); - n = Net.accept(this.fd, newfd, isaa); + n = implAccept(this.fd, newfd, saa); if (blocking) { while (IOStatus.okayToRetry(n) && isOpen()) { park(Net.POLLIN); - n = Net.accept(this.fd, newfd, isaa); + n = implAccept(this.fd, newfd, saa); } } } finally { @@ -318,12 +403,31 @@ public SocketChannel accept() throws IOException { } if (n > 0) { - return finishAccept(newfd, isaa[0]); + return finishAccept(newfd, saa[0]); } else { return null; } } + private int implAccept(FileDescriptor fd, FileDescriptor newfd, SocketAddress[] saa) + throws IOException + { + if (isUnixSocket()) { + UnixDomainSockets.checkPermission(); + String[] pa = new String[1]; + int n = UnixDomainSockets.accept(fd, newfd, pa); + if (n > 0) + saa[0] = UnixDomainSocketAddress.of(pa[0]); + return n; + } else { + InetSocketAddress[] issa = new InetSocketAddress[1]; + int n = Net.accept(fd, newfd, issa); + if (n > 0) + saa[0] = issa[0]; + return n; + } + } + /** * Accepts a new connection with a given timeout. This method requires the * channel to be configured in blocking mode. @@ -337,7 +441,7 @@ public SocketChannel accept() throws IOException { SocketChannel blockingAccept(long nanos) throws IOException { int n = 0; FileDescriptor newfd = new FileDescriptor(); - InetSocketAddress[] isaa = new InetSocketAddress[1]; + SocketAddress[] saa = new SocketAddress[1]; acceptLock.lock(); try { @@ -351,14 +455,14 @@ SocketChannel blockingAccept(long nanos) throws IOException { lockedConfigureBlocking(false); try { long startNanos = System.nanoTime(); - n = Net.accept(fd, newfd, isaa); + n = implAccept(fd, newfd, saa); while (n == IOStatus.UNAVAILABLE && isOpen()) { long remainingNanos = nanos - (System.nanoTime() - startNanos); if (remainingNanos <= 0) { throw new SocketTimeoutException("Accept timed out"); } park(Net.POLLIN, remainingNanos); - n = Net.accept(fd, newfd, isaa); + n = implAccept(fd, newfd, saa); } } finally { // restore socket to blocking mode (if channel is open) @@ -372,10 +476,10 @@ SocketChannel blockingAccept(long nanos) throws IOException { } assert n > 0; - return finishAccept(newfd, isaa[0]); + return finishAccept(newfd, saa[0]); } - private SocketChannel finishAccept(FileDescriptor newfd, InetSocketAddress isa) + private SocketChannel finishAccept(FileDescriptor newfd, SocketAddress sa) throws IOException { try { @@ -383,11 +487,14 @@ private SocketChannel finishAccept(FileDescriptor newfd, InetSocketAddress isa) IOUtil.configureBlocking(newfd, true); // check permitted to accept connections from the remote address - SecurityManager sm = System.getSecurityManager(); - if (sm != null) { - sm.checkAccept(isa.getAddress().getHostAddress(), isa.getPort()); + if (isNetSocket()) { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + InetSocketAddress isa = (InetSocketAddress) sa; + sm.checkAccept(isa.getAddress().getHostAddress(), isa.getPort()); + } } - return new SocketChannelImpl(provider(), family, newfd, isa); + return new SocketChannelImpl(provider(), family, newfd, sa); } catch (Exception e) { nd.close(newfd); throw e; @@ -536,7 +643,7 @@ boolean isBound() { /** * Returns the local address, or null if not bound */ - InetSocketAddress localAddress() { + SocketAddress localAddress() { synchronized (stateLock) { return localAddress; } @@ -605,9 +712,11 @@ public String toString() { sb.append("closed"); } else { synchronized (stateLock) { - InetSocketAddress addr = localAddress; + SocketAddress addr = localAddress; if (addr == null) { sb.append("unbound"); + } else if (isUnixSocket()) { + sb.append(UnixDomainSockets.getRevealedLocalAddressAsString(addr)); } else { sb.append(Net.getRevealedLocalAddressAsString(addr)); } diff --git a/src/java.base/share/classes/sun/nio/ch/SocketAdaptor.java b/src/java.base/share/classes/sun/nio/ch/SocketAdaptor.java index 6e53efc6744..f5ce85fc5c6 100644 --- a/src/java.base/share/classes/sun/nio/ch/SocketAdaptor.java +++ b/src/java.base/share/classes/sun/nio/ch/SocketAdaptor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2020, 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,6 +72,14 @@ static Socket create(SocketChannelImpl sc) { } } + private InetSocketAddress localAddress() { + return (InetSocketAddress) sc.localAddress(); + } + + private InetSocketAddress remoteAddress() { + return (InetSocketAddress) sc.remoteAddress(); + } + @Override public void connect(SocketAddress remote) throws IOException { connect(remote, 0); @@ -106,7 +114,7 @@ public void bind(SocketAddress local) throws IOException { @Override public InetAddress getInetAddress() { - InetSocketAddress remote = sc.remoteAddress(); + InetSocketAddress remote = remoteAddress(); if (remote == null) { return null; } else { @@ -117,7 +125,7 @@ public InetAddress getInetAddress() { @Override public InetAddress getLocalAddress() { if (sc.isOpen()) { - InetSocketAddress local = sc.localAddress(); + InetSocketAddress local = localAddress(); if (local != null) { return Net.getRevealedLocalAddress(local).getAddress(); } @@ -127,7 +135,7 @@ public InetAddress getLocalAddress() { @Override public int getPort() { - InetSocketAddress remote = sc.remoteAddress(); + InetSocketAddress remote = remoteAddress(); if (remote == null) { return 0; } else { @@ -137,7 +145,7 @@ public int getPort() { @Override public int getLocalPort() { - InetSocketAddress local = sc.localAddress(); + InetSocketAddress local = localAddress(); if (local == null) { return -1; } else { @@ -152,12 +160,7 @@ public SocketAddress getRemoteSocketAddress() { @Override public SocketAddress getLocalSocketAddress() { - InetSocketAddress local = sc.localAddress(); - if (local != null) { - return Net.getRevealedLocalAddress(local); - } else { - return null; - } + return Net.getRevealedLocalAddress(sc.localAddress()); } @Override diff --git a/src/java.base/share/classes/sun/nio/ch/SocketChannelImpl.java b/src/java.base/share/classes/sun/nio/ch/SocketChannelImpl.java index 43a50f5c0d6..bb5669c0377 100644 --- a/src/java.base/share/classes/sun/nio/ch/SocketChannelImpl.java +++ b/src/java.base/share/classes/sun/nio/ch/SocketChannelImpl.java @@ -36,7 +36,6 @@ import java.net.SocketException; import java.net.SocketOption; import java.net.SocketTimeoutException; -import java.net.StandardProtocolFamily; import java.net.StandardSocketOptions; import java.nio.ByteBuffer; import java.nio.channels.AlreadyBoundException; @@ -50,11 +49,15 @@ import java.nio.channels.SelectionKey; import java.nio.channels.SocketChannel; import java.nio.channels.spi.SelectorProvider; +import java.nio.file.Path; import java.util.Collections; import java.util.HashSet; -import java.util.Objects; import java.util.Set; +import java.util.Objects; import java.util.concurrent.locks.ReentrantLock; +import static java.net.StandardProtocolFamily.INET; +import static java.net.StandardProtocolFamily.INET6; +import static java.net.StandardProtocolFamily.UNIX; import sun.net.ConnectionResetException; import sun.net.NetHooks; @@ -114,52 +117,35 @@ class SocketChannelImpl private long writerThread; // Binding - private InetSocketAddress localAddress; - private InetSocketAddress remoteAddress; + private SocketAddress localAddress; + private SocketAddress remoteAddress; // Socket adaptor, created on demand private Socket socket; // -- End of fields protected by stateLock - // Constructor for normal connecting sockets - // SocketChannelImpl(SelectorProvider sp) throws IOException { - this(sp, Net.isIPv6Available() - ? StandardProtocolFamily.INET6 - : StandardProtocolFamily.INET); + this(sp, Net.isIPv6Available() ? INET6 : INET); } SocketChannelImpl(SelectorProvider sp, ProtocolFamily family) throws IOException { super(sp); Objects.requireNonNull(family, "'family' is null"); - if ((family != StandardProtocolFamily.INET) && - (family != StandardProtocolFamily.INET6)) { + if ((family != INET) && (family != INET6) && (family != UNIX)) { throw new UnsupportedOperationException("Protocol family not supported"); } - if (family == StandardProtocolFamily.INET6 && !Net.isIPv6Available()) { + if (family == INET6 && !Net.isIPv6Available()) { throw new UnsupportedOperationException("IPv6 not available"); } - this.family = family; - this.fd = Net.socket(family, true); - this.fdVal = IOUtil.fdVal(fd); - } - SocketChannelImpl(SelectorProvider sp, FileDescriptor fd, boolean bound) - throws IOException - { - super(sp); - this.family = Net.isIPv6Available() - ? StandardProtocolFamily.INET6 - : StandardProtocolFamily.INET; - this.fd = fd; - this.fdVal = IOUtil.fdVal(fd); - - if (bound) { - synchronized (stateLock) { - this.localAddress = Net.localAddress(fd); - } + this.family = family; + if (family == UNIX) { + this.fd = UnixDomainSockets.socket(); + } else { + this.fd = Net.socket(family, true); } + this.fdVal = IOUtil.fdVal(fd); } // Constructor for sockets obtained from server sockets @@ -167,7 +153,7 @@ class SocketChannelImpl SocketChannelImpl(SelectorProvider sp, ProtocolFamily family, FileDescriptor fd, - InetSocketAddress isa) + SocketAddress remoteAddress) throws IOException { super(sp); @@ -175,12 +161,30 @@ class SocketChannelImpl this.fd = fd; this.fdVal = IOUtil.fdVal(fd); synchronized (stateLock) { - this.localAddress = Net.localAddress(fd); - this.remoteAddress = isa; + if (family == UNIX) { + this.localAddress = UnixDomainSockets.localAddress(fd); + } else { + this.localAddress = Net.localAddress(fd); + } + this.remoteAddress = remoteAddress; this.state = ST_CONNECTED; } } + /** + * Returns true if this channel is to a INET or INET6 socket. + */ + boolean isNetSocket() { + return (family == INET) || (family == INET6); + } + + /** + * Returns true if this channel is to a UNIX socket. + */ + boolean isUnixSocket() { + return (family == UNIX); + } + /** * Checks that the channel is open. * @@ -215,8 +219,13 @@ private void ensureOpenAndConnected() throws ClosedChannelException { @Override public Socket socket() { synchronized (stateLock) { - if (socket == null) - socket = SocketAdaptor.create(this); + if (socket == null) { + if (isNetSocket()) { + socket = SocketAdaptor.create(this); + } else { + throw new UnsupportedOperationException("Not supported"); + } + } return socket; } } @@ -225,7 +234,11 @@ public Socket socket() { public SocketAddress getLocalAddress() throws IOException { synchronized (stateLock) { ensureOpen(); - return Net.getRevealedLocalAddress(localAddress); + if (isUnixSocket()) { + return UnixDomainSockets.getRevealedLocalAddress(localAddress); + } else { + return Net.getRevealedLocalAddress(localAddress); + } } } @@ -250,15 +263,17 @@ public SocketChannel setOption(SocketOption name, T value) synchronized (stateLock) { ensureOpen(); - if (name == StandardSocketOptions.IP_TOS) { - Net.setSocketOption(fd, family, name, value); - return this; - } - - if (name == StandardSocketOptions.SO_REUSEADDR && Net.useExclusiveBind()) { - // SO_REUSEADDR emulated when using exclusive bind - isReuseAddress = (Boolean)value; - return this; + if (isNetSocket()) { + if (name == StandardSocketOptions.IP_TOS) { + // special handling for IP_TOS + Net.setSocketOption(fd, family, name, value); + return this; + } + if (name == StandardSocketOptions.SO_REUSEADDR && Net.useExclusiveBind()) { + // SO_REUSEADDR emulated when using exclusive bind + isReuseAddress = (Boolean) value; + return this; + } } // no options that require special handling @@ -279,14 +294,15 @@ public T getOption(SocketOption name) synchronized (stateLock) { ensureOpen(); - if (name == StandardSocketOptions.SO_REUSEADDR && Net.useExclusiveBind()) { - // SO_REUSEADDR emulated when using exclusive bind - return (T)Boolean.valueOf(isReuseAddress); - } - - // special handling for IP_TOS - if (name == StandardSocketOptions.IP_TOS) { - return (T) Net.getSocketOption(fd, family, name); + if (isNetSocket()) { + if (name == StandardSocketOptions.IP_TOS) { + // special handling for IP_TOS + return (T) Net.getSocketOption(fd, family, name); + } + if (name == StandardSocketOptions.SO_REUSEADDR && Net.useExclusiveBind()) { + // SO_REUSEADDR emulated when using exclusive bind + return (T) Boolean.valueOf(isReuseAddress); + } } // no options that require special handling @@ -295,9 +311,10 @@ public T getOption(SocketOption name) } private static class DefaultOptionsHolder { - static final Set> defaultOptions = defaultOptions(); + static final Set> defaultInetOptions = defaultInetOptions(); + static final Set> defaultUnixOptions = defaultUnixOptions(); - private static Set> defaultOptions() { + private static Set> defaultInetOptions() { HashSet> set = new HashSet<>(); set.add(StandardSocketOptions.SO_SNDBUF); set.add(StandardSocketOptions.SO_RCVBUF); @@ -314,11 +331,24 @@ private static Set> defaultOptions() { set.addAll(ExtendedSocketOptions.clientSocketOptions()); return Collections.unmodifiableSet(set); } + + private static Set> defaultUnixOptions() { + HashSet> set = new HashSet<>(); + set.add(StandardSocketOptions.SO_SNDBUF); + set.add(StandardSocketOptions.SO_RCVBUF); + set.add(StandardSocketOptions.SO_LINGER); + set.addAll(ExtendedSocketOptions.unixDomainSocketOptions()); + return Collections.unmodifiableSet(set); + } } @Override public final Set> supportedOptions() { - return DefaultOptionsHolder.defaultOptions; + if (isUnixSocket()) { + return DefaultOptionsHolder.defaultUnixOptions; + } else { + return DefaultOptionsHolder.defaultInetOptions; + } } /** @@ -625,7 +655,7 @@ private boolean tryLockedConfigureBlocking(boolean block) throws IOException { /** * Returns the local address, or null if not bound */ - InetSocketAddress localAddress() { + SocketAddress localAddress() { synchronized (stateLock) { return localAddress; } @@ -634,7 +664,7 @@ InetSocketAddress localAddress() { /** * Returns the remote address, or null if not connected */ - InetSocketAddress remoteAddress() { + SocketAddress remoteAddress() { synchronized (stateLock) { return remoteAddress; } @@ -652,19 +682,11 @@ public SocketChannel bind(SocketAddress local) throws IOException { throw new ConnectionPendingException(); if (localAddress != null) throw new AlreadyBoundException(); - InetSocketAddress isa; - if (local == null) { - isa = new InetSocketAddress(Net.anyLocalAddress(family), 0); + if (isUnixSocket()) { + localAddress = unixBind(local); } else { - isa = Net.checkAddress(local, family); - } - SecurityManager sm = System.getSecurityManager(); - if (sm != null) { - sm.checkListen(isa.getPort()); + localAddress = netBind(local); } - NetHooks.beforeTcpBind(fd, isa.getAddress(), isa.getPort()); - Net.bind(family, fd, isa.getAddress(), isa.getPort()); - localAddress = Net.localAddress(fd); } } finally { writeLock.unlock(); @@ -675,6 +697,38 @@ public SocketChannel bind(SocketAddress local) throws IOException { return this; } + private SocketAddress unixBind(SocketAddress local) throws IOException { + UnixDomainSockets.checkPermission(); + if (local == null) { + return UnixDomainSockets.UNNAMED; + } else { + Path path = UnixDomainSockets.checkAddress(local).getPath(); + if (path.toString().isEmpty()) { + return UnixDomainSockets.UNNAMED; + } else { + // bind to non-empty path + UnixDomainSockets.bind(fd, path); + return UnixDomainSockets.localAddress(fd); + } + } + } + + private SocketAddress netBind(SocketAddress local) throws IOException { + InetSocketAddress isa; + if (local == null) { + isa = new InetSocketAddress(Net.anyLocalAddress(family), 0); + } else { + isa = Net.checkAddress(local, family); + } + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkListen(isa.getPort()); + } + NetHooks.beforeTcpBind(fd, isa.getAddress(), isa.getPort()); + Net.bind(family, fd, isa.getAddress(), isa.getPort()); + return Net.localAddress(fd); + } + @Override public boolean isConnected() { return (state == ST_CONNECTED); @@ -694,7 +748,7 @@ public boolean isConnectionPending() { * @throws ConnectionPendingException is a connection is pending * @throws IOException if the pre-connect hook fails */ - private void beginConnect(boolean blocking, InetSocketAddress isa) + private void beginConnect(boolean blocking, SocketAddress sa) throws IOException { if (blocking) { @@ -711,9 +765,11 @@ private void beginConnect(boolean blocking, InetSocketAddress isa) assert state == ST_UNCONNECTED; this.state = ST_CONNECTIONPENDING; - if (localAddress == null) + if (isNetSocket() && (localAddress == null)) { + InetSocketAddress isa = (InetSocketAddress) sa; NetHooks.beforeTcpConnect(fd, isa.getAddress(), isa.getPort()); - remoteAddress = isa; + } + remoteAddress = sa; if (blocking) { // record thread so it can be signalled if needed @@ -737,7 +793,11 @@ private void endConnect(boolean blocking, boolean completed) if (completed) { synchronized (stateLock) { if (state == ST_CONNECTIONPENDING) { - localAddress = Net.localAddress(fd); + if (isUnixSocket()) { + localAddress = UnixDomainSockets.localAddress(fd); + } else { + localAddress = Net.localAddress(fd); + } state = ST_CONNECTED; } } @@ -747,29 +807,34 @@ private void endConnect(boolean blocking, boolean completed) /** * Checks the remote address to which this channel is to be connected. */ - private InetSocketAddress checkRemote(SocketAddress sa) { - InetSocketAddress isa = Net.checkAddress(sa, family); - SecurityManager sm = System.getSecurityManager(); - if (sm != null) { - sm.checkConnect(isa.getAddress().getHostAddress(), isa.getPort()); - } - InetAddress address = isa.getAddress(); - if (address.isAnyLocalAddress()) { - int port = isa.getPort(); - if (address instanceof Inet4Address) { - return new InetSocketAddress(Net.inet4LoopbackAddress(), port); + private SocketAddress checkRemote(SocketAddress sa) { + if (isUnixSocket()) { + UnixDomainSockets.checkPermission(); + return UnixDomainSockets.checkAddress(sa); + } else { + InetSocketAddress isa = Net.checkAddress(sa, family); + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkConnect(isa.getAddress().getHostAddress(), isa.getPort()); + } + InetAddress address = isa.getAddress(); + if (address.isAnyLocalAddress()) { + int port = isa.getPort(); + if (address instanceof Inet4Address) { + return new InetSocketAddress(Net.inet4LoopbackAddress(), port); + } else { + assert family == INET6; + return new InetSocketAddress(Net.inet6LoopbackAddress(), port); + } } else { - assert family == StandardProtocolFamily.INET6; - return new InetSocketAddress(Net.inet6LoopbackAddress(), port); + return isa; } - } else { - return isa; } } @Override public boolean connect(SocketAddress remote) throws IOException { - InetSocketAddress isa = checkRemote(remote); + SocketAddress sa = checkRemote(remote); try { readLock.lock(); try { @@ -778,11 +843,13 @@ public boolean connect(SocketAddress remote) throws IOException { boolean blocking = isBlocking(); boolean connected = false; try { - beginConnect(blocking, isa); - int n = Net.connect(family, - fd, - isa.getAddress(), - isa.getPort()); + beginConnect(blocking, sa); + int n; + if (isUnixSocket()) { + n = UnixDomainSockets.connect(fd, sa); + } else { + n = Net.connect(family, fd, sa); + } if (n > 0) { connected = true; } else if (blocking) { @@ -807,7 +874,7 @@ public boolean connect(SocketAddress remote) throws IOException { } catch (IOException ioe) { // connect failed, close the channel close(); - throw SocketExceptions.of(ioe, isa); + throw SocketExceptions.of(ioe, sa); } } @@ -848,7 +915,11 @@ private void endFinishConnect(boolean blocking, boolean completed) if (completed) { synchronized (stateLock) { if (state == ST_CONNECTIONPENDING) { - localAddress = Net.localAddress(fd); + if (isUnixSocket()) { + localAddress = UnixDomainSockets.localAddress(fd); + } else { + localAddress = Net.localAddress(fd); + } state = ST_CONNECTED; } } @@ -1087,7 +1158,7 @@ private boolean finishTimedConnect(long nanos) throws IOException { * @throws SocketTimeoutException if the read timeout elapses */ void blockingConnect(SocketAddress remote, long nanos) throws IOException { - InetSocketAddress isa = checkRemote(remote); + SocketAddress sa = checkRemote(remote); try { readLock.lock(); try { @@ -1097,11 +1168,16 @@ void blockingConnect(SocketAddress remote, long nanos) throws IOException { throw new IllegalBlockingModeException(); boolean connected = false; try { - beginConnect(true, isa); + beginConnect(true, sa); // change socket to non-blocking lockedConfigureBlocking(false); try { - int n = Net.connect(fd, isa.getAddress(), isa.getPort()); + int n; + if (isUnixSocket()) { + n = UnixDomainSockets.connect(fd, sa); + } else { + n = Net.connect(family, fd, sa); + } connected = (n > 0) ? true : finishTimedConnect(nanos); } finally { // restore socket to blocking mode (if channel is open) @@ -1119,7 +1195,7 @@ void blockingConnect(SocketAddress remote, long nanos) throws IOException { } catch (IOException ioe) { // connect failed, close the channel close(); - throw SocketExceptions.of(ioe, isa); + throw SocketExceptions.of(ioe, sa); } } @@ -1390,10 +1466,14 @@ public String toString() { sb.append(" oshut"); break; } - InetSocketAddress addr = localAddress(); + SocketAddress addr = localAddress(); if (addr != null) { sb.append(" local="); - sb.append(Net.getRevealedLocalAddressAsString(addr)); + if (isUnixSocket()) { + sb.append(UnixDomainSockets.getRevealedLocalAddressAsString(addr)); + } else { + sb.append(Net.getRevealedLocalAddressAsString(addr)); + } } if (remoteAddress() != null) { sb.append(" remote="); diff --git a/src/java.base/share/classes/sun/nio/ch/UnixDomainSockets.java b/src/java.base/share/classes/sun/nio/ch/UnixDomainSockets.java new file mode 100644 index 00000000000..634f5694605 --- /dev/null +++ b/src/java.base/share/classes/sun/nio/ch/UnixDomainSockets.java @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.nio.ch; + +import java.io.FileDescriptor; +import java.io.IOException; +import java.net.BindException; +import java.net.NetPermission; +import java.net.SocketAddress; +import java.net.UnixDomainSocketAddress; +import java.nio.channels.UnsupportedAddressTypeException; +import java.nio.file.FileSystems; +import java.nio.file.InvalidPathException; +import java.nio.file.Path; +import java.nio.file.spi.FileSystemProvider; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.util.Random; +import sun.nio.fs.AbstractFileSystemProvider; + +class UnixDomainSockets { + private UnixDomainSockets() { } + + static final UnixDomainSocketAddress UNNAMED = UnixDomainSocketAddress.of(""); + + private static final boolean supported; + + private static final String tempDir = UnixDomainSocketsUtil.getTempDir(); + + private static final NetPermission accessUnixDomainSocket = + new NetPermission("accessUnixDomainSocket"); + + static boolean isSupported() { + return supported; + } + + static void checkPermission() { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkPermission(accessUnixDomainSocket); + } + + static UnixDomainSocketAddress getRevealedLocalAddress(SocketAddress sa) { + UnixDomainSocketAddress addr = (UnixDomainSocketAddress) sa; + try { + checkPermission(); + // Security check passed + } catch (SecurityException e) { + // Return unnamed address only if security check fails + addr = UNNAMED; + } + return addr; + } + + static UnixDomainSocketAddress localAddress(FileDescriptor fd) throws IOException { + String path = new String(localAddress0(fd), UnixDomainSocketsUtil.getCharset()); + return UnixDomainSocketAddress.of(path); + } + + private static native byte[] localAddress0(FileDescriptor fd) throws IOException; + + static String getRevealedLocalAddressAsString(SocketAddress sa) { + return (System.getSecurityManager() != null) ? sa.toString() : ""; + } + + static UnixDomainSocketAddress checkAddress(SocketAddress sa) { + if (sa == null) + throw new NullPointerException(); + if (!(sa instanceof UnixDomainSocketAddress)) + throw new UnsupportedAddressTypeException(); + return (UnixDomainSocketAddress) sa; + } + + static byte[] getPathBytes(Path path) { + FileSystemProvider provider = FileSystems.getDefault().provider(); + return ((AbstractFileSystemProvider) provider).getSunPathForSocketFile(path); + } + + static FileDescriptor socket() throws IOException { + return IOUtil.newFD(socket0()); + } + + static void bind(FileDescriptor fd, Path addr) throws IOException { + byte[] path = getPathBytes(addr); + bind0(fd, path); + } + + private static Random getRandom() { + try { + return SecureRandom.getInstance("NativePRNGNonBlocking"); + } catch (NoSuchAlgorithmException e) { + return new SecureRandom(); // This should not fail + } + } + + private static final Random random = getRandom(); + + /** + * Return a possible temporary name to bind to, which is different for each call + * Name is of the form /socket_ + */ + static UnixDomainSocketAddress generateTempName() throws IOException { + String dir = UnixDomainSockets.tempDir; + if (dir == null) + throw new BindException("Could not locate temporary directory for sockets"); + int rnd = random.nextInt(Integer.MAX_VALUE); + try { + Path path = Path.of(dir, "socket_" + rnd); + return UnixDomainSocketAddress.of(path); + } catch (InvalidPathException e) { + throw new BindException("Invalid temporary directory"); + } + } + + static int connect(FileDescriptor fd, SocketAddress sa) throws IOException { + return UnixDomainSockets.connect(fd, ((UnixDomainSocketAddress) sa).getPath()); + } + + static int connect(FileDescriptor fd, Path path) throws IOException { + return connect0(fd, getPathBytes(path)); + } + + static int accept(FileDescriptor fd, FileDescriptor newfd, String[] paths) + throws IOException + { + Object[] array = new Object[1]; + int n = accept0(fd, newfd, array); + if (n > 0) { + byte[] bytes = (byte[]) array[0]; + paths[0] = new String(bytes, UnixDomainSocketsUtil.getCharset()); + } + return n; + } + + private static native boolean socketSupported(); + + private static native int socket0() throws IOException; + + private static native void bind0(FileDescriptor fd, byte[] path) + throws IOException; + + private static native int connect0(FileDescriptor fd, byte[] path) + throws IOException; + + private static native int accept0(FileDescriptor fd, FileDescriptor newfd, Object[] array) + throws IOException; + + static { + // Load all required native libs + IOUtil.load(); + supported = socketSupported(); + } +} diff --git a/src/java.base/share/classes/sun/nio/fs/AbstractFileSystemProvider.java b/src/java.base/share/classes/sun/nio/fs/AbstractFileSystemProvider.java index 679f5857132..b100d3a64a4 100644 --- a/src/java.base/share/classes/sun/nio/fs/AbstractFileSystemProvider.java +++ b/src/java.base/share/classes/sun/nio/fs/AbstractFileSystemProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2020, 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 @@ -154,4 +154,10 @@ public boolean exists(Path file) { return false; } } + + /** + * Returns a path name as bytes for a Unix domain socket. + * Different encodings may be used for these names on some platforms. + */ + public abstract byte[] getSunPathForSocketFile(Path file); } diff --git a/src/java.base/share/classes/sun/reflect/annotation/TypeAnnotation.java b/src/java.base/share/classes/sun/reflect/annotation/TypeAnnotation.java index 6fc8ad93384..bcd0761dfa6 100644 --- a/src/java.base/share/classes/sun/reflect/annotation/TypeAnnotation.java +++ b/src/java.base/share/classes/sun/reflect/annotation/TypeAnnotation.java @@ -92,16 +92,8 @@ public static enum TypeAnnotationTarget { METHOD_FORMAL_PARAMETER, THROWS, /** - * {@preview Associated with records, a preview feature of the Java language. - * - * This enum constant is associated with records, a preview - * feature of the Java language. Preview features - * may be removed in a future release, or upgraded to permanent - * features of the Java language.} - * @since 14 + * @since 16 */ - @jdk.internal.PreviewFeature(feature=jdk.internal.PreviewFeature.Feature.RECORDS, - essentialAPI=false) RECORD_COMPONENT; } diff --git a/src/java.base/share/classes/sun/security/pkcs/PKCS7.java b/src/java.base/share/classes/sun/security/pkcs/PKCS7.java index bac69e07842..0dca814eb76 100644 --- a/src/java.base/share/classes/sun/security/pkcs/PKCS7.java +++ b/src/java.base/share/classes/sun/security/pkcs/PKCS7.java @@ -28,9 +28,6 @@ import java.io.*; import java.math.BigInteger; import java.net.URI; -import java.security.interfaces.EdECPrivateKey; -import java.security.spec.InvalidParameterSpecException; -import java.security.spec.PSSParameterSpec; import java.util.*; import java.security.cert.X509Certificate; import java.security.cert.CertificateException; diff --git a/src/java.base/share/classes/sun/security/pkcs/SignerInfo.java b/src/java.base/share/classes/sun/security/pkcs/SignerInfo.java index 23fedb789dd..d84e7182216 100644 --- a/src/java.base/share/classes/sun/security/pkcs/SignerInfo.java +++ b/src/java.base/share/classes/sun/security/pkcs/SignerInfo.java @@ -260,8 +260,6 @@ public void derEncode(OutputStream out) throws IOException { out.write(tmp.toByteArray()); } - - /* * Returns the (user) certificate pertaining to this SignerInfo. */ @@ -503,24 +501,27 @@ SignerInfo verify(PKCS7 block, byte[] data) /** * Derives the signature algorithm name from the digest algorithm - * name and the encryption algorithm name inside a PKCS7 SignerInfo. + * and the encryption algorithm inside a PKCS7 SignerInfo. + * + * The digest algorithm is in the form "DIG", and the encryption + * algorithm can be in any of the 3 forms: * - * For old style PKCS7 files where we use RSA, DSA, EC as encAlgId - * a DIGESTwithENC algorithm is returned. For new style RSASSA-PSS - * and EdDSA encryption, this method ensures digAlgId is compatible - * with the algorithm. + * 1. Old style key algorithm like RSA, DSA, EC, this method returns + * DIGwithKEY. + * 2. New style signature algorithm in the form of HASHwithKEY, this + * method returns DIGwithKEY. Please note this is not HASHwithKEY. + * 3. Modern signature algorithm like RSASSA-PSS and EdDSA, this method + * returns the signature algorithm itself but ensures digAlgId is + * compatible with the algorithm as described in RFC 4056 and 8419. * * @param digAlgId the digest algorithm - * @param encAlgId the encryption or signature algorithm + * @param encAlgId the encryption algorithm * @param directSign whether the signature is calculated on the content * directly. This makes difference for Ed448. */ public static String makeSigAlg(AlgorithmId digAlgId, AlgorithmId encAlgId, boolean directSign) throws NoSuchAlgorithmException { String encAlg = encAlgId.getName(); - if (encAlg.contains("with")) { - return encAlg; - } switch (encAlg) { case "RSASSA-PSS": PSSParameterSpec spec = (PSSParameterSpec) @@ -547,11 +548,16 @@ public static String makeSigAlg(AlgorithmId digAlgId, AlgorithmId encAlgId, return encAlg; default: String digAlg = digAlgId.getName(); + String keyAlg = SignatureUtil.extractKeyAlgFromDwithE(encAlg); + if (keyAlg == null) { + // The encAlg used to be only the key alg + keyAlg = encAlg; + } if (digAlg.startsWith("SHA-")) { digAlg = "SHA" + digAlg.substring(4); } - if (encAlg.equals("EC")) encAlg = "ECDSA"; - return digAlg + "with" + encAlg; + if (keyAlg.equals("EC")) keyAlg = "ECDSA"; + return digAlg + "with" + keyAlg; } } diff --git a/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java b/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java index ca8e208f28a..f9b5357e269 100644 --- a/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java +++ b/src/java.base/share/classes/sun/security/pkcs12/PKCS12KeyStore.java @@ -65,6 +65,7 @@ import javax.security.auth.DestroyFailedException; import javax.security.auth.x500.X500Principal; +import sun.security.action.GetPropertyAction; import sun.security.tools.KeyStoreUtil; import sun.security.util.*; import sun.security.pkcs.ContentInfo; @@ -79,48 +80,10 @@ * Implements the PKCS#12 PFX protected using the Password privacy mode. * The contents are protected using Password integrity mode. * - * Currently these PBE algorithms are used by default: - * - PBEWithSHA1AndDESede to encrypt private keys, iteration count 50000. - * - PBEWithSHA1AndRC2_40 to encrypt certificates, iteration count 50000. - * - * The default Mac algorithm is HmacPBESHA1, iteration count 100000. - * - * Supported encryption of various implementations : - * - * Software and mode. Certificate encryption Private key encryption - * --------------------------------------------------------------------- - * MSIE4 (domestic 40 bit RC2. 40 bit RC2 - * and xport versions) - * PKCS#12 export. - * - * MSIE4, 5 (domestic 40 bit RC2, 40 bit RC2, - * and export versions) 3 key triple DES 3 key triple DES - * PKCS#12 import. - * - * MSIE5 40 bit RC2 3 key triple DES, - * PKCS#12 export. with SHA1 (168 bits) - * - * Netscape Communicator 40 bit RC2 3 key triple DES, - * (domestic and export with SHA1 (168 bits) - * versions) PKCS#12 export - * - * Netscape Communicator 40 bit ciphers only All. - * (export version) - * PKCS#12 import. - * - * Netscape Communicator All. All. - * (domestic or fortified - * version) PKCS#12 import. - * - * OpenSSL PKCS#12 code. All. All. - * --------------------------------------------------------------------- - * - * NOTE: PKCS12 KeyStore supports PrivateKeyEntry and TrustedCertficateEntry. - * PKCS#12 is mainly used to deliver private keys with their associated - * certificate chain and aliases. In a PKCS12 keystore, entries are - * identified by the alias, and a localKeyId is required to match the - * private key with the certificate. Trusted certificate entries are identified - * by the presence of an trustedKeyUsage attribute. + * NOTE: In a PKCS12 keystore, entries are identified by the alias, and + * a localKeyId is required to match the private key with the certificate. + * Trusted certificate entries are identified by the presence of an + * trustedKeyUsage attribute. * * @author Seema Malkani * @author Jeff Nisewanger @@ -130,6 +93,32 @@ */ public final class PKCS12KeyStore extends KeyStoreSpi { + // Hardcoded defaults. They should be the same with commented out + // lines inside the java.security file. + private static final String DEFAULT_CERT_PBE_ALGORITHM + = "PBEWithHmacSHA256AndAES_256"; + private static final String DEFAULT_KEY_PBE_ALGORITHM + = "PBEWithHmacSHA256AndAES_256"; + private static final String DEFAULT_MAC_ALGORITHM = "HmacPBESHA256"; + private static final int DEFAULT_CERT_PBE_ITERATION_COUNT = 10000; + private static final int DEFAULT_KEY_PBE_ITERATION_COUNT = 10000; + private static final int DEFAULT_MAC_ITERATION_COUNT = 10000; + + // Legacy settings. Used when "keystore.pkcs12.legacy" is set. + private static final String LEGACY_CERT_PBE_ALGORITHM + = "PBEWithSHA1AndRC2_40"; + private static final String LEGACY_KEY_PBE_ALGORITHM + = "PBEWithSHA1AndDESede"; + private static final String LEGACY_MAC_ALGORITHM = "HmacPBESHA1"; + private static final int LEGACY_PBE_ITERATION_COUNT = 50000; + private static final int LEGACY_MAC_ITERATION_COUNT = 100000; + + // Big switch. When this system property is set. Legacy settings + // are used no matter what other keystore.pkcs12.* properties are set. + // Note: This is only a system property, there's no same-name + // security property defined. + private static final String USE_LEGACY_PROP = "keystore.pkcs12.legacy"; + // special PKCS12 keystore that supports PKCS12 and JKS file formats public static final class DualFormatPKCS12 extends KeyStoreDelegator { public DualFormatPKCS12() { @@ -845,9 +834,6 @@ private SecretKey getPBEKey(char[] password) throws IOException * Encrypt private key or secret key using Password-based encryption (PBE) * as defined in PKCS#5. * - * NOTE: By default, pbeWithSHAAnd3-KeyTripleDES-CBC algorithmID is - * used to derive the key and IV. - * * @return encrypted private key or secret key encoded as * EncryptedPrivateKeyInfo */ @@ -1866,9 +1852,6 @@ private byte[] createSafeContent() * Encrypt the contents using Password-based (PBE) encryption * as defined in PKCS #5. * - * NOTE: Currently pbeWithSHAAnd40BiteRC2-CBC algorithmID is used - * to derive the key and IV. - * * @return encrypted contents encoded as EncryptedContentInfo */ private byte[] encryptContent(byte[] data, char[] password) @@ -2640,25 +2623,42 @@ public boolean engineProbe(InputStream stream) throws IOException { return result; } - // 8076190: Customizing the generation of a PKCS12 keystore + // The following methods are related to customizing + // the generation of a PKCS12 keystore or private/secret + // key entries. + + private static boolean useLegacy() { + return GetPropertyAction.privilegedGetProperty( + USE_LEGACY_PROP) != null; + } private static String defaultCertProtectionAlgorithm() { + if (useLegacy()) { + return LEGACY_CERT_PBE_ALGORITHM; + } String result = SecurityProperties.privilegedGetOverridable( "keystore.pkcs12.certProtectionAlgorithm"); return (result != null && !result.isEmpty()) - ? result : "PBEWithSHA1AndRC2_40"; + ? result : DEFAULT_CERT_PBE_ALGORITHM; } private static int defaultCertPbeIterationCount() { + if (useLegacy()) { + return LEGACY_PBE_ITERATION_COUNT; + } String result = SecurityProperties.privilegedGetOverridable( "keystore.pkcs12.certPbeIterationCount"); return (result != null && !result.isEmpty()) - ? string2IC("certPbeIterationCount", result) : 50000; + ? string2IC("certPbeIterationCount", result) + : DEFAULT_CERT_PBE_ITERATION_COUNT; } // Read both "keystore.pkcs12.keyProtectionAlgorithm" and // "keystore.PKCS12.keyProtectionAlgorithm" for compatibility. private static String defaultKeyProtectionAlgorithm() { + if (useLegacy()) { + return LEGACY_KEY_PBE_ALGORITHM; + } String result = AccessController.doPrivileged(new PrivilegedAction() { public String run() { String result; @@ -2680,28 +2680,39 @@ public String run() { } }); return (result != null && !result.isEmpty()) - ? result : "PBEWithSHA1AndDESede"; + ? result : DEFAULT_KEY_PBE_ALGORITHM; } private static int defaultKeyPbeIterationCount() { + if (useLegacy()) { + return LEGACY_PBE_ITERATION_COUNT; + } String result = SecurityProperties.privilegedGetOverridable( "keystore.pkcs12.keyPbeIterationCount"); return (result != null && !result.isEmpty()) - ? string2IC("keyPbeIterationCount", result) : 50000; + ? string2IC("keyPbeIterationCount", result) + : DEFAULT_KEY_PBE_ITERATION_COUNT; } private static String defaultMacAlgorithm() { + if (useLegacy()) { + return LEGACY_MAC_ALGORITHM; + } String result = SecurityProperties.privilegedGetOverridable( "keystore.pkcs12.macAlgorithm"); return (result != null && !result.isEmpty()) - ? result : "HmacPBESHA1"; + ? result : DEFAULT_MAC_ALGORITHM; } private static int defaultMacIterationCount() { + if (useLegacy()) { + return LEGACY_MAC_ITERATION_COUNT; + } String result = SecurityProperties.privilegedGetOverridable( "keystore.pkcs12.macIterationCount"); return (result != null && !result.isEmpty()) - ? string2IC("macIterationCount", result) : 100000; + ? string2IC("macIterationCount", result) + : DEFAULT_MAC_ITERATION_COUNT; } private static int string2IC(String type, String value) { diff --git a/src/java.base/share/classes/sun/security/util/Cache.java b/src/java.base/share/classes/sun/security/util/Cache.java index 9a2e2fc29b0..5e1eef17ee4 100644 --- a/src/java.base/share/classes/sun/security/util/Cache.java +++ b/src/java.base/share/classes/sun/security/util/Cache.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2020, 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 @@ -265,8 +265,7 @@ public MemoryCache(boolean soft, int maxSize, int lifetime) { else this.queue = null; - int buckets = (int)(maxSize / LOAD_FACTOR) + 1; - cacheMap = new LinkedHashMap<>(buckets, LOAD_FACTOR, true); + cacheMap = new LinkedHashMap<>(1, LOAD_FACTOR, true); } /** diff --git a/src/java.base/share/classes/sun/security/util/KnownOIDs.java b/src/java.base/share/classes/sun/security/util/KnownOIDs.java index bbdbf5a4713..cdb24121722 100644 --- a/src/java.base/share/classes/sun/security/util/KnownOIDs.java +++ b/src/java.base/share/classes/sun/security/util/KnownOIDs.java @@ -354,7 +354,7 @@ public enum KnownOIDs { ECDH("1.3.132.1.12"), // OIW secsig 1.3.14.3.* - OIW_DES_CBC("1.3.14.3.2.7", "DES/CBC"), + OIW_DES_CBC("1.3.14.3.2.7", "DES/CBC", "DES"), OIW_DSA("1.3.14.3.2.12", "DSA") { @Override @@ -371,6 +371,8 @@ public enum KnownOIDs { boolean registerNames() { return false; } }, + DESede("1.3.14.3.2.17", "DESede"), + SHA_1("1.3.14.3.2.26", "SHA-1", "SHA", "SHA1"), OIW_SHA1withDSA("1.3.14.3.2.27", "SHA1withDSA") { diff --git a/src/java.base/share/classes/sun/security/util/SignatureUtil.java b/src/java.base/share/classes/sun/security/util/SignatureUtil.java index 4ad03a6f731..0a17105355b 100644 --- a/src/java.base/share/classes/sun/security/util/SignatureUtil.java +++ b/src/java.base/share/classes/sun/security/util/SignatureUtil.java @@ -282,6 +282,32 @@ public static String extractDigestAlgFromDwithE(String signatureAlgorithm) { } } + /** + * Extracts the key algorithm name from a signature + * algorithm name in either the "DIGESTwithENCRYPTION" or the + * "DIGESTwithENCRYPTIONandWHATEVER" format. + * + * @return the key algorithm name, or null if the input + * is not in either of the formats. + */ + public static String extractKeyAlgFromDwithE(String signatureAlgorithm) { + signatureAlgorithm = signatureAlgorithm.toUpperCase(Locale.ENGLISH); + int with = signatureAlgorithm.indexOf("WITH"); + String keyAlgorithm = null; + if (with > 0) { + int and = signatureAlgorithm.indexOf("AND", with + 4); + if (and > 0) { + keyAlgorithm = signatureAlgorithm.substring(with + 4, and); + } else { + keyAlgorithm = signatureAlgorithm.substring(with + 4); + } + if (keyAlgorithm.equalsIgnoreCase("ECDSA")) { + keyAlgorithm = "EC"; + } + } + return keyAlgorithm; + } + /** * Returns default AlgorithmParameterSpec for a key used in a signature. * This is only useful for RSASSA-PSS now, which is the only algorithm diff --git a/src/java.base/share/conf/security/java.security b/src/java.base/share/conf/security/java.security index b84a9d3e0cc..ddc4b87d6ee 100644 --- a/src/java.base/share/conf/security/java.security +++ b/src/java.base/share/conf/security/java.security @@ -1144,33 +1144,33 @@ jceks.key.serialFilter = java.base/java.lang.Enum;java.base/java.security.KeyRep # The algorithm used to encrypt a certificate. This can be any non-Hmac PBE # algorithm defined in the Cipher section of the Java Security Standard # Algorithm Names Specification. When set to "NONE", the certificate -# is not encrypted. The default value is "PBEWithSHA1AndRC2_40". -#keystore.pkcs12.certProtectionAlgorithm = PBEWithSHA1AndRC2_40 +# is not encrypted. The default value is "PBEWithHmacSHA256AndAES_256". +#keystore.pkcs12.certProtectionAlgorithm = PBEWithHmacSHA256AndAES_256 # The iteration count used by the PBE algorithm when encrypting a certificate. -# This value must be a positive integer. The default value is 50000. -#keystore.pkcs12.certPbeIterationCount = 50000 +# This value must be a positive integer. The default value is 10000. +#keystore.pkcs12.certPbeIterationCount = 10000 # The algorithm used to encrypt a private key or secret key. This can be # any non-Hmac PBE algorithm defined in the Cipher section of the Java # Security Standard Algorithm Names Specification. The value must not be "NONE". -# The default value is "PBEWithSHA1AndDESede". -#keystore.pkcs12.keyProtectionAlgorithm = PBEWithSHA1AndDESede +# The default value is "PBEWithHmacSHA256AndAES_256". +#keystore.pkcs12.keyProtectionAlgorithm = PBEWithHmacSHA256AndAES_256 # The iteration count used by the PBE algorithm when encrypting a private key # or a secret key. This value must be a positive integer. The default value -# is 50000. -#keystore.pkcs12.keyPbeIterationCount = 50000 +# is 10000. +#keystore.pkcs12.keyPbeIterationCount = 10000 # The algorithm used to calculate the optional MacData at the end of a PKCS12 # file. This can be any HmacPBE algorithm defined in the Mac section of the # Java Security Standard Algorithm Names Specification. When set to "NONE", -# no Mac is generated. The default value is "HmacPBESHA1". -#keystore.pkcs12.macAlgorithm = HmacPBESHA1 +# no Mac is generated. The default value is "HmacPBESHA256". +#keystore.pkcs12.macAlgorithm = HmacPBESHA256 # The iteration count used by the MacData algorithm. This value must be a -# positive integer. The default value is 100000. -#keystore.pkcs12.macIterationCount = 100000 +# positive integer. The default value is 10000. +#keystore.pkcs12.macIterationCount = 10000 # # Enhanced exception message information @@ -1308,4 +1308,4 @@ jdk.io.permissionsUseCanonicalPath=false # properties. In the case that both properties are simultaneously set, the # System value prevails. The default value of the property is "false". # -#jdk.security.allowNonCaAnchor=true \ No newline at end of file +#jdk.security.allowNonCaAnchor=true diff --git a/src/java.base/unix/classes/sun/nio/ch/InheritedChannel.java b/src/java.base/unix/classes/sun/nio/ch/InheritedChannel.java index 845433becb1..3642db89871 100644 --- a/src/java.base/unix/classes/sun/nio/ch/InheritedChannel.java +++ b/src/java.base/unix/classes/sun/nio/ch/InheritedChannel.java @@ -32,10 +32,13 @@ import java.net.Inet6Address; import java.net.InetSocketAddress; import java.net.ProtocolFamily; +import java.net.SocketAddress; +import java.net.UnixDomainSocketAddress; import java.nio.channels.Channel; import java.nio.channels.spi.SelectorProvider; import static java.net.StandardProtocolFamily.INET6; import static java.net.StandardProtocolFamily.INET; +import static java.net.StandardProtocolFamily.UNIX; class InheritedChannel { @@ -45,10 +48,10 @@ class InheritedChannel { private static final int SOCK_DGRAM = 2; // socket address type - private static final int AF_UNKNOWN = -1; - private static final int AF_INET = 1; - private static final int AF_INET6 = 2; - private static final int AF_UNIX = 3; + static final int AF_UNKNOWN = -1; + static final int AF_INET = 1; + static final int AF_INET6 = 2; + static final int AF_UNIX = 3; // oflag values when opening a file private static final int O_RDONLY = 0; @@ -75,6 +78,24 @@ private static void detachIOStreams() { } } + static ProtocolFamily protocolFamily(SocketAddress sa) { + if (sa instanceof UnixDomainSocketAddress) { + return UNIX; + } else { + InetSocketAddress isa = (InetSocketAddress) sa; + return (isa.getAddress() instanceof Inet6Address) ? INET6 : INET; + } + } + + static ProtocolFamily protocolFamily(int family) { + return switch (family) { + case AF_INET -> INET; + case AF_INET6 -> INET6; + case AF_UNIX -> UNIX; + default -> throw new IllegalArgumentException(); + }; + } + /* * Override the implCloseSelectableChannel for each channel type - this * allows us to "detach" the standard streams after closing and ensures @@ -82,16 +103,12 @@ private static void detachIOStreams() { */ public static class InheritedSocketChannelImpl extends SocketChannelImpl { - static ProtocolFamily family(InetSocketAddress isa) { - return (isa.getAddress() instanceof Inet6Address) ? INET6 : INET; - } - InheritedSocketChannelImpl(SelectorProvider sp, FileDescriptor fd, - InetSocketAddress remote) + SocketAddress remote) throws IOException { - super(sp, family(remote), fd, remote); + super(sp, protocolFamily(remote), fd, remote); } protected void implCloseSelectableChannel() throws IOException { @@ -100,39 +117,24 @@ protected void implCloseSelectableChannel() throws IOException { } } - public static class InheritedUnixChannelImpl extends UnixDomainSocketChannelImpl { - - InheritedUnixChannelImpl(FileDescriptor fd) - throws IOException - { - super(fd); - } - - protected void implCloseSelectableChannel() throws IOException { - super.implCloseChannel(); - detachIOStreams(); - } - } - - public static class InheritedServerSocketChannelImpl extends - ServerSocketChannelImpl { + public static class InheritedServerSocketChannelImpl extends ServerSocketChannelImpl { InheritedServerSocketChannelImpl(SelectorProvider sp, + ProtocolFamily family, FileDescriptor fd) throws IOException { - super(sp, fd, true); + super(sp, family, fd, true); } + @Override protected void implCloseSelectableChannel() throws IOException { super.implCloseSelectableChannel(); detachIOStreams(); } - } - public static class InheritedDatagramChannelImpl extends - DatagramChannelImpl { + public static class InheritedDatagramChannelImpl extends DatagramChannelImpl { InheritedDatagramChannelImpl(SelectorProvider sp, FileDescriptor fd) @@ -151,16 +153,13 @@ protected void implCloseSelectableChannel() throws IOException { * If there's a SecurityManager then check for the appropriate * RuntimePermission. */ - private static void checkAccess(Channel c) { + private static void checkAccess() { SecurityManager sm = System.getSecurityManager(); if (sm != null) { - sm.checkPermission( - new RuntimePermission("inheritedChannel") - ); + sm.checkPermission(new RuntimePermission("inheritedChannel")); } } - /* * If standard inherited channel is connected to a socket then return a Channel * of the appropriate type based standard input. @@ -197,7 +196,7 @@ private static Channel createChannel() throws IOException { // Now create the channel. If the socket is a streams socket then - // we see if tthere is a peer (ie: connected). If so, then we + // we see if there is a peer (ie: connected). If so, then we // create a SocketChannel, otherwise a ServerSocketChannel. // If the socket is a datagram socket then create a DatagramChannel @@ -209,19 +208,21 @@ private static Channel createChannel() throws IOException { int family = addressFamily(fdVal); if (family == AF_UNKNOWN) return null; + ProtocolFamily pfamily = protocolFamily(family); if (family == AF_UNIX) { if (isConnected(fdVal)) { - return new InheritedUnixChannelImpl(fd); + var sa = UnixDomainSocketAddress.of(unixPeerAddress(fdVal)); + return new InheritedSocketChannelImpl(provider, fd, sa); } else { - // listener. unsupported. - return null; + return new InheritedServerSocketChannelImpl(provider, pfamily, fd); } } - InetAddress ia = peerAddress0(fdVal); + InetAddress ia = inetPeerAddress0(fdVal); if (ia == null) { - c = new InheritedServerSocketChannelImpl(provider, fd); + c = new InheritedServerSocketChannelImpl(provider, pfamily, fd); } else { int port = peerPort0(fdVal); + assert port > 0; InetSocketAddress isa = new InetSocketAddress(ia, port); c = new InheritedSocketChannelImpl(provider, fd, isa); @@ -253,11 +254,15 @@ public static synchronized Channel getChannel() throws IOException { // if there is a channel then do the security check before // returning it. if (channel != null) { - checkAccess(channel); + checkAccess(); } return channel; } + private static String unixPeerAddress(int fd) throws IOException { + byte[] bytes = unixPeerAddress0(fd); + return new String(bytes); + } // -- Native methods -- @@ -268,7 +273,8 @@ public static synchronized Channel getChannel() throws IOException { private static native void close0(int fd) throws IOException; private static native int soType0(int fd); private static native int addressFamily(int fd); - private static native InetAddress peerAddress0(int fd); + private static native InetAddress inetPeerAddress0(int fd); + private static native byte[] unixPeerAddress0(int fd); private static native int peerPort0(int fd); // return true if socket is connected to a peer diff --git a/src/java.base/unix/classes/sun/nio/ch/UnixDomainSocketChannelImpl.java b/src/java.base/unix/classes/sun/nio/ch/UnixDomainSocketChannelImpl.java deleted file mode 100644 index d54c881f089..00000000000 --- a/src/java.base/unix/classes/sun/nio/ch/UnixDomainSocketChannelImpl.java +++ /dev/null @@ -1,266 +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 sun.nio.ch; - -import java.io.FileDescriptor; -import java.io.IOException; -import java.nio.ByteBuffer; -import java.nio.channels.AsynchronousCloseException; -import java.nio.channels.ByteChannel; -import java.nio.channels.ClosedChannelException; -import java.nio.channels.NotYetConnectedException; -import java.nio.channels.spi.AbstractInterruptibleChannel; -import java.util.Objects; -import java.util.concurrent.locks.ReentrantLock; - -import static java.util.concurrent.TimeUnit.NANOSECONDS; - -class UnixDomainSocketChannelImpl - extends AbstractInterruptibleChannel - implements ByteChannel -{ - // Used to make native read and write calls - private static final NativeDispatcher nd = new SocketDispatcher(); - - // Our file descriptor object - private final FileDescriptor fd; - // Lock held by current reading or connecting thread - private final ReentrantLock readLock = new ReentrantLock(); - - // Lock held by current writing or connecting thread - private final ReentrantLock writeLock = new ReentrantLock(); - - // Lock for managing close state - private final Object stateLock = new Object(); - - // Channel state - private static final int ST_INUSE = 0; - private static final int ST_CLOSING = 1; - private static final int ST_CLOSED = 2; - private int state; - - // IDs of native threads doing reads and writes, for signalling - private long readerThread; - private long writerThread; - - UnixDomainSocketChannelImpl(FileDescriptor fd) - throws IOException - { - this.fd = fd; - } - - /** - * Checks that the channel is open. - * - * @throws ClosedChannelException if channel is closed (or closing) - */ - private void ensureOpen() throws ClosedChannelException { - if (!isOpen()) - throw new ClosedChannelException(); - } - - /** - * Closes the socket if there are no I/O operations in progress - */ - private boolean tryClose() throws IOException { - assert Thread.holdsLock(stateLock) && state == ST_CLOSING; - if (readerThread == 0 && writerThread == 0) { - state = ST_CLOSED; - nd.close(fd); - return true; - } else { - return false; - } - } - - /** - * Complete closure of pre-closed socket (release the file descriptor) - */ - private void tryFinishClose() { - try { - tryClose(); - } catch (IOException ignore) { } - } - - /** - * Marks the beginning of a read operation - * - * @throws ClosedChannelException if the channel is closed - * @throws NotYetConnectedException if the channel is not yet connected - */ - private void beginRead() throws ClosedChannelException { - // set hook for Thread.interrupt - begin(); - synchronized (stateLock) { - ensureOpen(); - readerThread = NativeThread.current(); - } - } - - /** - * Marks the end of a read operation that may have blocked. - * - * @throws AsynchronousCloseException if the channel was closed due to this - * thread being interrupted on a blocking read operation. - */ - private void endRead(boolean completed) - throws AsynchronousCloseException - { - synchronized (stateLock) { - readerThread = 0; - if (state == ST_CLOSING) { - tryFinishClose(); - } - } - end(completed); - } - - @Override - public int read(ByteBuffer buf) throws IOException { - Objects.requireNonNull(buf); - - readLock.lock(); - try { - int n = 0; - try { - beginRead(); - n = IOUtil.read(fd, buf, -1, nd); - while (IOStatus.okayToRetry(n) && isOpen()) { - park(Net.POLLIN, 0L); - n = IOUtil.read(fd, buf, -1, nd); - } - } finally { - endRead(n > 0); - } - return n; - } finally { - readLock.unlock(); - } - } - - /** - * Marks the beginning of a write operation that might block. - * - * @throws ClosedChannelException if the channel is closed - * @throws NotYetConnectedException if the channel is not yet connected - */ - private void beginWrite() throws ClosedChannelException { - begin(); - synchronized (stateLock) { - // set hook for Thread.interrupt - ensureOpen(); - writerThread = NativeThread.current(); - } - } - - /** - * Marks the end of a write operation that may have blocked. - * - * @throws AsynchronousCloseException if the channel was closed due to this - * thread being interrupted on a blocking write operation. - */ - private void endWrite(boolean completed) - throws AsynchronousCloseException - { - synchronized (stateLock) { - writerThread = 0; - if (state == ST_CLOSING) { - tryFinishClose(); - } - } - end(completed); - } - - void park(int event, long nanos) throws IOException { - long millis; - if (nanos <= 0) { - millis = -1; - } else { - millis = NANOSECONDS.toMillis(nanos); - } - Net.poll(fd, event, millis); - } - - @Override - public int write(ByteBuffer buf) throws IOException { - Objects.requireNonNull(buf); - - writeLock.lock(); - try { - int n = 0; - try { - beginWrite(); - n = IOUtil.write(fd, buf, -1, nd); - while (IOStatus.okayToRetry(n) && isOpen()) { - park(Net.POLLOUT, 0L); - n = IOUtil.write(fd, buf, -1, nd); - } - } finally { - endWrite(n > 0); - } - return n; - } finally { - writeLock.unlock(); - } - } - - /** - * Closes this channel - * - * If there is an I/O operation in progress then the socket is pre-closed - * and the I/O threads signalled, in which case the final close is deferred - * until all I/O operations complete. - */ - @Override - protected void implCloseChannel() throws IOException { - synchronized (stateLock) { - assert state == ST_INUSE; - state = ST_CLOSING; - if (!tryClose()) { - long reader = readerThread; - long writer = writerThread; - if (reader != 0 || writer != 0) { - nd.preClose(fd); - if (reader != 0) - NativeThread.signal(reader); - if (writer != 0) - NativeThread.signal(writer); - } - } - } - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append(this.getClass().getSuperclass().getName()); - sb.append('['); - if (!isOpen()) - sb.append("closed"); - sb.append(']'); - return sb.toString(); - } -} diff --git a/src/java.base/share/classes/sun/nio/ch/Secrets.java b/src/java.base/unix/classes/sun/nio/ch/UnixDomainSocketsUtil.java similarity index 50% rename from src/java.base/share/classes/sun/nio/ch/Secrets.java rename to src/java.base/unix/classes/sun/nio/ch/UnixDomainSocketsUtil.java index f76ab1d75a0..4fd3e5f6a48 100644 --- a/src/java.base/share/classes/sun/nio/ch/Secrets.java +++ b/src/java.base/unix/classes/sun/nio/ch/UnixDomainSocketsUtil.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 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 @@ -25,39 +25,41 @@ package sun.nio.ch; -import java.nio.channels.SocketChannel; -import java.nio.channels.ServerSocketChannel; -import java.nio.channels.spi.SelectorProvider; -import java.io.FileDescriptor; -import java.io.IOException; +import java.nio.charset.Charset; +import java.security.AccessController; +import java.security.PrivilegedAction; +import sun.net.NetProperties; +import jdk.internal.util.StaticProperty; /** - * Provides access to implementation private constructors and methods. + * Platform specific utility functions */ +class UnixDomainSocketsUtil { + private UnixDomainSocketsUtil() { } -public final class Secrets { - private Secrets() { } - - private static SelectorProvider provider() { - SelectorProvider p = SelectorProvider.provider(); - if (!(p instanceof SelectorProviderImpl)) - throw new UnsupportedOperationException(); - return p; - } - - public static SocketChannel newSocketChannel(FileDescriptor fd) { - try { - return new SocketChannelImpl(provider(), fd, false); - } catch (IOException ioe) { - throw new AssertionError(ioe); - } + static Charset getCharset() { + return Charset.defaultCharset(); } - public static ServerSocketChannel newServerSocketChannel(FileDescriptor fd) { - try { - return new ServerSocketChannelImpl(provider(), fd, false); - } catch (IOException ioe) { - throw new AssertionError(ioe); - } + /** + * Return the temp directory for storing automatically bound + * server sockets. + * + * On UNIX we search the following directories in sequence: + * + * 1. ${jdk.net.unixdomain.tmpdir} if set as system property + * 2. ${jdk.net.unixdomain.tmpdir} if set as net property + * 3. ${java.io.tmpdir} system property + */ + static String getTempDir() { + PrivilegedAction action = () -> { + String s = NetProperties.get("jdk.net.unixdomain.tmpdir"); + if (s != null && s.length() > 0) { + return s; + } else { + return StaticProperty.javaIoTmpDir(); + } + }; + return AccessController.doPrivileged(action); } } diff --git a/src/java.base/unix/classes/sun/nio/fs/UnixFileSystemProvider.java b/src/java.base/unix/classes/sun/nio/fs/UnixFileSystemProvider.java index 87284a9feb7..5443f8cac63 100644 --- a/src/java.base/unix/classes/sun/nio/fs/UnixFileSystemProvider.java +++ b/src/java.base/unix/classes/sun/nio/fs/UnixFileSystemProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2020, 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 @@ -352,7 +352,14 @@ public boolean isHidden(Path obj) { UnixPath name = file.getFileName(); if (name == null) return false; - return (name.asByteArray()[0] == '.'); + + byte[] path; + if (name.isEmpty()) { // corner case for empty paths + path = name.getFileSystem().defaultDirectory(); + } else { + path = name.asByteArray(); + } + return path[0] == '.'; } /** @@ -557,4 +564,10 @@ protected String implProbeContentType(Path file) throws IOException { } }; } + + @Override + public byte[] getSunPathForSocketFile(Path obj) { + UnixPath file = UnixPath.toUnixPath(obj); + return file.getByteArrayForSysCalls(); + } } diff --git a/src/java.base/unix/classes/sun/nio/fs/UnixPath.java b/src/java.base/unix/classes/sun/nio/fs/UnixPath.java index 804b5632846..92d71c53591 100644 --- a/src/java.base/unix/classes/sun/nio/fs/UnixPath.java +++ b/src/java.base/unix/classes/sun/nio/fs/UnixPath.java @@ -243,7 +243,7 @@ private void initOffsets() { } // returns {@code true} if this path is an empty path - private boolean isEmpty() { + boolean isEmpty() { return path.length == 0; } diff --git a/src/java.base/unix/classes/sun/nio/fs/UnixUserPrincipals.java b/src/java.base/unix/classes/sun/nio/fs/UnixUserPrincipals.java index b7a9e7692f0..03054fd8dea 100644 --- a/src/java.base/unix/classes/sun/nio/fs/UnixUserPrincipals.java +++ b/src/java.base/unix/classes/sun/nio/fs/UnixUserPrincipals.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,7 +33,7 @@ * Unix implementation of java.nio.file.attribute.UserPrincipal */ -class UnixUserPrincipals { +public class UnixUserPrincipals { private static User createSpecial(String name) { return new User(-1, name); } static final User SPECIAL_OWNER = createSpecial("OWNER@"); @@ -108,7 +108,7 @@ static class Group extends User implements GroupPrincipal { } // return UserPrincipal representing given uid - static User fromUid(int uid) { + public static User fromUid(int uid) { String name; try { name = Util.toString(getpwuid(uid)); @@ -119,7 +119,7 @@ static User fromUid(int uid) { } // return GroupPrincipal representing given gid - static Group fromGid(int gid) { + public static Group fromGid(int gid) { String name; try { name = Util.toString(getgrgid(gid)); diff --git a/src/java.base/unix/conf/net.properties b/src/java.base/unix/conf/net.properties new file mode 100644 index 00000000000..6d72511ad95 --- /dev/null +++ b/src/java.base/unix/conf/net.properties @@ -0,0 +1,15 @@ +# +# Default directory where automatically bound Unix domain server +# sockets are stored. Sockets are automatically bound when bound +# with a null address. +# +# On Unix the search order to determine this directory is: +# +# 1. System property jdk.net.unixdomain.tmpdir +# +# 2. Networking property jdk.net.unixdomain.tmpdir specified +# in this file (effective default) +# +# 3. System property java.io.tmpdir +# +jdk.net.unixdomain.tmpdir=/tmp diff --git a/src/java.base/unix/native/libnet/NetworkInterface.c b/src/java.base/unix/native/libnet/NetworkInterface.c index 0581b8e90ec..67f6004ecec 100644 --- a/src/java.base/unix/native/libnet/NetworkInterface.c +++ b/src/java.base/unix/native/libnet/NetworkInterface.c @@ -205,7 +205,6 @@ JNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByName0 jboolean isCopy; const char* name_utf; char *colonP; - char searchName[IFNAMESIZE]; jobject obj = NULL; if (name != NULL) { @@ -229,15 +228,11 @@ JNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByName0 // search the list of interfaces based on name, // if it is virtual sub interface search with parent first. - strncpy(searchName, name_utf, IFNAMESIZE); - searchName[IFNAMESIZE - 1] = '\0'; - colonP = strchr(searchName, ':'); - if (colonP != NULL) { - *colonP = '\0'; - } + colonP = strchr(name_utf, ':'); + size_t limit = colonP != NULL ? (size_t)(colonP - name_utf) : strlen(name_utf); curr = ifs; while (curr != NULL) { - if (strcmp(searchName, curr->name) == 0) { + if (strlen(curr->name) == limit && memcmp(name_utf, curr->name, limit) == 0) { break; } curr = curr->next; diff --git a/src/java.base/unix/native/libnio/ch/InheritedChannel.c b/src/java.base/unix/native/libnio/ch/InheritedChannel.c index f19068fb2fa..eb8abc2aee4 100644 --- a/src/java.base/unix/native/libnio/ch/InheritedChannel.c +++ b/src/java.base/unix/native/libnio/ch/InheritedChannel.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2020, 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 @@ -34,10 +34,11 @@ #include "jni.h" #include "jni_util.h" #include "net_util.h" +#include "nio_util.h" #include "sun_nio_ch_InheritedChannel.h" -static int matchFamily(SOCKETADDRESS *sa) { +static int toInetFamily(SOCKETADDRESS *sa) { return (sa->sa.sa_family == (ipv6_available() ? AF_INET6 : AF_INET)); } @@ -49,7 +50,7 @@ Java_sun_nio_ch_InheritedChannel_initIDs(JNIEnv *env, jclass cla) } JNIEXPORT jobject JNICALL -Java_sun_nio_ch_InheritedChannel_peerAddress0(JNIEnv *env, jclass cla, jint fd) +Java_sun_nio_ch_InheritedChannel_inetPeerAddress0(JNIEnv *env, jclass cla, jint fd) { SOCKETADDRESS sa; socklen_t len = sizeof(SOCKETADDRESS); @@ -57,7 +58,7 @@ Java_sun_nio_ch_InheritedChannel_peerAddress0(JNIEnv *env, jclass cla, jint fd) jint remote_port; if (getpeername(fd, &sa.sa, &len) == 0) { - if (matchFamily(&sa)) { + if (toInetFamily(&sa)) { remote_ia = NET_SockaddrToInetAddress(env, &sa, (int *)&remote_port); } } @@ -65,6 +66,21 @@ Java_sun_nio_ch_InheritedChannel_peerAddress0(JNIEnv *env, jclass cla, jint fd) return remote_ia; } +JNIEXPORT jbyteArray JNICALL +Java_sun_nio_ch_InheritedChannel_unixPeerAddress0(JNIEnv *env, jclass cla, jint fd) +{ + struct sockaddr_un sa; + socklen_t len = sizeof(struct sockaddr_un); + jobject remote_sa = NULL; + + if (getpeername(fd, (struct sockaddr *)&sa, &len) == 0) { + if (sa.sun_family == AF_UNIX) { + remote_sa = sockaddrToUnixAddressBytes(env, &sa, len); + } + } + return remote_sa; +} + JNIEXPORT jint JNICALL Java_sun_nio_ch_InheritedChannel_peerPort0(JNIEnv *env, jclass cla, jint fd) { @@ -72,8 +88,8 @@ Java_sun_nio_ch_InheritedChannel_peerPort0(JNIEnv *env, jclass cla, jint fd) socklen_t len = sizeof(SOCKETADDRESS); jint remote_port = -1; - if (getpeername(fd, &sa.sa, &len) == 0) { - if (matchFamily(&sa)) { + if (getpeername(fd, (struct sockaddr *)&sa.sa, &len) == 0) { + if (toInetFamily(&sa)) { NET_SockaddrToInetAddress(env, &sa, (int *)&remote_port); } } diff --git a/src/java.base/unix/native/libnio/ch/UnixDomainSockets.c b/src/java.base/unix/native/libnio/ch/UnixDomainSockets.c new file mode 100644 index 00000000000..f0febabed6c --- /dev/null +++ b/src/java.base/unix/native/libnio/ch/UnixDomainSockets.c @@ -0,0 +1,194 @@ +/* + * Copyright (c) 2020, 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "jni.h" +#include "java_props.h" +#include "jni_util.h" +#include "jvm.h" +#include "jlong.h" +#include "sun_nio_ch_Net.h" +#include "nio_util.h" +#include "nio.h" + +/* Subtle platform differences in how unnamed sockets (empty path) + * are returned from getsockname() + */ +#ifdef MACOSX + #define ZERO_PATHLEN(len) (JNI_FALSE) +#else + #define ZERO_PATHLEN(len) (len == offsetof(struct sockaddr_un, sun_path)) +#endif + +jbyteArray sockaddrToUnixAddressBytes(JNIEnv *env, struct sockaddr_un *sa, socklen_t len) +{ + if (sa->sun_family == AF_UNIX) { + int namelen; + if (ZERO_PATHLEN(len)) { + namelen = 0; + } else { + namelen = strlen(sa->sun_path); + } + jbyteArray name = (*env)->NewByteArray(env, namelen); + if (namelen != 0) { + (*env)->SetByteArrayRegion(env, name, 0, namelen, (jbyte*)sa->sun_path); + if ((*env)->ExceptionOccurred(env)) { + return NULL; + } + } + return name; + } + return NULL; +} + +jint unixSocketAddressToSockaddr(JNIEnv *env, jbyteArray path, struct sockaddr_un *sa, int *len) +{ + memset(sa, 0, sizeof(struct sockaddr_un)); + sa->sun_family = AF_UNIX; + int ret; + const char* pname = (const char *)(*env)->GetByteArrayElements(env, path, NULL); + if (pname == NULL) { + JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Unix domain path not present"); + return -1; + } + size_t name_len = (*env)->GetArrayLength(env, path); + if (name_len > MAX_UNIX_DOMAIN_PATH_LEN) { + JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Unix domain path too long"); + ret = -1; + } else { + memcpy(sa->sun_path, pname, name_len); + *len = (int)(offsetof(struct sockaddr_un, sun_path) + name_len + 1); + ret = 0; + } + (*env)->ReleaseByteArrayElements(env, path, (jbyte *)pname, 0); + return ret; +} + +JNIEXPORT jboolean JNICALL +Java_sun_nio_ch_UnixDomainSockets_socketSupported(JNIEnv *env, jclass cl) +{ + return JNI_TRUE; +} + +JNIEXPORT jint JNICALL +Java_sun_nio_ch_UnixDomainSockets_socket0(JNIEnv *env, jclass cl) +{ + int fd = socket(PF_UNIX, SOCK_STREAM, 0); + if (fd < 0) { + return handleSocketError(env, errno); + } + return fd; +} + +JNIEXPORT void JNICALL +Java_sun_nio_ch_UnixDomainSockets_bind0(JNIEnv *env, jclass clazz, jobject fdo, jbyteArray path) +{ + struct sockaddr_un sa; + int sa_len = 0; + int rv = 0; + + if (unixSocketAddressToSockaddr(env, path, &sa, &sa_len) != 0) + return; + + rv = bind(fdval(env, fdo), (struct sockaddr *)&sa, sa_len); + if (rv != 0) { + handleSocketError(env, errno); + } +} + +JNIEXPORT jint JNICALL +Java_sun_nio_ch_UnixDomainSockets_connect0(JNIEnv *env, jclass clazz, jobject fdo, jbyteArray path) +{ + struct sockaddr_un sa; + int sa_len = 0; + int rv; + + if (unixSocketAddressToSockaddr(env, path, &sa, &sa_len) != 0) { + return IOS_THROWN; + } + + rv = connect(fdval(env, fdo), (struct sockaddr *)&sa, sa_len); + if (rv != 0) { + if (errno == EINPROGRESS) { + return IOS_UNAVAILABLE; + } else if (errno == EINTR) { + return IOS_INTERRUPTED; + } + return handleSocketError(env, errno); + } + return 1; +} + +JNIEXPORT jint JNICALL +Java_sun_nio_ch_UnixDomainSockets_accept0(JNIEnv *env, jclass clazz, jobject fdo, jobject newfdo, + jobjectArray array) +{ + jint fd = fdval(env, fdo); + jint newfd; + struct sockaddr_un sa; + socklen_t sa_len = sizeof(struct sockaddr_un); + jbyteArray address; + + newfd = accept(fd, (struct sockaddr *)&sa, &sa_len); + if (newfd < 0) { + if (errno == EAGAIN || errno == EWOULDBLOCK) + return IOS_UNAVAILABLE; + if (errno == EINTR) + return IOS_INTERRUPTED; + JNU_ThrowIOExceptionWithLastError(env, "Accept failed"); + return IOS_THROWN; + } + + setfdval(env, newfdo, newfd); + + address = sockaddrToUnixAddressBytes(env, &sa, sa_len); + CHECK_NULL_RETURN(address, IOS_THROWN); + + (*env)->SetObjectArrayElement(env, array, 0, address); + + return 1; +} + +JNIEXPORT jbyteArray JNICALL +Java_sun_nio_ch_UnixDomainSockets_localAddress0(JNIEnv *env, jclass clazz, jobject fdo) +{ + struct sockaddr_un sa; + socklen_t sa_len = sizeof(struct sockaddr_un); + int port; + if (getsockname(fdval(env, fdo), (struct sockaddr *)&sa, &sa_len) < 0) { + handleSocketError(env, errno); + return NULL; + } + return sockaddrToUnixAddressBytes(env, &sa, sa_len); +} + diff --git a/src/java.base/unix/native/libnio/ch/nio_util.h b/src/java.base/unix/native/libnio/ch/nio_util.h index 5ebbdd7f859..5e20934678c 100644 --- a/src/java.base/unix/native/libnio/ch/nio_util.h +++ b/src/java.base/unix/native/libnio/ch/nio_util.h @@ -29,6 +29,7 @@ #include "jlong.h" #include #include +#include #define RESTARTABLE(_cmd, _result) do { \ do { \ @@ -47,6 +48,12 @@ #endif #endif +/* 2 bytes to allow for null at end of string and null at start of string + * for abstract name + */ +#define MAX_UNIX_DOMAIN_PATH_LEN \ + (int)(sizeof(((struct sockaddr_un *)0)->sun_path)-2) + /* NIO utility procedures */ @@ -62,3 +69,15 @@ jlong convertLongReturnVal(JNIEnv *env, jlong n, jboolean reading); /* Defined in Net.c */ jint handleSocketError(JNIEnv *env, jint errorValue); + +/* Defined in UnixDomainSockets.c */ + +jbyteArray sockaddrToUnixAddressBytes(JNIEnv *env, + struct sockaddr_un *sa, + socklen_t len); + +jint unixSocketAddressToSockaddr(JNIEnv *env, + jbyteArray uaddr, + struct sockaddr_un *sa, + int *len); + diff --git a/src/java.base/windows/classes/sun/nio/ch/PipeImpl.java b/src/java.base/windows/classes/sun/nio/ch/PipeImpl.java index 88510f231c8..57d0adb1959 100644 --- a/src/java.base/windows/classes/sun/nio/ch/PipeImpl.java +++ b/src/java.base/windows/classes/sun/nio/ch/PipeImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2020, 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,8 +31,14 @@ import java.io.IOException; import java.net.InetAddress; import java.net.InetSocketAddress; +import java.net.SocketAddress; +import java.net.UnixDomainSocketAddress; +import java.net.StandardProtocolFamily; +import java.net.StandardSocketOptions; import java.nio.*; import java.nio.channels.*; +import java.nio.file.Files; +import java.nio.file.Path; import java.nio.channels.spi.*; import java.security.AccessController; import java.security.PrivilegedExceptionAction; @@ -55,16 +61,17 @@ class PipeImpl private static final Random RANDOM_NUMBER_GENERATOR = new SecureRandom(); // Source and sink channels - private SourceChannel source; - private SinkChannel sink; + private final SourceChannel source; + private final SinkChannel sink; private class Initializer implements PrivilegedExceptionAction { private final SelectorProvider sp; - - private IOException ioe = null; + private IOException ioe; + SourceChannelImpl source; + SinkChannelImpl sink; private Initializer(SelectorProvider sp) { this.sp = sp; @@ -103,23 +110,20 @@ public void run() { ServerSocketChannel ssc = null; SocketChannel sc1 = null; SocketChannel sc2 = null; + // Loopback address + SocketAddress sa = null; try { // Create secret with a backing array. ByteBuffer secret = ByteBuffer.allocate(NUM_SECRET_BYTES); ByteBuffer bb = ByteBuffer.allocate(NUM_SECRET_BYTES); - // Loopback address - InetAddress lb = InetAddress.getLoopbackAddress(); - assert(lb.isLoopbackAddress()); - InetSocketAddress sa = null; for(;;) { // Bind ServerSocketChannel to a port on the loopback // address if (ssc == null || !ssc.isOpen()) { - ssc = ServerSocketChannel.open(); - ssc.socket().bind(new InetSocketAddress(lb, 0)); - sa = new InetSocketAddress(lb, ssc.socket().getLocalPort()); + ssc = createListener(); + sa = ssc.getLocalAddress(); } // Establish connection (assume connections are eagerly @@ -160,18 +164,43 @@ public void run() { try { if (ssc != null) ssc.close(); + if (sa instanceof UnixDomainSocketAddress) { + Path path = ((UnixDomainSocketAddress) sa).getPath(); + Files.deleteIfExists(path); + } } catch (IOException e2) {} } } } } - PipeImpl(final SelectorProvider sp) throws IOException { + /** + * Creates a Pipe implementation that supports buffering. + */ + PipeImpl(SelectorProvider sp) throws IOException { + this(sp, true); + } + + /** + * Creates Pipe implementation that supports optionally buffering. + * + * @implNote The pipe uses Unix domain sockets where possible. It uses a + * loopback connection on older editions of Windows. When buffering is + * disabled then it sets TCP_NODELAY on the sink channel. + */ + PipeImpl(SelectorProvider sp, boolean buffering) throws IOException { + Initializer initializer = new Initializer(sp); try { - AccessController.doPrivileged(new Initializer(sp)); - } catch (PrivilegedActionException x) { - throw (IOException)x.getCause(); + AccessController.doPrivileged(initializer); + SinkChannelImpl sink = initializer.sink; + if (sink.isNetSocket() && !buffering) { + sink.setOption(StandardSocketOptions.TCP_NODELAY, true); + } + } catch (PrivilegedActionException pae) { + throw (IOException) pae.getCause(); } + this.source = initializer.source; + this.sink = initializer.sink; } public SourceChannel source() { @@ -182,4 +211,25 @@ public SinkChannel sink() { return sink; } + private static volatile boolean noUnixDomainSockets; + + private static ServerSocketChannel createListener() throws IOException { + ServerSocketChannel listener = null; + if (!noUnixDomainSockets) { + try { + listener = ServerSocketChannel.open(StandardProtocolFamily.UNIX); + return listener.bind(null); + } catch (UnsupportedOperationException | IOException e) { + // IOException is most likely to be caused by the temporary directory + // name being too long. Possibly should log this. + noUnixDomainSockets = true; + if (listener != null) + listener.close(); + } + } + listener = ServerSocketChannel.open(); + InetAddress lb = InetAddress.getLoopbackAddress(); + listener.bind(new InetSocketAddress(lb, 0)); + return listener; + } } diff --git a/src/java.base/windows/classes/sun/nio/ch/SinkChannelImpl.java b/src/java.base/windows/classes/sun/nio/ch/SinkChannelImpl.java index 66437deb87a..6b6352edac0 100644 --- a/src/java.base/windows/classes/sun/nio/ch/SinkChannelImpl.java +++ b/src/java.base/windows/classes/sun/nio/ch/SinkChannelImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2020, 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,6 +30,7 @@ import java.io.IOException; import java.io.FileDescriptor; +import java.net.SocketOption; import java.nio.ByteBuffer; import java.nio.channels.*; import java.nio.channels.spi.*; @@ -44,19 +45,27 @@ class SinkChannelImpl implements SelChImpl { // The SocketChannel assoicated with this pipe - final SocketChannel sc; + private final SocketChannelImpl sc; public FileDescriptor getFD() { - return ((SocketChannelImpl)sc).getFD(); + return sc.getFD(); } public int getFDVal() { - return ((SocketChannelImpl)sc).getFDVal(); + return sc.getFDVal(); } SinkChannelImpl(SelectorProvider sp, SocketChannel sc) { super(sp); - this.sc = sc; + this.sc = (SocketChannelImpl) sc; + } + + boolean isNetSocket() { + return sc.isNetSocket(); + } + + void setOption(SocketOption name, T value) throws IOException { + sc.setOption(name, value); } protected void implCloseSelectableChannel() throws IOException { diff --git a/src/java.base/windows/classes/sun/nio/ch/UnixDomainSocketsUtil.java b/src/java.base/windows/classes/sun/nio/ch/UnixDomainSocketsUtil.java new file mode 100644 index 00000000000..ff1507f5931 --- /dev/null +++ b/src/java.base/windows/classes/sun/nio/ch/UnixDomainSocketsUtil.java @@ -0,0 +1,68 @@ +/* + * 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.nio.ch; + +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.security.AccessController; +import java.security.PrivilegedAction; +import sun.net.NetProperties; +import jdk.internal.util.StaticProperty; + +class UnixDomainSocketsUtil { + private UnixDomainSocketsUtil() { } + + static Charset getCharset() { + return StandardCharsets.UTF_8; + } + + /** + * Return the temp directory for storing automatically bound + * server sockets. + * + * On Windows we search the following directories in sequence: + * + * 1. ${jdk.net.unixdomain.tmpdir} if set as system property + * 2. ${jdk.net.unixdomain.tmpdir} if set as net property + * 3. %TEMP% + * 4. ${java.io.tmpdir} + */ + static String getTempDir() { + PrivilegedAction action = () -> { + String s = NetProperties.get("jdk.net.unixdomain.tmpdir"); + if (s != null) { + return s; + } + String temp = System.getenv("TEMP"); + if (temp != null) { + return temp; + } + return StaticProperty.javaIoTmpDir(); + }; + return AccessController.doPrivileged(action); + } +} + diff --git a/src/java.base/windows/classes/sun/nio/ch/WindowsSelectorImpl.java b/src/java.base/windows/classes/sun/nio/ch/WindowsSelectorImpl.java index f5f73da1eec..328437cefb9 100644 --- a/src/java.base/windows/classes/sun/nio/ch/WindowsSelectorImpl.java +++ b/src/java.base/windows/classes/sun/nio/ch/WindowsSelectorImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2020, 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,6 +30,7 @@ import java.nio.channels.Pipe; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; +import java.nio.channels.SelectableChannel; import java.nio.channels.spi.SelectorProvider; import java.util.ArrayDeque; import java.util.ArrayList; @@ -139,14 +140,9 @@ private static final class MapEntry { WindowsSelectorImpl(SelectorProvider sp) throws IOException { super(sp); pollWrapper = new PollArrayWrapper(INIT_CAP); - wakeupPipe = Pipe.open(); + wakeupPipe = new PipeImpl(sp, false); wakeupSourceFd = ((SelChImpl)wakeupPipe.source()).getFDVal(); - - // Disable the Nagle algorithm so that the wakeup is more immediate - SinkChannelImpl sink = (SinkChannelImpl)wakeupPipe.sink(); - (sink.sc).socket().setTcpNoDelay(true); - wakeupSinkFd = ((SelChImpl)sink).getFDVal(); - + wakeupSinkFd = ((SelChImpl)wakeupPipe.sink()).getFDVal(); pollWrapper.addWakeupSocket(wakeupSourceFd, 0); } @@ -413,19 +409,19 @@ private int processFDSet(long updateCount, // processDeregisterQueue. if (me == null) continue; - SelectionKeyImpl sk = me.ski; + SelectionKeyImpl ski = me.ski; // The descriptor may be in the exceptfds set because there is // OOB data queued to the socket. If there is OOB data then it // is discarded and the key is not added to the selected set. - if (isExceptFds && - (sk.channel() instanceof SocketChannelImpl) && - discardUrgentData(desc)) - { + SelectableChannel sc = ski.channel(); + if (isExceptFds && (sc instanceof SocketChannelImpl) + && ((SocketChannelImpl) sc).isNetSocket() + && discardUrgentData(desc)) { continue; } - int updated = processReadyEvents(rOps, sk, action); + int updated = processReadyEvents(rOps, ski, action); if (updated > 0 && me.updateCount != updateCount) { me.updateCount = updateCount; numKeysUpdated++; diff --git a/src/java.base/windows/classes/sun/nio/fs/WindowsFileSystemProvider.java b/src/java.base/windows/classes/sun/nio/fs/WindowsFileSystemProvider.java index ad3ec2d7e3c..0435e17c1b5 100644 --- a/src/java.base/windows/classes/sun/nio/fs/WindowsFileSystemProvider.java +++ b/src/java.base/windows/classes/sun/nio/fs/WindowsFileSystemProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,6 +28,7 @@ import java.nio.file.*; import java.nio.file.attribute.*; import java.nio.channels.*; +import java.nio.charset.StandardCharsets; import java.net.URI; import java.util.concurrent.ExecutorService; import java.io.*; @@ -622,4 +623,12 @@ public Path readSymbolicLink(Path obj1) throws IOException { String target = WindowsLinkSupport.readLink(link); return WindowsPath.createFromNormalizedPath(fs, target); } + + @Override + public byte[] getSunPathForSocketFile(Path obj) { + WindowsPath file = WindowsPath.toWindowsPath(obj); + String s = file.toString(); + return s.getBytes(StandardCharsets.UTF_8); + } + } diff --git a/src/java.base/windows/conf/net.properties b/src/java.base/windows/conf/net.properties new file mode 100644 index 00000000000..04598400a5e --- /dev/null +++ b/src/java.base/windows/conf/net.properties @@ -0,0 +1,19 @@ +# +# Default directory where automatically bound Unix domain server +# sockets are stored. Sockets are automatically bound when bound +# with a null address. +# +# The search order for the directory on Windows is: +# +# 1. System property "jdk.net.unixdomain.tmpdir" +# +# 2. Networking property "jdk.net.unixdomain.tmpdir" specified +# in this file (not set by default) +# +# 3. The TEMP environment variable (the effective default) +# +# 4. The java.io.tmpdir system property +# +#jdk.net.unixdomain.tmpdir= +# + diff --git a/src/java.base/windows/native/libnio/ch/UnixDomainSockets.c b/src/java.base/windows/native/libnio/ch/UnixDomainSockets.c new file mode 100644 index 00000000000..1869009a1f9 --- /dev/null +++ b/src/java.base/windows/native/libnio/ch/UnixDomainSockets.c @@ -0,0 +1,196 @@ +/* + * Copyright (c) 2020, 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. + */ + +#include +#include + +#include "jni.h" +#include "jni_util.h" +#include "jvm.h" +#include "jlong.h" +#include "nio.h" +#include "nio_util.h" +#include "net_util.h" + +#include "java_net_InetAddress.h" +#include "sun_nio_ch_Net.h" +#include "sun_nio_ch_PollArrayWrapper.h" + +jbyteArray sockaddrToUnixAddressBytes(JNIEnv *env, struct sockaddr_un *sa, socklen_t len) +{ + if (sa->sun_family == AF_UNIX) { + int namelen = (int)strlen(sa->sun_path); + jbyteArray name = (*env)->NewByteArray(env, namelen); + if (name != NULL) { + (*env)->SetByteArrayRegion(env, name, 0, namelen, (jbyte*)sa->sun_path); + if ((*env)->ExceptionOccurred(env)) { + return NULL; + } + } + return name; + } + return NULL; +} + +jint unixSocketAddressToSockaddr(JNIEnv *env, jbyteArray addr, struct sockaddr_un *sa, int *len) +{ + memset(sa, 0, sizeof(struct sockaddr_un)); + sa->sun_family = AF_UNIX; + if (addr == 0L) { + /* Do explicit bind on Windows */ + *len = (int)(offsetof(struct sockaddr_un, sun_path)); + return 0; + } + int ret; + jboolean isCopy; + char *pname = (*env)->GetByteArrayElements(env, addr, &isCopy); + if (pname == NULL) { + JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Unix domain path not present"); + return -1; + } + + size_t name_len = (size_t)(*env)->GetArrayLength(env, addr); + if (name_len > MAX_UNIX_DOMAIN_PATH_LEN) { + JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "Unix domain path too long"); + ret = -1; + } else { + strncpy(sa->sun_path, pname, name_len); + *len = (int)(offsetof(struct sockaddr_un, sun_path) + name_len); + ret = 0; + } + (*env)->ReleaseByteArrayElements(env, addr, pname, JNI_ABORT); + return ret; +} + +JNIEXPORT jboolean JNICALL +Java_sun_nio_ch_UnixDomainSockets_socketSupported(JNIEnv *env, jclass cl) +{ + SOCKET s = socket(PF_UNIX, SOCK_STREAM, 0); + if (s == INVALID_SOCKET) { + return JNI_FALSE; + } + closesocket(s); + return JNI_TRUE; +} + +JNIEXPORT jint JNICALL +Java_sun_nio_ch_UnixDomainSockets_socket0(JNIEnv *env, jclass cl) +{ + SOCKET s = socket(PF_UNIX, SOCK_STREAM, 0); + if (s == INVALID_SOCKET) { + return handleSocketError(env, WSAGetLastError()); + } + SetHandleInformation((HANDLE)s, HANDLE_FLAG_INHERIT, 0); + return (int)s; +} + +/** + * Windows does not support auto bind. So, the windows version of unixSocketAddressToSockaddr + * looks out for a null 'uaddr' and handles it specially + */ +JNIEXPORT void JNICALL +Java_sun_nio_ch_UnixDomainSockets_bind0(JNIEnv *env, jclass clazz, jobject fdo, jbyteArray addr) +{ + struct sockaddr_un sa; + int sa_len = 0; + int rv = 0; + + if (unixSocketAddressToSockaddr(env, addr, &sa, &sa_len) != 0) + return; + + rv = bind(fdval(env, fdo), (struct sockaddr *)&sa, sa_len); + if (rv == SOCKET_ERROR) { + int err = WSAGetLastError(); + NET_ThrowNew(env, err, "bind"); + } +} + +JNIEXPORT jint JNICALL +Java_sun_nio_ch_UnixDomainSockets_connect0(JNIEnv *env, jclass clazz, jobject fdo, jbyteArray addr) +{ + struct sockaddr_un sa; + int sa_len = 0; + int rv; + + if (unixSocketAddressToSockaddr(env, addr, &sa, &sa_len) != 0) { + return IOS_THROWN; + } + + rv = connect(fdval(env, fdo), (const struct sockaddr *)&sa, sa_len); + if (rv != 0) { + int err = WSAGetLastError(); + if (err == WSAEINPROGRESS || err == WSAEWOULDBLOCK) { + return IOS_UNAVAILABLE; + } + NET_ThrowNew(env, err, "connect"); + return IOS_THROWN; + } + return 1; +} + +JNIEXPORT jint JNICALL +Java_sun_nio_ch_UnixDomainSockets_accept0(JNIEnv *env, jclass clazz, jobject fdo, jobject newfdo, + jobjectArray array) +{ + jint fd = fdval(env, fdo); + jint newfd; + struct sockaddr_un sa; + socklen_t sa_len = sizeof(sa); + jbyteArray address; + + memset((char *)&sa, 0, sizeof(sa)); + newfd = (jint) accept(fd, (struct sockaddr *)&sa, &sa_len); + if (newfd == INVALID_SOCKET) { + int theErr = (jint)WSAGetLastError(); + if (theErr == WSAEWOULDBLOCK) { + return IOS_UNAVAILABLE; + } + JNU_ThrowIOExceptionWithLastError(env, "Accept failed"); + return IOS_THROWN; + } + + SetHandleInformation((HANDLE)(UINT_PTR)newfd, HANDLE_FLAG_INHERIT, 0); + setfdval(env, newfdo, newfd); + + address = sockaddrToUnixAddressBytes(env, &sa, sa_len); + CHECK_NULL_RETURN(address, IOS_THROWN); + (*env)->SetObjectArrayElement(env, array, 0, address); + + return 1; +} + +JNIEXPORT jbyteArray JNICALL +Java_sun_nio_ch_UnixDomainSockets_localAddress0(JNIEnv *env, jclass clazz, jobject fdo) +{ + struct sockaddr_un sa; + int sa_len = sizeof(sa); + + if (getsockname(fdval(env, fdo), (struct sockaddr *)&sa, &sa_len) == SOCKET_ERROR) { + JNU_ThrowIOExceptionWithLastError(env, "getsockname"); + return NULL; + } + return sockaddrToUnixAddressBytes(env, &sa, sa_len); +} + diff --git a/src/java.base/windows/native/libnio/ch/nio_util.h b/src/java.base/windows/native/libnio/ch/nio_util.h index 8a1cf562e33..750bc4d61df 100644 --- a/src/java.base/windows/native/libnio/ch/nio_util.h +++ b/src/java.base/windows/native/libnio/ch/nio_util.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2020, 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,6 +24,8 @@ */ #include +#include +#include #include "jni.h" @@ -35,6 +37,9 @@ */ #define MAX_BUFFER_SIZE ((128*1024)-1) +#define MAX_UNIX_DOMAIN_PATH_LEN \ + (int)(sizeof(((struct sockaddr_un *)0)->sun_path)-2) + jint fdval(JNIEnv *env, jobject fdo); void setfdval(JNIEnv *env, jobject fdo, jint val); jlong handleval(JNIEnv *env, jobject fdo); @@ -74,3 +79,11 @@ struct iovec { /* POLLCONN must not equal any of the other constants (see winsock2.h). */ #define POLLCONN 0x2000 #endif + +/* Defined in UnixDomainSockets.c */ + +jbyteArray sockaddrToUnixAddressBytes(JNIEnv *env, struct sockaddr_un *sa, socklen_t len); + +jint unixSocketAddressToSockaddr(JNIEnv *env, jbyteArray uaddr, + struct sockaddr_un *sa, int *len); + diff --git a/src/java.compiler/share/classes/javax/lang/model/element/ElementKind.java b/src/java.compiler/share/classes/javax/lang/model/element/ElementKind.java index 28af5334e9f..c16a4c7f978 100644 --- a/src/java.compiler/share/classes/javax/lang/model/element/ElementKind.java +++ b/src/java.compiler/share/classes/javax/lang/model/element/ElementKind.java @@ -109,33 +109,15 @@ public enum ElementKind { MODULE, /** - * {@preview Associated with records, a preview feature of the Java language. - * - * This enum constant is associated with records, a preview - * feature of the Java language. Preview features - * may be removed in a future release, or upgraded to permanent - * features of the Java language.} - * * A record type. - * @since 14 + * @since 16 */ - @jdk.internal.PreviewFeature(feature=jdk.internal.PreviewFeature.Feature.RECORDS, - essentialAPI=false) RECORD, /** - * {@preview Associated with records, a preview feature of the Java language. - * - * This enum constant is associated with records, a preview - * feature of the Java language. Preview features - * may be removed in a future release, or upgraded to permanent - * features of the Java language.} - * * A record component of a {@code record}. - * @since 14 + * @since 16 */ - @jdk.internal.PreviewFeature(feature=jdk.internal.PreviewFeature.Feature.RECORDS, - essentialAPI=false) RECORD_COMPONENT, /** diff --git a/src/java.compiler/share/classes/javax/lang/model/element/ElementVisitor.java b/src/java.compiler/share/classes/javax/lang/model/element/ElementVisitor.java index 440a9e156fe..44635fa62d3 100644 --- a/src/java.compiler/share/classes/javax/lang/model/element/ElementVisitor.java +++ b/src/java.compiler/share/classes/javax/lang/model/element/ElementVisitor.java @@ -211,13 +211,6 @@ default R visitModule(ModuleElement e, P p) { } /** - * {@preview Associated with records, a preview feature of the Java language. - * - * This method is associated with records, a preview - * feature of the Java language. Preview features - * may be removed in a future release, or upgraded to permanent - * features of the Java language.} - * * Visits a record component element. * * @implSpec The default implementation visits a {@code @@ -226,11 +219,8 @@ default R visitModule(ModuleElement e, P p) { * @param e the element to visit * @param p a visitor-specified parameter * @return a visitor-specified result - * @since 14 + * @since 16 */ - @jdk.internal.PreviewFeature(feature=jdk.internal.PreviewFeature.Feature.RECORDS, - essentialAPI=false) - @SuppressWarnings("preview") default R visitRecordComponent(RecordComponentElement e, P p) { return visitUnknown(e, p); } diff --git a/src/java.compiler/share/classes/javax/lang/model/element/RecordComponentElement.java b/src/java.compiler/share/classes/javax/lang/model/element/RecordComponentElement.java index be4bd7c2680..c4e781baade 100644 --- a/src/java.compiler/share/classes/javax/lang/model/element/RecordComponentElement.java +++ b/src/java.compiler/share/classes/javax/lang/model/element/RecordComponentElement.java @@ -26,19 +26,10 @@ package javax.lang.model.element; /** - * {@preview Associated with records, a preview feature of the Java language. - * - * This class is associated with records, a preview - * feature of the Java language. Preview features - * may be removed in a future release, or upgraded to permanent - * features of the Java language.} - * * Represents a record component. * - * @since 14 + * @since 16 */ -@jdk.internal.PreviewFeature(feature=jdk.internal.PreviewFeature.Feature.RECORDS, - essentialAPI=false) public interface RecordComponentElement extends Element { /** * Returns the enclosing element of this record component. diff --git a/src/java.compiler/share/classes/javax/lang/model/element/TypeElement.java b/src/java.compiler/share/classes/javax/lang/model/element/TypeElement.java index 0be3401bbc4..836ad989c35 100644 --- a/src/java.compiler/share/classes/javax/lang/model/element/TypeElement.java +++ b/src/java.compiler/share/classes/javax/lang/model/element/TypeElement.java @@ -180,13 +180,6 @@ public interface TypeElement extends Element, Parameterizable, QualifiedNameable List getTypeParameters(); /** - * {@preview Associated with records, a preview feature of the Java language. - * - * This method is associated with records, a preview - * feature of the Java language. Preview features - * may be removed in a future release, or upgraded to permanent - * features of the Java language.} - * * Returns the record components of this type element in * declaration order. * @@ -196,11 +189,8 @@ public interface TypeElement extends Element, Parameterizable, QualifiedNameable * @return the record components, or an empty list if there are * none * - * @since 14 + * @since 16 */ - @jdk.internal.PreviewFeature(feature=jdk.internal.PreviewFeature.Feature.RECORDS, - essentialAPI=false) - @SuppressWarnings("preview") default List getRecordComponents() { return List.of(); } diff --git a/src/java.compiler/share/classes/javax/lang/model/util/AbstractElementVisitor14.java b/src/java.compiler/share/classes/javax/lang/model/util/AbstractElementVisitor14.java index 051479f9208..3f0126b2ce1 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/AbstractElementVisitor14.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/AbstractElementVisitor14.java @@ -31,13 +31,6 @@ import static javax.lang.model.SourceVersion.*; /** - * {@preview Associated with records, a preview feature of the Java language. - * - * This class is associated with records, a preview - * feature of the Java language. Preview features - * may be removed in a future release, or upgraded to permanent - * features of the Java language.} - * * A skeletal visitor of program elements with default behavior * appropriate for the {@link SourceVersion#RELEASE_14 RELEASE_14} * source version. @@ -54,10 +47,8 @@ * @see AbstractElementVisitor7 * @see AbstractElementVisitor8 * @see AbstractElementVisitor9 - * @since 14 + * @since 16 */ -@jdk.internal.PreviewFeature(feature=jdk.internal.PreviewFeature.Feature.RECORDS, - essentialAPI=false) @SupportedSourceVersion(RELEASE_16) public abstract class AbstractElementVisitor14 extends AbstractElementVisitor9 { /** @@ -77,7 +68,6 @@ protected AbstractElementVisitor14(){ * @param p {@inheritDoc} * @return {@inheritDoc} */ - @SuppressWarnings("preview") @Override public abstract R visitRecordComponent(RecordComponentElement t, P p); } diff --git a/src/java.compiler/share/classes/javax/lang/model/util/ElementFilter.java b/src/java.compiler/share/classes/javax/lang/model/util/ElementFilter.java index 7cb58c943a9..270074f0d52 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/ElementFilter.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/ElementFilter.java @@ -112,42 +112,22 @@ private ElementFilter() {} // Do not instantiate. } /** - * {@preview Associated with records, a preview feature of the Java language. - * - * This method is associated with records, a preview - * feature of the Java language. Preview features - * may be removed in a future release, or upgraded to permanent - * features of the Java language.} - * * Returns a list of record components in {@code elements}. * @return a list of record components in {@code elements} * @param elements the elements to filter - * @since 14 + * @since 16 */ - @jdk.internal.PreviewFeature(feature=jdk.internal.PreviewFeature.Feature.RECORDS, - essentialAPI=false) - @SuppressWarnings("preview") public static List recordComponentsIn(Iterable elements) { return listFilter(elements, RECORD_COMPONENT_KIND, RecordComponentElement.class); } /** - * {@preview Associated with records, a preview feature of the Java language. - * - * This method is associated with records, a preview - * feature of the Java language. Preview features - * may be removed in a future release, or upgraded to permanent - * features of the Java language.} - * * Returns a set of record components in {@code elements}. * @return a set of record components in {@code elements} * @param elements the elements to filter - * @since 14 + * @since 16 */ - @jdk.internal.PreviewFeature(feature=jdk.internal.PreviewFeature.Feature.RECORDS, - essentialAPI=false) - @SuppressWarnings("preview") public static Set recordComponentsIn(Set elements) { return setFilter(elements, RECORD_COMPONENT_KIND, RecordComponentElement.class); diff --git a/src/java.compiler/share/classes/javax/lang/model/util/ElementKindVisitor14.java b/src/java.compiler/share/classes/javax/lang/model/util/ElementKindVisitor14.java index 1e7c92e1567..fd96c6ecad6 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/ElementKindVisitor14.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/ElementKindVisitor14.java @@ -31,13 +31,6 @@ import javax.lang.model.SourceVersion; /** - * {@preview Associated with records, a preview feature of the Java language. - * - * This class is associated with records, a preview - * feature of the Java language. Preview features - * may be removed in a future release, or upgraded to permanent - * features of the Java language.} - * * A visitor of program elements based on their {@linkplain * ElementKind kind} with default behavior appropriate for the {@link * SourceVersion#RELEASE_14 RELEASE_14} source version. @@ -66,10 +59,8 @@ * @see ElementKindVisitor7 * @see ElementKindVisitor8 * @see ElementKindVisitor9 - * @since 14 + * @since 16 */ -@jdk.internal.PreviewFeature(feature=jdk.internal.PreviewFeature.Feature.RECORDS, - essentialAPI=false) @SupportedSourceVersion(RELEASE_16) public class ElementKindVisitor14 extends ElementKindVisitor9 { /** @@ -99,7 +90,6 @@ protected ElementKindVisitor14(R defaultValue) { * @param p a visitor-specified parameter * @return the result of {@code defaultAction} */ - @SuppressWarnings("preview") @Override public R visitRecordComponent(RecordComponentElement e, P p) { return defaultAction(e, p); diff --git a/src/java.compiler/share/classes/javax/lang/model/util/ElementKindVisitor6.java b/src/java.compiler/share/classes/javax/lang/model/util/ElementKindVisitor6.java index 356accba1e0..3d40feed869 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/ElementKindVisitor6.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/ElementKindVisitor6.java @@ -217,13 +217,6 @@ public R visitTypeAsInterface(TypeElement e, P p) { } /** - * {@preview Associated with records, a preview feature of the Java language. - * - * This method is associated with records, a preview - * feature of the Java language. Preview features - * may be removed in a future release, or upgraded to permanent - * features of the Java language.} - * * Visits a {@code RECORD} type element. * * @implSpec This implementation calls {@code visitUnknown}. @@ -232,10 +225,8 @@ public R visitTypeAsInterface(TypeElement e, P p) { * @param p a visitor-specified parameter * @return the result of {@code visitUnknown} * - * @since 14 + * @since 16 */ - @jdk.internal.PreviewFeature(feature=jdk.internal.PreviewFeature.Feature.RECORDS, - essentialAPI=false) public R visitTypeAsRecord(TypeElement e, P p) { return visitUnknown(e, p); } diff --git a/src/java.compiler/share/classes/javax/lang/model/util/ElementScanner14.java b/src/java.compiler/share/classes/javax/lang/model/util/ElementScanner14.java index d0e92f911f5..5e5d484fa83 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/ElementScanner14.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/ElementScanner14.java @@ -33,13 +33,6 @@ import static javax.lang.model.SourceVersion.*; /** - * {@preview Associated with records, a preview feature of the Java language. - * - * This class is associated with records, a preview - * feature of the Java language. Preview features - * may be removed in a future release, or upgraded to permanent - * features of the Java language.} - * * A scanning visitor of program elements with default behavior * appropriate for the {@link SourceVersion#RELEASE_14 RELEASE_14} * source version. @@ -81,10 +74,8 @@ * @see ElementScanner7 * @see ElementScanner8 * @see ElementScanner9 - * @since 14 + * @since 16 */ -@jdk.internal.PreviewFeature(feature=jdk.internal.PreviewFeature.Feature.RECORDS, - essentialAPI=false) @SupportedSourceVersion(RELEASE_16) public class ElementScanner14 extends ElementScanner9 { /** @@ -156,7 +147,6 @@ private List createScanningList(Parameterizable element, * @param p a visitor-specified parameter * @return the result of the scan */ - @SuppressWarnings("preview") @Override public R visitRecordComponent(RecordComponentElement e, P p) { return scan(e.getEnclosedElements(), p); diff --git a/src/java.compiler/share/classes/javax/lang/model/util/Elements.java b/src/java.compiler/share/classes/javax/lang/model/util/Elements.java index ef00175d454..95cb8263afa 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/Elements.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/Elements.java @@ -51,11 +51,30 @@ public interface Elements { /** - * Returns a package given its fully qualified name if the package is unique in the environment. - * If running with modules, all modules in the modules graph are searched for matching packages. - * - * @param name fully qualified package name, or an empty string for an unnamed package - * @return the specified package, or {@code null} if it cannot be uniquely found + * Returns a package given its fully qualified name if the package is uniquely + * determinable in the environment. + * + * If running with modules, packages of the given name are searched in a + * two-stage process: + *

    + *
  • find non-empty packages with the given name returned by + * {@link #getPackageElement(ModuleElement, CharSequence)}, + * where the provided ModuleSymbol is any + * root module, + *
  • + *
  • if the above yields an empty list, search + * {@link #getAllModuleElements() all modules} for observable + * packages with the given name + *
  • + *
+ * + * If this process leads to a list with a single element, + * the single element is returned, otherwise null is returned. + * + * @param name fully qualified package name, + * or an empty string for an unnamed package + * @return the specified package, + * or {@code null} if no package can be uniquely determined. */ PackageElement getPackageElement(CharSequence name); @@ -119,12 +138,29 @@ default Set getAllPackageElements(CharSequence name) { } /** - * Returns a type element given its canonical name if the type element is unique in the environment. - * If running with modules, all modules in the modules graph are searched for matching - * type elements. - * - * @param name the canonical name - * @return the named type element, or {@code null} if it cannot be uniquely found + * Returns a type element given its canonical name if the type element is uniquely + * determinable in the environment. + * + * If running with modules, type elements of the given name are + * searched in a two-stage process: + *
    + *
  • find type elements with the given name returned by + * {@link #getTypeElement(ModuleElement, CharSequence)}, + * where the provided ModuleSymbol is any + * root module, + *
  • + *
  • if the above yields an empty list, search + * {@link #getAllModuleElements() all modules} for observable + * type elements with the given name + *
  • + *
+ * + * If this process leads to a list with a single element, + * the single element is returned, otherwise null is returned. + * + * @param name the canonical name + * @return the named type element, + * or {@code null} if no type element can be uniquely determined. */ TypeElement getTypeElement(CharSequence name); @@ -632,13 +668,6 @@ boolean overrides(ExecutableElement overrider, ExecutableElement overridden, boolean isFunctionalInterface(TypeElement type); /** - * {@preview Associated with records, a preview feature of the Java language. - * - * This method is associated with records, a preview - * feature of the Java language. Preview features - * may be removed in a future release, or upgraded to permanent - * features of the Java language.} - * * Returns the record component for the given accessor. Returns null if the * given method is not a record component accessor. * @@ -653,11 +682,8 @@ boolean overrides(ExecutableElement overrider, ExecutableElement overridden, * @param accessor the method for which the record component should be found. * @return the record component, or null if the given method is not an record * component accessor - * @since 14 + * @since 16 */ - @jdk.internal.PreviewFeature(feature=jdk.internal.PreviewFeature.Feature.RECORDS, - essentialAPI=false) - @SuppressWarnings("preview") default RecordComponentElement recordComponentFor(ExecutableElement accessor) { if (accessor.getEnclosingElement().getKind() == ElementKind.RECORD) { for (RecordComponentElement rec : ElementFilter.recordComponentsIn(accessor.getEnclosingElement().getEnclosedElements())) { diff --git a/src/java.compiler/share/classes/javax/lang/model/util/SimpleElementVisitor14.java b/src/java.compiler/share/classes/javax/lang/model/util/SimpleElementVisitor14.java index 5d0768eb0b0..9150f27d0fe 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/SimpleElementVisitor14.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/SimpleElementVisitor14.java @@ -31,13 +31,6 @@ import static javax.lang.model.SourceVersion.*; /** - * {@preview Associated with records, a preview feature of the Java language. - * - * This class is associated with records, a preview - * feature of the Java language. Preview features - * may be removed in a future release, or upgraded to permanent - * features of the Java language.} - * * A simple visitor of program elements with default behavior * appropriate for the {@link SourceVersion#RELEASE_14 RELEASE_14} * source version. @@ -62,10 +55,8 @@ * @see SimpleElementVisitor7 * @see SimpleElementVisitor8 * @see SimpleElementVisitor9 - * @since 14 + * @since 16 */ -@jdk.internal.PreviewFeature(feature=jdk.internal.PreviewFeature.Feature.RECORDS, - essentialAPI=false) @SupportedSourceVersion(RELEASE_16) public class SimpleElementVisitor14 extends SimpleElementVisitor9 { /** @@ -96,7 +87,6 @@ protected SimpleElementVisitor14(R defaultValue){ * @param p a visitor-specified parameter * @return {@inheritDoc} */ - @SuppressWarnings("preview") @Override public R visitRecordComponent(RecordComponentElement e, P p) { return defaultAction(e, p); diff --git a/src/java.desktop/share/classes/java/awt/Component.java b/src/java.desktop/share/classes/java/awt/Component.java index ad19383cd58..98a8cdc03b7 100644 --- a/src/java.desktop/share/classes/java/awt/Component.java +++ b/src/java.desktop/share/classes/java/awt/Component.java @@ -207,7 +207,7 @@ * * How to Use the Focus Subsystem, * a section in The Java Tutorial, and the - * Focus Specification + * Focus Specification * for more information. * * @author Arthur van Hoff @@ -7651,7 +7651,7 @@ public void requestFocus(FocusEvent.Cause cause) { * @param temporary true if the focus change is temporary, * such as when the window loses the focus; for * more information on temporary focus changes see the - *Focus Specification + *Focus Specification * @return {@code false} if the focus change request is guaranteed to * fail; {@code true} if it is likely to succeed * @see java.awt.event.FocusEvent @@ -7719,7 +7719,7 @@ protected boolean requestFocus(boolean temporary) { * @param temporary true if the focus change is temporary, * such as when the window loses the focus; for * more information on temporary focus changes see the - *Focus Specification + *Focus Specification * * @param cause the cause why the focus is requested * @return {@code false} if the focus change request is guaranteed to @@ -7886,7 +7886,7 @@ public boolean requestFocusInWindow(FocusEvent.Cause cause) { * @param temporary true if the focus change is temporary, * such as when the window loses the focus; for * more information on temporary focus changes see the - *Focus Specification + *Focus Specification * @return {@code false} if the focus change request is guaranteed to * fail; {@code true} if it is likely to succeed * @see #requestFocus diff --git a/src/java.desktop/share/classes/java/awt/Container.java b/src/java.desktop/share/classes/java/awt/Container.java index ee754201f5e..557111c07d3 100644 --- a/src/java.desktop/share/classes/java/awt/Container.java +++ b/src/java.desktop/share/classes/java/awt/Container.java @@ -83,7 +83,7 @@ * * How to Use the Focus Subsystem, * a section in The Java Tutorial, and the - * Focus Specification + * Focus Specification * for more information. * * @author Arthur van Hoff diff --git a/src/java.desktop/share/classes/java/awt/DefaultFocusTraversalPolicy.java b/src/java.desktop/share/classes/java/awt/DefaultFocusTraversalPolicy.java index 4a9e10166fa..ebfa17302ee 100644 --- a/src/java.desktop/share/classes/java/awt/DefaultFocusTraversalPolicy.java +++ b/src/java.desktop/share/classes/java/awt/DefaultFocusTraversalPolicy.java @@ -57,7 +57,7 @@ * * How to Use the Focus Subsystem, * a section in The Java Tutorial, and the - * Focus Specification + * Focus Specification * for more information. * * @author David Mendenhall diff --git a/src/java.desktop/share/classes/java/awt/DefaultKeyboardFocusManager.java b/src/java.desktop/share/classes/java/awt/DefaultKeyboardFocusManager.java index de60e1e747c..47ddefaabd2 100644 --- a/src/java.desktop/share/classes/java/awt/DefaultKeyboardFocusManager.java +++ b/src/java.desktop/share/classes/java/awt/DefaultKeyboardFocusManager.java @@ -52,7 +52,7 @@ * * How to Use the Focus Subsystem, * a section in The Java Tutorial, and the - * Focus Specification + * Focus Specification * for more information. * * @author David Mendenhall diff --git a/src/java.desktop/share/classes/java/awt/EventQueue.java b/src/java.desktop/share/classes/java/awt/EventQueue.java index 9ee82f2e2f0..0e19ab5483a 100644 --- a/src/java.desktop/share/classes/java/awt/EventQueue.java +++ b/src/java.desktop/share/classes/java/awt/EventQueue.java @@ -95,7 +95,7 @@ * @since 1.1 */ public class EventQueue { - private static final AtomicInteger threadInitNumber = new AtomicInteger(0); + private static final AtomicInteger threadInitNumber = new AtomicInteger(); private static final int LOW_PRIORITY = 0; private static final int NORM_PRIORITY = 1; diff --git a/src/java.desktop/share/classes/java/awt/FocusTraversalPolicy.java b/src/java.desktop/share/classes/java/awt/FocusTraversalPolicy.java index 9bcc326771f..551de6a89b8 100644 --- a/src/java.desktop/share/classes/java/awt/FocusTraversalPolicy.java +++ b/src/java.desktop/share/classes/java/awt/FocusTraversalPolicy.java @@ -52,7 +52,7 @@ * * How to Use the Focus Subsystem, * a section in The Java Tutorial, and the - * Focus Specification + * Focus Specification * for more information. * * @author David Mendenhall diff --git a/src/java.desktop/share/classes/java/awt/KeyboardFocusManager.java b/src/java.desktop/share/classes/java/awt/KeyboardFocusManager.java index f6079ede2ec..b317513756a 100644 --- a/src/java.desktop/share/classes/java/awt/KeyboardFocusManager.java +++ b/src/java.desktop/share/classes/java/awt/KeyboardFocusManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2020, 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 @@ -88,7 +88,7 @@ * * How to Use the Focus Subsystem, * a section in The Java Tutorial, and the - * Focus Specification + * Focus Specification * for more information. * * @author David Mendenhall diff --git a/src/java.desktop/share/classes/java/awt/color/ColorSpace.java b/src/java.desktop/share/classes/java/awt/color/ColorSpace.java index 24978e1917f..ecb40c2844f 100644 --- a/src/java.desktop/share/classes/java/awt/color/ColorSpace.java +++ b/src/java.desktop/share/classes/java/awt/color/ColorSpace.java @@ -102,12 +102,12 @@ public abstract class ColorSpace implements Serializable { /** * One of the {@code ColorSpace} type constants. */ - private int type; + private final int type; /** * The number of components in the color space. */ - private int numComponents; + private final int numComponents; private transient String [] compName = null; // Cache of singletons for the predefined color spaces. @@ -242,6 +242,7 @@ public abstract class ColorSpace implements Serializable { */ @Native public static final int TYPE_FCLR = 25; + /** * The sRGB color space defined at * @@ -275,11 +276,11 @@ public abstract class ColorSpace implements Serializable { * number of components. * * @param type one of the {@code ColorSpace} type constants - * @param numcomponents the number of components in the color space + * @param numComponents the number of components in the color space */ - protected ColorSpace(int type, int numcomponents) { + protected ColorSpace(int type, int numComponents) { this.type = type; - this.numComponents = numcomponents; + this.numComponents = numComponents; } /** @@ -441,8 +442,8 @@ public boolean isCS_sRGB () { * {@link ICC_ColorSpace#toCIEXYZ(float[]) toCIEXYZ} method of * {@code ICC_ColorSpace} for further information. * - * @param colorvalue a float array with length of at least the number of - * components in this {@code ColorSpace} + * @param colorvalue a float array with length of at least the number of + * components in this {@code ColorSpace} * @return a float array of length 3 * @throws ArrayIndexOutOfBoundsException if array length is not at least * the number of components in this {@code ColorSpace}. @@ -508,11 +509,7 @@ public int getNumComponents() { */ public String getName (int idx) { /* REMIND - handle common cases here */ - if ((idx < 0) || (idx > numComponents - 1)) { - throw new IllegalArgumentException( - "Component index out of range: " + idx); - } - + rangeCheck(idx); if (compName == null) { switch (type) { case ColorSpace.TYPE_XYZ: @@ -573,10 +570,7 @@ public String getName (int idx) { * @since 1.4 */ public float getMinValue(int component) { - if ((component < 0) || (component > numComponents - 1)) { - throw new IllegalArgumentException( - "Component index out of range: " + component); - } + rangeCheck(component); return 0.0f; } @@ -592,17 +586,21 @@ public float getMinValue(int component) { * @since 1.4 */ public float getMaxValue(int component) { - if ((component < 0) || (component > numComponents - 1)) { - throw new IllegalArgumentException( - "Component index out of range: " + component); - } + rangeCheck(component); return 1.0f; } - /* - * Returns {@code true} if {@code cspace} is the XYZspace. + /** + * Checks that {@code component} is in range of the number of components. + * + * @param component the component index + * @throws IllegalArgumentException if component is less than 0 or greater + * than {@code numComponents - 1} */ - static boolean isCS_CIEXYZ(ColorSpace cspace) { - return (cspace == XYZspace); + final void rangeCheck(int component) { + if (component < 0 || component > getNumComponents() - 1) { + throw new IllegalArgumentException( + "Component index out of range: " + component); + } } } diff --git a/src/java.desktop/share/classes/java/awt/color/ICC_ColorSpace.java b/src/java.desktop/share/classes/java/awt/color/ICC_ColorSpace.java index 6b399f66723..73b5f1ebb92 100644 --- a/src/java.desktop/share/classes/java/awt/color/ICC_ColorSpace.java +++ b/src/java.desktop/share/classes/java/awt/color/ICC_ColorSpace.java @@ -569,10 +569,7 @@ public float[] fromCIEXYZ(float[] colorvalue) { * @since 1.4 */ public float getMinValue(int component) { - if ((component < 0) || (component > this.getNumComponents() - 1)) { - throw new IllegalArgumentException( - "Component index out of range: " + component); - } + rangeCheck(component); return minVal[component]; } @@ -595,10 +592,7 @@ public float getMinValue(int component) { * @since 1.4 */ public float getMaxValue(int component) { - if ((component < 0) || (component > this.getNumComponents() - 1)) { - throw new IllegalArgumentException( - "Component index out of range: " + component); - } + rangeCheck(component); return maxVal[component]; } diff --git a/src/java.desktop/share/classes/java/awt/color/ICC_ProfileGray.java b/src/java.desktop/share/classes/java/awt/color/ICC_ProfileGray.java index 66cc81ac8f8..fdc6b51c060 100644 --- a/src/java.desktop/share/classes/java/awt/color/ICC_ProfileGray.java +++ b/src/java.desktop/share/classes/java/awt/color/ICC_ProfileGray.java @@ -115,10 +115,7 @@ public float[] getMediaWhitePoint() { * single gamma value */ public float getGamma() { - float theGamma; - - theGamma = super.getGamma(ICC_Profile.icSigGrayTRCTag); - return theGamma; + return getGamma(ICC_Profile.icSigGrayTRCTag); } /** @@ -140,10 +137,6 @@ public float getGamma() { * table */ public short[] getTRC() { - short[] theTRC; - - theTRC = super.getTRC(ICC_Profile.icSigGrayTRCTag); - return theTRC; + return getTRC(ICC_Profile.icSigGrayTRCTag); } - } diff --git a/src/java.desktop/share/classes/java/awt/color/ICC_ProfileRGB.java b/src/java.desktop/share/classes/java/awt/color/ICC_ProfileRGB.java index 12827c0b465..a316b98522e 100644 --- a/src/java.desktop/share/classes/java/awt/color/ICC_ProfileRGB.java +++ b/src/java.desktop/share/classes/java/awt/color/ICC_ProfileRGB.java @@ -103,7 +103,7 @@ public class ICC_ProfileRGB extends ICC_Profile { /** * Constructs an new {@code ICC_ProfileRGB} from a CMM ID. * - * @param p the CMM ID for the profile. + * @param p the CMM ID for the profile. */ ICC_ProfileRGB(Profile p) { super(p); @@ -113,7 +113,7 @@ public class ICC_ProfileRGB extends ICC_Profile { * Constructs a new {@code ICC_ProfileRGB} from a * {@code ProfileDeferralInfo} object. * - * @param pdi + * @param pdi */ ICC_ProfileRGB(ProfileDeferralInfo pdi) { super(pdi); @@ -143,22 +143,12 @@ public float[] getMediaWhitePoint() { * {@code greenColorantTag}, and {@code blueColorantTag} */ public float[][] getMatrix() { - float[][] theMatrix = new float[3][3]; - float[] tmpMatrix; - - tmpMatrix = getXYZTag(ICC_Profile.icSigRedColorantTag); - theMatrix[0][0] = tmpMatrix[0]; - theMatrix[1][0] = tmpMatrix[1]; - theMatrix[2][0] = tmpMatrix[2]; - tmpMatrix = getXYZTag(ICC_Profile.icSigGreenColorantTag); - theMatrix[0][1] = tmpMatrix[0]; - theMatrix[1][1] = tmpMatrix[1]; - theMatrix[2][1] = tmpMatrix[2]; - tmpMatrix = getXYZTag(ICC_Profile.icSigBlueColorantTag); - theMatrix[0][2] = tmpMatrix[0]; - theMatrix[1][2] = tmpMatrix[1]; - theMatrix[2][2] = tmpMatrix[2]; - return theMatrix; + float[] red = getXYZTag(ICC_Profile.icSigRedColorantTag); + float[] green = getXYZTag(ICC_Profile.icSigGreenColorantTag); + float[] blue = getXYZTag(ICC_Profile.icSigBlueColorantTag); + return new float[][]{{red[0], green[0], blue[0]}, + {red[1], green[1], blue[1]}, + {red[2], green[2], blue[2]}}; } /** @@ -181,33 +171,14 @@ public float[][] getMatrix() { * @param component the {@code ICC_ProfileRGB} constant that represents the * component whose TRC you want to retrieve * @return the gamma value as a float + * @throws IllegalArgumentException if the component is not + * {@code REDCOMPONENT}, {@code GREENCOMPONENT}, or + * {@code BLUECOMPONENT} * @throws ProfileDataException if the profile does not specify the * corresponding TRC as a single gamma value */ public float getGamma(int component) { - float theGamma; - int theSignature; - - switch (component) { - case REDCOMPONENT: - theSignature = ICC_Profile.icSigRedTRCTag; - break; - - case GREENCOMPONENT: - theSignature = ICC_Profile.icSigGreenTRCTag; - break; - - case BLUECOMPONENT: - theSignature = ICC_Profile.icSigBlueTRCTag; - break; - - default: - throw new IllegalArgumentException("Must be Red, Green, or Blue"); - } - - theGamma = super.getGamma(theSignature); - - return theGamma; + return super.getGamma(toTag(component)); } /** @@ -232,33 +203,32 @@ public float getGamma(int component) { * component whose TRC you want to retrieve: {@code REDCOMPONENT}, * {@code GREENCOMPONENT}, or {@code BLUECOMPONENT} * @return a short array representing the TRC + * @throws IllegalArgumentException if the component is not + * {@code REDCOMPONENT}, {@code GREENCOMPONENT}, or + * {@code BLUECOMPONENT} * @throws ProfileDataException if the profile does not specify the * corresponding TRC as a table */ public short[] getTRC(int component) { - short[] theTRC; - int theSignature; - - switch (component) { - case REDCOMPONENT: - theSignature = ICC_Profile.icSigRedTRCTag; - break; - - case GREENCOMPONENT: - theSignature = ICC_Profile.icSigGreenTRCTag; - break; - - case BLUECOMPONENT: - theSignature = ICC_Profile.icSigBlueTRCTag; - break; - - default: - throw new IllegalArgumentException("Must be Red, Green, or Blue"); - } - - theTRC = super.getTRC(theSignature); - - return theTRC; + return super.getTRC(toTag(component)); } + /** + * Converts the {@code ICC_ProfileRGB} constant to the appropriate tag. + * + * @param component the {@code ICC_ProfileRGB} constant + * @return the tag signature + * @throws IllegalArgumentException if the component is not + * {@code REDCOMPONENT}, {@code GREENCOMPONENT}, or + * {@code BLUECOMPONENT} + */ + private static int toTag(int component) { + return switch (component) { + case REDCOMPONENT -> ICC_Profile.icSigRedTRCTag; + case GREENCOMPONENT -> ICC_Profile.icSigGreenTRCTag; + case BLUECOMPONENT -> ICC_Profile.icSigBlueTRCTag; + default -> throw new IllegalArgumentException( + "Must be Red, Green, or Blue"); + }; + } } diff --git a/src/java.desktop/share/classes/java/awt/doc-files/DesktopProperties.html b/src/java.desktop/share/classes/java/awt/doc-files/DesktopProperties.html index e6790a53bcf..1e68b086e4e 100644 --- a/src/java.desktop/share/classes/java/awt/doc-files/DesktopProperties.html +++ b/src/java.desktop/share/classes/java/awt/doc-files/DesktopProperties.html @@ -36,8 +36,8 @@

AWT Desktop Properties

The following refers to standard AWT desktop properties that may be obtained via the -
-Toolkit.getDesktopProperty method. +{@link java.awt.Toolkit#getDesktopProperty(java.lang.String) +Toolkit.getDesktopProperty} method.

Each desktop property is named by a unique string, which is the "name" of that property. @@ -86,9 +86,9 @@

Desktop Font Rendering Hints

These are applied by platform-specific heavyweight components. However an application may want to render text using the same text antialiasing on a drawing surface or lightweight (non-platform) component using - Graphics2D methods. +{@link java.awt.Graphics2D Graphics2D} methods. This is particularly important when creating - Swing components which +{@link javax.swing.JComponent Swing components} which are required to appear consistent with native desktop components or other Swing components. @@ -97,9 +97,8 @@

Basic Usage

"awt.font.desktophints" can be used to obtain the rendering hints that best match the desktop settings. -The return value is a - Map of - RenderingHints which +The return value is a {@link java.util.Map Map} of +{@link java.awt.RenderingHints RenderingHints} which can be directly applied to a Graphics2D.

It is a Map as more than one hint may be needed. @@ -116,8 +115,7 @@

Advanced Usage Tips

Listening for changes

An application can listen for changes in the property -using a -PropertyChangeListener : +using a {@link java.beans.PropertyChangeListener PropertyChangeListener}:


 tk.addPropertyChangeListener("awt.font.desktophints", pcl);
 
@@ -134,10 +132,10 @@

Listening for changes

Text Measurement

Text always needs to be measured using the same - FontRenderContext +{@link java.awt.font.FontRenderContext FontRenderContext} as used for rendering. The text anti-aliasing hint is a component of the FontRenderContext. -A FontMetrics +A {@link java.awt.FontMetrics FontMetrics} obtained from the Graphics object on which the hint has been set will measure text appropriately. This is not a unique requirement for clients that specify this hint diff --git a/src/java.desktop/share/classes/javax/imageio/metadata/doc-files/tiff_metadata.html b/src/java.desktop/share/classes/javax/imageio/metadata/doc-files/tiff_metadata.html index cfd7fdfa3ca..fc918e78eeb 100644 --- a/src/java.desktop/share/classes/javax/imageio/metadata/doc-files/tiff_metadata.html +++ b/src/java.desktop/share/classes/javax/imageio/metadata/doc-files/tiff_metadata.html @@ -5,7 +5,7 @@ TIFF Metadata Format Specification and Usage Notes @@ -90,7 +90,7 @@

Color Conversion

Color Spaces

The raw color space assigned by default, i.e., in the absence of a -user-supplied ImageTypeSpecifier, +user-supplied {@link javax.imageio.ImageTypeSpecifier ImageTypeSpecifier}, will be the first among the following which applies:
    @@ -158,8 +158,8 @@

    Color Spaces

    ICC Profiles

    If an ICC profile is contained in the image metadata -( -BaselineTIFFTagSet.TAG_ICC_PROFILE, tag number 34675), +({@link javax.imageio.plugins.tiff.BaselineTIFFTagSet BaselineTIFFTagSet}. +TAG_ICC_PROFILE, tag number 34675), an attempt will be made to use it to create the color space of the loaded image. It will be used if the data layout is of component type and the number of samples per pixel equals or is one greater than the number @@ -174,15 +174,13 @@

    ICC Profiles

  • Obtain the image metadata from ImageReader.getImageMetadata
  • Extract the ICC profile field and its value.
  • -
  • Create an -ICC_ColorSpace from an - -ICC_Profile created from the ICC profile field data +
  • Create an {@link java.awt.color.ICC_ColorSpace ICC_ColorSpace} from an +{@link java.awt.color.ICC_Profile ICC_Profile} created from the ICC profile field data using ICC_Profile.getInstance(byte[]).
  • Create an ImageTypeSpecifier from the new color space using one of its factory methods which accepts an ICC_ColorSpace. -
  • Create a compatible ImageReadParam +
  • Create a compatible {@link javax.imageio.ImageReadParam ImageReadParam} and set the ImageTypeSpecifier using ImageReadParam.setDestinationType.
  • Pass the parameter object to the appropriate read method.
  • @@ -206,7 +204,7 @@

    Metadata Issues

    metadata. The reader is informed to disregard all metadata as usual via the ignoreMetadata parameter of ImageReader.setInput(Object,boolean,boolean). It is -informed of which TIFFTags to +informed of which {@link javax.imageio.plugins.tiff.TIFFTag TIFFTag}s to recognize or not to recognize via TIFFImageReadParam.addAllowedTagSet(TIFFTagSet) and TIFFImageReadParam.removeAllowedTagSet(TIFFTagSet). @@ -221,7 +219,7 @@

    Metadata Issues

    TIFFImageReadParam.setReadUnknownTags(boolean) has been invoked with parameter true. -

    Use of a TIFFDirectory +

    Use of a {@link javax.imageio.plugins.tiff.TIFFDirectory TIFFDirectory} object may simplify gaining access to metadata values. An instance of TIFFDirectory may be created from the IIOMetadata object returned by the TIFF reader using the @@ -481,9 +479,9 @@

    Reading Compressed Exif Images

    Writing Images

    -TIFF images are written by a ImageWriter which may be +TIFF images are written by a {@link javax.imageio.ImageWriter ImageWriter} which may be controlled by its public interface as well as via a supplied -ImageWriteParam. For an ImageWriteParam returned +{@link javax.imageio.ImageWriteParam ImageWriteParam}. For an ImageWriteParam returned by the getDefaultWriteParam() method of the TIFF ImageWriter, the canWriteTiles() and canWriteCompressed() methods will return true; the canOffsetTiles() and @@ -631,9 +629,9 @@

    ICC Profiles

    An ICC Profile field will be written if either:
    • one is present in the native image metadata -IIOMetadata instance supplied to the writer, +{@link javax.imageio.metadata.IIOMetadata IIOMetadata} instance supplied to the writer, or
    • -
    • the ColorSpace +
    • the {@link java.awt.color.ColorSpace ColorSpace} of the destination ImageTypeSpecifier is an instance of ICC_ColorSpace which is not one of the standard color spaces defined by the CS_* constants in the @@ -748,7 +746,7 @@

      Metadata Issues

      Setting up the image metadata to write to a TIFF stream may be simplified by using the TIFFDirectory class which represents a TIFF IFD. A field in a TIFF IFD is represented by an -instance of TIFFField. For each +instance of {@link javax.imageio.plugins.tiff.TIFFField TIFFField}. For each field to be written a TIFFField may be added to the TIFFDirectory and the latter converted to an IIOMetadata object by invoking diff --git a/src/java.desktop/share/classes/javax/print/DocFlavor.java b/src/java.desktop/share/classes/javax/print/DocFlavor.java index a52b0e18852..da3f4f18762 100644 --- a/src/java.desktop/share/classes/javax/print/DocFlavor.java +++ b/src/java.desktop/share/classes/javax/print/DocFlavor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2020, 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 @@ -156,9 +156,9 @@ * the primary IANA name but is guaranteed to be understood by this VM. For * common flavors, the pre-defined *HOST {@code DocFlavors} may be used. *

      - * See character - * encodings for more information on the character encodings supported on - * the Java platform. + * See + * character encodings for more information on the character encodings + * supported on the Java platform. * *


      *

      Recommended DocFlavors

      diff --git a/src/java.desktop/share/classes/javax/swing/TimerQueue.java b/src/java.desktop/share/classes/javax/swing/TimerQueue.java index 9160b956e95..85e5b3a6aa1 100644 --- a/src/java.desktop/share/classes/javax/swing/TimerQueue.java +++ b/src/java.desktop/share/classes/javax/swing/TimerQueue.java @@ -248,7 +248,7 @@ static class DelayedTimer implements Delayed { * Sequence number to break scheduling ties, and in turn to * guarantee FIFO order among tied entries. */ - private static final AtomicLong sequencer = new AtomicLong(0); + private static final AtomicLong sequencer = new AtomicLong(); /** Sequence number to break ties FIFO */ private final long sequenceNumber; diff --git a/src/java.desktop/share/classes/sun/awt/AppContext.java b/src/java.desktop/share/classes/sun/awt/AppContext.java index cc4547ddc02..b8d902801a9 100644 --- a/src/java.desktop/share/classes/sun/awt/AppContext.java +++ b/src/java.desktop/share/classes/sun/awt/AppContext.java @@ -208,7 +208,7 @@ public boolean isDisposed() { * number is 1. If so, it returns the sole AppContext without * checking Thread.currentThread(). */ - private static final AtomicInteger numAppContexts = new AtomicInteger(0); + private static final AtomicInteger numAppContexts = new AtomicInteger(); /* diff --git a/src/java.desktop/windows/native/libawt/windows/awt_Clipboard.cpp b/src/java.desktop/windows/native/libawt/windows/awt_Clipboard.cpp index 12f47a2e732..2aadcd5a08c 100644 --- a/src/java.desktop/windows/native/libawt/windows/awt_Clipboard.cpp +++ b/src/java.desktop/windows/native/libawt/windows/awt_Clipboard.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2020, 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,9 +42,7 @@ jobject AwtClipboard::theCurrentClipboard; BOOL AwtClipboard::isGettingOwnership = FALSE; volatile jmethodID AwtClipboard::handleContentsChangedMID; -volatile BOOL AwtClipboard::skipInitialWmDrawClipboardMsg = TRUE; volatile BOOL AwtClipboard::isClipboardViewerRegistered = FALSE; -volatile HWND AwtClipboard::hwndNextViewer = NULL; #define GALLOCFLG (GMEM_DDESHARE | GMEM_MOVEABLE | GMEM_ZEROINIT) @@ -59,27 +57,11 @@ void AwtClipboard::LostOwnership(JNIEnv *env) { } } -void AwtClipboard::WmChangeCbChain(WPARAM wParam, LPARAM lParam) { - if ((HWND)wParam == hwndNextViewer) { - hwndNextViewer = (HWND)lParam; - } else if (hwndNextViewer != NULL) { - ::SendMessage(hwndNextViewer, WM_CHANGECBCHAIN, wParam, lParam); - } -} - -void AwtClipboard::WmDrawClipboard(JNIEnv *env, WPARAM wParam, LPARAM lParam) { - if (skipInitialWmDrawClipboardMsg) { - // skipping the first contents change notification as it comes - // immediately after registering the clipboard viewer window - // and it is not caused by an actual contents change. - skipInitialWmDrawClipboardMsg = FALSE; - return; - } +void AwtClipboard::WmClipboardUpdate(JNIEnv *env) { if (theCurrentClipboard != NULL) { env->CallVoidMethod(theCurrentClipboard, handleContentsChangedMID); DASSERT(!safe_ExceptionOccurred(env)); } - ::SendMessage(hwndNextViewer, WM_DRAWCLIPBOARD, wParam, lParam); } void AwtClipboard::RegisterClipboardViewer(JNIEnv *env, jobject jclipboard) { @@ -96,7 +78,7 @@ void AwtClipboard::RegisterClipboardViewer(JNIEnv *env, jobject jclipboard) { env->GetMethodID(cls, "handleContentsChanged", "()V"); DASSERT(AwtClipboard::handleContentsChangedMID != NULL); - hwndNextViewer = ::SetClipboardViewer(AwtToolkit::GetInstance().GetHWnd()); + ::AddClipboardFormatListener(AwtToolkit::GetInstance().GetHWnd()); isClipboardViewerRegistered = TRUE; } @@ -104,10 +86,8 @@ void AwtClipboard::UnregisterClipboardViewer(JNIEnv *env) { TRY; if (isClipboardViewerRegistered) { - ::ChangeClipboardChain(AwtToolkit::GetInstance().GetHWnd(), AwtClipboard::hwndNextViewer); - AwtClipboard::hwndNextViewer = NULL; + ::RemoveClipboardFormatListener(AwtToolkit::GetInstance().GetHWnd()); isClipboardViewerRegistered = FALSE; - skipInitialWmDrawClipboardMsg = TRUE; } CATCH_BAD_ALLOC; diff --git a/src/java.desktop/windows/native/libawt/windows/awt_Clipboard.h b/src/java.desktop/windows/native/libawt/windows/awt_Clipboard.h index a9e9d71d544..7821dacdb74 100644 --- a/src/java.desktop/windows/native/libawt/windows/awt_Clipboard.h +++ b/src/java.desktop/windows/native/libawt/windows/awt_Clipboard.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2003, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2020, 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,10 +36,7 @@ class AwtClipboard { private: static BOOL isGettingOwnership; - // handle to the next window in the clipboard viewer chain - static volatile HWND hwndNextViewer; static volatile BOOL isClipboardViewerRegistered; - static volatile BOOL skipInitialWmDrawClipboardMsg; static volatile jmethodID handleContentsChangedMID; public: @@ -57,8 +54,7 @@ class AwtClipboard { } static void LostOwnership(JNIEnv *env); - static void WmChangeCbChain(WPARAM wparam, LPARAM lparam); - static void WmDrawClipboard(JNIEnv *env, WPARAM wparam, LPARAM lparam); + static void WmClipboardUpdate(JNIEnv *env); static void RegisterClipboardViewer(JNIEnv *env, jobject jclipboard); static void UnregisterClipboardViewer(JNIEnv *env); }; diff --git a/src/java.desktop/windows/native/libawt/windows/awt_Toolkit.cpp b/src/java.desktop/windows/native/libawt/windows/awt_Toolkit.cpp index 7a7148d888d..1ab9c6f6278 100644 --- a/src/java.desktop/windows/native/libawt/windows/awt_Toolkit.cpp +++ b/src/java.desktop/windows/native/libawt/windows/awt_Toolkit.cpp @@ -1067,12 +1067,8 @@ LRESULT CALLBACK AwtToolkit::WndProc(HWND hWnd, UINT message, AwtClipboard::LostOwnership((JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2)); return 0; } - case WM_CHANGECBCHAIN: { - AwtClipboard::WmChangeCbChain(wParam, lParam); - return 0; - } - case WM_DRAWCLIPBOARD: { - AwtClipboard::WmDrawClipboard((JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2), wParam, lParam); + case WM_CLIPBOARDUPDATE: { + AwtClipboard::WmClipboardUpdate((JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2)); return 0; } case WM_AWT_LIST_SETMULTISELECT: { diff --git a/src/java.logging/share/classes/java/util/logging/LogRecord.java b/src/java.logging/share/classes/java/util/logging/LogRecord.java index af602a2947d..d628d7ffbe1 100644 --- a/src/java.logging/share/classes/java/util/logging/LogRecord.java +++ b/src/java.logging/share/classes/java/util/logging/LogRecord.java @@ -72,7 +72,7 @@ public class LogRecord implements java.io.Serializable { private static final AtomicLong globalSequenceNumber - = new AtomicLong(0); + = new AtomicLong(); /** * Logging message level diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/WindowUpdateSender.java b/src/java.net.http/share/classes/jdk/internal/net/http/WindowUpdateSender.java index e85b92786f6..cc529208a87 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/WindowUpdateSender.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/WindowUpdateSender.java @@ -39,7 +39,7 @@ abstract class WindowUpdateSender { final int limit; final Http2Connection connection; - final AtomicInteger received = new AtomicInteger(0); + final AtomicInteger received = new AtomicInteger(); WindowUpdateSender(Http2Connection connection) { this(connection, connection.clientSettings.getParameter(SettingsFrame.INITIAL_WINDOW_SIZE)); diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/common/SSLFlowDelegate.java b/src/java.net.http/share/classes/jdk/internal/net/http/common/SSLFlowDelegate.java index f81b454181d..573ac85899d 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/common/SSLFlowDelegate.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/common/SSLFlowDelegate.java @@ -375,7 +375,7 @@ void stop() { scheduler.stop(); } - AtomicInteger count = new AtomicInteger(0); + AtomicInteger count = new AtomicInteger(); // minimum number of bytes required to call unwrap. // Usually this is 0, unless there was a buffer underflow. diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/common/SubscriberWrapper.java b/src/java.net.http/share/classes/jdk/internal/net/http/common/SubscriberWrapper.java index f45c4a06352..f9c098a05d5 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/common/SubscriberWrapper.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/common/SubscriberWrapper.java @@ -74,7 +74,7 @@ public enum SchedulingAction { CONTINUE, RETURN, RESCHEDULE } private final CompletableFuture cf; private final SequentialScheduler pushScheduler; private final AtomicReference errorRef = new AtomicReference<>(); - final AtomicLong upstreamWindow = new AtomicLong(0); + final AtomicLong upstreamWindow = new AtomicLong(); /** * Wraps the given downstream subscriber. For each call to {@link diff --git a/src/java.prefs/share/classes/java/util/prefs/Preferences.java b/src/java.prefs/share/classes/java/util/prefs/Preferences.java index 1fe279b9ab8..ff35fde4bd6 100644 --- a/src/java.prefs/share/classes/java/util/prefs/Preferences.java +++ b/src/java.prefs/share/classes/java/util/prefs/Preferences.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2020, 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 @@ -194,7 +194,7 @@ *
        * *
      1. If the system property - * {@code java.util.prefs.PreferencesFactory} is defined, then it is + * {@systemProperty java.util.prefs.PreferencesFactory} is defined, then it is * taken to be the fully-qualified name of a class implementing the * {@code PreferencesFactory} interface. The class is loaded and * instantiated; if this process fails then an unspecified error is diff --git a/src/java.rmi/share/classes/java/rmi/server/ObjID.java b/src/java.rmi/share/classes/java/rmi/server/ObjID.java index 9cd1ff57c46..86179c2ba0f 100644 --- a/src/java.rmi/share/classes/java/rmi/server/ObjID.java +++ b/src/java.rmi/share/classes/java/rmi/server/ObjID.java @@ -84,7 +84,7 @@ public final class ObjID implements Serializable { /** indicate compatibility with JDK 1.1.x version of class */ private static final long serialVersionUID = -6386392263968365220L; - private static final AtomicLong nextObjNum = new AtomicLong(0); + private static final AtomicLong nextObjNum = new AtomicLong(); private static final UID mySpace = new UID(); private static final SecureRandom secureRandom = new SecureRandom(); diff --git a/src/java.rmi/share/classes/sun/rmi/runtime/RuntimeUtil.java b/src/java.rmi/share/classes/sun/rmi/runtime/RuntimeUtil.java index 1eca061def1..98e7df3c90c 100644 --- a/src/java.rmi/share/classes/sun/rmi/runtime/RuntimeUtil.java +++ b/src/java.rmi/share/classes/sun/rmi/runtime/RuntimeUtil.java @@ -30,7 +30,6 @@ import java.security.PrivilegedAction; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.ThreadFactory; -import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.logging.Level; @@ -70,7 +69,7 @@ private RuntimeUtil() { scheduler = new ScheduledThreadPoolExecutor( schedulerThreads, new ThreadFactory() { - private final AtomicInteger count = new AtomicInteger(0); + private final AtomicInteger count = new AtomicInteger(); public Thread newThread(Runnable runnable) { try { return AccessController.doPrivileged( diff --git a/src/java.rmi/share/classes/sun/rmi/server/UnicastServerRef.java b/src/java.rmi/share/classes/sun/rmi/server/UnicastServerRef.java index 06980f17c08..c946ff5be3d 100644 --- a/src/java.rmi/share/classes/sun/rmi/server/UnicastServerRef.java +++ b/src/java.rmi/share/classes/sun/rmi/server/UnicastServerRef.java @@ -128,8 +128,6 @@ public class UnicastServerRef extends UnicastRef private static final Map,?> withoutSkeletons = Collections.synchronizedMap(new WeakHashMap,Void>()); - private final AtomicInteger methodCallIDCount = new AtomicInteger(0); - /** * Create a new (empty) Unicast server remote reference. * The filter is null to defer to the default ObjectInputStream filter, if any. diff --git a/src/java.rmi/share/classes/sun/rmi/transport/tcp/TCPTransport.java b/src/java.rmi/share/classes/sun/rmi/transport/tcp/TCPTransport.java index dd15491f1e3..780943128d6 100644 --- a/src/java.rmi/share/classes/sun/rmi/transport/tcp/TCPTransport.java +++ b/src/java.rmi/share/classes/sun/rmi/transport/tcp/TCPTransport.java @@ -115,7 +115,7 @@ public Thread newThread(Runnable runnable) { }); /** total connections handled */ - private static final AtomicInteger connectionCount = new AtomicInteger(0); + private static final AtomicInteger connectionCount = new AtomicInteger(); /** client host for the current thread's connection */ private static final ThreadLocal diff --git a/src/jdk.compiler/share/classes/com/sun/source/tree/Tree.java b/src/jdk.compiler/share/classes/com/sun/source/tree/Tree.java index f368973b550..24d1305202e 100644 --- a/src/jdk.compiler/share/classes/com/sun/source/tree/Tree.java +++ b/src/jdk.compiler/share/classes/com/sun/source/tree/Tree.java @@ -649,19 +649,9 @@ public enum Kind { PROVIDES(ProvidesTree.class), /** - * {@preview Associated with records, a preview feature of the Java language. - * - * This enum constant is associated with records, a preview - * feature of the Java language. Preview features - * may be removed in a future release, or upgraded to permanent - * features of the Java language.} - * * Used for instances of {@link ClassTree} representing records. - * - * @since 14 + * @since 16 */ - @jdk.internal.PreviewFeature(feature=jdk.internal.PreviewFeature.Feature.RECORDS, - essentialAPI=false) RECORD(ClassTree.class), /** diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Preview.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Preview.java index d79f3f7b51a..b81adaa7583 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Preview.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Preview.java @@ -167,7 +167,6 @@ public boolean isEnabled() { public boolean isPreview(Feature feature) { if (feature == Feature.PATTERN_MATCHING_IN_INSTANCEOF || feature == Feature.REIFIABLE_TYPES_INSTANCEOF || - feature == Feature.RECORDS || feature == Feature.SEALED_CLASSES) return true; //Note: this is a backdoor which allows to optionally treat all features as 'preview' (for testing). diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java index f1725857891..baff49db6d7 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Check.java @@ -159,8 +159,7 @@ protected Check(Context context) { deferredLintHandler = DeferredLintHandler.instance(context); - allowRecords = (!preview.isPreview(Feature.RECORDS) || preview.isEnabled()) && - Feature.RECORDS.allowedInSource(source); + allowRecords = Feature.RECORDS.allowedInSource(source); allowSealed = (!preview.isPreview(Feature.SEALED_CLASSES) || preview.isEnabled()) && Feature.SEALED_CLASSES.allowedInSource(source); } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java index 562e8ab8071..727d2989adf 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java @@ -150,8 +150,7 @@ protected Resolve(Context context) { Feature.POST_APPLICABILITY_VARARGS_ACCESS_CHECK.allowedInSource(source); polymorphicSignatureScope = WriteableScope.create(syms.noSymbol); allowModules = Feature.MODULES.allowedInSource(source); - allowRecords = (!preview.isPreview(Feature.RECORDS) || preview.isEnabled()) && - Feature.RECORDS.allowedInSource(source); + allowRecords = Feature.RECORDS.allowedInSource(source); } /** error symbols, which are returned when resolution fails diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java index a0085a3e6e1..4528d0de44d 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/ClassReader.java @@ -272,8 +272,7 @@ protected ClassReader(Context context) { Source source = Source.instance(context); preview = Preview.instance(context); allowModules = Feature.MODULES.allowedInSource(source); - allowRecords = (!preview.isPreview(Feature.RECORDS) || preview.isEnabled()) && - Feature.RECORDS.allowedInSource(source); + allowRecords = Feature.RECORDS.allowedInSource(source); allowSealedTypes = (!preview.isPreview(Feature.SEALED_CLASSES) || preview.isEnabled()) && Feature.SEALED_CLASSES.allowedInSource(source); diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/model/JavacElements.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/model/JavacElements.java index ab789be7708..73cd45f7fac 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/model/JavacElements.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/model/JavacElements.java @@ -25,6 +25,7 @@ package com.sun.tools.javac.model; +import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; @@ -198,43 +199,48 @@ private S unboundNameToSymbol(String methodName, return (S) resultCache.computeIfAbsent(Pair.of(methodName, nameStr), p -> { Set found = new LinkedHashSet<>(); + Set allModules = new HashSet<>(modules.allModules()); - for (ModuleSymbol msym : modules.allModules()) { - S sym = nameToSymbol(msym, nameStr, clazz); + allModules.removeAll(modules.getRootModules()); - if (sym == null) - continue; + for (Set modules : Arrays.asList(modules.getRootModules(), allModules)) { + for (ModuleSymbol msym : modules) { + S sym = nameToSymbol(msym, nameStr, clazz); + + if (sym == null) + continue; - if (clazz == ClassSymbol.class) { - // Always include classes - found.add(sym); - } else if (clazz == PackageSymbol.class) { - // In module mode, ignore the "spurious" empty packages that "enclose" module-specific packages. - // For example, if a module contains classes or package info in package p.q.r, it will also appear - // to have additional packages p.q and p, even though these packages have no content other - // than the subpackage. We don't want those empty packages showing up in searches for p or p.q. - if (!sym.members().isEmpty() || ((PackageSymbol) sym).package_info != null) { + if (clazz == ClassSymbol.class) { + // Always include classes found.add(sym); + } else if (clazz == PackageSymbol.class) { + // In module mode, ignore the "spurious" empty packages that "enclose" module-specific packages. + // For example, if a module contains classes or package info in package p.q.r, it will also appear + // to have additional packages p.q and p, even though these packages have no content other + // than the subpackage. We don't want those empty packages showing up in searches for p or p.q. + if (!sym.members().isEmpty() || ((PackageSymbol) sym).package_info != null) { + found.add(sym); + } } } - } - if (found.size() == 1) { - return Optional.of(found.iterator().next()); - } else if (found.size() > 1) { - //more than one element found, produce a note: - if (alreadyWarnedDuplicates.add(methodName + ":" + nameStr)) { - String moduleNames = found.stream() - .map(s -> s.packge().modle) - .map(m -> m.toString()) - .collect(Collectors.joining(", ")); - log.note(Notes.MultipleElements(methodName, nameStr, moduleNames)); + if (found.size() == 1) { + return Optional.of(found.iterator().next()); + } else if (found.size() > 1) { + //more than one element found, produce a note: + if (alreadyWarnedDuplicates.add(methodName + ":" + nameStr)) { + String moduleNames = found.stream() + .map(s -> s.packge().modle) + .map(m -> m.toString()) + .collect(Collectors.joining(", ")); + log.note(Notes.MultipleElements(methodName, nameStr, moduleNames)); + } + return Optional.empty(); + } else { + //not found, try another option } - return Optional.empty(); - } else { - //not found: - return Optional.empty(); } + return Optional.empty(); }).orElse(null); } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java index 3f9fa813071..ebcc76dc70b 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java @@ -184,8 +184,7 @@ protected JavacParser(ParserFactory fac, endPosTable = newEndPosTable(keepEndPositions); this.allowYieldStatement = (!preview.isPreview(Feature.SWITCH_EXPRESSION) || preview.isEnabled()) && Feature.SWITCH_EXPRESSION.allowedInSource(source); - this.allowRecords = (!preview.isPreview(Feature.RECORDS) || preview.isEnabled()) && - Feature.RECORDS.allowedInSource(source); + this.allowRecords = Feature.RECORDS.allowedInSource(source); this.allowSealedTypes = (!preview.isPreview(Feature.SEALED_CLASSES) || preview.isEnabled()) && Feature.SEALED_CLASSES.allowedInSource(source); } @@ -3717,7 +3716,7 @@ protected JCStatement classOrRecordOrInterfaceOrEnumDeclaration(JCModifiers mods } else { int pos = token.pos; List errs; - if (token.kind == IDENTIFIER && token.name() == names.record && preview.isEnabled()) { + if (token.kind == IDENTIFIER && token.name() == names.record) { checkSourceLevel(Feature.RECORDS); JCErroneous erroneousTree = syntaxError(token.pos, List.of(mods), Errors.RecordHeaderExpected); return toP(F.Exec(erroneousTree)); @@ -4214,7 +4213,7 @@ protected boolean isRecordStart() { (peekToken(TokenKind.IDENTIFIER, TokenKind.LPAREN) || peekToken(TokenKind.IDENTIFIER, TokenKind.EOF) || peekToken(TokenKind.IDENTIFIER, TokenKind.LT))) { - checkSourceLevel(Feature.RECORDS); + checkSourceLevel(Feature.RECORDS); return true; } else { return false; diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/VM.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/VM.java index 871ba282747..b038917954d 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/VM.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/VM.java @@ -118,7 +118,7 @@ public class VM { public static int Flags_INTERNAL; public static int Flags_JIMAGE_RESOURCE; private static int Flags_VALUE_ORIGIN_MASK; - private static int Flags_ORIG_COMMAND_LINE; + private static int Flags_WAS_SET_ON_COMMAND_LINE; /** This is only present in a non-core build */ private CodeCache codeCache; /** This is only present in a C1 build */ @@ -195,7 +195,7 @@ public String getOriginString() { return "management"; } else if (origin == Flags_ERGONOMIC) { String result = ""; - if ((flags & Flags_ORIG_COMMAND_LINE) == Flags_ORIG_COMMAND_LINE) { + if ((flags & Flags_WAS_SET_ON_COMMAND_LINE) == Flags_WAS_SET_ON_COMMAND_LINE) { result = "command line, "; } return result + "ergonomic"; @@ -490,17 +490,17 @@ private VM(TypeDataBase db, JVMDebugger debugger, boolean isBigEndian) { bytesPerLong = db.lookupIntConstant("BytesPerLong").intValue(); bytesPerWord = db.lookupIntConstant("BytesPerWord").intValue(); heapWordSize = db.lookupIntConstant("HeapWordSize").intValue(); - Flags_DEFAULT = db.lookupIntConstant("JVMFlag::DEFAULT").intValue(); - Flags_COMMAND_LINE = db.lookupIntConstant("JVMFlag::COMMAND_LINE").intValue(); - Flags_ENVIRON_VAR = db.lookupIntConstant("JVMFlag::ENVIRON_VAR").intValue(); - Flags_CONFIG_FILE = db.lookupIntConstant("JVMFlag::CONFIG_FILE").intValue(); - Flags_MANAGEMENT = db.lookupIntConstant("JVMFlag::MANAGEMENT").intValue(); - Flags_ERGONOMIC = db.lookupIntConstant("JVMFlag::ERGONOMIC").intValue(); - Flags_ATTACH_ON_DEMAND = db.lookupIntConstant("JVMFlag::ATTACH_ON_DEMAND").intValue(); - Flags_INTERNAL = db.lookupIntConstant("JVMFlag::INTERNAL").intValue(); - Flags_JIMAGE_RESOURCE = db.lookupIntConstant("JVMFlag::JIMAGE_RESOURCE").intValue(); + Flags_DEFAULT = db.lookupIntConstant("JVMFlagOrigin::DEFAULT").intValue(); + Flags_COMMAND_LINE = db.lookupIntConstant("JVMFlagOrigin::COMMAND_LINE").intValue(); + Flags_ENVIRON_VAR = db.lookupIntConstant("JVMFlagOrigin::ENVIRON_VAR").intValue(); + Flags_CONFIG_FILE = db.lookupIntConstant("JVMFlagOrigin::CONFIG_FILE").intValue(); + Flags_MANAGEMENT = db.lookupIntConstant("JVMFlagOrigin::MANAGEMENT").intValue(); + Flags_ERGONOMIC = db.lookupIntConstant("JVMFlagOrigin::ERGONOMIC").intValue(); + Flags_ATTACH_ON_DEMAND = db.lookupIntConstant("JVMFlagOrigin::ATTACH_ON_DEMAND").intValue(); + Flags_INTERNAL = db.lookupIntConstant("JVMFlagOrigin::INTERNAL").intValue(); + Flags_JIMAGE_RESOURCE = db.lookupIntConstant("JVMFlagOrigin::JIMAGE_RESOURCE").intValue(); Flags_VALUE_ORIGIN_MASK = db.lookupIntConstant("JVMFlag::VALUE_ORIGIN_MASK").intValue(); - Flags_ORIG_COMMAND_LINE = db.lookupIntConstant("JVMFlag::ORIG_COMMAND_LINE").intValue(); + Flags_WAS_SET_ON_COMMAND_LINE = db.lookupIntConstant("JVMFlag::WAS_SET_ON_COMMAND_LINE").intValue(); oopSize = db.lookupIntConstant("oopSize").intValue(); intType = db.lookupType("int"); diff --git a/src/jdk.httpserver/share/classes/com/sun/net/httpserver/HttpContext.java b/src/jdk.httpserver/share/classes/com/sun/net/httpserver/HttpContext.java index a6161e5b674..405d4acb818 100644 --- a/src/jdk.httpserver/share/classes/com/sun/net/httpserver/HttpContext.java +++ b/src/jdk.httpserver/share/classes/com/sun/net/httpserver/HttpContext.java @@ -28,15 +28,18 @@ import java.util.Map; /** - * HttpContext represents a mapping between the root URI path of an application - * to a {@link HttpHandler} which is invoked to handle requests destined - * for that path on the associated HttpServer or HttpsServer. - *

        - * HttpContext instances are created by the create methods in HttpServer - * and HttpsServer - *

        - * A chain of {@link Filter} objects can be added to a HttpContext. All exchanges processed by the - * context can be pre- and post-processed by each Filter in the chain. + * {@code HttpContext} represents a mapping between the root {@link java.net.URI} + * path of an application to a {@link HttpHandler} which is invoked to handle + * requests destined for that path on the associated {@link HttpServer} or + * {@link HttpsServer}. + * + *

        {@code HttpContext} instances are created by the create methods in + * {@code HttpServer} and {@code HttpsServer}. + * + *

        A chain of {@link Filter} objects can be added to a {@code HttpContext}. + * All exchanges processed by the context can be pre- and post-processed by each + * {@code Filter} in the chain. + * * @since 1.6 */ public abstract class HttpContext { @@ -44,73 +47,79 @@ public abstract class HttpContext { /** * Constructor for subclasses to call. */ - protected HttpContext () { + protected HttpContext() { } /** - * returns the handler for this context - * @return the HttpHandler for this context + * Returns the handler for this context. + * + * @return the {@code HttpHandler} for this context */ - public abstract HttpHandler getHandler () ; + public abstract HttpHandler getHandler(); /** * Sets the handler for this context, if not already set. - * @param h the handler to set for this context - * @throws IllegalArgumentException if this context's handler is already set. - * @throws NullPointerException if handler is null + * + * @param handler the handler to set for this context + * @throws IllegalArgumentException if the context for this handler is already set. + * @throws NullPointerException if handler is {@code null} */ - public abstract void setHandler (HttpHandler h) ; + public abstract void setHandler(HttpHandler handler); /** - * returns the path this context was created with - * @return this context's path + * Returns the path this context was created with. + * + * @return the context of this path */ - public abstract String getPath() ; + public abstract String getPath(); /** - * returns the server this context was created with - * @return this context's server + * Returns the server this context was created with. + * + * @return the context of this server */ - public abstract HttpServer getServer () ; + public abstract HttpServer getServer(); /** - * returns a mutable Map, which can be used to pass - * configuration and other data to Filter modules - * and to the context's exchange handler. - *

        - * Every attribute stored in this Map will be visible to - * every HttpExchange processed by this context + * Returns a mutable {@link Map}, which can be used to pass configuration + * and other data to {@link Filter} modules and to the context's exchange + * handler. + * + *

        Every attribute stored in this {@code Map} will be visible to every + * {@code HttpExchange} processed by this context. * - * @return a map containing the attributes of this context + * @return a {@code Map} containing the attributes of this context */ public abstract Map getAttributes() ; /** - * returns this context's list of Filters. This is the - * actual list used by the server when dispatching requests - * so modifications to this list immediately affect the - * the handling of exchanges. + * Returns this context's {@link List} of {@linkplain Filter filters}. This + * is the actual list used by the server when dispatching requests so + * modifications to this list immediately affect the the handling of exchanges. + * + * @return a {@link List} containing the filters of this context */ public abstract List getFilters(); /** - * Sets the Authenticator for this HttpContext. Once an authenticator - * is establised on a context, all client requests must be - * authenticated, and the given object will be invoked to validate each - * request. Each call to this method replaces any previous value set. - * @param auth the authenticator to set. If null then any - * previously set authenticator is removed, - * and client authentication will no longer be required. - * @return the previous Authenticator, if any set, or null - * otherwise. + * Sets the {@link Authenticator} for this {@code HttpContext}. Once an authenticator + * is establised on a context, all client requests must be authenticated, + * and the given object will be invoked to validate each request. Each call + * to this method replaces any previous value set. + * + * @param auth the {@code Authenticator} to set. If {@code null} then any previously + * set {@code Authenticator} is removed, and client authentication + * will no longer be required. + * @return the previous {@code Authenticator}, if any set, or {@code null} otherwise. */ - public abstract Authenticator setAuthenticator (Authenticator auth); + public abstract Authenticator setAuthenticator(Authenticator auth); /** - * Returns the currently set Authenticator for this context + * Returns the currently set {@link Authenticator} for this context * if one exists. - * @return this HttpContext's Authenticator, or null - * if none is set. + * + * @return this {@linkplain HttpContext HttpContext's} {@code Authenticator}, + * or {@code null} if none is set */ - public abstract Authenticator getAuthenticator (); + public abstract Authenticator getAuthenticator(); } diff --git a/src/jdk.httpserver/share/classes/com/sun/net/httpserver/HttpHandler.java b/src/jdk.httpserver/share/classes/com/sun/net/httpserver/HttpHandler.java index 8ea7024e686..8f54bb1530f 100644 --- a/src/jdk.httpserver/share/classes/com/sun/net/httpserver/HttpHandler.java +++ b/src/jdk.httpserver/share/classes/com/sun/net/httpserver/HttpHandler.java @@ -30,6 +30,7 @@ /** * A handler which is invoked to process HTTP exchanges. Each * HTTP exchange is handled by one of these handlers. + * * @since 1.6 */ public interface HttpHandler { @@ -37,9 +38,10 @@ public interface HttpHandler { * Handle the given request and generate an appropriate response. * See {@link HttpExchange} for a description of the steps * involved in handling an exchange. + * * @param exchange the exchange containing the request from the - * client and used to send the response - * @throws NullPointerException if exchange is null + * client and used to send the response + * @throws NullPointerException if exchange is {@code null} */ public abstract void handle (HttpExchange exchange) throws IOException; } diff --git a/src/jdk.httpserver/share/classes/com/sun/net/httpserver/HttpPrincipal.java b/src/jdk.httpserver/share/classes/com/sun/net/httpserver/HttpPrincipal.java index 863c74c9a38..43db2ab0474 100644 --- a/src/jdk.httpserver/share/classes/com/sun/net/httpserver/HttpPrincipal.java +++ b/src/jdk.httpserver/share/classes/com/sun/net/httpserver/HttpPrincipal.java @@ -34,12 +34,14 @@ public class HttpPrincipal implements Principal { private String username, realm; /** - * creates a HttpPrincipal from the given username and realm - * @param username The name of the user within the realm - * @param realm The realm. - * @throws NullPointerException if either username or realm are null + * Creates a {@code HttpPrincipal} from the given {@code username} and + * {@code realm}. + * + * @param username the name of the user within the realm + * @param realm the realm for this user + * @throws NullPointerException if either username or realm are {@code null} */ - public HttpPrincipal (String username, String realm) { + public HttpPrincipal(String username, String realm) { if (username == null || realm == null) { throw new NullPointerException(); } @@ -48,12 +50,16 @@ public HttpPrincipal (String username, String realm) { } /** - * Compares two HttpPrincipal. Returns true - * if another is an instance of HttpPrincipal, and its - * username and realm are equal to this object's username - * and realm. Returns false otherwise. + * Compare two instances of {@code HttpPrincipal}. Returns {@code true} if + * another is an instance of {@code HttpPrincipal}, and its username + * and realm are equal to this object's username and realm. Returns {@code false} + * otherwise. + * + * @param another the object to compare this instance of {@code HttpPrincipal} against + * @return {@code true} or {@code false} depending on whether objects are + * equal or not */ - public boolean equals (Object another) { + public boolean equals(Object another) { if (!(another instanceof HttpPrincipal)) { return false; } @@ -63,41 +69,47 @@ public boolean equals (Object another) { } /** - * returns the contents of this principal in the form - * realm:username + * Returns the contents of this principal in the form + * realm:username. + * + * @return the contents of this principal in the form realm:username */ public String getName() { return username; } /** - * returns the username this object was created with. + * Returns the {@code username} this object was created with. * - * @return The name of the user assoicated with this object + * @return the name of the user associated with this object */ public String getUsername() { return username; } /** - * returns the realm this object was created with. + * Returns the {@code realm} this object was created with. * - * @return The realm associated with this object + * @return the realm associated with this object */ public String getRealm() { return realm; } /** - * returns a hashcode for this HttpPrincipal. This is calculated - * as (getUsername()+getRealm().hashCode() + * Returns a hashcode for this {@code HttpPrincipal}. This is calculated + * as {@code (getUsername()+getRealm()).hashCode()}. + * + * @return the hashcode for this object */ public int hashCode() { return (username+realm).hashCode(); } /** - * returns the same string as getName() + * Returns the same string as {@link #getName()}. + * + * @return the name associated with this object */ public String toString() { return getName(); diff --git a/src/jdk.httpserver/share/classes/com/sun/net/httpserver/HttpsConfigurator.java b/src/jdk.httpserver/share/classes/com/sun/net/httpserver/HttpsConfigurator.java index dbd46a5ac5b..8cd9e3affa2 100644 --- a/src/jdk.httpserver/share/classes/com/sun/net/httpserver/HttpsConfigurator.java +++ b/src/jdk.httpserver/share/classes/com/sun/net/httpserver/HttpsConfigurator.java @@ -25,23 +25,17 @@ package com.sun.net.httpserver; -import java.net.*; -import java.io.*; -import java.nio.*; -import java.security.*; -import java.nio.channels.*; -import java.util.*; -import java.util.concurrent.*; -import javax.net.ssl.*; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLParameters; /** * This class is used to configure the https parameters for each incoming - * https connection on a HttpsServer. Applications need to override + * https connection on a {@link HttpsServer}. Applications need to override * the {@link #configure(HttpsParameters)} method in order to change * the default configuration. - *

        - * The following example shows how this may be done: + * + *

        The following example shows how this may be done: * *

          * SSLContext sslContext = SSLContext.getInstance (....);
        @@ -65,6 +59,7 @@
          *     }
          * });
          * 
        + * * @since 1.6 */ public class HttpsConfigurator { @@ -72,11 +67,12 @@ public class HttpsConfigurator { private SSLContext context; /** - * Creates an Https configuration, with the given SSLContext. - * @param context the SSLContext to use for this configurator - * @throws NullPointerException if no SSLContext supplied + * Creates a Https configuration, with the given {@link SSLContext}. + * + * @param context the {@code SSLContext} to use for this configurator + * @throws NullPointerException if no {@code SSLContext} supplied */ - public HttpsConfigurator (SSLContext context) { + public HttpsConfigurator(SSLContext context) { if (context == null) { throw new NullPointerException ("null SSLContext"); } @@ -84,33 +80,33 @@ public HttpsConfigurator (SSLContext context) { } /** - * Returns the SSLContext for this HttpsConfigurator. - * @return the SSLContext + * Returns the {@link SSLContext} for this {@code HttpsConfigurator}. + * + * @return the {@code SSLContext} */ public SSLContext getSSLContext() { return context; } -//BEGIN_TIGER_EXCLUDE /** - * Called by the HttpsServer to configure the parameters - * for a https connection currently being established. - * The implementation of configure() must call - * {@link HttpsParameters#setSSLParameters(SSLParameters)} - * in order to set the SSL parameters for the connection. - *

        - * The default implementation of this method uses the - * SSLParameters returned from

        - * {@code getSSLContext().getDefaultSSLParameters()} - *

        - * configure() may be overridden in order to modify this behavior. - * See, the example above. - * @param params the HttpsParameters to be configured. + * Called by the {@link HttpsServer} to configure the parameters for a https + * connection currently being established. The implementation of configure() + * must call {@link HttpsParameters#setSSLParameters(SSLParameters)} in order + * to set the SSL parameters for the connection. + * + *

        The default implementation of this method uses the + * SSLParameters returned from: + * + *

        {@code getSSLContext().getDefaultSSLParameters()} + * + *

        configure() may be overridden in order to modify this behavior. See + * example above. + * + * @param params the {@code HttpsParameters} to be configured * * @since 1.6 */ - public void configure (HttpsParameters params) { + public void configure(HttpsParameters params) { params.setSSLParameters (getSSLContext().getDefaultSSLParameters()); } -//END_TIGER_EXCLUDE } diff --git a/src/jdk.incubator.jpackage/linux/classes/jdk/incubator/jpackage/internal/LinuxPackageBundler.java b/src/jdk.incubator.jpackage/linux/classes/jdk/incubator/jpackage/internal/LinuxPackageBundler.java index 5d67234180a..622d93dab35 100644 --- a/src/jdk.incubator.jpackage/linux/classes/jdk/incubator/jpackage/internal/LinuxPackageBundler.java +++ b/src/jdk.incubator.jpackage/linux/classes/jdk/incubator/jpackage/internal/LinuxPackageBundler.java @@ -79,17 +79,24 @@ final public boolean validate(Map params) } } - withFindNeededPackages = LibProvidersLookup.supported(); - if (!withFindNeededPackages) { - final String advice; - if ("deb".equals(getID())) { - advice = "message.deb-ldd-not-available.advice"; - } else { - advice = "message.rpm-ldd-not-available.advice"; + if (!isDefault()) { + withFindNeededPackages = false; + Log.verbose(MessageFormat.format(I18N.getString( + "message.not-default-bundler-no-dependencies-lookup"), + getName())); + } else { + withFindNeededPackages = LibProvidersLookup.supported(); + if (!withFindNeededPackages) { + final String advice; + if ("deb".equals(getID())) { + advice = "message.deb-ldd-not-available.advice"; + } else { + advice = "message.rpm-ldd-not-available.advice"; + } + // Let user know package dependencies will not be generated. + Log.error(String.format("%s\n%s", I18N.getString( + "message.ldd-not-available"), I18N.getString(advice))); } - // Let user know package dependencies will not be generated. - Log.error(String.format("%s\n%s", I18N.getString( - "message.ldd-not-available"), I18N.getString(advice))); } // Packaging specific validation @@ -192,7 +199,6 @@ private List getListOfNeededPackages( neededLibPackages = Collections.emptyList(); if (!Files.exists(thePackage.sourceRoot())) { Log.info(I18N.getString("warning.foreign-app-image")); - } } diff --git a/src/jdk.incubator.jpackage/linux/classes/jdk/incubator/jpackage/internal/resources/LinuxResources.properties b/src/jdk.incubator.jpackage/linux/classes/jdk/incubator/jpackage/internal/resources/LinuxResources.properties index 0474234e171..4c4d2ac7bf4 100644 --- a/src/jdk.incubator.jpackage/linux/classes/jdk/incubator/jpackage/internal/resources/LinuxResources.properties +++ b/src/jdk.incubator.jpackage/linux/classes/jdk/incubator/jpackage/internal/resources/LinuxResources.properties @@ -62,6 +62,7 @@ message.deb-ldd-not-available.advice=Install "libc-bin" DEB package to get ldd. message.rpm-ldd-not-available.advice=Install "glibc-common" RPM package to get ldd. warning.foreign-app-image=Warning: app-image dir not generated by jpackage. +message.not-default-bundler-no-dependencies-lookup={0} is not the default package type. Package dependencies will not be generated. error.unexpected-package-property=Expected value of "{0}" property is [{1}]. Actual value in output package is [{2}]. Looks like custom "{3}" file from resource directory contained hard coded value of "{0}" property error.unexpected-package-property.advice=Use [{0}] pattern string instead of hard coded value [{1}] of {2} property in custom "{3}" file diff --git a/src/jdk.incubator.jpackage/linux/classes/jdk/incubator/jpackage/internal/resources/LinuxResources_ja.properties b/src/jdk.incubator.jpackage/linux/classes/jdk/incubator/jpackage/internal/resources/LinuxResources_ja.properties index 48a0f3438a9..03e66e1ad26 100644 --- a/src/jdk.incubator.jpackage/linux/classes/jdk/incubator/jpackage/internal/resources/LinuxResources_ja.properties +++ b/src/jdk.incubator.jpackage/linux/classes/jdk/incubator/jpackage/internal/resources/LinuxResources_ja.properties @@ -40,8 +40,6 @@ resource.menu-shortcut-descriptor=\u30E1\u30CB\u30E5\u30FC\u30FB\u30B7\u30E7\u30 resource.menu-icon=\u30E1\u30CB\u30E5\u30FC\u30FB\u30A2\u30A4\u30B3\u30F3 resource.rpm-spec-file=RPM\u4ED5\u69D8\u30D5\u30A1\u30A4\u30EB -warning.foreign-app-image=Warning: app-image dir not generated by jpackage. - error.tool-not-found.advice=\u5FC5\u8981\u306A\u30D1\u30C3\u30B1\u30FC\u30B8\u3092\u30A4\u30F3\u30B9\u30C8\u30FC\u30EB\u3057\u3066\u304F\u3060\u3055\u3044 error.tool-old-version.advice=\u5FC5\u8981\u306A\u30D1\u30C3\u30B1\u30FC\u30B8\u3092\u30A4\u30F3\u30B9\u30C8\u30FC\u30EB\u3057\u3066\u304F\u3060\u3055\u3044 @@ -63,6 +61,9 @@ message.ldd-not-available=ldd\u30B3\u30DE\u30F3\u30C9\u304C\u898B\u3064\u304B\u3 message.deb-ldd-not-available.advice="libc-bin" DEB\u30D1\u30C3\u30B1\u30FC\u30B8\u3092\u30A4\u30F3\u30B9\u30C8\u30FC\u30EB\u3057\u3066ldd\u3092\u53D6\u5F97\u3057\u307E\u3059\u3002 message.rpm-ldd-not-available.advice="glibc-common" RPM\u30D1\u30C3\u30B1\u30FC\u30B8\u3092\u30A4\u30F3\u30B9\u30C8\u30FC\u30EB\u3057\u3066ldd\u3092\u53D6\u5F97\u3057\u307E\u3059\u3002 +warning.foreign-app-image=Warning: app-image dir not generated by jpackage. +message.not-default-bundler-no-dependencies-lookup={0} is not the default package type. Package dependencies will not be generated. + error.unexpected-package-property="{0}"\u30D7\u30ED\u30D1\u30C6\u30A3\u306B\u5FC5\u8981\u306A\u5024\u306F[{1}]\u3067\u3059\u3002\u51FA\u529B\u30D1\u30C3\u30B1\u30FC\u30B8\u306E\u5B9F\u969B\u306E\u5024\u306F[{2}]\u3067\u3059\u3002\u30EA\u30BD\u30FC\u30B9\u30FB\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u306E\u30AB\u30B9\u30BF\u30E0"{3}"\u30D5\u30A1\u30A4\u30EB\u306B\u306F\u3001"{0}"\u30D7\u30ED\u30D1\u30C6\u30A3\u306E\u30CF\u30FC\u30C9\u30B3\u30FC\u30C9\u3055\u308C\u305F\u5024\u304C\u542B\u307E\u308C\u3066\u3044\u308B\u3088\u3046\u3067\u3059 error.unexpected-package-property.advice=\u30AB\u30B9\u30BF\u30E0"{3}"\u30D5\u30A1\u30A4\u30EB\u3067{2}\u30D7\u30ED\u30D1\u30C6\u30A3\u306E\u30CF\u30FC\u30C9\u30B3\u30FC\u30C9\u3055\u308C\u305F\u5024[{1}]\u3067\u306F\u306A\u304F\u3001[{0}]\u30D1\u30BF\u30FC\u30F3\u6587\u5B57\u5217\u3092\u4F7F\u7528\u3057\u3066\u304F\u3060\u3055\u3044 error.unexpected-default-package-property.advice=\u30AB\u30B9\u30BF\u30E0"{1}"\u30D5\u30A1\u30A4\u30EB\u3067{0}\u30D7\u30ED\u30D1\u30C6\u30A3\u306E\u5024\u3092\u660E\u793A\u7684\u306B\u8A2D\u5B9A\u3057\u306A\u3044\u3067\u304F\u3060\u3055\u3044 diff --git a/src/jdk.incubator.jpackage/linux/classes/jdk/incubator/jpackage/internal/resources/LinuxResources_zh_CN.properties b/src/jdk.incubator.jpackage/linux/classes/jdk/incubator/jpackage/internal/resources/LinuxResources_zh_CN.properties index 52feabd13f4..3c899a8c44f 100644 --- a/src/jdk.incubator.jpackage/linux/classes/jdk/incubator/jpackage/internal/resources/LinuxResources_zh_CN.properties +++ b/src/jdk.incubator.jpackage/linux/classes/jdk/incubator/jpackage/internal/resources/LinuxResources_zh_CN.properties @@ -40,8 +40,6 @@ resource.menu-shortcut-descriptor=\u83DC\u5355\u5FEB\u6377\u65B9\u5F0F\u63CF\u8F resource.menu-icon=\u83DC\u5355\u56FE\u6807 resource.rpm-spec-file=RPM \u89C4\u8303\u6587\u4EF6 -warning.foreign-app-image=Warning: app-image dir not generated by jpackage. - error.tool-not-found.advice=\u8BF7\u5B89\u88C5\u6240\u9700\u7684\u7A0B\u5E8F\u5305 error.tool-old-version.advice=\u8BF7\u5B89\u88C5\u6240\u9700\u7684\u7A0B\u5E8F\u5305 @@ -63,6 +61,9 @@ message.ldd-not-available=\u672A\u627E\u5230 ldd \u547D\u4EE4\u3002\u5C06\u4E0D\ message.deb-ldd-not-available.advice=\u5B89\u88C5 "libc-bin" DEB \u7A0B\u5E8F\u5305\u4EE5\u83B7\u53D6 ldd\u3002 message.rpm-ldd-not-available.advice=\u5B89\u88C5 "glibc-common" RPM \u7A0B\u5E8F\u5305\u4EE5\u83B7\u53D6 ldd\u3002 +warning.foreign-app-image=Warning: app-image dir not generated by jpackage. +message.not-default-bundler-no-dependencies-lookup={0} is not the default package type. Package dependencies will not be generated. + error.unexpected-package-property="{0}" \u5C5E\u6027\u7684\u9884\u671F\u503C\u4E3A [{1}]\u3002\u8F93\u51FA\u7A0B\u5E8F\u5305\u4E2D\u7684\u5B9E\u9645\u503C\u4E3A [{2}]\u3002\u4E0E\u5B9A\u5236\u7684 "{3}" \u6587\u4EF6\u76F8\u4F3C\uFF0C\u8BE5\u6587\u4EF6\u6240\u5728\u7684\u8D44\u6E90\u76EE\u5F55\u4E2D\u5305\u542B "{0}" \u5C5E\u6027\u7684\u786C\u7F16\u7801\u503C error.unexpected-package-property.advice=\u5728\u5B9A\u5236\u7684 "{3}" \u6587\u4EF6\u4E2D\u4F7F\u7528 [{0}] \u6A21\u5F0F\u5B57\u7B26\u4E32\uFF0C\u800C\u975E {2} \u5C5E\u6027\u7684\u786C\u7F16\u7801\u503C [{1}] error.unexpected-default-package-property.advice=\u8BF7\u52FF\u5728\u5B9A\u5236\u7684 "{1}" \u6587\u4EF6\u4E2D\u663E\u5F0F\u8BBE\u7F6E {0} \u5C5E\u6027\u7684\u503C diff --git a/src/jdk.incubator.jpackage/macosx/classes/jdk/incubator/jpackage/internal/MacDmgBundler.java b/src/jdk.incubator.jpackage/macosx/classes/jdk/incubator/jpackage/internal/MacDmgBundler.java index 709f6f1a530..2973731010f 100644 --- a/src/jdk.incubator.jpackage/macosx/classes/jdk/incubator/jpackage/internal/MacDmgBundler.java +++ b/src/jdk.incubator.jpackage/macosx/classes/jdk/incubator/jpackage/internal/MacDmgBundler.java @@ -473,15 +473,6 @@ private Path buildDMG( Map params, //add license if needed if (Files.exists(getConfig_LicenseFile(params))) { - //hdiutil unflatten your_image_file.dmg - pb = new ProcessBuilder( - hdiutil, - "unflatten", - finalDMG.toAbsolutePath().toString() - ); - IOUtils.exec(pb); - - //add license pb = new ProcessBuilder( hdiutil, "udifrez", @@ -490,15 +481,6 @@ private Path buildDMG( Map params, getConfig_LicenseFile(params).toAbsolutePath().toString() ); IOUtils.exec(pb); - - //hdiutil flatten your_image_file.dmg - pb = new ProcessBuilder( - hdiutil, - "flatten", - finalDMG.toAbsolutePath().toString() - ); - IOUtils.exec(pb); - } //Delete the temporary image diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/AbstractVector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/AbstractVector.java index 93a124f44d4..3b882a67503 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/AbstractVector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/AbstractVector.java @@ -500,7 +500,7 @@ ArithmeticException divZeroException() { final AbstractVector defaultReinterpret(AbstractSpecies rsp) { int blen = Math.max(this.bitSize(), rsp.vectorBitSize()) / Byte.SIZE; - ByteOrder bo = ByteOrder.LITTLE_ENDIAN; + ByteOrder bo = ByteOrder.nativeOrder(); ByteBuffer bb = ByteBuffer.allocate(blen); this.intoByteBuffer(bb, 0, bo); VectorMask m = rsp.maskAll(true); diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJDKReflection.java b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJDKReflection.java index bdccf28d68b..a7c2aa5d203 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJDKReflection.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJDKReflection.java @@ -404,6 +404,14 @@ JavaConstant readFieldValue(HotSpotResolvedJavaField field, Object obj, boolean assert obj != null; assert !field.isStatic() || obj instanceof Class; long displacement = field.getOffset(); + if (obj instanceof Class && field.getName().equals("componentType")) { + Class clazz = (Class) obj; + if (!clazz.isArray()) { + // Class.componentType for non-array classes can transiently contain an int[] that's + // used for locking so always return null to mimic Class.getComponentType() + return JavaConstant.NULL_POINTER; + } + } assert checkRead(field.getJavaKind(), displacement, (HotSpotResolvedObjectType) runtime().getHostJVMCIBackend().getMetaAccess().lookupJavaType(field.isStatic() ? (Class) obj : obj.getClass()), diff --git a/src/jdk.jartool/share/classes/jdk/security/jarsigner/JarSigner.java b/src/jdk.jartool/share/classes/jdk/security/jarsigner/JarSigner.java index 10da7f56dd1..4a17faec022 100644 --- a/src/jdk.jartool/share/classes/jdk/security/jarsigner/JarSigner.java +++ b/src/jdk.jartool/share/classes/jdk/security/jarsigner/JarSigner.java @@ -34,7 +34,6 @@ import sun.security.pkcs.PKCS9Attributes; import sun.security.timestamp.HttpTimestamper; import sun.security.tools.PathList; -import sun.security.tools.jarsigner.TimestampedSigner; import sun.security.util.Event; import sun.security.util.ManifestDigester; import sun.security.util.SignatureFileVerifier; @@ -122,7 +121,6 @@ public static class Builder { String tSADigestAlg; boolean sectionsonly = false; boolean internalsf = false; - boolean directsign = false; String altSignerPath; String altSigner; @@ -358,10 +356,6 @@ public Builder eventHandler(BiConsumer handler) { *

      2. "sectionsonly": "true" if the .SF file only contains the hash * value for each section of the manifest and not for the whole * manifest, "false" otherwise. Default "false". - *
      3. "directsign": "true" if the signature is calculated on the - * content directly, "false" if it's calculated on signed attributes - * which itself is calculated from the content and stored in the - * signer's SignerInfo. Default "false". *
    * All property names are case-insensitive. * @@ -395,9 +389,6 @@ public Builder setProperty(String key, String value) { case "sectionsonly": this.sectionsonly = parseBoolean("sectionsonly", value); break; - case "directsign": - this.directsign = parseBoolean("directsign", value); - break; case "altsignerpath": altSignerPath = value; break; @@ -510,7 +501,6 @@ public JarSigner build() { private final String tSADigestAlg; private final boolean sectionsonly; // do not "sign" the whole manifest private final boolean internalsf; // include the .SF inside the PKCS7 block - private final boolean directsign; @Deprecated(since="16", forRemoval=true) private final String altSignerPath; @@ -561,9 +551,12 @@ private JarSigner(JarSigner.Builder builder) { this.altSigner = builder.altSigner; this.altSignerPath = builder.altSignerPath; - this.directsign = this.altSigner != null - ? true - : builder.directsign; + // altSigner cannot support modern algorithms like RSASSA-PSS and EdDSA + if (altSigner != null + && !sigalg.toUpperCase(Locale.ENGLISH).contains("WITH")) { + throw new IllegalArgumentException( + "Customized ContentSigner is not supported for " + sigalg); + } } /** @@ -666,8 +659,6 @@ public String getProperty(String key) { return Boolean.toString(sectionsonly); case "altsignerpath": return altSignerPath; - case "directsign": - return Boolean.toString(directsign); case "altsigner": return altSigner; default: @@ -855,20 +846,7 @@ private void sign0(ZipFile zipFile, OutputStream os) sf.write(baos); byte[] content = baos.toByteArray(); - // Use new method if directSign is false or it's a modern - // algorithm not supported by existing ContentSigner. - // Make this always true after we remove ContentSigner. - boolean useNewMethod = !directsign - || !sigalg.toUpperCase(Locale.ENGLISH).contains("WITH"); - - // For newer sigalg without "with", always use the new PKCS7 - // generateToken method. Otherwise, use deprecated ContentSigner. - if (useNewMethod) { - if (altSigner != null) { - throw new IllegalArgumentException(directsign - ? ("Customized ContentSigner is not supported for " + sigalg) - : "Customized ContentSigner does not support authenticated attributes"); - } + if (altSigner == null) { Function timestamper = null; if (tsaUrl != null) { timestamper = s -> { @@ -889,7 +867,7 @@ private void sign0(ZipFile zipFile, OutputStream os) } // We now create authAttrs in block data, so "direct == false". block = PKCS7.generateNewSignedData(sigalg, sigProvider, privateKey, certChain, - content, internalsf, directsign, timestamper); + content, internalsf, false, timestamper); } else { Signature signer = SignatureUtil.fromKey(sigalg, privateKey, sigProvider); signer.update(content); @@ -901,9 +879,7 @@ private void sign0(ZipFile zipFile, OutputStream os) tSADigestAlg, signature, signer.getAlgorithm(), certChain, content, zipFile); @SuppressWarnings("removal") - ContentSigner signingMechanism = (altSigner != null) - ? loadSigningMechanism(altSigner, altSignerPath) - : new TimestampedSigner(); + ContentSigner signingMechanism = loadSigningMechanism(altSigner, altSignerPath); block = signingMechanism.generateSignedData( params, !internalsf, diff --git a/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Main.java b/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Main.java index a38c5e60623..23e04724eca 100644 --- a/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Main.java +++ b/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Main.java @@ -163,7 +163,6 @@ public static void main(String args[]) throws Exception { boolean debug = false; // debug boolean signManifest = true; // "sign" the whole manifest boolean externalSF = true; // leave the .SF out of the PKCS7 block - boolean directSign = false; // sign SF directly or thru signedAttrs boolean strict = false; // treat warnings as error boolean revocationCheck = false; // Revocation check flag @@ -473,8 +472,6 @@ String[] parseArgs(String args[]) throws Exception { signManifest = false; } else if (collator.compare(flags, "-internalsf") ==0) { externalSF = false; - } else if (collator.compare(flags, "-directsign") ==0) { - directSign = true; } else if (collator.compare(flags, "-verify") ==0) { verify = true; } else if (collator.compare(flags, "-verbose") ==0) { @@ -663,9 +660,6 @@ static void fullusage() { System.out.println(rb.getString (".internalsf.include.the.SF.file.inside.the.signature.block")); System.out.println(); - System.out.println(rb.getString - (".directsign.sign.the.SF.file.directly.no.signerinfo.signedattributes")); - System.out.println(); System.out.println(rb.getString (".sectionsonly.don.t.compute.hash.of.entire.manifest")); System.out.println(); @@ -1773,7 +1767,6 @@ void signJar(String jarName, String alias) builder.setProperty("sectionsOnly", Boolean.toString(!signManifest)); builder.setProperty("internalSF", Boolean.toString(!externalSF)); - builder.setProperty("directsign", Boolean.toString(directSign)); FileOutputStream fos = null; try { diff --git a/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Resources.java b/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Resources.java index c58840ee319..7158e2f1f83 100644 --- a/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Resources.java +++ b/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Resources.java @@ -101,8 +101,6 @@ public class Resources extends java.util.ListResourceBundle { " (This option is deprecated and will be removed in a future release.)"}, {".internalsf.include.the.SF.file.inside.the.signature.block", "[-internalsf] include the .SF file inside the signature block"}, - {".directsign.sign.the.SF.file.directly.no.signerinfo.signedattributes", - "[-directsign] sign the .SF file directly (no SignerInfo signedAttributes)"}, {".sectionsonly.don.t.compute.hash.of.entire.manifest", "[-sectionsonly] don't compute hash of entire manifest"}, {".protected.keystore.has.protected.authentication.path", diff --git a/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/TimestampedSigner.java b/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/TimestampedSigner.java deleted file mode 100644 index 035e758f490..00000000000 --- a/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/TimestampedSigner.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright (c) 2007, 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package sun.security.tools.jarsigner; - -import java.io.IOException; -import java.net.URI; -import java.security.NoSuchAlgorithmException; -import java.security.cert.CertificateException; -import java.security.cert.X509Certificate; - -import com.sun.jarsigner.*; -import sun.security.pkcs.PKCS7; - -/** - * This class implements a content signing service. - * It generates a timestamped signature for a given content according to - * RFC 3161. - * The signature along with a trusted timestamp and the signer's certificate - * are all packaged into a standard PKCS #7 Signed Data message. - * - * @author Vincent Ryan - */ -@Deprecated(since="16", forRemoval=true) -@SuppressWarnings("removal") -public final class TimestampedSigner extends ContentSigner { - - /** - * Instantiates a content signer that supports timestamped signatures. - */ - public TimestampedSigner() { - } - - /** - * Generates a PKCS #7 signed data message that includes a signature - * timestamp. - * This method is used when a signature has already been generated. - * The signature, a signature timestamp, the signer's certificate chain, - * and optionally the content that was signed, are packaged into a PKCS #7 - * signed data message. - * - * @param params The non-null input parameters. - * @param omitContent true if the content should be omitted from the - * signed data message. Otherwise the content is included. - * @param applyTimestamp true if the signature should be timestamped. - * Otherwise timestamping is not performed. - * @return A PKCS #7 signed data message including a signature timestamp. - * @throws NoSuchAlgorithmException The exception is thrown if the signature - * algorithm is unrecognised. - * @throws CertificateException The exception is thrown if an error occurs - * while processing the signer's certificate or the TSA's - * certificate. - * @throws IOException The exception is thrown if an error occurs while - * generating the signature timestamp or while generating the signed - * data message. - * @throws NullPointerException The exception is thrown if parameters is - * null. - */ - public byte[] generateSignedData(ContentSignerParameters params, - boolean omitContent, boolean applyTimestamp) - throws NoSuchAlgorithmException, CertificateException, IOException { - - if (params == null) { - throw new NullPointerException(); - } - - X509Certificate[] signerChain = params.getSignerCertificateChain(); - byte[] signature = params.getSignature(); - - // Include or exclude content - byte[] content = (omitContent == true) ? null : params.getContent(); - - URI tsaURI = null; - if (applyTimestamp) { - tsaURI = params.getTimestampingAuthority(); - if (tsaURI == null) { - // Examine TSA cert - tsaURI = PKCS7.getTimestampingURI( - params.getTimestampingAuthorityCertificate()); - if (tsaURI == null) { - throw new CertificateException( - "Subject Information Access extension not found"); - } - } - } - return PKCS7.generateSignedData(signature, signerChain, content, - params.getSignatureAlgorithm(), tsaURI, - params.getTSAPolicyID(), - params.getTSADigestAlg()); - } -} diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AllClassesIndexWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AllClassesIndexWriter.java index f1ad9e1febb..51df14460f4 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AllClassesIndexWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AllClassesIndexWriter.java @@ -30,7 +30,7 @@ import javax.lang.model.element.TypeElement; -import com.sun.source.doctree.DocTree; +import com.sun.source.doctree.DeprecatedTree; import jdk.javadoc.internal.doclets.formats.html.markup.BodyContents; import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder; import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; @@ -165,7 +165,7 @@ protected void addTableRow(Table table, TypeElement klass) { ContentBuilder description = new ContentBuilder(); if (utils.isDeprecated(klass)) { description.add(getDeprecatedPhrase(klass)); - List tags = utils.getDeprecatedTrees(klass); + List tags = utils.getDeprecatedTrees(klass); if (!tags.isEmpty()) { addSummaryDeprecatedComment(klass, tags.get(0), description); } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassWriterImpl.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassWriterImpl.java index cb8acb741ff..e8108101436 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassWriterImpl.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassWriterImpl.java @@ -41,6 +41,7 @@ import javax.lang.model.type.TypeMirror; import javax.lang.model.util.SimpleElementVisitor8; +import com.sun.source.doctree.DeprecatedTree; import com.sun.source.doctree.DocTree; import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder; import jdk.javadoc.internal.doclets.formats.html.markup.Entity; @@ -507,7 +508,7 @@ public boolean isFunctionalInterface() { @Override public void addClassDeprecationInfo(Content classInfoTree) { - List deprs = utils.getBlockTags(typeElement, DocTree.Kind.DEPRECATED); + List deprs = utils.getDeprecatedTrees(typeElement); if (utils.isDeprecated(typeElement)) { Content deprLabel = HtmlTree.SPAN(HtmlStyle.deprecatedLabel, getDeprecatedPhrase(typeElement)); Content div = HtmlTree.DIV(HtmlStyle.deprecationBlock, deprLabel); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/DeprecatedListWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/DeprecatedListWriter.java index 14bc4a6387c..37063140e81 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/DeprecatedListWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/DeprecatedListWriter.java @@ -25,6 +25,7 @@ package jdk.javadoc.internal.doclets.formats.html; +import com.sun.source.doctree.DeprecatedTree; import jdk.javadoc.internal.doclets.formats.html.markup.Table; import jdk.javadoc.internal.doclets.formats.html.markup.TableHeader; @@ -397,7 +398,7 @@ protected void addDeprecatedAPI(SortedSet deprList, String id, String h link = getDeprecatedLink(e); } Content desc = new ContentBuilder(); - List tags = utils.getDeprecatedTrees(e); + List tags = utils.getDeprecatedTrees(e); if (!tags.isEmpty()) { addInlineDeprecatedComment(e, tags.get(0), desc); } else { diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java index 2cc37855bb3..c51a0589929 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java @@ -57,6 +57,7 @@ import com.sun.source.doctree.AttributeTree; import com.sun.source.doctree.AttributeTree.ValueKind; import com.sun.source.doctree.CommentTree; +import com.sun.source.doctree.DeprecatedTree; import com.sun.source.doctree.DocRootTree; import com.sun.source.doctree.DocTree; import com.sun.source.doctree.DocTree.Kind; @@ -1167,7 +1168,7 @@ public Content getDeprecatedPhrase(Element e) { * @param tag the inline tag to be added * @param htmltree the content tree to which the comment will be added */ - public void addInlineDeprecatedComment(Element e, DocTree tag, Content htmltree) { + public void addInlineDeprecatedComment(Element e, DeprecatedTree tag, Content htmltree) { CommentHelper ch = utils.getCommentHelper(e); addCommentTags(e, ch.getBody(tag), true, false, false, htmltree); } @@ -1193,7 +1194,7 @@ public void addSummaryComment(Element element, List firstSent addCommentTags(element, firstSentenceTags, false, true, true, htmltree); } - public void addSummaryDeprecatedComment(Element element, DocTree tag, Content htmltree) { + public void addSummaryDeprecatedComment(Element element, DeprecatedTree tag, Content htmltree) { CommentHelper ch = utils.getCommentHelper(element); List body = ch.getBody(tag); addCommentTags(element, ch.getFirstSentenceTrees(body), true, true, true, htmltree); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlSerialFieldWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlSerialFieldWriter.java index 013028288bd..039b3d45550 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlSerialFieldWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlSerialFieldWriter.java @@ -33,6 +33,7 @@ import com.sun.source.doctree.DocTree; +import com.sun.source.doctree.SerialTree; import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder; import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; import jdk.javadoc.internal.doclets.formats.html.markup.TagName; @@ -165,7 +166,7 @@ public void addMemberDescription(VariableElement field, Content contentTree) { if (!utils.getFullBody(field).isEmpty()) { writer.addInlineComment(field, contentTree); } - List tags = utils.getBlockTags(field, DocTree.Kind.SERIAL); + List tags = utils.getSerialTrees(field); if (!tags.isEmpty()) { writer.addInlineComment(field, tags.get(0), contentTree); } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/IndexWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/IndexWriter.java index 76e5174265e..863a88db95e 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/IndexWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/IndexWriter.java @@ -37,7 +37,7 @@ import javax.lang.model.element.PackageElement; import javax.lang.model.element.TypeElement; -import com.sun.source.doctree.DocTree; +import com.sun.source.doctree.DeprecatedTree; import jdk.javadoc.internal.doclets.formats.html.markup.BodyContents; import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder; @@ -300,13 +300,12 @@ protected void addTagDescription(IndexItem item, Content dlTree) { * @param contentTree the content tree to which the comment will be added */ protected void addComment(Element element, Content contentTree) { - List tags; Content span = HtmlTree.SPAN(HtmlStyle.deprecatedLabel, getDeprecatedPhrase(element)); HtmlTree div = new HtmlTree(TagName.DIV); div.setStyle(HtmlStyle.deprecationBlock); if (utils.isDeprecated(element)) { div.add(span); - tags = utils.getBlockTags(element, DocTree.Kind.DEPRECATED); + List tags = utils.getDeprecatedTrees(element); if (!tags.isEmpty()) addInlineDeprecatedComment(element, tags.get(0), div); contentTree.add(div); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ModuleWriterImpl.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ModuleWriterImpl.java index 44ab67c3079..1bc26ee63bf 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ModuleWriterImpl.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ModuleWriterImpl.java @@ -40,6 +40,7 @@ import javax.lang.model.element.TypeElement; import javax.lang.model.util.ElementFilter; +import com.sun.source.doctree.DeprecatedTree; import com.sun.source.doctree.DocTree; import jdk.javadoc.doclet.DocletEnvironment.ModuleMode; import jdk.javadoc.internal.doclets.formats.html.markup.BodyContents; @@ -369,14 +370,14 @@ public void computeModulesData() { } }); // Generate the map of all services listed using @provides, and the description. - utils.getBlockTags(mdle, DocTree.Kind.PROVIDES).forEach(tree -> { + utils.getProvidesTrees(mdle).forEach(tree -> { TypeElement t = ch.getServiceType(tree); if (t != null) { providesTrees.put(t, commentTagsToContent(tree, mdle, ch.getDescription(tree), false, true)); } }); // Generate the map of all services listed using @uses, and the description. - utils.getBlockTags(mdle, DocTree.Kind.USES).forEach(tree -> { + utils.getUsesTrees(mdle).forEach(tree -> { TypeElement t = ch.getServiceType(tree); if (t != null) { usesTrees.put(t, commentTagsToContent(tree, mdle, ch.getDescription(tree), false, true)); @@ -802,7 +803,7 @@ public void addProvidesList(Table table) { * @param div the content tree to which the deprecation information will be added */ public void addDeprecationInfo(Content div) { - List deprs = utils.getBlockTags(mdle, DocTree.Kind.DEPRECATED); + List deprs = utils.getDeprecatedTrees(mdle); if (utils.isDeprecated(mdle)) { CommentHelper ch = utils.getCommentHelper(mdle); HtmlTree deprDiv = new HtmlTree(TagName.DIV); @@ -860,9 +861,8 @@ public void printDocument(Content contentTree) throws DocFileIOException { * @param pkg the PackageDoc that is added */ public void addPackageDeprecationInfo(Content li, PackageElement pkg) { - List deprs; if (utils.isDeprecated(pkg)) { - deprs = utils.getDeprecatedTrees(pkg); + List deprs = utils.getDeprecatedTrees(pkg); HtmlTree deprDiv = new HtmlTree(TagName.DIV); deprDiv.setStyle(HtmlStyle.deprecationBlock); Content deprPhrase = HtmlTree.SPAN(HtmlStyle.deprecatedLabel, getDeprecatedPhrase(pkg)); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageWriterImpl.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageWriterImpl.java index 005097639ca..2940b37fd17 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageWriterImpl.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageWriterImpl.java @@ -32,6 +32,7 @@ import javax.lang.model.element.PackageElement; import javax.lang.model.element.TypeElement; +import com.sun.source.doctree.DeprecatedTree; import com.sun.source.doctree.DocTree; import jdk.javadoc.internal.doclets.formats.html.markup.BodyContents; import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder; @@ -142,7 +143,7 @@ public Content getContentHeader() { * @param div the content tree to which the deprecation information will be added */ public void addDeprecationInfo(Content div) { - List deprs = utils.getBlockTags(packageElement, DocTree.Kind.DEPRECATED); + List deprs = utils.getDeprecatedTrees(packageElement); if (utils.isDeprecated(packageElement)) { CommentHelper ch = utils.getCommentHelper(packageElement); HtmlTree deprDiv = new HtmlTree(TagName.DIV); @@ -223,7 +224,7 @@ public void addClassesSummary(SortedSet classes, String label, ContentBuilder description = new ContentBuilder(); if (utils.isDeprecated(klass)) { description.add(getDeprecatedPhrase(klass)); - List tags = utils.getDeprecatedTrees(klass); + List tags = utils.getDeprecatedTrees(klass); if (!tags.isEmpty()) { addSummaryDeprecatedComment(klass, tags.get(0), description); } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SubWriterHolderWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SubWriterHolderWriter.java index c6f0463b645..593005a09a0 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SubWriterHolderWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SubWriterHolderWriter.java @@ -30,6 +30,7 @@ import javax.lang.model.element.Element; import javax.lang.model.element.TypeElement; +import com.sun.source.doctree.DeprecatedTree; import com.sun.source.doctree.DocTree; import jdk.javadoc.internal.doclets.formats.html.markup.BodyContents; import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder; @@ -108,7 +109,7 @@ protected void addIndexComment(Element member, Content contentTree) { */ protected void addIndexComment(Element member, List firstSentenceTags, Content tdSummary) { - List deprs = utils.getBlockTags(member, DocTree.Kind.DEPRECATED); + List deprs = utils.getDeprecatedTrees(member); Content div; if (utils.isDeprecated(member)) { Content deprLabel = HtmlTree.SPAN(HtmlStyle.deprecatedLabel, getDeprecatedPhrase(member)); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/TagletWriterImpl.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/TagletWriterImpl.java index 7fcf7006bb2..dc90bf4bf94 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/TagletWriterImpl.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/TagletWriterImpl.java @@ -37,10 +37,15 @@ import javax.lang.model.type.TypeMirror; import javax.lang.model.util.SimpleElementVisitor14; +import com.sun.source.doctree.DeprecatedTree; import com.sun.source.doctree.DocTree; import com.sun.source.doctree.IndexTree; +import com.sun.source.doctree.LiteralTree; import com.sun.source.doctree.ParamTree; +import com.sun.source.doctree.ReturnTree; +import com.sun.source.doctree.SeeTree; import com.sun.source.doctree.SystemPropertyTree; +import com.sun.source.doctree.ThrowsTree; import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder; import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle; import jdk.javadoc.internal.doclets.formats.html.markup.HtmlTree; @@ -109,16 +114,15 @@ protected Content codeTagOutput(Element element, DocTree tag) { } @Override - protected Content indexTagOutput(Element element, DocTree tag) { + protected Content indexTagOutput(Element element, IndexTree tag) { CommentHelper ch = utils.getCommentHelper(element); - IndexTree itt = (IndexTree) tag; - String tagText = ch.getText(itt.getSearchTerm()); + String tagText = ch.getText(tag.getSearchTerm()); if (tagText.charAt(0) == '"' && tagText.charAt(tagText.length() - 1) == '"') { tagText = tagText.substring(1, tagText.length() - 1) .replaceAll("\\s+", " "); } - String desc = ch.getText(itt.getDescription()); + String desc = ch.getText(tag.getDescription()); return createAnchorAndSearchIndex(element, tagText, desc, tag); } @@ -137,7 +141,7 @@ public Content getDocRootOutput() { public Content deprecatedTagOutput(Element element) { ContentBuilder result = new ContentBuilder(); CommentHelper ch = utils.getCommentHelper(element); - List deprs = utils.getBlockTags(element, DocTree.Kind.DEPRECATED); + List deprs = utils.getDeprecatedTrees(element); if (utils.isTypeElement(element)) { if (utils.isDeprecated(element)) { result.add(HtmlTree.SPAN(HtmlStyle.deprecatedLabel, @@ -171,7 +175,7 @@ public Content deprecatedTagOutput(Element element) { } @Override - protected Content literalTagOutput(Element element, DocTree tag) { + protected Content literalTagOutput(Element element, LiteralTree tag) { CommentHelper ch = utils.getCommentHelper(element); Content result = new StringContent(utils.normalizeNewlines(ch.getText(tag))); return result; @@ -191,12 +195,12 @@ public Content getParamHeader(ParamTaglet.ParamKind kind) { @Override @SuppressWarnings("preview") - public Content paramTagOutput(Element element, DocTree paramTag, String paramName) { + public Content paramTagOutput(Element element, ParamTree paramTag, String paramName) { ContentBuilder body = new ContentBuilder(); CommentHelper ch = utils.getCommentHelper(element); // define id attributes for state components so that generated descriptions may refer to them boolean defineID = (element.getKind() == ElementKind.RECORD) - && (paramTag instanceof ParamTree) && !((ParamTree) paramTag).isTypeParameter(); + && !paramTag.isTypeParameter(); Content nameTree = new StringContent(paramName); body.add(HtmlTree.CODE(defineID ? HtmlTree.SPAN_ID("param-" + paramName, nameTree) : nameTree)); body.add(" - "); @@ -206,7 +210,7 @@ public Content paramTagOutput(Element element, DocTree paramTag, String paramNam } @Override - public Content returnTagOutput(Element element, DocTree returnTag) { + public Content returnTagOutput(Element element, ReturnTree returnTag) { CommentHelper ch = utils.getCommentHelper(element); return new ContentBuilder( HtmlTree.DT(contents.returns), @@ -215,7 +219,7 @@ public Content returnTagOutput(Element element, DocTree returnTag) { } @Override - public Content seeTagOutput(Element holder, List seeTags) { + public Content seeTagOutput(Element holder, List seeTags) { ContentBuilder body = new ContentBuilder(); for (DocTree dt : seeTags) { appendSeparatorIfNotEmpty(body); @@ -279,9 +283,8 @@ public Content simpleBlockTagOutput(Element element, List sim } @Override - protected Content systemPropertyTagOutput(Element element, DocTree tag) { - SystemPropertyTree itt = (SystemPropertyTree) tag; - String tagText = itt.getPropertyName().toString(); + protected Content systemPropertyTagOutput(Element element, SystemPropertyTree tag) { + String tagText = tag.getPropertyName().toString(); return HtmlTree.CODE(createAnchorAndSearchIndex(element, tagText, resources.getText("doclet.System_Property"), tag)); } @@ -292,7 +295,7 @@ public Content getThrowsHeader() { } @Override - public Content throwsTagOutput(Element element, DocTree throwsTag, TypeMirror substituteType) { + public Content throwsTagOutput(Element element, ThrowsTree throwsTag, TypeMirror substituteType) { ContentBuilder body = new ContentBuilder(); CommentHelper ch = utils.getCommentHelper(element); Element exception = ch.getException(throwsTag); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/MemberSummaryBuilder.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/MemberSummaryBuilder.java index a549baf5253..2e593830faf 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/MemberSummaryBuilder.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/MemberSummaryBuilder.java @@ -38,6 +38,7 @@ import com.sun.source.doctree.DocCommentTree; import com.sun.source.doctree.DocTree; import com.sun.source.doctree.DocTree.Kind; +import com.sun.source.doctree.SinceTree; import com.sun.source.doctree.UnknownBlockTagTree; import jdk.javadoc.internal.doclets.toolkit.ClassWriter; import jdk.javadoc.internal.doclets.toolkit.Content; @@ -335,7 +336,7 @@ private void processProperty(Element member, } // copy certain tags - List tags = utils.getBlockTags(property, Kind.SINCE); + List tags = utils.getBlockTags(property, Kind.SINCE, SinceTree.class); blockTags.addAll(tags); List bTags = utils.getBlockTags(property, diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/SerializedFormBuilder.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/SerializedFormBuilder.java index 595810f74fd..2516073ee5b 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/SerializedFormBuilder.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/builders/SerializedFormBuilder.java @@ -36,8 +36,8 @@ import javax.lang.model.element.TypeElement; import javax.lang.model.element.VariableElement; -import com.sun.source.doctree.DocTree; import com.sun.source.doctree.SerialFieldTree; +import com.sun.source.doctree.SerialTree; import jdk.javadoc.internal.doclets.toolkit.Content; import jdk.javadoc.internal.doclets.toolkit.DocletException; import jdk.javadoc.internal.doclets.toolkit.SerializedFormWriter; @@ -472,10 +472,7 @@ protected void buildSerialFieldTagsInfo(Content serializableFieldsTree) { // element.) SortedSet tags = new TreeSet<>(utils.comparators.makeSerialFieldTreeComparator()); // sort the elements - for (DocTree dt : utils.getSerialFieldTrees(field)) { - SerialFieldTree st = (SerialFieldTree) dt; - tags.add(st); - } + tags.addAll(utils.getSerialFieldTrees(field)); CommentHelper ch = utils.getCommentHelper(field); for (SerialFieldTree tag : tags) { @@ -574,7 +571,7 @@ private static boolean serialDocInclude(Utils utils, Element element) { if (utils.isEnum(element)) { return false; } - List serial = utils.getSerialTrees(element); + List serial = utils.getSerialTrees(element); if (!serial.isEmpty()) { CommentHelper ch = utils.getCommentHelper(element); String serialtext = Utils.toLowerCase(ch.getText(serial.get(0))); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/IndexTaglet.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/IndexTaglet.java index e2307aacfba..d67cb44f003 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/IndexTaglet.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/IndexTaglet.java @@ -29,6 +29,7 @@ import javax.lang.model.element.Element; import com.sun.source.doctree.DocTree; +import com.sun.source.doctree.IndexTree; import jdk.javadoc.doclet.Taglet.Location; import jdk.javadoc.internal.doclets.toolkit.Content; @@ -46,6 +47,6 @@ public class IndexTaglet extends BaseTaglet { @Override public Content getInlineTagOutput(Element element, DocTree tag, TagletWriter writer) { - return writer.indexTagOutput(element, tag); + return writer.indexTagOutput(element, (IndexTree) tag); } } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/LiteralTaglet.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/LiteralTaglet.java index 3c1e9b6639b..50df1c8fdcc 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/LiteralTaglet.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/LiteralTaglet.java @@ -29,6 +29,7 @@ import javax.lang.model.element.Element; import com.sun.source.doctree.DocTree; +import com.sun.source.doctree.LiteralTree; import jdk.javadoc.doclet.Taglet.Location; import jdk.javadoc.internal.doclets.toolkit.Content; /** @@ -52,6 +53,6 @@ public class LiteralTaglet extends BaseTaglet { @Override public Content getInlineTagOutput(Element e, DocTree tag, TagletWriter writer) { - return writer.literalTagOutput(e, tag); + return writer.literalTagOutput(e, (LiteralTree) tag); } } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/ParamTaglet.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/ParamTaglet.java index f1f617a154e..199d28b66c3 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/ParamTaglet.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/ParamTaglet.java @@ -165,7 +165,7 @@ public Content getAllBlockTagOutput(Element holder, TagletWriter writer) { * @return the content representation of these {@code @param DocTree}s. */ private Content getTagletOutput(ParamKind kind, Element holder, - TagletWriter writer, List formalParameters, List paramTags) { + TagletWriter writer, List formalParameters, List paramTags) { Content result = writer.getOutputInstance(); Set alreadyDocumented = new HashSet<>(); if (!paramTags.isEmpty()) { @@ -210,7 +210,7 @@ private Content getInheritedTagletOutput(ParamKind kind, Element holder, CommentHelper ch = utils.getCommentHelper(holder); ch.setOverrideElement(inheritedDoc.holder); Content content = processParamTag(holder, kind, writer, - inheritedDoc.holderTag, + (ParamTree) inheritedDoc.holderTag, lname, alreadyDocumented.isEmpty()); result.add(content); @@ -240,13 +240,13 @@ private Content getInheritedTagletOutput(ParamKind kind, Element holder, * @return the Content representation of this {@code @param DocTree}. */ private Content processParamTags(Element e, ParamKind kind, - List paramTags, Map rankMap, TagletWriter writer, + List paramTags, Map rankMap, TagletWriter writer, Set alreadyDocumented) { Messages messages = writer.configuration().getMessages(); Content result = writer.getOutputInstance(); if (!paramTags.isEmpty()) { CommentHelper ch = writer.configuration().utils.getCommentHelper(e); - for (DocTree dt : paramTags) { + for (ParamTree dt : paramTags) { String name = ch.getParameterName(dt); String paramName = kind != ParamKind.TYPE_PARAMETER ? name.toString() @@ -294,7 +294,7 @@ private Content processParamTags(Element e, ParamKind kind, * */ private Content processParamTag(Element e, ParamKind kind, - TagletWriter writer, DocTree paramTag, String name, + TagletWriter writer, ParamTree paramTag, String name, boolean isFirstParam) { Content result = writer.getOutputInstance(); if (isFirstParam) { diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/ReturnTaglet.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/ReturnTaglet.java index 3aebf49fe71..15983f90403 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/ReturnTaglet.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/ReturnTaglet.java @@ -34,6 +34,7 @@ import javax.lang.model.type.TypeMirror; import com.sun.source.doctree.DocTree; +import com.sun.source.doctree.ReturnTree; import jdk.javadoc.doclet.Taglet.Location; import jdk.javadoc.internal.doclets.toolkit.Content; import jdk.javadoc.internal.doclets.toolkit.Messages; @@ -58,7 +59,7 @@ public ReturnTaglet() { @Override public void inherit(DocFinder.Input input, DocFinder.Output output) { - List tags = input.utils.getBlockTags(input.element, DocTree.Kind.RETURN); + List tags = input.utils.getReturnTrees(input.element); CommentHelper ch = input.utils.getCommentHelper(input.element); if (!tags.isEmpty()) { output.holder = input.element; @@ -74,7 +75,7 @@ public Content getAllBlockTagOutput(Element holder, TagletWriter writer) { Messages messages = writer.configuration().getMessages(); Utils utils = writer.configuration().utils; TypeMirror returnType = utils.getReturnType(writer.getCurrentPageElement(), (ExecutableElement)holder); - List tags = utils.getBlockTags(holder, DocTree.Kind.RETURN); + List tags = utils.getReturnTrees(holder); //Make sure we are not using @return tag on method with void return type. if (returnType != null && utils.isVoid(returnType)) { @@ -94,6 +95,6 @@ public Content getAllBlockTagOutput(Element holder, TagletWriter writer) { ch.setOverrideElement(inheritedDoc.holder); ntags.add(inheritedDoc.holderTag); } - return !ntags.isEmpty() ? writer.returnTagOutput(holder, ntags.get(0)) : null; + return !ntags.isEmpty() ? writer.returnTagOutput(holder, (ReturnTree) ntags.get(0)) : null; } } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/SeeTaglet.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/SeeTaglet.java index 24222758ee7..60863371ae8 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/SeeTaglet.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/SeeTaglet.java @@ -31,6 +31,7 @@ import javax.lang.model.element.Element; import com.sun.source.doctree.DocTree; +import com.sun.source.doctree.SeeTree; import jdk.javadoc.doclet.Taglet.Location; import jdk.javadoc.internal.doclets.toolkit.Content; import jdk.javadoc.internal.doclets.toolkit.util.CommentHelper; @@ -54,7 +55,7 @@ public SeeTaglet() { @Override public void inherit(DocFinder.Input input, DocFinder.Output output) { - List tags = input.utils.getSeeTrees(input.element); + List tags = input.utils.getSeeTrees(input.element); if (!tags.isEmpty()) { CommentHelper ch = input.utils.getCommentHelper(input.element); output.holder = input.element; @@ -68,7 +69,7 @@ public void inherit(DocFinder.Input input, DocFinder.Output output) { @Override public Content getAllBlockTagOutput(Element holder, TagletWriter writer) { Utils utils = writer.configuration().utils; - List tags = utils.getSeeTrees(holder); + List tags = utils.getSeeTrees(holder); Element e = holder; if (tags.isEmpty() && utils.isExecutableElement(holder)) { Input input = new DocFinder.Input(utils, holder, this); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/SystemPropertyTaglet.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/SystemPropertyTaglet.java index c94c7172b65..84bfe329343 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/SystemPropertyTaglet.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/SystemPropertyTaglet.java @@ -26,6 +26,7 @@ package jdk.javadoc.internal.doclets.toolkit.taglets; import com.sun.source.doctree.DocTree; +import com.sun.source.doctree.SystemPropertyTree; import jdk.javadoc.doclet.Taglet.Location; import jdk.javadoc.internal.doclets.toolkit.Content; @@ -50,6 +51,6 @@ public class SystemPropertyTaglet extends BaseTaglet { @Override public Content getInlineTagOutput(Element element, DocTree tag, TagletWriter writer) { - return writer.systemPropertyTagOutput(element, tag); + return writer.systemPropertyTagOutput(element, (SystemPropertyTree) tag); } } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/TagletWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/TagletWriter.java index d0defd1c2ff..692022aed9a 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/TagletWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/TagletWriter.java @@ -34,6 +34,13 @@ import javax.lang.model.type.TypeMirror; import com.sun.source.doctree.DocTree; +import com.sun.source.doctree.IndexTree; +import com.sun.source.doctree.LiteralTree; +import com.sun.source.doctree.ParamTree; +import com.sun.source.doctree.ReturnTree; +import com.sun.source.doctree.SeeTree; +import com.sun.source.doctree.SystemPropertyTree; +import com.sun.source.doctree.ThrowsTree; import jdk.javadoc.internal.doclets.toolkit.BaseConfiguration; import jdk.javadoc.internal.doclets.toolkit.Content; import jdk.javadoc.internal.doclets.toolkit.taglets.Taglet.UnsupportedTagletOperationException; @@ -85,7 +92,7 @@ protected TagletWriter(boolean isFirstSentence) { * * @return the output */ - protected abstract Content indexTagOutput(Element element, DocTree tag); + protected abstract Content indexTagOutput(Element element, IndexTree tag); /** * Returns the output for a {@code {@docRoot}} tag. @@ -111,7 +118,7 @@ protected TagletWriter(boolean isFirstSentence) { * * @return the output */ - protected abstract Content literalTagOutput(Element element, DocTree tag); + protected abstract Content literalTagOutput(Element element, LiteralTree tag); /** * Returns the header for the {@code @param} tags. @@ -133,7 +140,7 @@ protected TagletWriter(boolean isFirstSentence) { * * @return the output */ - protected abstract Content paramTagOutput(Element element, DocTree paramTag, String paramName); + protected abstract Content paramTagOutput(Element element, ParamTree paramTag, String paramName); /** * Returns the output for a {@code @return} tag. @@ -143,7 +150,7 @@ protected TagletWriter(boolean isFirstSentence) { * * @return the output */ - protected abstract Content returnTagOutput(Element element, DocTree returnTag); + protected abstract Content returnTagOutput(Element element, ReturnTree returnTag); /** * Returns the output for {@code @see} tags. @@ -153,7 +160,7 @@ protected TagletWriter(boolean isFirstSentence) { * * @return the output */ - protected abstract Content seeTagOutput(Element element, List seeTags); + protected abstract Content seeTagOutput(Element element, List seeTags); /** * Returns the output for a series of simple tags. @@ -174,7 +181,7 @@ protected TagletWriter(boolean isFirstSentence) { * * @return the output */ - protected abstract Content systemPropertyTagOutput(Element element, DocTree systemPropertyTag); + protected abstract Content systemPropertyTagOutput(Element element, SystemPropertyTree systemPropertyTag); /** * Returns the header for the {@code @throws} tag. @@ -192,7 +199,7 @@ protected TagletWriter(boolean isFirstSentence) { * * @return the output */ - protected abstract Content throwsTagOutput(Element element, DocTree throwsTag, TypeMirror substituteType); + protected abstract Content throwsTagOutput(Element element, ThrowsTree throwsTag, TypeMirror substituteType); /** * Returns the output for a default {@code @throws} tag. diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/ThrowsTaglet.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/ThrowsTaglet.java index bf2ab199e37..bea65063128 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/ThrowsTaglet.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/taglets/ThrowsTaglet.java @@ -35,6 +35,7 @@ import java.util.Map; import java.util.Map.Entry; import java.util.Set; +import java.util.stream.Collectors; import javax.lang.model.element.Element; import javax.lang.model.element.ExecutableElement; @@ -43,6 +44,7 @@ import javax.lang.model.type.TypeMirror; import com.sun.source.doctree.DocTree; +import com.sun.source.doctree.ThrowsTree; import jdk.javadoc.doclet.Taglet.Location; import jdk.javadoc.internal.doclets.toolkit.Content; @@ -72,7 +74,8 @@ public void inherit(DocFinder.Input input, DocFinder.Output output) { Element exception; CommentHelper ch = utils.getCommentHelper(input.element); if (input.tagId == null) { - exception = ch.getException(input.docTreeInfo.docTree); + exception = input.docTreeInfo.docTree instanceof ThrowsTree + ? ch.getException((ThrowsTree) input.docTreeInfo.docTree) : null; input.tagId = exception == null ? ch.getExceptionName(input.docTreeInfo.docTree).getSignature() : utils.getFullyQualifiedName(exception); @@ -80,18 +83,18 @@ public void inherit(DocFinder.Input input, DocFinder.Output output) { exception = input.utils.findClass(input.element, input.tagId); } - for (DocTree dt : input.utils.getThrowsTrees(input.element)) { - Element exc = ch.getException(dt); + for (ThrowsTree tt : input.utils.getThrowsTrees(input.element)) { + Element exc = ch.getException(tt); if (exc != null && (input.tagId.equals(utils.getSimpleName(exc)) || (input.tagId.equals(utils.getFullyQualifiedName(exc))))) { output.holder = input.element; - output.holderTag = dt; + output.holderTag = tt; output.inlineTags = ch.getBody(output.holderTag); - output.tagList.add(dt); + output.tagList.add(tt); } else if (exception != null && exc != null && utils.isTypeElement(exc) && utils.isTypeElement(exception) && utils.isSubclassOf((TypeElement)exc, (TypeElement)exception)) { - output.tagList.add(dt); + output.tagList.add(tt); } } } @@ -129,7 +132,7 @@ private Content inheritThrowsDocumentation(Element holder, Utils utils = writer.configuration().utils; Content result = writer.getOutputInstance(); if (utils.isExecutableElement(holder)) { - Map, ExecutableElement> declaredExceptionTags = new LinkedHashMap<>(); + Map, ExecutableElement> declaredExceptionTags = new LinkedHashMap<>(); for (TypeMirror declaredExceptionType : declaredExceptionTypes) { Input input = new DocFinder.Input(utils, holder, this, utils.getTypeName(declaredExceptionType, false)); @@ -143,7 +146,10 @@ private Content inheritThrowsDocumentation(Element holder, if (inheritedDoc.holder == null) { inheritedDoc.holder = holder; } - declaredExceptionTags.put(inheritedDoc.tagList, (ExecutableElement)inheritedDoc.holder); + List inheritedTags = inheritedDoc.tagList.stream() + .map(t -> (ThrowsTree) t) + .collect(Collectors.toList()); + declaredExceptionTags.put(inheritedTags, (ExecutableElement) inheritedDoc.holder); } } result.add(throwsTagsOutput(declaredExceptionTags, writer, alreadyDocumented, @@ -161,7 +167,7 @@ public Content getAllBlockTagOutput(Element holder, TagletWriter writer) { List thrownTypes = instantiatedType.getThrownTypes(); Map typeSubstitutions = getSubstitutedThrownTypes( ((ExecutableElement) holder).getThrownTypes(), thrownTypes); - Map, ExecutableElement> tagsMap = new LinkedHashMap<>(); + Map, ExecutableElement> tagsMap = new LinkedHashMap<>(); tagsMap.put(utils.getThrowsTrees(execHolder), execHolder); Content result = writer.getOutputInstance(); HashSet alreadyDocumented = new HashSet<>(); @@ -183,16 +189,16 @@ public Content getAllBlockTagOutput(Element holder, TagletWriter writer) { * @param allowDuplicates {@code true} if we allow duplicate tags to be documented * @return the generated content for the tags */ - protected Content throwsTagsOutput(Map, ExecutableElement> throwTags, + protected Content throwsTagsOutput(Map, ExecutableElement> throwTags, TagletWriter writer, Set alreadyDocumented, Map typeSubstitutions, boolean allowDuplicates) { Utils utils = writer.configuration().utils; Content result = writer.getOutputInstance(); if (!throwTags.isEmpty()) { - for (Entry, ExecutableElement> entry : throwTags.entrySet()) { + for (Entry, ExecutableElement> entry : throwTags.entrySet()) { CommentHelper ch = utils.getCommentHelper(entry.getValue()); Element e = entry.getValue(); - for (DocTree dt : entry.getKey()) { + for (ThrowsTree dt : entry.getKey()) { Element te = ch.getException(dt); String excName = ch.getExceptionName(dt).toString(); TypeMirror substituteType = typeSubstitutions.get(excName); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/CommentHelper.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/CommentHelper.java index a77b2912157..6d2d955917e 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/CommentHelper.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/CommentHelper.java @@ -200,13 +200,8 @@ public TypeMirror getType(ReferenceTree rtree) { return null; } - public Element getException(DocTree dtree) { - if (dtree.getKind() == THROWS || dtree.getKind() == EXCEPTION) { - ThrowsTree tt = (ThrowsTree)dtree; - ReferenceTree exceptionName = tt.getExceptionName(); - return getElement(exceptionName); - } - return null; + public Element getException(ThrowsTree tt) { + return getElement(tt.getExceptionName()); } public List getDescription(DocTree dtree) { diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Utils.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Utils.java index 1b74a3f7dd4..bc4b5d5bbec 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Utils.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Utils.java @@ -91,14 +91,23 @@ import javax.tools.JavaFileManager.Location; import javax.tools.StandardLocation; +import com.sun.source.doctree.DeprecatedTree; import com.sun.source.doctree.DocCommentTree; import com.sun.source.doctree.DocTree; import com.sun.source.doctree.DocTree.Kind; import com.sun.source.doctree.EndElementTree; import com.sun.source.doctree.ParamTree; +import com.sun.source.doctree.ProvidesTree; +import com.sun.source.doctree.ReturnTree; +import com.sun.source.doctree.SeeTree; +import com.sun.source.doctree.SerialDataTree; +import com.sun.source.doctree.SerialFieldTree; +import com.sun.source.doctree.SerialTree; import com.sun.source.doctree.StartElementTree; import com.sun.source.doctree.TextTree; +import com.sun.source.doctree.ThrowsTree; import com.sun.source.doctree.UnknownBlockTagTree; +import com.sun.source.doctree.UsesTree; import com.sun.source.tree.CompilationUnitTree; import com.sun.source.tree.LineMap; import com.sun.source.util.DocSourcePositions; @@ -945,8 +954,8 @@ public SortedSet getTypeElementsAsSortedSet(Iterable t return set; } - public List getSerialDataTrees(ExecutableElement member) { - return getBlockTags(member, SERIAL_DATA); + public List getSerialDataTrees(ExecutableElement member) { + return getBlockTags(member, SERIAL_DATA, SerialDataTree.class); } public FileObject getFileObject(TypeElement te) { @@ -2591,10 +2600,22 @@ public List getBlockTags(Element element, Predicate .collect(Collectors.toList()); } + public List getBlockTags(Element element, Predicate filter, Class tClass) { + return getBlockTags(element).stream() + .filter(t -> t.getKind() != ERRONEOUS) + .filter(filter) + .map(t -> tClass.cast(t)) + .collect(Collectors.toList()); + } + public List getBlockTags(Element element, DocTree.Kind kind) { return getBlockTags(element, t -> t.getKind() == kind); } + public List getBlockTags(Element element, DocTree.Kind kind, Class tClass) { + return getBlockTags(element, t -> t.getKind() == kind, tClass); + } + public List getBlockTags(Element element, DocTree.Kind kind, DocTree.Kind altKind) { return getBlockTags(element, t -> t.getKind() == kind || t.getKind() == altKind); } @@ -2780,28 +2801,30 @@ public List getBody(Element element) { : docCommentTree.getFullBody(); } - public List getDeprecatedTrees(Element element) { - return getBlockTags(element, DEPRECATED); + public List getDeprecatedTrees(Element element) { + return getBlockTags(element, DEPRECATED, DeprecatedTree.class); } - public List getProvidesTrees(Element element) { - return getBlockTags(element, PROVIDES); + public List getProvidesTrees(Element element) { + return getBlockTags(element, PROVIDES, ProvidesTree.class); } - public List getSeeTrees(Element element) { - return getBlockTags(element, SEE); + public List getSeeTrees(Element element) { + return getBlockTags(element, SEE, SeeTree.class); } - public List getSerialTrees(Element element) { - return getBlockTags(element, SERIAL); + public List getSerialTrees(Element element) { + return getBlockTags(element, SERIAL, SerialTree.class); } - public List getSerialFieldTrees(VariableElement field) { - return getBlockTags(field, DocTree.Kind.SERIAL_FIELD); + public List getSerialFieldTrees(VariableElement field) { + return getBlockTags(field, DocTree.Kind.SERIAL_FIELD, SerialFieldTree.class); } - public List getThrowsTrees(Element element) { - return getBlockTags(element, DocTree.Kind.EXCEPTION, DocTree.Kind.THROWS); + public List getThrowsTrees(Element element) { + return getBlockTags(element, + t -> switch (t.getKind()) { case EXCEPTION, THROWS -> true; default -> false; }, + ThrowsTree.class); } public List getTypeParamTrees(Element element) { @@ -2813,22 +2836,17 @@ public List getParamTrees(Element element) { } private List getParamTrees(Element element, boolean isTypeParameters) { - List out = new ArrayList<>(); - for (DocTree dt : getBlockTags(element, PARAM)) { - ParamTree pt = (ParamTree) dt; - if (pt.isTypeParameter() == isTypeParameters) { - out.add(pt); - } - } - return out; + return getBlockTags(element, + t -> t.getKind() == PARAM && ((ParamTree) t).isTypeParameter() == isTypeParameters, + ParamTree.class); } - public List getReturnTrees(Element element) { - return new ArrayList<>(getBlockTags(element, RETURN)); + public List getReturnTrees(Element element) { + return new ArrayList<>(getBlockTags(element, RETURN, ReturnTree.class)); } - public List getUsesTrees(Element element) { - return getBlockTags(element, USES); + public List getUsesTrees(Element element) { + return getBlockTags(element, USES, UsesTree.class); } public List getFirstSentenceTrees(Element element) { diff --git a/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c b/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c index 78ca29796aa..96773392fc3 100644 --- a/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c +++ b/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2007, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2020, 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 @@ -836,6 +836,7 @@ threadControl_onHook(void) */ node->isStarted = JNI_TRUE; } + jvmtiDeallocate(threads); } } END_WITH_LOCAL_REFS(env) @@ -1515,22 +1516,9 @@ threadControl_suspendAll(void) error = AGENT_ERROR_OUT_OF_MEMORY; goto err; } - if (canSuspendResumeThreadLists()) { - error = commonSuspendList(env, count, threads); - if (error != JVMTI_ERROR_NONE) { - goto err; - } - } else { - - int i; - - for (i = 0; i < count; i++) { - error = commonSuspend(env, threads[i], JNI_FALSE); - - if (error != JVMTI_ERROR_NONE) { - goto err; - } - } + error = commonSuspendList(env, count, threads); + if (error != JVMTI_ERROR_NONE) { + goto err; } /* @@ -1549,7 +1537,8 @@ threadControl_suspendAll(void) suspendAllCount++; } - err: ; + err: + jvmtiDeallocate(threads); } END_WITH_LOCAL_REFS(env) @@ -1588,12 +1577,7 @@ threadControl_resumeAll(void) * no need to get the whole thread list from JVMTI (unlike * suspendAll). */ - if (canSuspendResumeThreadLists()) { - error = commonResumeList(env); - } else { - error = enumerateOverThreadList(env, &runningThreads, - resumeHelper, NULL); - } + error = commonResumeList(env); if ((error == JVMTI_ERROR_NONE) && (otherThreads.first != NULL)) { error = enumerateOverThreadList(env, &otherThreads, resumeHelper, NULL); diff --git a/src/jdk.jdwp.agent/share/native/libjdwp/util.c b/src/jdk.jdwp.agent/share/native/libjdwp/util.c index 2f73f33cbbc..d40bb32b101 100644 --- a/src/jdk.jdwp.agent/share/native/libjdwp/util.c +++ b/src/jdk.jdwp.agent/share/native/libjdwp/util.c @@ -699,12 +699,12 @@ methodClass(jmethodID method, jclass *pclazz) jvmtiError error; *pclazz = NULL; - error = FUNC_PTR(gdata->jvmti,GetMethodDeclaringClass) + error = JVMTI_FUNC_PTR(gdata->jvmti,GetMethodDeclaringClass) (gdata->jvmti, method, pclazz); return error; } -/* Returns a local ref to the declaring class for a method, or NULL. */ +/* Returns the start and end locations of the specified method. */ jvmtiError methodLocation(jmethodID method, jlocation *ploc1, jlocation *ploc2) { @@ -727,7 +727,7 @@ methodSignature(jmethodID method, char *signature = NULL; char *generic_signature = NULL; - error = FUNC_PTR(gdata->jvmti,GetMethodName) + error = JVMTI_FUNC_PTR(gdata->jvmti,GetMethodName) (gdata->jvmti, method, &name, &signature, &generic_signature); if ( pname != NULL ) { @@ -962,16 +962,6 @@ jvmtiMicroVersion(void) >> JVMTI_VERSION_SHIFT_MICRO; } -jboolean -canSuspendResumeThreadLists(void) -{ - jvmtiError error; - jvmtiCapabilities cap; - - error = jvmtiGetCapabilities(&cap); - return (error == JVMTI_ERROR_NONE && cap.can_suspend); -} - jvmtiError getSourceDebugExtension(jclass clazz, char **extensionPtr) { @@ -1019,7 +1009,7 @@ debugMonitorEnter(jrawMonitorID monitor) { jvmtiError error; while (JNI_TRUE) { - error = FUNC_PTR(gdata->jvmti,RawMonitorEnter) + error = JVMTI_FUNC_PTR(gdata->jvmti,RawMonitorEnter) (gdata->jvmti, monitor); error = ignore_vm_death(error); if (error == JVMTI_ERROR_INTERRUPT) { @@ -1038,7 +1028,7 @@ debugMonitorExit(jrawMonitorID monitor) { jvmtiError error; - error = FUNC_PTR(gdata->jvmti,RawMonitorExit) + error = JVMTI_FUNC_PTR(gdata->jvmti,RawMonitorExit) (gdata->jvmti, monitor); error = ignore_vm_death(error); if (error != JVMTI_ERROR_NONE) { @@ -1050,7 +1040,7 @@ void debugMonitorWait(jrawMonitorID monitor) { jvmtiError error; - error = FUNC_PTR(gdata->jvmti,RawMonitorWait) + error = JVMTI_FUNC_PTR(gdata->jvmti,RawMonitorWait) (gdata->jvmti, monitor, ((jlong)(-1))); /* @@ -1095,7 +1085,7 @@ void debugMonitorTimedWait(jrawMonitorID monitor, jlong millis) { jvmtiError error; - error = FUNC_PTR(gdata->jvmti,RawMonitorWait) + error = JVMTI_FUNC_PTR(gdata->jvmti,RawMonitorWait) (gdata->jvmti, monitor, millis); if (error == JVMTI_ERROR_INTERRUPT) { /* See comment above */ @@ -1113,7 +1103,7 @@ debugMonitorNotify(jrawMonitorID monitor) { jvmtiError error; - error = FUNC_PTR(gdata->jvmti,RawMonitorNotify) + error = JVMTI_FUNC_PTR(gdata->jvmti,RawMonitorNotify) (gdata->jvmti, monitor); error = ignore_vm_death(error); if (error != JVMTI_ERROR_NONE) { @@ -1126,7 +1116,7 @@ debugMonitorNotifyAll(jrawMonitorID monitor) { jvmtiError error; - error = FUNC_PTR(gdata->jvmti,RawMonitorNotifyAll) + error = JVMTI_FUNC_PTR(gdata->jvmti,RawMonitorNotifyAll) (gdata->jvmti, monitor); error = ignore_vm_death(error); if (error != JVMTI_ERROR_NONE) { @@ -1140,7 +1130,7 @@ debugMonitorCreate(char *name) jrawMonitorID monitor; jvmtiError error; - error = FUNC_PTR(gdata->jvmti,CreateRawMonitor) + error = JVMTI_FUNC_PTR(gdata->jvmti,CreateRawMonitor) (gdata->jvmti, name, &monitor); if (error != JVMTI_ERROR_NONE) { EXIT_ERROR(error, "on creation of a raw monitor"); @@ -1153,7 +1143,7 @@ debugMonitorDestroy(jrawMonitorID monitor) { jvmtiError error; - error = FUNC_PTR(gdata->jvmti,DestroyRawMonitor) + error = JVMTI_FUNC_PTR(gdata->jvmti,DestroyRawMonitor) (gdata->jvmti, monitor); error = ignore_vm_death(error); if (error != JVMTI_ERROR_NONE) { @@ -1212,7 +1202,7 @@ classSignature(jclass clazz, char **psignature, char **pgeneric_signature) * pgeneric_signature can be NULL, and GetClassSignature * accepts NULL. */ - error = FUNC_PTR(gdata->jvmti,GetClassSignature) + error = JVMTI_FUNC_PTR(gdata->jvmti,GetClassSignature) (gdata->jvmti, clazz, &signature, pgeneric_signature); if ( psignature != NULL ) { @@ -1784,7 +1774,7 @@ jvmtiAllocate(jint numBytes) if ( numBytes == 0 ) { return NULL; } - error = FUNC_PTR(gdata->jvmti,Allocate) + error = JVMTI_FUNC_PTR(gdata->jvmti,Allocate) (gdata->jvmti, numBytes, (unsigned char**)&ptr); if (error != JVMTI_ERROR_NONE ) { EXIT_ERROR(error, "Can't allocate jvmti memory"); @@ -1799,7 +1789,7 @@ jvmtiDeallocate(void *ptr) if ( ptr == NULL ) { return; } - error = FUNC_PTR(gdata->jvmti,Deallocate) + error = JVMTI_FUNC_PTR(gdata->jvmti,Deallocate) (gdata->jvmti, ptr); if (error != JVMTI_ERROR_NONE ) { EXIT_ERROR(error, "Can't deallocate jvmti memory"); diff --git a/src/jdk.jdwp.agent/share/native/libjdwp/util.h b/src/jdk.jdwp.agent/share/native/libjdwp/util.h index c4d31774c64..43c4b143471 100644 --- a/src/jdk.jdwp.agent/share/native/libjdwp/util.h +++ b/src/jdk.jdwp.agent/share/native/libjdwp/util.h @@ -337,7 +337,6 @@ jint jvmtiMajorVersion(void); jint jvmtiMinorVersion(void); jint jvmtiMicroVersion(void); jvmtiError getSourceDebugExtension(jclass clazz, char **extensionPtr); -jboolean canSuspendResumeThreadLists(void); jrawMonitorID debugMonitorCreate(char *name); void debugMonitorEnter(jrawMonitorID theLock); diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/AbstractEventStream.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/AbstractEventStream.java index 1d6dc27e808..05558ff3551 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/AbstractEventStream.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/AbstractEventStream.java @@ -48,7 +48,7 @@ * an event stream. */ abstract class AbstractEventStream implements EventStream { - private final static AtomicLong counter = new AtomicLong(0); + private final static AtomicLong counter = new AtomicLong(); private final Object terminated = new Object(); private final Runnable flushOperation = () -> dispatcher().runFlushActions(); diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/instrument/SocketChannelImplInstrumentor.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/instrument/SocketChannelImplInstrumentor.java index 0e0486b6ab0..08f1b567cff 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/instrument/SocketChannelImplInstrumentor.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/instrument/SocketChannelImplInstrumentor.java @@ -27,8 +27,9 @@ import java.io.IOException; import java.net.InetSocketAddress; +import java.net.SocketAddress; +import java.net.UnixDomainSocketAddress; import java.nio.ByteBuffer; - import jdk.jfr.events.Handlers; import jdk.jfr.internal.handlers.EventHandler; @@ -41,8 +42,6 @@ final class SocketChannelImplInstrumentor { private SocketChannelImplInstrumentor() { } - private InetSocketAddress remoteAddress; - @SuppressWarnings("deprecation") @JIInstrumentationMethod public int read(ByteBuffer dst) throws IOException { @@ -58,16 +57,28 @@ public int read(ByteBuffer dst) throws IOException { } finally { long duration = EventHandler.timestamp() - start; if (handler.shouldCommit(duration)) { - String hostString = remoteAddress.getAddress().toString(); - int delimiterIndex = hostString.lastIndexOf('/'); + SocketAddress remoteAddress = getRemoteAddress(); + if (remoteAddress instanceof InetSocketAddress) { + InetSocketAddress isa = (InetSocketAddress) remoteAddress; + String hostString = isa.getAddress().toString(); + int delimiterIndex = hostString.lastIndexOf('/'); - String host = hostString.substring(0, delimiterIndex); - String address = hostString.substring(delimiterIndex + 1); - int port = remoteAddress.getPort(); - if (bytesRead < 0) { - handler.write(start, duration, host, address, port, 0, 0L, true); + String host = hostString.substring(0, delimiterIndex); + String address = hostString.substring(delimiterIndex + 1); + int port = isa.getPort(); + if (bytesRead < 0) { + handler.write(start, duration, host, address, port, 0, 0L, true); + } else { + handler.write(start, duration, host, address, port, 0, bytesRead, false); + } } else { - handler.write(start, duration, host, address, port, 0, bytesRead, false); + UnixDomainSocketAddress udsa = (UnixDomainSocketAddress) remoteAddress; + String path = "[" + udsa.getPath().toString() + "]"; + if (bytesRead < 0) { + handler.write(start, duration, "Unix domain socket", path, 0, 0, 0L, true); + } else { + handler.write(start, duration, "Unix domain socket", path, 0, 0, bytesRead, false); + } } } } @@ -81,7 +92,6 @@ public long read(ByteBuffer[] dsts, int offset, int length) throws IOException { if (!handler.isEnabled()) { return read(dsts, offset, length); } - long bytesRead = 0; long start = 0; try { @@ -90,16 +100,28 @@ public long read(ByteBuffer[] dsts, int offset, int length) throws IOException { } finally { long duration = EventHandler.timestamp() - start; if (handler.shouldCommit(duration)) { - String hostString = remoteAddress.getAddress().toString(); - int delimiterIndex = hostString.lastIndexOf('/'); + SocketAddress remoteAddress = getRemoteAddress(); + if (remoteAddress instanceof InetSocketAddress) { + InetSocketAddress isa = (InetSocketAddress) remoteAddress; + String hostString = isa.getAddress().toString(); + int delimiterIndex = hostString.lastIndexOf('/'); - String host = hostString.substring(0, delimiterIndex); - String address = hostString.substring(delimiterIndex + 1); - int port = remoteAddress.getPort(); - if (bytesRead < 0) { - handler.write(start, duration, host, address, port, 0, 0L, true); + String host = hostString.substring(0, delimiterIndex); + String address = hostString.substring(delimiterIndex + 1); + int port = isa.getPort(); + if (bytesRead < 0) { + handler.write(start, duration, host, address, port, 0, 0L, true); + } else { + handler.write(start, duration, host, address, port, 0, bytesRead, false); + } } else { - handler.write(start, duration, host, address, port, 0, bytesRead, false); + UnixDomainSocketAddress udsa = (UnixDomainSocketAddress) remoteAddress; + String path = "[" + udsa.getPath().toString() + "]"; + if (bytesRead < 0) { + handler.write(start, duration, "Unix domain socket", path, 0, 0, 0L, true); + } else { + handler.write(start, duration, "Unix domain socket", path, 0, 0, bytesRead, false); + } } } } @@ -121,19 +143,32 @@ public int write(ByteBuffer buf) throws IOException { } finally { long duration = EventHandler.timestamp() - start; if (handler.shouldCommit(duration)) { - String hostString = remoteAddress.getAddress().toString(); - int delimiterIndex = hostString.lastIndexOf('/'); - - String host = hostString.substring(0, delimiterIndex); - String address = hostString.substring(delimiterIndex + 1); - int port = remoteAddress.getPort(); long bytes = bytesWritten < 0 ? 0 : bytesWritten; - handler.write(start, duration, host, address, port, bytes); + SocketAddress remoteAddress = getRemoteAddress(); + if (remoteAddress instanceof InetSocketAddress) { + InetSocketAddress isa = (InetSocketAddress) remoteAddress; + String hostString = isa.getAddress().toString(); + int delimiterIndex = hostString.lastIndexOf('/'); + + String host = hostString.substring(0, delimiterIndex); + String address = hostString.substring(delimiterIndex + 1); + int port = isa.getPort(); + handler.write(start, duration, host, address, port, bytes); + } else { + UnixDomainSocketAddress udsa = (UnixDomainSocketAddress) remoteAddress; + String path = "[" + udsa.getPath().toString() + "]"; + handler.write(start, duration, "Unix domain socket", path, 0, bytes); + } } } return bytesWritten; } + public SocketAddress getRemoteAddress() throws IOException { + // gets replaced by call to instrumented class + return null; + } + @SuppressWarnings("deprecation") @JIInstrumentationMethod public long write(ByteBuffer[] srcs, int offset, int length) throws IOException { @@ -149,14 +184,22 @@ public long write(ByteBuffer[] srcs, int offset, int length) throws IOException } finally { long duration = EventHandler.timestamp() - start; if (handler.shouldCommit(duration)) { - String hostString = remoteAddress.getAddress().toString(); - int delimiterIndex = hostString.lastIndexOf('/'); - - String host = hostString.substring(0, delimiterIndex); - String address = hostString.substring(delimiterIndex + 1); - int port = remoteAddress.getPort(); long bytes = bytesWritten < 0 ? 0 : bytesWritten; - handler.write(start, duration, host, address, port, bytes); + SocketAddress remoteAddress = getRemoteAddress(); + if (remoteAddress instanceof InetSocketAddress) { + InetSocketAddress isa = (InetSocketAddress) remoteAddress; + String hostString = isa.getAddress().toString(); + int delimiterIndex = hostString.lastIndexOf('/'); + + String host = hostString.substring(0, delimiterIndex); + String address = hostString.substring(delimiterIndex + 1); + int port = isa.getPort(); + handler.write(start, duration, host, address, port, bytes); + } else { + UnixDomainSocketAddress udsa = (UnixDomainSocketAddress) remoteAddress; + String path = "[" + udsa.getPath().toString() + "]"; + handler.write(start, duration, "Unix domain socket", path, 0, bytes); + } } } return bytesWritten; diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/instrument/ThrowableTracer.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/instrument/ThrowableTracer.java index 404a3fd772d..d3f03636605 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/instrument/ThrowableTracer.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/instrument/ThrowableTracer.java @@ -32,7 +32,7 @@ public final class ThrowableTracer { - private static final AtomicLong numThrowables = new AtomicLong(0); + private static final AtomicLong numThrowables = new AtomicLong(); public static void traceError(Error e, String message) { if (e instanceof OutOfMemoryError) { diff --git a/src/java.base/share/man/jfr.1 b/src/jdk.jfr/share/man/jfr.1 similarity index 100% rename from src/java.base/share/man/jfr.1 rename to src/jdk.jfr/share/man/jfr.1 diff --git a/src/jdk.net/linux/classes/jdk/net/LinuxSocketOptions.java b/src/jdk.net/linux/classes/jdk/net/LinuxSocketOptions.java index e0ded9dd364..aac634e6aed 100644 --- a/src/jdk.net/linux/classes/jdk/net/LinuxSocketOptions.java +++ b/src/jdk.net/linux/classes/jdk/net/LinuxSocketOptions.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2020, 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,12 @@ package jdk.net; import java.net.SocketException; +import java.nio.file.attribute.UserPrincipal; +import java.nio.file.attribute.GroupPrincipal; import java.security.AccessController; import java.security.PrivilegedAction; import jdk.net.ExtendedSocketOptions.PlatformSocketOptions; +import sun.nio.fs.UnixUserPrincipals; class LinuxSocketOptions extends PlatformSocketOptions { @@ -54,6 +57,10 @@ boolean keepAliveOptionsSupported() { return keepAliveOptionsSupported0(); } + boolean peerCredentialsSupported() { + return true; + } + @Override void setTcpkeepAliveProbes(int fd, final int value) throws SocketException { setTcpkeepAliveProbes0(fd, value); @@ -94,6 +101,16 @@ int getIncomingNapiId(int fd) throws SocketException { return getIncomingNapiId0(fd); } + @Override + UnixDomainPrincipal getSoPeerCred(int fd) throws SocketException { + long l = getSoPeerCred0(fd); + int uid = (int)(l >> 32); + int gid = (int)l; + UserPrincipal user = UnixUserPrincipals.fromUid(uid); + GroupPrincipal group = UnixUserPrincipals.fromGid(gid); + return new UnixDomainPrincipal(user, group); + } + private static native void setTcpkeepAliveProbes0(int fd, int value) throws SocketException; private static native void setTcpKeepAliveTime0(int fd, int value) throws SocketException; private static native void setTcpKeepAliveIntvl0(int fd, int value) throws SocketException; @@ -102,6 +119,7 @@ int getIncomingNapiId(int fd) throws SocketException { private static native int getTcpKeepAliveIntvl0(int fd) throws SocketException; private static native void setQuickAck0(int fd, boolean on) throws SocketException; private static native boolean getQuickAck0(int fd) throws SocketException; + private static native long getSoPeerCred0(int fd) throws SocketException; private static native boolean keepAliveOptionsSupported0(); private static native boolean quickAckSupported0(); private static native boolean incomingNapiIdSupported0(); diff --git a/src/jdk.net/linux/native/libextnet/LinuxSocketOptions.c b/src/jdk.net/linux/native/libextnet/LinuxSocketOptions.c index 369fe6b3130..a10d9418e9d 100644 --- a/src/jdk.net/linux/native/libextnet/LinuxSocketOptions.c +++ b/src/jdk.net/linux/native/libextnet/LinuxSocketOptions.c @@ -23,6 +23,8 @@ * questions. */ #include +#include +#include #include #include #include @@ -109,6 +111,29 @@ JNIEXPORT jboolean JNICALL Java_jdk_net_LinuxSocketOptions_quickAckSupported0 return socketOptionSupported(SOL_SOCKET, TCP_QUICKACK); } +/* + * Class: jdk_net_LinuxSocketOptions + * Method: getSoPeerCred0 + * Signature: (I)L + */ +JNIEXPORT jlong JNICALL Java_jdk_net_LinuxSocketOptions_getSoPeerCred0 + (JNIEnv *env, jclass clazz, jint fd) { + + int rv; + struct ucred cred; + socklen_t len = sizeof(cred); + + if ((rv=getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cred, &len)) < 0) { + handleError(env, rv, "get SO_PEERCRED failed"); + } else { + if ((int)cred.uid == -1) { + handleError(env, -1, "get SO_PEERCRED failed"); + cred.uid = cred.gid = -1; + } + } + return (((jlong)cred.uid) << 32) | (cred.gid & 0xffffffffL); +} + /* * Class: jdk_net_LinuxSocketOptions * Method: keepAliveOptionsSupported0 diff --git a/src/jdk.net/macosx/classes/jdk/net/MacOSXSocketOptions.java b/src/jdk.net/macosx/classes/jdk/net/MacOSXSocketOptions.java index 065a233629b..88274d1b27e 100644 --- a/src/jdk.net/macosx/classes/jdk/net/MacOSXSocketOptions.java +++ b/src/jdk.net/macosx/classes/jdk/net/MacOSXSocketOptions.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2020, 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,12 @@ package jdk.net; import java.net.SocketException; +import java.nio.file.attribute.UserPrincipal; +import java.nio.file.attribute.GroupPrincipal; import java.security.AccessController; import java.security.PrivilegedAction; import jdk.net.ExtendedSocketOptions.PlatformSocketOptions; +import sun.nio.fs.UnixUserPrincipals; class MacOSXSocketOptions extends PlatformSocketOptions { @@ -49,6 +52,11 @@ void setTcpKeepAliveTime(int fd, final int value) throws SocketException { setTcpKeepAliveTime0(fd, value); } + @Override + boolean peerCredentialsSupported() { + return true; + } + @Override void setTcpKeepAliveIntvl(int fd, final int value) throws SocketException { setTcpKeepAliveIntvl0(fd, value); @@ -69,12 +77,23 @@ int getTcpKeepAliveIntvl(int fd) throws SocketException { return getTcpKeepAliveIntvl0(fd); } + @Override + UnixDomainPrincipal getSoPeerCred(int fd) throws SocketException { + long l = getSoPeerCred0(fd); + int uid = (int)(l >> 32); + int gid = (int)l; + UserPrincipal user = UnixUserPrincipals.fromUid(uid); + GroupPrincipal group = UnixUserPrincipals.fromGid(gid); + return new UnixDomainPrincipal(user, group); + } + private static native void setTcpkeepAliveProbes0(int fd, int value) throws SocketException; private static native void setTcpKeepAliveTime0(int fd, int value) throws SocketException; private static native void setTcpKeepAliveIntvl0(int fd, int value) throws SocketException; private static native int getTcpkeepAliveProbes0(int fd) throws SocketException; private static native int getTcpKeepAliveTime0(int fd) throws SocketException; private static native int getTcpKeepAliveIntvl0(int fd) throws SocketException; + private static native long getSoPeerCred0(int fd) throws SocketException; private static native boolean keepAliveOptionsSupported0(); static { if (System.getSecurityManager() == null) { diff --git a/src/jdk.net/macosx/native/libextnet/MacOSXSocketOptions.c b/src/jdk.net/macosx/native/libextnet/MacOSXSocketOptions.c index c16dab1a1c7..2e908c1f918 100644 --- a/src/jdk.net/macosx/native/libextnet/MacOSXSocketOptions.c +++ b/src/jdk.net/macosx/native/libextnet/MacOSXSocketOptions.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2020, 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,6 +23,7 @@ * questions. */ #include +#include #include #include #include @@ -123,6 +124,25 @@ JNIEXPORT jint JNICALL Java_jdk_net_MacOSXSocketOptions_getTcpkeepAliveProbes0 return optval; } +/* + * Class: jdk_net_MacOSXSocketOptions + * Method: getSoPeerCred0 + * Signature: (I)L + */ +JNIEXPORT jlong JNICALL Java_jdk_net_MacOSXSocketOptions_getSoPeerCred0 + (JNIEnv *env, jclass clazz, jint fd) { + + jint rv; + int uid, gid; + rv = getpeereid(fd, (uid_t *)&uid, (gid_t *)&gid); + handleError(env, rv, "get peer eid failed"); + if (rv == -1) { + uid = gid = -1; + } + return (((long)uid) << 32) | (gid & 0xffffffffL); +} + + /* * Class: jdk_net_MacOSXSocketOptions * Method: getTcpKeepAliveTime0 diff --git a/src/jdk.net/share/classes/jdk/net/ExtendedSocketOptions.java b/src/jdk.net/share/classes/jdk/net/ExtendedSocketOptions.java index 0a86bac9b6c..1d6855add17 100644 --- a/src/jdk.net/share/classes/jdk/net/ExtendedSocketOptions.java +++ b/src/jdk.net/share/classes/jdk/net/ExtendedSocketOptions.java @@ -180,6 +180,25 @@ private ExtendedSocketOptions() { } public static final SocketOption SO_INCOMING_NAPI_ID = new ExtSocketOption("SO_INCOMING_NAPI_ID", Integer.class); + /** + * Unix Domain peer credentials. + * + *

    The value of this socket option is a {@link UnixDomainPrincipal} that + * represents the credentials of a peer connected to a Unix Domain socket. + * The credentials are those that applied at the time the socket was first + * connected or accepted. + * + *

    The socket option is read-only and an attempt to set the socket option + * will throw {@code SocketException}. {@code SocketException} is also thrown + * when attempting to get the value of the socket option on an unconnected Unix + * Domain socket. + * + * @since 16 + */ + public static final SocketOption SO_PEERCRED + = new ExtSocketOption + ("SO_PEERCRED", UnixDomainPrincipal.class); + private static final PlatformSocketOptions platformSocketOptions = PlatformSocketOptions.get(); @@ -187,6 +206,8 @@ private ExtendedSocketOptions() { } platformSocketOptions.quickAckSupported(); private static final boolean keepAliveOptSupported = platformSocketOptions.keepAliveOptionsSupported(); + private static final boolean peerCredentialsSupported = + platformSocketOptions.peerCredentialsSupported(); private static final boolean incomingNapiIdOptSupported = platformSocketOptions.incomingNapiIdSupported(); private static final Set> extendedOptions = options(); @@ -202,6 +223,9 @@ static Set> options() { if (keepAliveOptSupported) { options.addAll(Set.of(TCP_KEEPCOUNT, TCP_KEEPIDLE, TCP_KEEPINTERVAL)); } + if (peerCredentialsSupported) { + options.add(SO_PEERCRED); + } return Collections.unmodifiableSet(options); } @@ -233,6 +257,8 @@ public void setOption(FileDescriptor fd, throw new UnsupportedOperationException("Attempt to set unsupported option " + option); else throw new SocketException("Attempt to set read only option " + option); + } else if (option == SO_PEERCRED) { + throw new SocketException("SO_PEERCRED cannot be set "); } else { throw new InternalError("Unexpected option " + option); } @@ -255,6 +281,8 @@ public Object getOption(FileDescriptor fd, return getTcpKeepAliveTime(fd); } else if (option == TCP_KEEPINTERVAL) { return getTcpKeepAliveIntvl(fd); + } else if (option == SO_PEERCRED) { + return getSoPeerCred(fd); } else if (option == SO_INCOMING_NAPI_ID) { return getIncomingNapiId(fd); } else { @@ -272,6 +300,11 @@ private static void setQuickAckOption(FileDescriptor fd, boolean enable) platformSocketOptions.setQuickAck(fdAccess.get(fd), enable); } + private static Object getSoPeerCred(FileDescriptor fd) + throws SocketException { + return platformSocketOptions.getSoPeerCred(fdAccess.get(fd)); + } + private static Object getQuickAckOption(FileDescriptor fd) throws SocketException { return platformSocketOptions.getQuickAck(fdAccess.get(fd)); @@ -345,6 +378,10 @@ static PlatformSocketOptions get() { return instance; } + boolean peerCredentialsSupported() { + return false; + } + void setQuickAck(int fd, boolean on) throws SocketException { throw new UnsupportedOperationException("unsupported TCP_QUICKACK option"); } @@ -369,6 +406,10 @@ void setTcpKeepAliveTime(int fd, final int value) throws SocketException { throw new UnsupportedOperationException("unsupported TCP_KEEPIDLE option"); } + UnixDomainPrincipal getSoPeerCred(int fd) throws SocketException { + throw new UnsupportedOperationException("unsupported SO_PEERCRED option"); + } + void setTcpKeepAliveIntvl(int fd, final int value) throws SocketException { throw new UnsupportedOperationException("unsupported TCP_KEEPINTVL option"); } diff --git a/src/jdk.net/share/classes/jdk/net/UnixDomainPrincipal.java b/src/jdk.net/share/classes/jdk/net/UnixDomainPrincipal.java new file mode 100644 index 00000000000..0808204d373 --- /dev/null +++ b/src/jdk.net/share/classes/jdk/net/UnixDomainPrincipal.java @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2020, 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.net; + +import java.nio.file.attribute.UserPrincipal; +import java.nio.file.attribute.GroupPrincipal; +import java.util.Objects; + +/** + * Represents the credentials of a peer connected to a + * + * Unix domain socket. + * + * @since 16 + */ + +public final class UnixDomainPrincipal { + private final UserPrincipal user; + private final GroupPrincipal group; + + /** + * Creates a UnixDomainPrincipal. + * + * @param user the user identity + * + * @param group the group identity + * + * @throws NullPointerException if {@code user} or {@code group} are {@code null}. + */ + public UnixDomainPrincipal(UserPrincipal user, GroupPrincipal group) { + this.user = Objects.requireNonNull(user); + this.group = Objects.requireNonNull(group); + } + + /** + * Returns true if {@code obj} is a {@code UnixDomainPrincipal} + * and its user and group are equal to this user and group. + * + * @param obj the object to compare with + * @return true if this equal to obj + */ + public boolean equals(Object obj) { + if (obj instanceof UnixDomainPrincipal) { + UnixDomainPrincipal that = (UnixDomainPrincipal) obj; + return Objects.equals(this.user, that.user) + && Objects.equals(this.group, that.group); + } + return false; + } + + /** + * Returns a hashcode calculated from the user and group + */ + public int hashCode() { + return Objects.hash(user, group); + } + + /** + * Returns this object's {@link UserPrincipal} + * + * @return this object's user + */ + public UserPrincipal user() { + return user; + } + + /** + * Returns this object's {@link GroupPrincipal} + * + * @return this object's user + */ + public GroupPrincipal group() { + return group; + } +} diff --git a/test/hotspot/gtest/gc/z/test_zForwarding.cpp b/test/hotspot/gtest/gc/z/test_zForwarding.cpp index 7e7be1379b5..1da6764801f 100644 --- a/test/hotspot/gtest/gc/z/test_zForwarding.cpp +++ b/test/hotspot/gtest/gc/z/test_zForwarding.cpp @@ -24,6 +24,7 @@ #include "precompiled.hpp" #include "gc/z/zAddress.inline.hpp" #include "gc/z/zForwarding.inline.hpp" +#include "gc/z/zForwardingAllocator.inline.hpp" #include "gc/z/zGlobals.hpp" #include "gc/z/zPage.inline.hpp" #include "unittest.hpp" @@ -157,14 +158,16 @@ class ZForwardingTest : public Test { const size_t live_bytes = live_objects * object_size; page.inc_live(live_objects, live_bytes); + // Setup allocator + ZForwardingAllocator allocator; + const uint32_t nentries = ZForwarding::nentries(&page); + allocator.reset((sizeof(ZForwarding)) + (nentries * sizeof(ZForwardingEntry))); + // Setup forwarding - ZForwarding* const forwarding = ZForwarding::create(&page); + ZForwarding* const forwarding = ZForwarding::alloc(&allocator, &page); // Actual test function (*function)(forwarding); - - // Teardown forwarding - ZForwarding::destroy(forwarding); } // Run the given function with a few different input values. diff --git a/test/hotspot/gtest/runtime/test_stackoverflow.cpp b/test/hotspot/gtest/runtime/test_stackoverflow.cpp new file mode 100644 index 00000000000..52a7611e839 --- /dev/null +++ b/test/hotspot/gtest/runtime/test_stackoverflow.cpp @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "runtime/os.hpp" +#include "runtime/globals.hpp" +#include "runtime/stackOverflow.hpp" +#include "utilities/align.hpp" +#include "utilities/globalDefinitions.hpp" +#include "utilities/ostream.hpp" +#include "unittest.hpp" + + +TEST_VM(StackOverflow, basics) { + StackOverflow so; + + // Make up a stack range. No need to allocate anything. Size has to be large enough + // to fit sum of all zones into them. + address base = (address) 0x40000000; + const size_t size = os::vm_page_size() * 100; + address end = base - size; + so.initialize(base, end); + + // Walking down the "stack" check for consistency of the three "in_stack_xxx" functions + enum { normal_stack, reserved_or_yellow_zone, red_zone } where = normal_stack; + for (address p = base - 1; p >= end; p -= os::vm_page_size()) { + // tty->print_cr(PTR_FORMAT " %d %d %d", p2i(p), + // (int)so.in_stack_reserved_zone(p), + // (int)so.in_stack_yellow_reserved_zone(p), + // (int)so.in_stack_red_zone(p)); + switch (where) { + case normal_stack: + ASSERT_FALSE(so.in_stack_red_zone(p)); + if (so.in_stack_yellow_reserved_zone(p)) { + if (StackReservedPages > 0) { + ASSERT_TRUE(so.in_stack_reserved_zone(p)); + } else { + ASSERT_FALSE(so.in_stack_reserved_zone(p)); + } + where = reserved_or_yellow_zone; + } else { + ASSERT_FALSE(so.in_stack_reserved_zone((p))); + } + break; + case reserved_or_yellow_zone: + if (so.in_stack_red_zone(p)) { + ASSERT_FALSE(so.in_stack_yellow_reserved_zone(p)); + where = red_zone; + } else { + ASSERT_TRUE(so.in_stack_yellow_reserved_zone(p)); + } + break; + case red_zone: + ASSERT_TRUE(so.in_stack_red_zone(p)); + ASSERT_FALSE(so.in_stack_yellow_reserved_zone(p)); + ASSERT_FALSE(so.in_stack_reserved_zone((p))); + break; + } + } + ASSERT_EQ(where, red_zone); + + // Check bases. + ASSERT_FALSE(so.in_stack_red_zone(so.stack_red_zone_base())); + ASSERT_TRUE(so.in_stack_red_zone(so.stack_red_zone_base() - 1)); + ASSERT_TRUE(so.in_stack_yellow_reserved_zone(so.stack_red_zone_base())); + ASSERT_FALSE(so.in_stack_reserved_zone(so.stack_reserved_zone_base())); + if (so.stack_reserved_zone_size() > 0) { + ASSERT_TRUE(so.in_stack_reserved_zone(so.stack_reserved_zone_base() - 1)); + } +} diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index a5afc8bc4e5..680184d8403 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -64,6 +64,8 @@ compiler/rtm/print/TestPrintPreciseRTMLockingStatistics.java 8183263 generic-x64 compiler/c2/Test8004741.java 8235801 generic-all +compiler/loopstripmining/BackedgeNodeWithOutOfLoopControl.java 8255120 generic-all + ############################################################################# # :hotspot_gc diff --git a/test/hotspot/jtreg/TEST.ROOT b/test/hotspot/jtreg/TEST.ROOT index 77e1850538a..0ef3c2d2dc4 100644 --- a/test/hotspot/jtreg/TEST.ROOT +++ b/test/hotspot/jtreg/TEST.ROOT @@ -75,7 +75,8 @@ requires.properties= \ vm.compiler2.enabled \ vm.musl \ docker.support \ - test.vm.gc.nvdimm + test.vm.gc.nvdimm \ + jdk.containerized # Minimum jtreg version requiredVersion=5.1 b1 diff --git a/test/hotspot/jtreg/TEST.groups b/test/hotspot/jtreg/TEST.groups index 6037df5c2b8..3a53477ed88 100644 --- a/test/hotspot/jtreg/TEST.groups +++ b/test/hotspot/jtreg/TEST.groups @@ -202,7 +202,6 @@ tier1_gc_2 = \ -gc/g1/ \ -gc/logging/TestUnifiedLoggingSwitchStress.java \ -gc/stress \ - -gc/survivorAlignment/TestPromotionFromSurvivorToTenuredAfterMinorGC.java \ -gc/metaspace/CompressedClassSpaceSizeInJmapHeap.java \ -gc/shenandoah \ -gc/nvdimm @@ -307,6 +306,7 @@ tier1_runtime = \ -runtime/cds/CdsSameObjectAlignment.java \ -runtime/cds/SharedBaseAddress.java \ -runtime/Thread/CancellableThreadTest.java \ + -runtime/Thread/ThreadCountLimit.java \ -runtime/Thread/TestThreadDumpMonitorContention.java \ -runtime/Unsafe/RangeCheck.java \ sanity/ \ @@ -325,6 +325,7 @@ hotspot_appcds_dynamic = \ -runtime/cds/appcds/dynamicArchive \ -runtime/cds/appcds/loaderConstraints/DynamicLoaderConstraintsTest.java \ -runtime/cds/appcds/javaldr/ArrayTest.java \ + -runtime/cds/appcds/javaldr/ExceptionDuringDumpAtObjectsInitPhase.java \ -runtime/cds/appcds/javaldr/GCSharedStringsDuringDump.java \ -runtime/cds/appcds/javaldr/HumongousDuringDump.java \ -runtime/cds/appcds/javaldr/LockDuringDump.java \ diff --git a/test/hotspot/jtreg/compiler/jvmci/compilerToVM/IsCompilableTest.java b/test/hotspot/jtreg/compiler/jvmci/compilerToVM/IsCompilableTest.java index 7b6727515e2..e9d38bddde0 100644 --- a/test/hotspot/jtreg/compiler/jvmci/compilerToVM/IsCompilableTest.java +++ b/test/hotspot/jtreg/compiler/jvmci/compilerToVM/IsCompilableTest.java @@ -27,6 +27,7 @@ * @requires vm.jvmci & vm.compMode == "Xmixed" * @library /test/lib / * @library ../common/patches + * @modules jdk.internal.vm.compiler * @modules java.base/jdk.internal.misc * @modules java.base/jdk.internal.org.objectweb.asm * java.base/jdk.internal.org.objectweb.asm.tree @@ -41,6 +42,23 @@ * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI -XX:+UseJVMCICompiler * compiler.jvmci.compilerToVM.IsCompilableTest + */ + +/** + * @test + * @requires vm.jvmci & vm.compMode == "Xmixed" + * @library /test/lib / + * @library ../common/patches + * @modules java.base/jdk.internal.misc + * @modules java.base/jdk.internal.org.objectweb.asm + * java.base/jdk.internal.org.objectweb.asm.tree + * jdk.internal.vm.ci/jdk.vm.ci.hotspot + * jdk.internal.vm.ci/jdk.vm.ci.code + * jdk.internal.vm.ci/jdk.vm.ci.meta + * jdk.internal.vm.ci/jdk.vm.ci.runtime + * + * @build jdk.internal.vm.ci/jdk.vm.ci.hotspot.CompilerToVMHelper sun.hotspot.WhiteBox + * @run driver ClassFileInstaller sun.hotspot.WhiteBox * @run main/othervm -Xbootclasspath/a:. * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI -XX:-UseJVMCICompiler diff --git a/test/hotspot/jtreg/compiler/unsafe/TestUnsafeStaticFieldAccess.java b/test/hotspot/jtreg/compiler/unsafe/TestUnsafeStaticFieldAccess.java new file mode 100644 index 00000000000..ef31ebd8eb0 --- /dev/null +++ b/test/hotspot/jtreg/compiler/unsafe/TestUnsafeStaticFieldAccess.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8255466 + * @summary unsafe access to static field causes crash + * @modules java.base/jdk.internal.misc + * + * @run main/othervm -Xcomp -XX:CompileCommand=compileonly,TestUnsafeStaticFieldAccess::* TestUnsafeStaticFieldAccess + * + */ + +import jdk.internal.misc.Unsafe; +import java.lang.reflect.Field; + +public class TestUnsafeStaticFieldAccess { + private static final Unsafe UNSAFE = Unsafe.getUnsafe(); + private static final long offset; + private static volatile Class clazz; + + private static int field; + + static { + long o = 0; + for (Field f : TestUnsafeStaticFieldAccess.class.getDeclaredFields()) { + if (f.getName().equals("field")) { + o = UNSAFE.staticFieldOffset(f); + break; + } + } + offset = o; + clazz = TestUnsafeStaticFieldAccess.class; + } + + + public static void main(String[] args) { + for (int i = 0; i < 12000; i++) { + UNSAFE.getInt(clazz, offset); + } + } +} diff --git a/test/hotspot/jtreg/compiler/vectorization/TestForEachRem.java b/test/hotspot/jtreg/compiler/vectorization/TestForEachRem.java new file mode 100644 index 00000000000..12c5e5ba9ad --- /dev/null +++ b/test/hotspot/jtreg/compiler/vectorization/TestForEachRem.java @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8251994 + * @summary Test vectorization of Streams$RangeIntSpliterator::forEachRemaining + * @requires vm.compiler2.enabled & vm.compMode != "Xint" + * + * @run main compiler.vectorization.TestForEachRem test1 + * @run main compiler.vectorization.TestForEachRem test2 + * @run main compiler.vectorization.TestForEachRem test3 + * @run main compiler.vectorization.TestForEachRem test4 + */ + +package compiler.vectorization; + +import java.util.stream.IntStream; + +public class TestForEachRem { + static final int RANGE = 512; + static final int ITER = 100; + + static void test1(int[] data) { + IntStream.range(0, RANGE).parallel().forEach(j -> { + data[j] = j + 1; + }); + } + + static void test2(int[] data) { + IntStream.range(0, RANGE - 1).forEach(j -> { + data[j] = data[j] + data[j + 1]; + }); + } + + static void test3(int[] data, int A, int B) { + IntStream.range(0, RANGE - 1).forEach(j -> { + data[j] = A * data[j] + B * data[j + 1]; + }); + } + + static void test4(int[] data) { + IntStream.range(0, RANGE - 1).forEach(j -> { + data[j + 1] = data[j]; + }); + } + + static void verify(String name, int[] data, int[] gold) { + for (int i = 0; i < RANGE; i++) { + if (data[i] != gold[i]) { + throw new RuntimeException(" Invalid " + name + " result: data[" + i + "]: " + data[i] + " != " + gold[i]); + } + } + } + + public static void main(String[] args) { + int[] data = new int[RANGE]; + int[] gold = new int[RANGE]; + + if (args.length == 0) { + throw new RuntimeException(" Missing test name: test1, test2, test3, test4"); + } + + if (args[0].equals("test1")) { + System.out.println(" Run test1 ..."); + test1(gold); + for (int i = 0; i < ITER; i++) { + test1(data); + } + verify("test1", data, gold); + System.out.println(" Finished test1."); + } + + if (args[0].equals("test2")) { + System.out.println(" Run test2 ..."); + test1(gold); + test2(gold); + for (int i = 0; i < ITER; i++) { + test1(data); // reset + test2(data); + } + verify("test2", data, gold); + System.out.println(" Finished test2."); + } + + if (args[0].equals("test3")) { + System.out.println(" Run test3 ..."); + test1(gold); + test3(gold, 2, 3); + for (int i = 0; i < ITER; i++) { + test1(data); // reset + test3(data, 2, 3); + } + verify("test3", data, gold); + System.out.println(" Finished test3."); + } + + if (args[0].equals("test4")) { + System.out.println(" Run test4 ..."); + test1(gold); // reset + test4(gold); + for (int i = 0; i < ITER; i++) { + test1(data); // reset + test4(data); + } + verify("test4", data, gold); + System.out.println(" Finished test4."); + } + } +} diff --git a/test/hotspot/jtreg/compiler/vectorization/TestOptionVectorize.java b/test/hotspot/jtreg/compiler/vectorization/TestOptionVectorize.java new file mode 100644 index 00000000000..566868f68d4 --- /dev/null +++ b/test/hotspot/jtreg/compiler/vectorization/TestOptionVectorize.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8251994 + * @summary Test forced vectorization + * @requires vm.compiler2.enabled & vm.compMode != "Xint" + * + * @run main/othervm -XX:CompileCommand=option,*::test,Vectorize compiler.vectorization.TestOptionVectorize + */ + +package compiler.vectorization; + +import java.util.stream.IntStream; + +public class TestOptionVectorize { + static final int RANGE = 512; + static final int ITER = 100; + + static void init(double[] data) { + IntStream.range(0, RANGE).parallel().forEach(j -> { + data[j] = j + 1; + }); + } + + static void test(double[] data, double A, double B) { + for (int i = RANGE - 1; i > 0; i--) { + for (int j = 0; j <= i - 1; j++) { + data[j] = A * data[j + 1] + B * data[j]; + } + } + } + + static void verify(double[] data, double[] gold) { + for (int i = 0; i < RANGE; i++) { + if (data[i] != gold[i]) { + throw new RuntimeException(" Invalid result: data[" + i + "]: " + data[i] + " != " + gold[i]); + } + } + } + + public static void main(String[] args) { + double[] data = new double[RANGE]; + double[] gold = new double[RANGE]; + System.out.println(" Run test ..."); + init(gold); // reset + test(gold, 1.0, 2.0); + for (int i = 0; i < ITER; i++) { + init(data); // reset + test(data, 1.0, 2.0); + } + verify(data, gold); + System.out.println(" Finished test."); + } +} diff --git a/test/hotspot/jtreg/containers/cgroup/CgroupSubsystemFactory.java b/test/hotspot/jtreg/containers/cgroup/CgroupSubsystemFactory.java index d9b3c8b7fbe..ae38b865bf8 100644 --- a/test/hotspot/jtreg/containers/cgroup/CgroupSubsystemFactory.java +++ b/test/hotspot/jtreg/containers/cgroup/CgroupSubsystemFactory.java @@ -53,6 +53,9 @@ public class CgroupSubsystemFactory { private static final int INVALID_CGROUPS_V1 = 4; private static final int INVALID_CGROUPS_NO_MOUNT = 5; private Path existingDirectory; + private Path cgroupv1CgroupsJoinControllers; + private Path cgroupv1SelfCgroupsJoinControllers; + private Path cgroupv1MountInfoJoinControllers; private Path cgroupv1CgInfoZeroHierarchy; private Path cgroupv1MntInfoZeroHierarchy; private Path cgroupv2CgInfoZeroHierarchy; @@ -81,6 +84,17 @@ public class CgroupSubsystemFactory { "1:name=systemd:/user.slice/user-15263.slice/user@15263.service/gnome-terminal-server.service\n" + "0::/user.slice/user-15263.slice/user@15263.service/gnome-terminal-server.service"; private String procSelfCgroupV2UnifiedContent = "0::/user.slice/user-1000.slice/session-3.scope"; + private String procSelfCgroupV1JoinControllers = + "9:freezer:/\n" + + "8:rdma:/\n" + + "7:blkio:/user.slice\n" + + "6:devices:/user.slice\n" + + "5:pids:/user.slice/user-1000.slice/session-2.scope\n" + + "4:cpu,cpuacct,memory,net_cls,net_prio,hugetlb:/user.slice/user-1000.slice/session-2.scope\n" + + "3:cpuset:/\n" + + "2:perf_event:/\n" + + "1:name=systemd:/user.slice/user-1000.slice/session-2.scope\n" + + "0::/user.slice/user-1000.slice/session-2.scope\n"; private String cgroupsZeroHierarchy = "#subsys_name hierarchy num_cgroups enabled\n" + "cpuset 0 1 1\n" + @@ -92,6 +106,21 @@ public class CgroupSubsystemFactory { "net_cls 0 1 1\n" + "blkio 0 1 1\n" + "perf_event 0 1 1 "; + private String cgroupsNonZeroJoinControllers = + "#subsys_name hierarchy num_cgroups enabled\n" + + "cpuset\t3\t1\t1\n" + + "cpu\t4\t153\t1\n" + + "cpuacct\t4\t153\t1\n" + + "blkio\t7\t87\t1\n" + + "memory\t4\t153\t1\n" + + "devices\t6\t87\t1\n" + + "freezer\t9\t1\t1\n" + + "net_cls\t4\t153\t1\n" + + "perf_event\t2\t1\t1\n" + + "net_prio\t4\t153\t1\n" + + "hugetlb\t4\t153\t1\n" + + "pids\t5\t95\t1\n" + + "rdma\t8\t1\t1\n"; private String cgroupV2LineHybrid = "31 30 0:27 / /sys/fs/cgroup/unified rw,nosuid,nodev,noexec,relatime shared:5 - cgroup2 none rw,seclabel,nsdelegate\n"; private String cgroupv1MountInfoLineMemory = "35 30 0:31 / /sys/fs/cgroup/memory rw,nosuid,nodev,noexec,relatime shared:7 - cgroup none rw,seclabel,memory\n"; private String mntInfoHybridStub = @@ -110,6 +139,18 @@ public class CgroupSubsystemFactory { private String mntInfoHybridMissingMemory = mntInfoHybridStub; private String mntInfoHybrid = cgroupV2LineHybrid + mntInfoHybridRest; private String mntInfoHybridFlippedOrder = mntInfoHybridRest + cgroupV2LineHybrid; + private String mntInfoCgroupv1JoinControllers = + "31 22 0:26 / /sys/fs/cgroup ro,nosuid,nodev,noexec shared:9 - tmpfs tmpfs ro,mode=755\n" + + "32 31 0:27 / /sys/fs/cgroup/unified rw,nosuid,nodev,noexec,relatime shared:10 - cgroup2 cgroup2 rw,nsdelegate\n" + + "33 31 0:28 / /sys/fs/cgroup/systemd rw,nosuid,nodev,noexec,relatime shared:11 - cgroup cgroup rw,xattr,name=systemd\n" + + "36 31 0:31 / /sys/fs/cgroup/perf_event rw,nosuid,nodev,noexec,relatime shared:15 - cgroup cgroup rw,perf_event\n" + + "37 31 0:32 / /sys/fs/cgroup/cpuset rw,nosuid,nodev,noexec,relatime shared:16 - cgroup cgroup rw,cpuset\n" + + "38 31 0:33 / /sys/fs/cgroup/cpu,cpuacct,net_cls,net_prio,hugetlb,memory rw,nosuid,nodev,noexec,relatime shared:17 - cgroup cgroup rw,cpu,cpuacct,memory,net_cls,net_prio,hugetlb\n" + + "39 31 0:34 / /sys/fs/cgroup/pids rw,nosuid,nodev,noexec,relatime shared:18 - cgroup cgroup rw,pids\n" + + "40 31 0:35 / /sys/fs/cgroup/devices rw,nosuid,nodev,noexec,relatime shared:19 - cgroup cgroup rw,devices\n" + + "41 31 0:36 / /sys/fs/cgroup/blkio rw,nosuid,nodev,noexec,relatime shared:20 - cgroup cgroup rw,blkio\n" + + "42 31 0:37 / /sys/fs/cgroup/rdma rw,nosuid,nodev,noexec,relatime shared:21 - cgroup cgroup rw,rdma\n" + + "43 31 0:38 / /sys/fs/cgroup/freezer rw,nosuid,nodev,noexec,relatime shared:22 - cgroup cgroup rw,freezer\n"; private String mntInfoCgroupv1MoreCpusetLine = "121 32 0:37 / /cpusets rw,relatime shared:69 - cgroup none rw,cpuset\n"; private String mntInfoCgroupv1DoubleCpuset = mntInfoCgroupv1MoreCpusetLine + mntInfoHybrid; private String mntInfoCgroupv1DoubleCpuset2 = mntInfoHybrid + mntInfoCgroupv1MoreCpusetLine; @@ -175,6 +216,15 @@ private void setup() { cgroupv1MntInfoSystemdOnly = Paths.get(existingDirectory.toString(), "mnt_info_cgroupv1_systemd_only"); Files.writeString(cgroupv1MntInfoSystemdOnly, mntInfoCgroupsV1SystemdOnly); + + cgroupv1CgroupsJoinControllers = Paths.get(existingDirectory.toString(), "cgroups_cgv1_join_controllers"); + Files.writeString(cgroupv1CgroupsJoinControllers, cgroupsNonZeroJoinControllers); + + cgroupv1SelfCgroupsJoinControllers = Paths.get(existingDirectory.toString(), "self_cgroup_cgv1_join_controllers"); + Files.writeString(cgroupv1SelfCgroupsJoinControllers, procSelfCgroupV1JoinControllers); + + cgroupv1MountInfoJoinControllers = Paths.get(existingDirectory.toString(), "mntinfo_cgv1_join_controllers"); + Files.writeString(cgroupv1MountInfoJoinControllers, mntInfoCgroupv1JoinControllers); } catch (IOException e) { throw new RuntimeException(e); } @@ -192,6 +242,16 @@ private boolean isValidCgroup(int value) { return value == CGROUPS_V1 || value == CGROUPS_V2; } + public void testCgroupv1JoinControllerCombo(WhiteBox wb) { + String procCgroups = cgroupv1CgroupsJoinControllers.toString(); + String procSelfCgroup = cgroupv1SelfCgroupsJoinControllers.toString(); + String procSelfMountinfo = cgroupv1MountInfoJoinControllers.toString(); + int retval = wb.validateCgroup(procCgroups, procSelfCgroup, procSelfMountinfo); + Asserts.assertEQ(CGROUPS_V1, retval, "Join controllers should be properly detected"); + Asserts.assertTrue(isValidCgroup(retval)); + System.out.println("testCgroupv1JoinControllerMounts PASSED!"); + } + public void testCgroupv1MultipleCpusetMounts(WhiteBox wb, Path mountInfo) { String procCgroups = cgroupv1CgInfoNonZeroHierarchy.toString(); String procSelfCgroup = cgroupV1SelfCgroup.toString(); @@ -287,6 +347,7 @@ public static void main(String[] args) throws Exception { test.testCgroupv2NoCgroup2Fs(wb); test.testCgroupv1MultipleCpusetMounts(wb, test.cgroupv1MntInfoDoubleCpuset); test.testCgroupv1MultipleCpusetMounts(wb, test.cgroupv1MntInfoDoubleCpuset2); + test.testCgroupv1JoinControllerCombo(wb); } finally { test.teardown(); } diff --git a/test/hotspot/jtreg/gc/arguments/TestSurvivorAlignmentInBytesOption.java b/test/hotspot/jtreg/gc/arguments/TestSurvivorAlignmentInBytesOption.java deleted file mode 100644 index 6a515c7b10c..00000000000 --- a/test/hotspot/jtreg/gc/arguments/TestSurvivorAlignmentInBytesOption.java +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package gc.arguments; - -import jdk.test.lib.Platform; -import jdk.test.lib.process.ExitCode; -import jdk.test.lib.cli.CommandLineOptionTest; - -/** - * @test - * @bug 8031323 - * @summary Verify SurvivorAlignmentInBytes option processing. - * @library /test/lib - * @requires vm.opt.SurvivorAlignmentInBytes == null - * & vm.opt.ObjectAlignmentInBytes == null - * & vm.opt.UnlockExperimentalVMOptions == null - * & (vm.opt.IgnoreUnrecognizedVMOptions == null - * | vm.opt.IgnoreUnrecognizedVMOptions == "false") - * @modules java.base/jdk.internal.misc - * java.management - * @run driver gc.arguments.TestSurvivorAlignmentInBytesOption - */ -public class TestSurvivorAlignmentInBytesOption { - public static void main(String args[]) throws Throwable { - String optionName = "SurvivorAlignmentInBytes"; - String unlockExperimentalVMOpts = "UnlockExperimentalVMOptions"; - String optionIsExperimental - = CommandLineOptionTest.getExperimentalOptionErrorMessage( - optionName); - String valueIsTooSmall= ".*SurvivorAlignmentInBytes.*must be greater" - + " than or equal to ObjectAlignmentInBytes.*"; - String mustBePowerOf2 = ".*SurvivorAlignmentInBytes.*must be " - + "power of 2.*"; - - // Verify that without -XX:+UnlockExperimentalVMOptions usage of - // SurvivorAlignmentInBytes option will cause JVM startup failure - // with the warning message saying that that option is experimental. - String shouldFailMessage = String.format("JVM option '%s' is " - + "experimental.%nJVM startup should fail without " - + "-XX:+UnlockExperimentalVMOptions option", optionName); - CommandLineOptionTest.verifyJVMStartup( - new String[]{optionIsExperimental}, null, - shouldFailMessage, shouldFailMessage, - ExitCode.FAIL, false, - "-XX:-UnlockExperimentalVMOptions", - CommandLineOptionTest.prepareBooleanFlag( - unlockExperimentalVMOpts, false), - CommandLineOptionTest.prepareNumericFlag(optionName, 64)); - - // Verify that with -XX:+UnlockExperimentalVMOptions passed to JVM - // usage of SurvivorAlignmentInBytes option won't cause JVM startup - // failure. - String shouldPassMessage = String.format("JVM option '%s' is " - + "experimental.%nJVM startup should pass with " - + "-XX:+UnlockExperimentalVMOptions option", optionName); - String noWarningMessage = "There should be no warnings when use " - + "with -XX:+UnlockExperimentalVMOptions option"; - CommandLineOptionTest.verifyJVMStartup( - null, new String[]{optionIsExperimental}, - shouldPassMessage, noWarningMessage, - ExitCode.OK, false, - CommandLineOptionTest.prepareBooleanFlag( - unlockExperimentalVMOpts, true), - CommandLineOptionTest.prepareNumericFlag(optionName, 64)); - - // Verify that if specified SurvivorAlignmentInBytes is lower than - // ObjectAlignmentInBytes, then the JVM startup will fail with - // appropriate error message. - if (Platform.is64bit()) { - shouldFailMessage = String.format("JVM startup should fail with " - + "'%s' option value lower than ObjectAlignmentInBytes", optionName); - CommandLineOptionTest.verifyJVMStartup( - new String[]{valueIsTooSmall}, null, - shouldFailMessage, shouldFailMessage, - ExitCode.FAIL, false, - CommandLineOptionTest.prepareBooleanFlag( - unlockExperimentalVMOpts, true), - CommandLineOptionTest.prepareNumericFlag(optionName, 8), - CommandLineOptionTest.prepareNumericFlag("ObjectAlignmentInBytes", 16)); - } - - // Verify that if specified SurvivorAlignmentInBytes value is not - // a power of 2 then the JVM startup will fail with appropriate error - // message. - shouldFailMessage = String.format("JVM startup should fail with " - + "'%s' option value is not a power of 2", optionName); - CommandLineOptionTest.verifyJVMStartup( - new String[]{mustBePowerOf2}, null, - shouldFailMessage, shouldFailMessage, - ExitCode.FAIL, false, - CommandLineOptionTest.prepareBooleanFlag( - unlockExperimentalVMOpts, true), - CommandLineOptionTest.prepareNumericFlag(optionName, 127)); - - // Verify that if SurvivorAlignmentInBytes has correct value, then - // the JVM will be started without errors. - shouldPassMessage = String.format("JVM startup should pass with " - + "correct '%s' option value", optionName); - noWarningMessage = String.format("There should be no warnings when use " - + "correct '%s' option value", optionName); - CommandLineOptionTest.verifyJVMStartup( - null, new String[]{".*SurvivorAlignmentInBytes.*"}, - shouldPassMessage, noWarningMessage, - ExitCode.OK, false, - CommandLineOptionTest.prepareBooleanFlag( - unlockExperimentalVMOpts, true), - CommandLineOptionTest.prepareNumericFlag(optionName, 128)); - - // Verify that we can setup different SurvivorAlignmentInBytes values. - for (int alignment = 32; alignment <= 128; alignment *= 2) { - shouldPassMessage = String.format("JVM startup should pass with " - + "'%s' = %d", optionName, alignment); - CommandLineOptionTest.verifyOptionValue(optionName, - Integer.toString(alignment), shouldPassMessage, - CommandLineOptionTest.prepareBooleanFlag( - unlockExperimentalVMOpts, true), - CommandLineOptionTest.prepareNumericFlag( - optionName, alignment)); - } - } -} diff --git a/test/hotspot/jtreg/gc/shenandoah/compiler/TestBarrierExpansionDeadMemPhi.java b/test/hotspot/jtreg/gc/shenandoah/compiler/TestBarrierExpansionDeadMemPhi.java new file mode 100644 index 00000000000..80d73392a7b --- /dev/null +++ b/test/hotspot/jtreg/gc/shenandoah/compiler/TestBarrierExpansionDeadMemPhi.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2020, 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. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8255400 + * @summary C2 failures after JDK-8255000 + * @requires vm.gc.Shenandoah + * @modules java.base/jdk.internal.misc:+open + * + * @run main/othervm -XX:-UseOnStackReplacement -XX:-BackgroundCompilation -XX:-TieredCompilation -XX:+UseShenandoahGC TestBarrierExpansionDeadMemPhi + * + * + */ + +import jdk.internal.misc.Unsafe; +import java.util.Arrays; +import java.lang.reflect.Field; + +public class TestBarrierExpansionDeadMemPhi { + + static final jdk.internal.misc.Unsafe UNSAFE = Unsafe.getUnsafe(); + + static final long F_OFFSET; + + static class A { + int f; + } + + static { + try { + Field fField = A.class.getDeclaredField("f"); + F_OFFSET = UNSAFE.objectFieldOffset(fField); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + static int test(Object[] array) { + int f = 0; + for (int i = 0; i < 100; i++) { + f += UNSAFE.getInt(array[i], F_OFFSET); + } + return f; + } + + static public void main(String[] args) { + Object[] array = new Object[100]; + Arrays.fill(array, new A()); + + for (int i = 0; i < 20000; i++) { + test(array); + } + } +} diff --git a/test/hotspot/jtreg/gc/survivorAlignment/AlignmentHelper.java b/test/hotspot/jtreg/gc/survivorAlignment/AlignmentHelper.java deleted file mode 100644 index 39246cadb75..00000000000 --- a/test/hotspot/jtreg/gc/survivorAlignment/AlignmentHelper.java +++ /dev/null @@ -1,176 +0,0 @@ -/* - * Copyright (c) 2014, 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. - * - * 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 gc.survivorAlignment; - -import java.lang.management.MemoryPoolMXBean; -import java.util.Optional; - -import sun.hotspot.WhiteBox; - -/** - * Helper class aimed to provide information about alignment of objects in - * particular heap space, expected memory usage after objects' allocation so on. - */ -public class AlignmentHelper { - private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); - - private static final long OBJECT_ALIGNMENT_IN_BYTES_FOR_32_VM = 8L; - - /** - * Max relative allowed actual memory usage deviation from expected memory - * usage. - */ - private static final float MAX_RELATIVE_DEVIATION = 0.05f; // 5% - - public static final long OBJECT_ALIGNMENT_IN_BYTES = Optional.ofNullable( - AlignmentHelper.WHITE_BOX.getIntxVMFlag("ObjectAlignmentInBytes")) - .orElse(AlignmentHelper.OBJECT_ALIGNMENT_IN_BYTES_FOR_32_VM); - - public static final long SURVIVOR_ALIGNMENT_IN_BYTES = Optional.ofNullable( - AlignmentHelper.WHITE_BOX.getIntxVMFlag("SurvivorAlignmentInBytes")) - .orElseThrow(() ->new AssertionError( - "Unable to get SurvivorAlignmentInBytes value")); - /** - * Min amount of memory that will be occupied by an object. - */ - public static final long MIN_OBJECT_SIZE - = AlignmentHelper.WHITE_BOX.getObjectSize(new Object()); - /** - * Min amount of memory that will be occupied by an empty byte array. - */ - public static final long MIN_ARRAY_SIZE - = AlignmentHelper.WHITE_BOX.getObjectSize(new byte[0]); - - /** - * Precision at which actual memory usage in a heap space represented by - * this sizing helper could be measured. - */ - private final long memoryUsageMeasurementPrecision; - /** - * Min amount of memory that will be occupied by an object allocated in a - * heap space represented by this sizing helper. - */ - private final long minObjectSizeInThisSpace; - /** - * Object's alignment in a heap space represented by this sizing helper. - */ - private final long objectAlignmentInThisRegion; - /** - * MemoryPoolMXBean associated with a heap space represented by this sizing - * helper. - */ - private final MemoryPoolMXBean poolMXBean; - - private static long alignUp(long value, long alignment) { - return ((value - 1) / alignment + 1) * alignment; - } - - protected AlignmentHelper(long memoryUsageMeasurementPrecision, - long objectAlignmentInThisRegion, long minObjectSizeInThisSpace, - MemoryPoolMXBean poolMXBean) { - this.memoryUsageMeasurementPrecision = memoryUsageMeasurementPrecision; - this.minObjectSizeInThisSpace = minObjectSizeInThisSpace; - this.objectAlignmentInThisRegion = objectAlignmentInThisRegion; - this.poolMXBean = poolMXBean; - } - - /** - * Returns how many objects have to be allocated to fill - * {@code memoryToFill} bytes in this heap space using objects of size - * {@code objectSize}. - */ - public int getObjectsCount(long memoryToFill, long objectSize) { - return (int) (memoryToFill / getObjectSizeInThisSpace(objectSize)); - } - - /** - * Returns amount of memory that {@code objectsCount} of objects with size - * {@code objectSize} will occupy this this space after allocation. - */ - public long getExpectedMemoryUsage(long objectSize, int objectsCount) { - long correctedObjectSize = getObjectSizeInThisSpace(objectSize); - return AlignmentHelper.alignUp(correctedObjectSize * objectsCount, - memoryUsageMeasurementPrecision); - } - - /** - * Returns current memory usage in this heap space. - */ - public long getActualMemoryUsage() { - return poolMXBean.getUsage().getUsed(); - } - - /** - * Returns maximum memory usage deviation from {@code expectedMemoryUsage} - * given the max allowed relative deviation equal to - * {@code relativeDeviation}. - * - * Note that value returned by this method is aligned according to - * memory measurement precision for this heap space. - */ - public long getAllowedMemoryUsageDeviation(long expectedMemoryUsage) { - long unalignedDeviation = (long) (expectedMemoryUsage * - AlignmentHelper.MAX_RELATIVE_DEVIATION); - return AlignmentHelper.alignUp(unalignedDeviation, - memoryUsageMeasurementPrecision); - } - - /** - * Returns amount of memory that will be occupied by an object with size - * {@code objectSize} in this heap space. - */ - public long getObjectSizeInThisSpace(long objectSize) { - objectSize = Math.max(objectSize, minObjectSizeInThisSpace); - - long alignedObjectSize = AlignmentHelper.alignUp(objectSize, - objectAlignmentInThisRegion); - long sizeDiff = alignedObjectSize - objectSize; - - // If there is not enough space to fit padding object, then object will - // be aligned to {@code 2 * objectAlignmentInThisRegion}. - if (sizeDiff >= AlignmentHelper.OBJECT_ALIGNMENT_IN_BYTES - && sizeDiff < AlignmentHelper.MIN_OBJECT_SIZE) { - alignedObjectSize += AlignmentHelper.MIN_OBJECT_SIZE; - alignedObjectSize = AlignmentHelper.alignUp(alignedObjectSize, - objectAlignmentInThisRegion); - } - - return alignedObjectSize; - } - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - - builder.append(String.format("AlignmentHelper for memory pool '%s':%n", - poolMXBean.getName())); - builder.append(String.format("Memory usage measurement precision: %d%n", - memoryUsageMeasurementPrecision)); - builder.append(String.format("Min object size in this space: %d%n", - minObjectSizeInThisSpace)); - builder.append(String.format("Object alignment in this space: %d%n", - objectAlignmentInThisRegion)); - - return builder.toString(); - } -} diff --git a/test/hotspot/jtreg/gc/survivorAlignment/SurvivorAlignmentTestMain.java b/test/hotspot/jtreg/gc/survivorAlignment/SurvivorAlignmentTestMain.java deleted file mode 100644 index 6e2a70722b3..00000000000 --- a/test/hotspot/jtreg/gc/survivorAlignment/SurvivorAlignmentTestMain.java +++ /dev/null @@ -1,395 +0,0 @@ -/* - * Copyright (c) 2014, 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. - * - * 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 gc.survivorAlignment; - -import java.lang.management.ManagementFactory; -import java.lang.management.MemoryPoolMXBean; -import java.util.Objects; -import java.util.Optional; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import jdk.test.lib.Asserts; -import com.sun.management.ThreadMXBean; -import sun.hotspot.WhiteBox; -import jdk.internal.misc.Unsafe; - -/** - * Main class for tests on {@code SurvivorAlignmentInBytes} option. - * - * Typical usage is to obtain instance using fromArgs method, allocate objects - * and verify that actual memory usage in tested heap space is close to - * expected. - */ -public class SurvivorAlignmentTestMain { - enum HeapSpace { - EDEN, - SURVIVOR, - TENURED - } - - public static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); - - public static final long MAX_TENURING_THRESHOLD = Optional.ofNullable( - SurvivorAlignmentTestMain.WHITE_BOX.getIntxVMFlag( - "MaxTenuringThreshold")).orElse(15L); - - /** - * Regexp used to parse memory size params, like 2G, 34m or 15k. - */ - private static final Pattern SIZE_REGEX - = Pattern.compile("(?[0-9]+)(?[GMKgmk])?"); - - // Names of different heap spaces. - private static final String DEF_NEW_EDEN = "Eden Space"; - private static final String DEF_NEW_SURVIVOR = "Survivor Space"; - private static final String PAR_NEW_EDEN = "Par Eden Space"; - private static final String PAR_NEW_SURVIVOR = "Par Survivor Space"; - private static final String PS_EDEN = "PS Eden Space"; - private static final String PS_SURVIVOR = "PS Survivor Space"; - private static final String G1_EDEN = "G1 Eden Space"; - private static final String G1_SURVIVOR = "G1 Survivor Space"; - private static final String SERIAL_TENURED = "Tenured Gen"; - private static final String PS_TENURED = "PS Old Gen"; - private static final String G1_TENURED = "G1 Old Gen"; - - private static final long G1_HEAP_REGION_SIZE = Optional.ofNullable( - SurvivorAlignmentTestMain.WHITE_BOX.getUintxVMFlag( - "G1HeapRegionSize")).orElse(-1L); - - private static final AlignmentHelper EDEN_SPACE_HELPER; - private static final AlignmentHelper SURVIVOR_SPACE_HELPER; - private static final AlignmentHelper TENURED_SPACE_HELPER; - /** - * Amount of memory that should be filled during a test run. - */ - private final long memoryToFill; - /** - * The size of an objects that will be allocated during a test run. - */ - private final long objectSize; - /** - * Amount of memory that will be actually occupied by an object in eden - * space. - */ - private final long actualObjectSize; - /** - * Storage for allocated objects. - */ - private final Object[] garbage; - /** - * Heap space whose memory usage is a subject of assertions during the test - * run. - */ - private final HeapSpace testedSpace; - - private long[] baselinedThreadMemoryUsage = null; - private long[] threadIds = null; - - /** - * Initialize {@code EDEN_SPACE_HELPER}, {@code SURVIVOR_SPACE_HELPER} and - * {@code TENURED_SPACE_HELPER} to represent heap spaces in use. - * - * Note that regardless to GC object's alignment in survivor space is - * expected to be equal to {@code SurvivorAlignmentInBytes} value and - * alignment in other spaces is expected to be equal to - * {@code ObjectAlignmentInBytes} value. - * - * For G1 GC MXBeans could report memory usage only with region size - * precision (if an object allocated in some G1 heap region, then all region - * will claimed as used), so for G1's spaces precision is equal to - * {@code G1HeapRegionSize} value. - */ - static { - AlignmentHelper edenHelper = null; - AlignmentHelper survivorHelper = null; - AlignmentHelper tenuredHelper = null; - for (MemoryPoolMXBean pool : ManagementFactory.getMemoryPoolMXBeans()) { - switch (pool.getName()) { - case SurvivorAlignmentTestMain.DEF_NEW_EDEN: - case SurvivorAlignmentTestMain.PAR_NEW_EDEN: - case SurvivorAlignmentTestMain.PS_EDEN: - Asserts.assertNull(edenHelper, - "Only one bean for eden space is expected."); - edenHelper = new AlignmentHelper( - AlignmentHelper.OBJECT_ALIGNMENT_IN_BYTES, - AlignmentHelper.OBJECT_ALIGNMENT_IN_BYTES, - AlignmentHelper.MIN_OBJECT_SIZE, pool); - break; - case SurvivorAlignmentTestMain.G1_EDEN: - Asserts.assertNull(edenHelper, - "Only one bean for eden space is expected."); - edenHelper = new AlignmentHelper( - SurvivorAlignmentTestMain.G1_HEAP_REGION_SIZE, - AlignmentHelper.OBJECT_ALIGNMENT_IN_BYTES, - AlignmentHelper.MIN_OBJECT_SIZE, pool); - break; - case SurvivorAlignmentTestMain.DEF_NEW_SURVIVOR: - case SurvivorAlignmentTestMain.PAR_NEW_SURVIVOR: - case SurvivorAlignmentTestMain.PS_SURVIVOR: - Asserts.assertNull(survivorHelper, - "Only one bean for survivor space is expected."); - survivorHelper = new AlignmentHelper( - AlignmentHelper.OBJECT_ALIGNMENT_IN_BYTES, - AlignmentHelper.SURVIVOR_ALIGNMENT_IN_BYTES, - AlignmentHelper.MIN_OBJECT_SIZE, pool); - break; - case SurvivorAlignmentTestMain.G1_SURVIVOR: - Asserts.assertNull(survivorHelper, - "Only one bean for survivor space is expected."); - survivorHelper = new AlignmentHelper( - SurvivorAlignmentTestMain.G1_HEAP_REGION_SIZE, - AlignmentHelper.SURVIVOR_ALIGNMENT_IN_BYTES, - AlignmentHelper.MIN_OBJECT_SIZE, pool); - break; - case SurvivorAlignmentTestMain.SERIAL_TENURED: - case SurvivorAlignmentTestMain.PS_TENURED: - case SurvivorAlignmentTestMain.G1_TENURED: - Asserts.assertNull(tenuredHelper, - "Only one bean for tenured space is expected."); - tenuredHelper = new AlignmentHelper( - AlignmentHelper.OBJECT_ALIGNMENT_IN_BYTES, - AlignmentHelper.OBJECT_ALIGNMENT_IN_BYTES, - AlignmentHelper.MIN_OBJECT_SIZE, pool); - break; - } - } - EDEN_SPACE_HELPER = Objects.requireNonNull(edenHelper, - "AlignmentHelper for eden space should be initialized."); - SURVIVOR_SPACE_HELPER = Objects.requireNonNull(survivorHelper, - "AlignmentHelper for survivor space should be initialized."); - TENURED_SPACE_HELPER = Objects.requireNonNull(tenuredHelper, - "AlignmentHelper for tenured space should be initialized."); - } - /** - * Returns an SurvivorAlignmentTestMain instance constructed using CLI - * options. - * - * Following options are expected: - *

      - *
    • memoryToFill
    • - *
    • objectSize
    • - *
    - * - * Both argument may contain multiplier suffix k, m or g. - */ - public static SurvivorAlignmentTestMain fromArgs(String[] args) { - Asserts.assertEQ(args.length, 3, "Expected three arguments: " - + "memory size, object size and tested heap space name."); - - long memoryToFill = parseSize(args[0]); - long objectSize = Math.max(parseSize(args[1]), - AlignmentHelper.MIN_ARRAY_SIZE); - HeapSpace testedSpace = HeapSpace.valueOf(args[2]); - - return new SurvivorAlignmentTestMain(memoryToFill, objectSize, - testedSpace); - } - - /** - * Returns a value parsed from a string with format - * <integer><multiplier>. - */ - private static long parseSize(String sizeString) { - Matcher matcher = SIZE_REGEX.matcher(sizeString); - Asserts.assertTrue(matcher.matches(), - "sizeString should have following format \"[0-9]+([MBK])?\""); - long size = Long.valueOf(matcher.group("size")); - - if (matcher.group("multiplier") != null) { - long K = 1024L; - // fall through multipliers - switch (matcher.group("multiplier").toLowerCase()) { - case "g": - size *= K; - case "m": - size *= K; - case "k": - size *= K; - } - } - return size; - } - - private SurvivorAlignmentTestMain(long memoryToFill, long objectSize, - HeapSpace testedSpace) { - this.objectSize = objectSize; - this.memoryToFill = memoryToFill; - this.testedSpace = testedSpace; - - AlignmentHelper helper = SurvivorAlignmentTestMain.EDEN_SPACE_HELPER; - - this.actualObjectSize = helper.getObjectSizeInThisSpace( - this.objectSize); - int arrayLength = helper.getObjectsCount(memoryToFill, this.objectSize); - garbage = new Object[arrayLength]; - } - - /** - * Allocate byte arrays to fill {@code memoryToFill} memory. - */ - public void allocate() { - int byteArrayLength = Math.max((int) (objectSize - - Unsafe.ARRAY_BYTE_BASE_OFFSET), 0); - - for (int i = 0; i < garbage.length; i++) { - garbage[i] = new byte[byteArrayLength]; - } - } - - /** - * Release memory occupied after {@code allocate} call. - */ - public void release() { - for (int i = 0; i < garbage.length; i++) { - garbage[i] = null; - } - } - - /** - * Returns expected amount of memory occupied in a {@code heapSpace} by - * objects referenced from {@code garbage} array. - */ - public long getExpectedMemoryUsage() { - AlignmentHelper alignmentHelper = getAlignmentHelper(testedSpace); - return alignmentHelper.getExpectedMemoryUsage(objectSize, - garbage.length); - } - - /** - * Verifies that memory usage in a {@code heapSpace} deviates from - * {@code expectedUsage} for no more than {@code MAX_RELATIVE_DEVIATION}. - */ - public void verifyMemoryUsage(long expectedUsage) { - AlignmentHelper alignmentHelper = getAlignmentHelper(testedSpace); - - long actualMemoryUsage = alignmentHelper.getActualMemoryUsage(); - boolean otherThreadsAllocatedMemory = areOtherThreadsAllocatedMemory(); - - long memoryUsageDiff = Math.abs(actualMemoryUsage - expectedUsage); - long maxAllowedUsageDiff - = alignmentHelper.getAllowedMemoryUsageDeviation(expectedUsage); - - System.out.println("Verifying memory usage in space: " + testedSpace); - System.out.println("Allocated objects count: " + garbage.length); - System.out.println("Desired object size: " + objectSize); - System.out.println("Actual object size: " + actualObjectSize); - System.out.println("Expected object size in space: " - + alignmentHelper.getObjectSizeInThisSpace(objectSize)); - System.out.println("Expected memory usage: " + expectedUsage); - System.out.println("Actual memory usage: " + actualMemoryUsage); - System.out.println("Memory usage diff: " + memoryUsageDiff); - System.out.println("Max allowed usage diff: " + maxAllowedUsageDiff); - - if (memoryUsageDiff > maxAllowedUsageDiff - && otherThreadsAllocatedMemory) { - System.out.println("Memory usage diff is incorrect, but it seems " - + "like someone else allocated objects"); - return; - } - - Asserts.assertLTE(memoryUsageDiff, maxAllowedUsageDiff, - "Actual memory usage should not deviate from expected for " + - "more then " + maxAllowedUsageDiff); - } - - /** - * Baselines amount of memory allocated by each thread. - */ - public void baselineMemoryAllocation() { - ThreadMXBean bean = (ThreadMXBean) ManagementFactory.getThreadMXBean(); - threadIds = bean.getAllThreadIds(); - baselinedThreadMemoryUsage = bean.getThreadAllocatedBytes(threadIds); - } - - /** - * Checks if threads other then the current thread were allocating objects - * after baselinedThreadMemoryUsage call. - * - * If baselinedThreadMemoryUsage was not called, then this method will return - * {@code false}. - */ - public boolean areOtherThreadsAllocatedMemory() { - if (baselinedThreadMemoryUsage == null) { - return false; - } - - ThreadMXBean bean = (ThreadMXBean) ManagementFactory.getThreadMXBean(); - long currentMemoryAllocation[] - = bean.getThreadAllocatedBytes(threadIds); - boolean otherThreadsAllocatedMemory = false; - - System.out.println("Verifying amount of memory allocated by threads:"); - for (int i = 0; i < threadIds.length; i++) { - System.out.format("Thread %d%nbaseline allocation: %d" - + "%ncurrent allocation:%d%n", threadIds[i], - baselinedThreadMemoryUsage[i], currentMemoryAllocation[i]); - System.out.println(bean.getThreadInfo(threadIds[i])); - - long bytesAllocated = Math.abs(currentMemoryAllocation[i] - - baselinedThreadMemoryUsage[i]); - if (bytesAllocated > 0 - && threadIds[i] != Thread.currentThread().getId()) { - otherThreadsAllocatedMemory = true; - } - } - - return otherThreadsAllocatedMemory; - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - - builder.append(String.format("SurvivorAlignmentTestMain info:%n")); - builder.append(String.format("Desired object size: %d%n", objectSize)); - builder.append(String.format("Memory to fill: %d%n", memoryToFill)); - builder.append(String.format("Objects to be allocated: %d%n", - garbage.length)); - - builder.append(String.format("Alignment helpers to be used: %n")); - for (HeapSpace heapSpace: HeapSpace.values()) { - builder.append(String.format("For space %s:%n%s%n", heapSpace, - getAlignmentHelper(heapSpace))); - } - - return builder.toString(); - } - - /** - * Returns {@code AlignmentHelper} for a space {@code heapSpace}. - */ - public static AlignmentHelper getAlignmentHelper(HeapSpace heapSpace) { - switch (heapSpace) { - case EDEN: - return SurvivorAlignmentTestMain.EDEN_SPACE_HELPER; - case SURVIVOR: - return SurvivorAlignmentTestMain.SURVIVOR_SPACE_HELPER; - case TENURED: - return SurvivorAlignmentTestMain.TENURED_SPACE_HELPER; - default: - throw new Error("Unexpected heap space: " + heapSpace); - } - } -} diff --git a/test/hotspot/jtreg/gc/survivorAlignment/TestAllocationInEden.java b/test/hotspot/jtreg/gc/survivorAlignment/TestAllocationInEden.java deleted file mode 100644 index 45db235a50c..00000000000 --- a/test/hotspot/jtreg/gc/survivorAlignment/TestAllocationInEden.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package gc.survivorAlignment; - -/** - * @test gc.survivorAlignment.TestAllocationInEden - * @bug 8031323 - * @summary Verify that object's alignment in eden space is not affected by - * SurvivorAlignmentInBytes option. - * @requires vm.gc != "Z" & vm.gc != "Shenandoah" - * @library /test/lib - * @library / - * @modules java.base/jdk.internal.misc - * java.management - * @build sun.hotspot.WhiteBox - * @run driver ClassFileInstaller sun.hotspot.WhiteBox - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions - * -XX:+WhiteBoxAPI -XX:NewSize=64m -XX:MaxNewSize=64m - * -XX:SurvivorRatio=1 -XX:+UnlockExperimentalVMOptions - * -XX:SurvivorAlignmentInBytes=32 -XX:-UseTLAB -XX:-ResizePLAB - * -XX:OldSize=128m -XX:MaxHeapSize=192m - * -XX:-ExplicitGCInvokesConcurrent - * gc.survivorAlignment.TestAllocationInEden 10m 9 EDEN - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions - * -XX:+WhiteBoxAPI -XX:NewSize=64m -XX:MaxNewSize=64m - * -XX:SurvivorRatio=1 -XX:+UnlockExperimentalVMOptions - * -XX:SurvivorAlignmentInBytes=32 -XX:-UseTLAB -XX:-ResizePLAB - * -XX:OldSize=128m -XX:MaxHeapSize=192m - * -XX:-ExplicitGCInvokesConcurrent - * gc.survivorAlignment.TestAllocationInEden 10m 47 EDEN - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions - * -XX:+WhiteBoxAPI -XX:NewSize=64m -XX:MaxNewSize=64m - * -XX:SurvivorRatio=1 -XX:+UnlockExperimentalVMOptions - * -XX:SurvivorAlignmentInBytes=64 -XX:-UseTLAB -XX:-ResizePLAB - * -XX:OldSize=128m -XX:MaxHeapSize=192m - * -XX:-ExplicitGCInvokesConcurrent - * gc.survivorAlignment.TestAllocationInEden 10m 9 EDEN - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions - * -XX:+WhiteBoxAPI -XX:NewSize=64m -XX:MaxNewSize=64m - * -XX:SurvivorRatio=1 -XX:+UnlockExperimentalVMOptions - * -XX:SurvivorAlignmentInBytes=64 -XX:-UseTLAB -XX:-ResizePLAB - * -XX:OldSize=128m -XX:MaxHeapSize=192m - * -XX:-ExplicitGCInvokesConcurrent - * gc.survivorAlignment.TestAllocationInEden 10m 87 EDEN - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions - * -XX:+WhiteBoxAPI -XX:NewSize=64m -XX:MaxNewSize=64m - * -XX:SurvivorRatio=1 -XX:+UnlockExperimentalVMOptions - * -XX:SurvivorAlignmentInBytes=128 -XX:-UseTLAB -XX:-ResizePLAB - * -XX:OldSize=128m -XX:MaxHeapSize=192m - * -XX:-ExplicitGCInvokesConcurrent - * gc.survivorAlignment.TestAllocationInEden 10m 9 EDEN - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions - * -XX:+WhiteBoxAPI -XX:NewSize=64m -XX:MaxNewSize=64m - * -XX:SurvivorRatio=1 -XX:+UnlockExperimentalVMOptions - * -XX:SurvivorAlignmentInBytes=128 -XX:-UseTLAB -XX:-ResizePLAB - * -XX:OldSize=128m -XX:MaxHeapSize=192m - * -XX:-ExplicitGCInvokesConcurrent - * gc.survivorAlignment.TestAllocationInEden 10m 147 EDEN - */ -public class TestAllocationInEden { - public static void main(String args[]) { - SurvivorAlignmentTestMain test - = SurvivorAlignmentTestMain.fromArgs(args); - System.out.println(test); - - long expectedMemoryUsage = test.getExpectedMemoryUsage(); - test.baselineMemoryAllocation(); - System.gc(); - - test.allocate(); - - test.verifyMemoryUsage(expectedMemoryUsage); - } -} diff --git a/test/hotspot/jtreg/gc/survivorAlignment/TestPromotionFromEdenToTenured.java b/test/hotspot/jtreg/gc/survivorAlignment/TestPromotionFromEdenToTenured.java deleted file mode 100644 index cdbc1ffc0a0..00000000000 --- a/test/hotspot/jtreg/gc/survivorAlignment/TestPromotionFromEdenToTenured.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package gc.survivorAlignment; - -/** - * @test gc.survivorAlignment.TestPromotionFromEdenToTenured - * @bug 8031323 - * @summary Verify that objects promoted from eden space to tenured space during - * full GC are not aligned to SurvivorAlignmentInBytes value. - * @requires vm.gc != "Z" & vm.gc != "Shenandoah" - * @library /test/lib - * @library / - * @modules java.base/jdk.internal.misc - * java.management - * @build sun.hotspot.WhiteBox - * @run driver ClassFileInstaller sun.hotspot.WhiteBox - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions - * -XX:+WhiteBoxAPI -XX:NewSize=64m -XX:MaxNewSize=64m - * -XX:OldSize=32m -XX:MaxHeapSize=96m -XX:SurvivorRatio=1 - * -XX:-ExplicitGCInvokesConcurrent -XX:-ResizePLAB - * -XX:+UnlockExperimentalVMOptions - * -XX:SurvivorAlignmentInBytes=32 - * gc.survivorAlignment.TestPromotionFromEdenToTenured 10m 9 TENURED - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions - * -XX:+WhiteBoxAPI -XX:NewSize=64m -XX:MaxNewSize=64m - * -XX:OldSize=32m -XX:MaxHeapSize=96m -XX:SurvivorRatio=1 - * -XX:-ExplicitGCInvokesConcurrent -XX:-ResizePLAB - * -XX:+UnlockExperimentalVMOptions - * -XX:SurvivorAlignmentInBytes=32 - * gc.survivorAlignment.TestPromotionFromEdenToTenured 10m 47 TENURED - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions - * -XX:+WhiteBoxAPI -XX:NewSize=64m -XX:MaxNewSize=64m - * -XX:OldSize=32m -XX:MaxHeapSize=96m - * -XX:SurvivorRatio=1 -XX:-ExplicitGCInvokesConcurrent -XX:-ResizePLAB - * -XX:+UnlockExperimentalVMOptions - * -XX:SurvivorAlignmentInBytes=64 - * gc.survivorAlignment.TestPromotionFromEdenToTenured 10m 9 TENURED - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions - * -XX:+WhiteBoxAPI -XX:NewSize=64m -XX:MaxNewSize=64m - * -XX:OldSize=32m -XX:MaxHeapSize=128m - * -XX:SurvivorRatio=1 -XX:-ExplicitGCInvokesConcurrent -XX:-ResizePLAB - * -XX:+UnlockExperimentalVMOptions - * -XX:SurvivorAlignmentInBytes=64 - * gc.survivorAlignment.TestPromotionFromEdenToTenured 10m 87 TENURED - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions - * -XX:+WhiteBoxAPI -XX:NewSize=64m -XX:MaxNewSize=64m - * -XX:OldSize=32M -XX:MaxHeapSize=96m -XX:SurvivorRatio=1 - * -XX:-ExplicitGCInvokesConcurrent -XX:-ResizePLAB - * -XX:+UnlockExperimentalVMOptions - * -XX:SurvivorAlignmentInBytes=128 - * gc.survivorAlignment.TestPromotionFromEdenToTenured 10m 9 TENURED - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions - * -XX:+WhiteBoxAPI -XX:NewSize=64m -XX:MaxNewSize=64m - * -XX:OldSize=32m -XX:MaxHeapSize=96m -XX:SurvivorRatio=1 - * -XX:-ExplicitGCInvokesConcurrent -XX:-ResizePLAB - * -XX:+UnlockExperimentalVMOptions - * -XX:SurvivorAlignmentInBytes=128 - * gc.survivorAlignment.TestPromotionFromEdenToTenured 10m 147 TENURED - */ -public class TestPromotionFromEdenToTenured { - public static void main(String args[]) { - SurvivorAlignmentTestMain test - = SurvivorAlignmentTestMain.fromArgs(args); - System.out.println(test); - - long expectedMemoryUsage = test.getExpectedMemoryUsage(); - test.baselineMemoryAllocation(); - System.gc(); - // increase expected usage by current old gen usage - expectedMemoryUsage += SurvivorAlignmentTestMain.getAlignmentHelper( - SurvivorAlignmentTestMain.HeapSpace.TENURED) - .getActualMemoryUsage(); - - test.allocate(); - System.gc(); - - test.verifyMemoryUsage(expectedMemoryUsage); - } -} diff --git a/test/hotspot/jtreg/gc/survivorAlignment/TestPromotionFromSurvivorToTenuredAfterFullGC.java b/test/hotspot/jtreg/gc/survivorAlignment/TestPromotionFromSurvivorToTenuredAfterFullGC.java deleted file mode 100644 index 0f926f1d596..00000000000 --- a/test/hotspot/jtreg/gc/survivorAlignment/TestPromotionFromSurvivorToTenuredAfterFullGC.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package gc.survivorAlignment; - -/** - * @test gc.survivorAlignment.TestPromotionFromSurvivorToTenuredAfterFullGC - * @bug 8031323 - * @summary Verify that objects promoted from survivor space to tenured space - * during full GC are not aligned to SurvivorAlignmentInBytes value. - * @requires vm.gc != "Z" & vm.gc != "Shenandoah" - * @library /test/lib - * @library / - * @modules java.base/jdk.internal.misc - * java.management - * @build sun.hotspot.WhiteBox - * @run driver ClassFileInstaller sun.hotspot.WhiteBox - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions - * -XX:+WhiteBoxAPI -XX:NewSize=128m -XX:MaxNewSize=128m - * -XX:OldSize=32m -XX:MaxHeapSize=160m - * -XX:SurvivorRatio=1 -XX:-ExplicitGCInvokesConcurrent -XX:-ResizePLAB - * -XX:+UnlockExperimentalVMOptions - * -XX:SurvivorAlignmentInBytes=32 - * gc.survivorAlignment.TestPromotionFromSurvivorToTenuredAfterFullGC 10m 9 TENURED - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions - * -XX:+WhiteBoxAPI -XX:NewSize=128m -XX:MaxNewSize=128m - * -XX:OldSize=32m -XX:MaxHeapSize=160m -XX:-ResizePLAB - * -XX:SurvivorRatio=1 -XX:-ExplicitGCInvokesConcurrent - * -XX:+UnlockExperimentalVMOptions - * -XX:SurvivorAlignmentInBytes=32 - * gc.survivorAlignment.TestPromotionFromSurvivorToTenuredAfterFullGC 20m 47 - * TENURED - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions - * -XX:+WhiteBoxAPI -XX:NewSize=200m -XX:MaxNewSize=200m - * -XX:OldSize=32m -XX:MaxHeapSize=232m - * -XX:SurvivorRatio=1 -XX:-ExplicitGCInvokesConcurrent -XX:-ResizePLAB - * -XX:+UnlockExperimentalVMOptions - * -XX:SurvivorAlignmentInBytes=64 - * gc.survivorAlignment.TestPromotionFromSurvivorToTenuredAfterFullGC 10m 9 TENURED - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions - * -XX:+WhiteBoxAPI -XX:NewSize=128m -XX:MaxNewSize=128m - * -XX:OldSize=32m -XX:MaxHeapSize=160m - * -XX:SurvivorRatio=1 -XX:-ExplicitGCInvokesConcurrent -XX:-ResizePLAB - * -XX:+UnlockExperimentalVMOptions - * -XX:SurvivorAlignmentInBytes=64 - * gc.survivorAlignment.TestPromotionFromSurvivorToTenuredAfterFullGC 20m 87 - * TENURED - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions - * -XX:+WhiteBoxAPI -XX:NewSize=256m -XX:MaxNewSize=256m - * -XX:OldSize=32M -XX:MaxHeapSize=288m - * -XX:SurvivorRatio=1 -XX:-ExplicitGCInvokesConcurrent -XX:-ResizePLAB - * -XX:+UnlockExperimentalVMOptions - * -XX:SurvivorAlignmentInBytes=128 - * gc.survivorAlignment.TestPromotionFromSurvivorToTenuredAfterFullGC 10m 9 - * TENURED - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions - * -XX:+WhiteBoxAPI -XX:NewSize=128m -XX:MaxNewSize=128m - * -XX:OldSize=32m -XX:MaxHeapSize=160m - * -XX:SurvivorRatio=1 -XX:-ExplicitGCInvokesConcurrent -XX:-ResizePLAB - * -XX:+UnlockExperimentalVMOptions - * -XX:SurvivorAlignmentInBytes=128 - * gc.survivorAlignment.TestPromotionFromSurvivorToTenuredAfterFullGC 20m 147 - * TENURED - */ -public class TestPromotionFromSurvivorToTenuredAfterFullGC { - public static void main(String args[]) { - SurvivorAlignmentTestMain test - = SurvivorAlignmentTestMain.fromArgs(args); - System.out.println(test); - - long expectedMemoryUsage = test.getExpectedMemoryUsage(); - test.baselineMemoryAllocation(); - System.gc(); - // increase expected usage by current old gen usage - expectedMemoryUsage += SurvivorAlignmentTestMain.getAlignmentHelper( - SurvivorAlignmentTestMain.HeapSpace.TENURED) - .getActualMemoryUsage(); - - test.allocate(); - SurvivorAlignmentTestMain.WHITE_BOX.youngGC(); - System.gc(); - - test.verifyMemoryUsage(expectedMemoryUsage); - } -} diff --git a/test/hotspot/jtreg/gc/survivorAlignment/TestPromotionFromSurvivorToTenuredAfterMinorGC.java b/test/hotspot/jtreg/gc/survivorAlignment/TestPromotionFromSurvivorToTenuredAfterMinorGC.java deleted file mode 100644 index 8f45164163d..00000000000 --- a/test/hotspot/jtreg/gc/survivorAlignment/TestPromotionFromSurvivorToTenuredAfterMinorGC.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package gc.survivorAlignment; - -/** - * @test gc.survivorAlignment.TestPromotionFromSurvivorToTenuredAfterMinorGC - * @bug 8031323 - * @summary Verify that objects promoted from survivor space to tenured space - * when their age exceeded tenuring threshold are not aligned to - * SurvivorAlignmentInBytes value. - * @requires vm.gc != "Z" & vm.gc != "Shenandoah" - * @library /test/lib - * @library / - * @modules java.base/jdk.internal.misc - * java.management - * @build sun.hotspot.WhiteBox - * @run driver ClassFileInstaller sun.hotspot.WhiteBox - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions - * -XX:+WhiteBoxAPI -XX:NewSize=128m -XX:MaxNewSize=128m - * -XX:OldSize=32M -XX:MaxHeapSize=160m -XX:SurvivorRatio=1 -XX:-ResizePLAB - * -XX:-ExplicitGCInvokesConcurrent - * -XX:+UnlockExperimentalVMOptions - * -XX:SurvivorAlignmentInBytes=32 - * gc.survivorAlignment.TestPromotionFromSurvivorToTenuredAfterMinorGC 10m 9 - * TENURED - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions - * -XX:+WhiteBoxAPI -XX:NewSize=128m -XX:MaxNewSize=128m - * -XX:OldSize=32M -XX:MaxHeapSize=160m -XX:SurvivorRatio=1 -XX:-ResizePLAB - * -XX:-ExplicitGCInvokesConcurrent - * -XX:+UnlockExperimentalVMOptions - * -XX:SurvivorAlignmentInBytes=32 - * gc.survivorAlignment.TestPromotionFromSurvivorToTenuredAfterMinorGC 20m 47 - * TENURED - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions - * -XX:+WhiteBoxAPI -XX:NewSize=200m -XX:MaxNewSize=200m - * -XX:OldSize=32M -XX:MaxHeapSize=232m -XX:SurvivorRatio=1 -XX:-ResizePLAB - * -XX:-ExplicitGCInvokesConcurrent - * -XX:+UnlockExperimentalVMOptions - * -XX:SurvivorAlignmentInBytes=64 - * gc.survivorAlignment.TestPromotionFromSurvivorToTenuredAfterMinorGC 10m 9 - * TENURED - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions - * -XX:+WhiteBoxAPI -XX:NewSize=128m -XX:MaxNewSize=128m - * -XX:OldSize=32M -XX:MaxHeapSize=160m -XX:SurvivorRatio=1 -XX:-ResizePLAB - * -XX:-ExplicitGCInvokesConcurrent - * -XX:+UnlockExperimentalVMOptions - * -XX:SurvivorAlignmentInBytes=64 - * gc.survivorAlignment.TestPromotionFromSurvivorToTenuredAfterMinorGC 20m 87 - * TENURED - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions - * -XX:+WhiteBoxAPI -XX:NewSize=256m -XX:MaxNewSize=256m - * -XX:OldSize=32M -XX:MaxHeapSize=288m -XX:SurvivorRatio=1 -XX:-ResizePLAB - * -XX:-ExplicitGCInvokesConcurrent - * -XX:+UnlockExperimentalVMOptions - * -XX:SurvivorAlignmentInBytes=128 - * gc.survivorAlignment.TestPromotionFromSurvivorToTenuredAfterMinorGC 10m 9 - * TENURED - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions - * -XX:+WhiteBoxAPI -XX:NewSize=128m -XX:MaxNewSize=128m - * -XX:OldSize=32M -XX:MaxHeapSize=160m -XX:SurvivorRatio=1 -XX:-ResizePLAB - * -XX:-ExplicitGCInvokesConcurrent - * -XX:+UnlockExperimentalVMOptions - * -XX:SurvivorAlignmentInBytes=128 - * gc.survivorAlignment.TestPromotionFromSurvivorToTenuredAfterMinorGC 20m 147 - * TENURED - */ -public class TestPromotionFromSurvivorToTenuredAfterMinorGC { - public static void main(String args[]) throws Exception { - SurvivorAlignmentTestMain test - = SurvivorAlignmentTestMain.fromArgs(args); - System.out.println(test); - - long expectedMemoryUsage = test.getExpectedMemoryUsage(); - test.baselineMemoryAllocation(); - SurvivorAlignmentTestMain.WHITE_BOX.fullGC(); - // increase expected usage by current old gen usage - expectedMemoryUsage += SurvivorAlignmentTestMain.getAlignmentHelper( - SurvivorAlignmentTestMain.HeapSpace.TENURED) - .getActualMemoryUsage(); - - test.allocate(); - for (int i = 0; i <= SurvivorAlignmentTestMain.MAX_TENURING_THRESHOLD; i++) { - SurvivorAlignmentTestMain.WHITE_BOX.youngGC(); - } - - // Sometimes we see that data unrelated to the test has been allocated during - // the loop. This data is included in the expectedMemoryUsage since we look - // through all threads to see what they allocated. If this data is still in - // the survivor area however, it should not be included in expectedMemoryUsage - // since the verification below only look at what's in tenured space. - expectedMemoryUsage -= SurvivorAlignmentTestMain.getAlignmentHelper( - SurvivorAlignmentTestMain.HeapSpace.SURVIVOR) - .getActualMemoryUsage(); - test.verifyMemoryUsage(expectedMemoryUsage); - } -} diff --git a/test/hotspot/jtreg/gc/survivorAlignment/TestPromotionLABLargeSurvivorAlignment.java b/test/hotspot/jtreg/gc/survivorAlignment/TestPromotionLABLargeSurvivorAlignment.java deleted file mode 100644 index e0a92f550d4..00000000000 --- a/test/hotspot/jtreg/gc/survivorAlignment/TestPromotionLABLargeSurvivorAlignment.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2016, 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. - * - * 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 gc.survivorAlignment; - -/** - * @test gc.survivorAlignment.TestPromotionLABLargeSurvivorAlignment - * @bug 8060463 - * @summary Verify that objects promoted from eden space to survivor space - * with large values for SurvivorAlignmentInBytes succeed. - * @requires vm.opt.ExplicitGCInvokesConcurrent != true - * @run main/othervm -Xmx128m - * -XX:+UnlockExperimentalVMOptions - * -XX:SurvivorAlignmentInBytes=8 -XX:SurvivorRatio=1 - * -XX:-ExplicitGCInvokesConcurrent -XX:-ResizePLAB - * gc.survivorAlignment.TestPromotionLABLargeSurvivorAlignment - * @run main/othervm -Xmx128m - * -XX:+UnlockExperimentalVMOptions - * -XX:SurvivorAlignmentInBytes=16 -XX:SurvivorRatio=1 - * -XX:-ExplicitGCInvokesConcurrent -XX:-ResizePLAB - * gc.survivorAlignment.TestPromotionLABLargeSurvivorAlignment - * @run main/othervm -Xmx128m - * -XX:+UnlockExperimentalVMOptions - * -XX:SurvivorAlignmentInBytes=256 -XX:SurvivorRatio=1 - * -XX:-ExplicitGCInvokesConcurrent -XX:-ResizePLAB - * gc.survivorAlignment.TestPromotionLABLargeSurvivorAlignment - */ -public class TestPromotionLABLargeSurvivorAlignment { - public static void main(String args[]) { - Object garbage[] = new Object[1000000]; - for (int i = 0; i < garbage.length; i++) { - garbage[i] = new byte[0]; - } - for (int i = 0; i < 2; i++) { - System.gc(); - } - } -} - diff --git a/test/hotspot/jtreg/gc/survivorAlignment/TestPromotionToSurvivor.java b/test/hotspot/jtreg/gc/survivorAlignment/TestPromotionToSurvivor.java deleted file mode 100644 index 3a6cb7e3421..00000000000 --- a/test/hotspot/jtreg/gc/survivorAlignment/TestPromotionToSurvivor.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package gc.survivorAlignment; - -/** - * @test gc.survivorAlignment.TestPromotionToSurvivor - * @bug 8031323 - * @summary Verify that objects promoted from eden space to survivor space after - * minor GC are aligned to SurvivorAlignmentInBytes. - * @requires vm.gc != "Z" & vm.gc != "Shenandoah" - * @library /test/lib - * @library / - * @modules java.base/jdk.internal.misc - * java.management - * @build sun.hotspot.WhiteBox - * @run driver ClassFileInstaller sun.hotspot.WhiteBox - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions - * -XX:+WhiteBoxAPI -XX:NewSize=128m -XX:MaxNewSize=128m - * -XX:SurvivorRatio=1 -XX:+UnlockExperimentalVMOptions - * -XX:SurvivorAlignmentInBytes=32 -XX:OldSize=128m - * -XX:MaxHeapSize=256m -XX:-ExplicitGCInvokesConcurrent -XX:-ResizePLAB - * gc.survivorAlignment.TestPromotionToSurvivor 10m 9 SURVIVOR - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions - * -XX:+WhiteBoxAPI -XX:NewSize=128m -XX:MaxNewSize=128m - * -XX:SurvivorRatio=1 -XX:+UnlockExperimentalVMOptions - * -XX:SurvivorAlignmentInBytes=32 -XX:OldSize=128m - * -XX:MaxHeapSize=256m -XX:-ExplicitGCInvokesConcurrent -XX:-ResizePLAB - * gc.survivorAlignment.TestPromotionToSurvivor 20m 47 SURVIVOR - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions - * -XX:+WhiteBoxAPI -XX:NewSize=128m -XX:MaxNewSize=128m - * -XX:SurvivorRatio=1 -XX:+UnlockExperimentalVMOptions - * -XX:SurvivorAlignmentInBytes=64 -XX:OldSize=128m - * -XX:MaxHeapSize=256m -XX:-ExplicitGCInvokesConcurrent -XX:-ResizePLAB - * gc.survivorAlignment.TestPromotionToSurvivor 8m 9 SURVIVOR - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions - * -XX:+WhiteBoxAPI -XX:NewSize=128m -XX:MaxNewSize=128m - * -XX:SurvivorRatio=1 -XX:+UnlockExperimentalVMOptions - * -XX:SurvivorAlignmentInBytes=64 -XX:OldSize=128m - * -XX:MaxHeapSize=256m -XX:-ExplicitGCInvokesConcurrent -XX:-ResizePLAB - * gc.survivorAlignment.TestPromotionToSurvivor 20m 87 SURVIVOR - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions - * -XX:+WhiteBoxAPI -XX:NewSize=256m -XX:MaxNewSize=256m - * -XX:SurvivorRatio=1 -XX:+UnlockExperimentalVMOptions - * -XX:SurvivorAlignmentInBytes=128 -XX:OldSize=128m - * -XX:MaxHeapSize=384m -XX:-ExplicitGCInvokesConcurrent -XX:-ResizePLAB - * gc.survivorAlignment.TestPromotionToSurvivor 10m 9 SURVIVOR - * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions - * -XX:+WhiteBoxAPI -XX:NewSize=128m -XX:MaxNewSize=128m - * -XX:SurvivorRatio=1 -XX:+UnlockExperimentalVMOptions - * -XX:SurvivorAlignmentInBytes=128 -XX:OldSize=128m - * -XX:MaxHeapSize=256m -XX:-ExplicitGCInvokesConcurrent -XX:-ResizePLAB - * gc.survivorAlignment.TestPromotionToSurvivor 20m 147 SURVIVOR - */ -public class TestPromotionToSurvivor { - public static void main(String args[]) { - SurvivorAlignmentTestMain test - = SurvivorAlignmentTestMain.fromArgs(args); - System.out.println(test); - - long expectedUsage = test.getExpectedMemoryUsage(); - test.baselineMemoryAllocation(); - SurvivorAlignmentTestMain.WHITE_BOX.fullGC(); - - test.allocate(); - SurvivorAlignmentTestMain.WHITE_BOX.youngGC(); - - test.verifyMemoryUsage(expectedUsage); - } -} diff --git a/test/hotspot/jtreg/gtest/MetaspaceGtests.java b/test/hotspot/jtreg/gtest/MetaspaceGtests.java index efbd18327c9..f44315ea35d 100644 --- a/test/hotspot/jtreg/gtest/MetaspaceGtests.java +++ b/test/hotspot/jtreg/gtest/MetaspaceGtests.java @@ -87,6 +87,7 @@ /* @test id=balanced-no-ccs * @summary Run metaspace-related gtests with compressed class pointers off + * @requires vm.bits == 64 * @library /test/lib * @modules java.base/jdk.internal.misc * java.xml diff --git a/test/hotspot/jtreg/runtime/InvocationTests/invocationGraalTests.java b/test/hotspot/jtreg/runtime/InvocationTests/invocationGraalTests.java index 9c60973c67a..402b7c669a0 100644 --- a/test/hotspot/jtreg/runtime/InvocationTests/invocationGraalTests.java +++ b/test/hotspot/jtreg/runtime/InvocationTests/invocationGraalTests.java @@ -30,6 +30,7 @@ * @library /test/lib * @modules java.base/jdk.internal.org.objectweb.asm * java.base/jdk.internal.misc + * @modules jdk.internal.vm.compiler * @compile shared/AbstractGenerator.java shared/AccessCheck.java shared/AccessType.java * shared/Caller.java shared/ExecutorGenerator.java shared/Utils.java * shared/ByteArrayClassLoader.java shared/Checker.java shared/GenericClassGenerator.java diff --git a/test/hotspot/jtreg/runtime/Thread/ThreadCountLimit.java b/test/hotspot/jtreg/runtime/Thread/ThreadCountLimit.java index af61104b7e5..db8a263be5d 100644 --- a/test/hotspot/jtreg/runtime/Thread/ThreadCountLimit.java +++ b/test/hotspot/jtreg/runtime/Thread/ThreadCountLimit.java @@ -24,6 +24,7 @@ /** * @test * @summary Stress test that reaches the process limit for thread count, or time limit. + * @key stress * @run main ThreadCountLimit */ diff --git a/test/hotspot/jtreg/runtime/cds/appcds/BadBSM.java b/test/hotspot/jtreg/runtime/cds/appcds/BadBSM.java index 07d2c046f06..ae26d96d456 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/BadBSM.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/BadBSM.java @@ -42,7 +42,7 @@ public static void main(String[] args) throws Exception { OutputAnalyzer out = TestCommon.dump(appJar, TestCommon.list("WrongBSM", - "@lambda-proxy: WrongBSM 7")); + "@lambda-proxy WrongBSM 7")); out.shouldHaveExitValue(0); out.shouldContain( "is_supported_invokedynamic check failed for cp_index 7"); } diff --git a/test/hotspot/jtreg/runtime/cds/appcds/DumpClassListWithLF.java b/test/hotspot/jtreg/runtime/cds/appcds/DumpClassListWithLF.java index 6dba666c458..a0a898989e1 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/DumpClassListWithLF.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/DumpClassListWithLF.java @@ -105,5 +105,12 @@ appJar, classlist( "Hello", "@lambda-form-invoker [SPECIES_RESOLVE] java.lang.invoke.BoundMethodHandle$Species_L L"), "Incorrect number of items in the line: 3"); + // 10. The line with incorrect (less) number of items. + dumpShouldFail( + "TESTCASE 10: With incorrect @lambda-form-invoker tag", + appJar, classlist( + "Hello", + "@lambda-form-invoker-xxx [LF_RESOLVE] java.lang.invoke.DirectMethodHandle$Holder invokeStatic"), + "Invalid @ tag at the beginning of line \"@lambda-form-invoker-xxx\" line #2"); } } diff --git a/test/hotspot/jtreg/runtime/cds/appcds/LambdaProxyClasslist.java b/test/hotspot/jtreg/runtime/cds/appcds/LambdaProxyClasslist.java index cb755c368b2..adafa0d9c69 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/LambdaProxyClasslist.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/LambdaProxyClasslist.java @@ -43,35 +43,42 @@ public static void main(String[] args) throws Exception { // 1. No error with a correct @lambda-proxy entry. OutputAnalyzer out = TestCommon.dump(appJar, TestCommon.list("LambHello", - "@lambda-proxy: LambHello run ()Ljava/lang/Runnable; ()V REF_invokeStatic LambHello lambda$doTest$0 ()V ()V")); + "@lambda-proxy LambHello run ()Ljava/lang/Runnable; ()V REF_invokeStatic LambHello lambda$doTest$0 ()V ()V")); out.shouldHaveExitValue(0); // 2. Error if the @lambda-proxy entry is too short. out = TestCommon.dump(appJar, TestCommon.list("LambHello", - "@lambda-proxy: LambHello")); + "@lambda-proxy LambHello")); out.shouldContain("An error has occurred while processing class list file") - .shouldContain("Line with @ tag has too few items \"@lambda-proxy:\" line #2") + .shouldContain("Line with @ tag has too few items \"@lambda-proxy\" line #2") .shouldContain("class list format error") .shouldHaveExitValue(1); // 3. Warning message if there's an incorrect signature in the @lambda-proxy entry. out = TestCommon.dump(appJar, TestCommon.list("LambHello", - "@lambda-proxy: LambHello run ()Ljava/lang/Runnable; ()V REF_invokeStatic LambHello lambda$doTest$0 ()V ()Z")); + "@lambda-proxy LambHello run ()Ljava/lang/Runnable; ()V REF_invokeStatic LambHello lambda$doTest$0 ()V ()Z")); out.shouldContain("[warning][cds] No invoke dynamic constant pool entry can be found for class LambHello. The classlist is probably out-of-date.") .shouldHaveExitValue(0); // 4. More blank spaces in between items should be fine. out = TestCommon.dump(appJar, TestCommon.list("LambHello", - "@lambda-proxy: LambHello run ()Ljava/lang/Runnable; ()V REF_invokeStatic LambHello lambda$doTest$0 ()V ()V")); + "@lambda-proxy LambHello run ()Ljava/lang/Runnable; ()V REF_invokeStatic LambHello lambda$doTest$0 ()V ()V")); out.shouldHaveExitValue(0); // 5. Trailing spaces at the end of the @lambda-proxy line should be fine. out = TestCommon.dump(appJar, TestCommon.list("LambHello", - "@lambda-proxy: LambHello run ()Ljava/lang/Runnable; ()V REF_invokeStatic LambHello lambda$doTest$0 ()V ()V ")); + "@lambda-proxy LambHello run ()Ljava/lang/Runnable; ()V REF_invokeStatic LambHello lambda$doTest$0 ()V ()V ")); out.shouldHaveExitValue(0); + + // 6. Error on invalid @lambda-proxy tag + out = TestCommon.dump(appJar, + TestCommon.list("LambHello", + "@lambda-proxy: LambHello run ()Ljava/lang/Runnable; ()V REF_invokeStatic LambHello lambda$doTest$0 ()V ()V")); + out.shouldContain("Invalid @ tag at the beginning of line \"@lambda-proxy:\" line #2") + .shouldHaveExitValue(1); } } diff --git a/test/hotspot/jtreg/runtime/cds/appcds/javaldr/ExceptionDuringDumpAtObjectsInitPhase.java b/test/hotspot/jtreg/runtime/cds/appcds/javaldr/ExceptionDuringDumpAtObjectsInitPhase.java new file mode 100644 index 00000000000..78081a40f98 --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/javaldr/ExceptionDuringDumpAtObjectsInitPhase.java @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/* + * @test + * @summary Out of memory When dumping the CDS archive + * @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds /test/hotspot/jtreg/runtime/cds/appcds/test-classes + * @requires vm.cds.archived.java.heap + * @requires vm.jvmti + * @run driver ExceptionDuringDumpAtObjectsInitPhase + */ + +import jdk.test.lib.cds.CDSOptions; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; + +public class ExceptionDuringDumpAtObjectsInitPhase { + public static String appClasses[] = { + Hello.class.getName(), + }; + public static String agentClasses[] = { + GCDuringDumpTransformer.class.getName(), + GCDuringDumpTransformer.MyCleaner.class.getName(), + }; + + public static void main(String[] args) throws Throwable { + String agentJar = + ClassFileInstaller.writeJar("GCDuringDumpTransformer.jar", + ClassFileInstaller.Manifest.fromSourceFile("GCDuringDumpTransformer.mf"), + agentClasses); + + String appJar = + ClassFileInstaller.writeJar("GCDuringDumpApp.jar", appClasses); + + String gcLog = Boolean.getBoolean("test.cds.verbose.gc") ? + "-Xlog:gc*=info,gc+region=trace,gc+alloc+region=debug" : "-showversion"; + + // 1. Test with exception + System.out.println("1. Exception during dump"); + TestCommon.dump(appJar, + TestCommon.list(Hello.class.getName()), + "-XX:+UnlockDiagnosticVMOptions", + "-XX:+AllowArchivingWithJavaAgent", + "-javaagent:" + agentJar, + "-Xlog:cds,class+load", + "-Xmx32m", + "-Dtest.with.exception=true", + gcLog).shouldNotHaveExitValue(0) + .shouldContain("Preload Error: Failed to load jdk/internal/math/FDBigInteger") + .shouldContain("VM exits due to exception, use -Xlog:cds,exceptions=trace for detail"); + + // 2. Test with OOM + System.out.println("2. OOM during dump"); + TestCommon.dump(appJar, + TestCommon.list(Hello.class.getName()), + "-XX:+UnlockDiagnosticVMOptions", + "-XX:+AllowArchivingWithJavaAgent", + "-javaagent:" + agentJar, + "-Dtest.with.oom=true", + "-Xlog:cds,class+load", + "-Xmx12M", + gcLog).shouldNotHaveExitValue(0) + .shouldContain("Out of memory. Please run with a larger Java heap, current MaxHeapSize"); + } +} diff --git a/test/hotspot/jtreg/runtime/cds/appcds/javaldr/GCDuringDumpTransformer.java b/test/hotspot/jtreg/runtime/cds/appcds/javaldr/GCDuringDumpTransformer.java index c523f2cc7b9..f50be0cedb2 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/javaldr/GCDuringDumpTransformer.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/javaldr/GCDuringDumpTransformer.java @@ -26,10 +26,16 @@ import java.lang.instrument.Instrumentation; import java.lang.instrument.IllegalClassFormatException; import java.lang.ref.Cleaner; +import java.util.ArrayList; +import java.util.List; import java.security.ProtectionDomain; public class GCDuringDumpTransformer implements ClassFileTransformer { static boolean TEST_WITH_CLEANER = Boolean.getBoolean("test.with.cleaner"); + static boolean TEST_WITH_EXCEPTION = Boolean.getBoolean("test.with.exception"); + static boolean TEST_WITH_OOM = Boolean.getBoolean("test.with.oom"); + static List waste = new ArrayList(); + static Cleaner cleaner; static Thread thread; static Object garbage; @@ -45,6 +51,22 @@ public class GCDuringDumpTransformer implements ClassFileTransformer { public byte[] transform(ClassLoader loader, String name, Class classBeingRedefined, ProtectionDomain pd, byte[] buffer) throws IllegalClassFormatException { + // jdk/internal/math/FDBigInteger is loaded as part of archived heap. + if (name.equals("jdk/internal/math/FDBigInteger")) { + System.out.println("Transforming class jdk/internal/math/FDBigInteger"); + if (TEST_WITH_EXCEPTION) { + System.out.println("Return bad buffer for " + name); + return new byte[] {1, 2, 3, 4, 5, 6, 7, 8}; + } + if (TEST_WITH_OOM) { + // fill until OOM + System.out.println("Fill objects until OOM"); + for (;;) { + waste.add(new byte[64*1024]); + } + } + } + if (TEST_WITH_CLEANER) { if (name.equals("Hello")) { garbage = null; @@ -60,7 +82,6 @@ public byte[] transform(ClassLoader loader, String name, Class classBeingRede } catch (Throwable t2) {} } } - return null; } @@ -68,6 +89,8 @@ public byte[] transform(ClassLoader loader, String name, Class classBeingRede public static void premain(String agentArguments, Instrumentation instrumentation) { System.out.println("ClassFileTransformer.premain() is called: TEST_WITH_CLEANER = " + TEST_WITH_CLEANER); + System.out.println("ClassFileTransformer.premain() is called: TEST_WITH_EXCEPTION = " + TEST_WITH_EXCEPTION); + System.out.println("ClassFileTransformer.premain() is called: TEST_WITH_OOM = " + TEST_WITH_OOM); instrumentation.addTransformer(new GCDuringDumpTransformer(), /*canRetransform=*/true); savedInstrumentation = instrumentation; } diff --git a/test/hotspot/jtreg/runtime/records/RedefineRecord.java b/test/hotspot/jtreg/runtime/records/RedefineRecord.java index fc37a82f72e..2617421dd57 100644 --- a/test/hotspot/jtreg/runtime/records/RedefineRecord.java +++ b/test/hotspot/jtreg/runtime/records/RedefineRecord.java @@ -23,15 +23,15 @@ /* * @test + * @bug 8246774 * @library /test/lib * @summary Test that a class that is a record can be redefined. * @modules java.base/jdk.internal.misc * @modules java.instrument * jdk.jartool/sun.tools.jar * @requires vm.jvmti - * @compile --enable-preview -source ${jdk.version} RedefineRecord.java - * @run main/othervm --enable-preview RedefineRecord buildagent - * @run main/othervm/timeout=6000 --enable-preview RedefineRecord runtest + * @run main RedefineRecord buildagent + * @run main/othervm/timeout=6000 RedefineRecord runtest */ import java.io.FileNotFoundException; @@ -100,7 +100,6 @@ public static void main(String argv[]) throws Exception { "-XX:MetaspaceSize=12m", "-XX:MaxMetaspaceSize=12m", "-javaagent:redefineagent.jar", - "--enable-preview", "RedefineRecord"); OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldNotContain("processing of -javaagent failed"); diff --git a/test/hotspot/jtreg/runtime/records/abstractRecord.jcod b/test/hotspot/jtreg/runtime/records/abstractRecord.jcod index 494af79f3cc..0587cfd39f0 100644 --- a/test/hotspot/jtreg/runtime/records/abstractRecord.jcod +++ b/test/hotspot/jtreg/runtime/records/abstractRecord.jcod @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2020, 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,11 +24,11 @@ // This test was generated from this source and then modified: // record recordNames(int x, String y) {} -// This test is a Record marked as abstract. It should result in a -// ClassFormatError exception. +// This test is a Record marked as abstract. Loading this class should +// not cause a ClassFormatError exception. class abstractRecord { 0xCAFEBABE; - 65535; // minor version + 0; // minor version 60; // version [69] { // Constant Pool ; // first element is empty diff --git a/test/hotspot/jtreg/runtime/records/badRecordAttribute.jcod b/test/hotspot/jtreg/runtime/records/badRecordAttribute.jcod index a0e3638da03..c95e8e6c427 100644 --- a/test/hotspot/jtreg/runtime/records/badRecordAttribute.jcod +++ b/test/hotspot/jtreg/runtime/records/badRecordAttribute.jcod @@ -28,7 +28,7 @@ // Utf8. It should result in a ClassFormatError exception. class badRecordAttribute { 0xCAFEBABE; - 65535; // minor version + 0; // minor version 60; // version [69] { // Constant Pool ; // first element is empty diff --git a/test/hotspot/jtreg/runtime/records/ignoreRecordAttribute.java b/test/hotspot/jtreg/runtime/records/ignoreRecordAttribute.java deleted file mode 100644 index 8d864dca5ab..00000000000 --- a/test/hotspot/jtreg/runtime/records/ignoreRecordAttribute.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/* - * @test - * @summary test logging of reasons for ignoring Record attribute - * @library /test/lib - * @compile superNotJLRecord.jcod recordIgnoredVersion.jcod - * @run driver ignoreRecordAttribute - */ - -import jdk.test.lib.process.ProcessTools; -import jdk.test.lib.process.OutputAnalyzer; - -public class ignoreRecordAttribute { - - public static void main(String[] args) throws Exception { - String MAJOR_VERSION = Integer.toString(44 + Runtime.version().feature()); - ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("--enable-preview", - "-Xlog:class+record", "-Xshare:off", "superNotJLRecord"); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); - output.shouldContain("Ignoring Record attribute"); - output.shouldContain("because super type is not java.lang.Record"); - - pb = ProcessTools.createJavaProcessBuilder("--enable-preview", - "-Xlog:class+record", "-Xshare:off", "recordIgnoredVersion"); - output = new OutputAnalyzer(pb.start()); - output.shouldContain("Ignoring Record attribute"); - output.shouldContain("because class file version is not " + MAJOR_VERSION + ".65535"); - } - -} diff --git a/test/hotspot/jtreg/runtime/records/notFinalRecord.jcod b/test/hotspot/jtreg/runtime/records/notFinalRecord.jcod index 3ee433794d5..a5a24876f5a 100644 --- a/test/hotspot/jtreg/runtime/records/notFinalRecord.jcod +++ b/test/hotspot/jtreg/runtime/records/notFinalRecord.jcod @@ -24,11 +24,11 @@ // This test was generated from this source and then modified: // record recordNames(int x, String y) {} -// This test is a Record but not marked final. It should result in a -// ClassFormatError exception. +// This test is a Record but not marked final. Loading this class should +// not cause a ClassFormatError exception. class notFinalRecord { 0xCAFEBABE; - 65535; // minor version + 0; // minor version 60; // version [69] { // Constant Pool ; // first element is empty diff --git a/test/hotspot/jtreg/runtime/records/recordAttributeTest.java b/test/hotspot/jtreg/runtime/records/recordAttributeTest.java index 212ed6e3711..839334cc44a 100644 --- a/test/hotspot/jtreg/runtime/records/recordAttributeTest.java +++ b/test/hotspot/jtreg/runtime/records/recordAttributeTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2020, 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,10 +23,10 @@ /* * @test + * @bug 8246774 * @compile abstractRecord.jcod notFinalRecord.jcod oldRecordAttribute.jcod superNotJLRecord.jcod * @compile shortRecordAttribute.jcod twoRecordAttributes.jcod badRecordAttribute.jcod - * - * @run main/othervm --enable-preview recordAttributeTest + * @run main recordAttributeTest */ @@ -37,7 +37,7 @@ public class recordAttributeTest { public static void runTest(String className, String cfeMessage) { try { Class newClass = Class.forName(className); - throw new RuntimeException("Expected ClasFormatError exception not thrown"); + throw new RuntimeException("Expected ClassFormatError exception not thrown"); } catch (java.lang.ClassFormatError e) { String eMsg = e.getMessage(); if (!eMsg.contains(cfeMessage)) { @@ -54,13 +54,11 @@ public static void main(String... args) throws Throwable { runTest("twoRecordAttributes", "Multiple Record attributes in class"); - // Test loading a Record type marked abstract. This should throw ClassFormatError. - runTest("abstractRecord", - "Record attribute in non-final or abstract class"); + // Test loading a Record type marked abstract. This should not throw ClassFormatError. + Class abstractClass = Class.forName("abstractRecord"); - // Test loading a Record type that is not final. This should throw ClassFormatError. - runTest("notFinalRecord", - "Record attribute in non-final or abstract class"); + // Test loading a Record type that is not final. This should not throw ClassFormatError. + Class notFinalClass = Class.forName("notFinalRecord"); // Test loading a Record type that is badly formed. This should throw ClassFormatError. runTest("badRecordAttribute", @@ -73,8 +71,13 @@ public static void main(String... args) throws Throwable { // badly formed Record attribute. No exception should be thrown. Class newClass = Class.forName("oldRecordAttribute"); - // Test that loading a class whose super class is not java.lang.Record - // ignores a badly formed Record attribute. No exception should be thrown. - newClass = Class.forName("superNotJLRecord"); + // Test that loading a class containing an ill-formed Record attribute causes a + // ClassFormatError exception even though its super class is not java.lang.Record. + runTest("superNotJLRecord", "Truncated class file"); + + // Test that loading a class that contains a properly formed Record attribute + // does not cause a ClassFormatError exception even though its super class is not + // java.lang.Record. + Class superNoJLRClass = Class.forName("superNotJLRecordOK"); } } diff --git a/test/hotspot/jtreg/runtime/records/recordIgnoredVersion.jcod b/test/hotspot/jtreg/runtime/records/recordIgnoredVersion.jcod deleted file mode 100644 index b9b5d7c312d..00000000000 --- a/test/hotspot/jtreg/runtime/records/recordIgnoredVersion.jcod +++ /dev/null @@ -1,256 +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. - * - * 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. - */ - -// Record attribute is ignored because class file minor version is 0. -class recordIgnoredVersion { - 0xCAFEBABE; - 0; // minor version - 60; // version - [52] { // Constant Pool - ; // first element is empty - Method #2 #3; // #1 at 0x0A - class #4; // #2 at 0x0F - NameAndType #5 #6; // #3 at 0x12 - Utf8 "java/lang/Record"; // #4 at 0x17 - Utf8 ""; // #5 at 0x2A - Utf8 "()V"; // #6 at 0x33 - Field #8 #9; // #7 at 0x39 - class #10; // #8 at 0x3E - NameAndType #11 #12; // #9 at 0x41 - Utf8 "recordIgnoredVersion"; // #10 at 0x46 - Utf8 "x"; // #11 at 0x56 - Utf8 "I"; // #12 at 0x5A - Field #8 #9; // #13 at 0x5E - InvokeDynamic 0s #15; // #14 at 0x63 - NameAndType #16 #17; // #15 at 0x68 - Utf8 "toString"; // #16 at 0x6D - Utf8 "(LrecordIgnoredVersion;)Ljava/lang/String;"; // #17 at 0x78 - InvokeDynamic 0s #19; // #18 at 0x9E - NameAndType #20 #21; // #19 at 0xA3 - Utf8 "hashCode"; // #20 at 0xA8 - Utf8 "(LrecordIgnoredVersion;)I"; // #21 at 0xB3 - InvokeDynamic 0s #23; // #22 at 0xC8 - NameAndType #24 #25; // #23 at 0xCD - Utf8 "equals"; // #24 at 0xD2 - Utf8 "(LrecordIgnoredVersion;Ljava/lang/Object;)Z"; // #25 at 0xDB - Utf8 "(I)V"; // #26 at 0x0102 - Utf8 "Code"; // #27 at 0x0109 - Utf8 "LineNumberTable"; // #28 at 0x0110 - Utf8 "MethodParameters"; // #29 at 0x0122 - Utf8 "()Ljava/lang/String;"; // #30 at 0x0135 - Utf8 "()I"; // #31 at 0x014C - Utf8 "(Ljava/lang/Object;)Z"; // #32 at 0x0152 - Utf8 "SourceFile"; // #33 at 0x016A - Utf8 "recordIgnoredVersion.java"; // #34 at 0x0177 - Utf8 "Record"; // #35 at 0x018C - Utf8 "BootstrapMethods"; // #36 at 0x0195 - MethodHandle 6b #38; // #37 at 0x01A8 - Method #39 #40; // #38 at 0x01AC - class #41; // #39 at 0x01B1 - NameAndType #42 #43; // #40 at 0x01B4 - Utf8 "java/lang/runtime/ObjectMethods"; // #41 at 0x01B9 - Utf8 "bootstrap"; // #42 at 0x01DB - Utf8 "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/TypeDescriptor;Ljava/lang/Class;Ljava/lang/String;[Ljava/lang/invoke/MethodHandle;)Ljava/lang/Object;"; // #43 at 0x01E7 - String #11; // #44 at 0x029B - MethodHandle 1b #7; // #45 at 0x029E - Utf8 "InnerClasses"; // #46 at 0x02A2 - class #48; // #47 at 0x02B1 - Utf8 "java/lang/invoke/MethodHandles$Lookup"; // #48 at 0x02B4 - class #50; // #49 at 0x02DC - Utf8 "java/lang/invoke/MethodHandles"; // #50 at 0x02DF - Utf8 "Lookup"; // #51 at 0x0300 - } // Constant Pool - - 0x0030; // access [ ACC_SUPER ACC_FINAL ] - #8;// this_cpx - #2;// super_cpx - - [0] { // Interfaces - } // Interfaces - - [1] { // fields - { // Member at 0x0313 - 0x8012; // access - #11; // name_cpx - #12; // sig_cpx - [0] { // Attributes - } // Attributes - } // Member - } // fields - - [5] { // methods - { // Member at 0x031D - 0x0001; // access - #5; // name_cpx - #26; // sig_cpx - [2] { // Attributes - Attr(#27, 34) { // Code at 0x0325 - 2; // max_stack - 2; // max_locals - Bytes[10]{ - 0x2AB700012A1BB500; - 0x07B1; - } - [0] { // Traps - } // end Traps - [1] { // Attributes - Attr(#28, 6) { // LineNumberTable at 0x0341 - [1] { // LineNumberTable - 0 1; // at 0x034D - } - } // end LineNumberTable - } // Attributes - } // end Code - ; - Attr(#29, 5) { // MethodParameters at 0x034D - 0x01000B8000; - } // end MethodParameters - } // Attributes - } // Member - ; - { // Member at 0x0358 - 0x8001; // access - #16; // name_cpx - #30; // sig_cpx - [1] { // Attributes - Attr(#27, 31) { // Code at 0x0360 - 1; // max_stack - 1; // max_locals - Bytes[7]{ - 0x2ABA000E0000B0; - } - [0] { // Traps - } // end Traps - [1] { // Attributes - Attr(#28, 6) { // LineNumberTable at 0x0379 - [1] { // LineNumberTable - 0 1; // at 0x0385 - } - } // end LineNumberTable - } // Attributes - } // end Code - } // Attributes - } // Member - ; - { // Member at 0x0385 - 0x8011; // access - #20; // name_cpx - #31; // sig_cpx - [1] { // Attributes - Attr(#27, 31) { // Code at 0x038D - 1; // max_stack - 1; // max_locals - Bytes[7]{ - 0x2ABA00120000AC; - } - [0] { // Traps - } // end Traps - [1] { // Attributes - Attr(#28, 6) { // LineNumberTable at 0x03A6 - [1] { // LineNumberTable - 0 1; // at 0x03B2 - } - } // end LineNumberTable - } // Attributes - } // end Code - } // Attributes - } // Member - ; - { // Member at 0x03B2 - 0x8011; // access - #24; // name_cpx - #32; // sig_cpx - [1] { // Attributes - Attr(#27, 32) { // Code at 0x03BA - 2; // max_stack - 2; // max_locals - Bytes[8]{ - 0x2A2BBA00160000AC; - } - [0] { // Traps - } // end Traps - [1] { // Attributes - Attr(#28, 6) { // LineNumberTable at 0x03D4 - [1] { // LineNumberTable - 0 1; // at 0x03E0 - } - } // end LineNumberTable - } // Attributes - } // end Code - } // Attributes - } // Member - ; - { // Member at 0x03E0 - 0x8001; // access - #11; // name_cpx - #31; // sig_cpx - [1] { // Attributes - Attr(#27, 29) { // Code at 0x03E8 - 1; // max_stack - 1; // max_locals - Bytes[5]{ - 0x2AB4000DAC; - } - [0] { // Traps - } // end Traps - [1] { // Attributes - Attr(#28, 6) { // LineNumberTable at 0x03FF - [1] { // LineNumberTable - 0 1; // at 0x040B - } - } // end LineNumberTable - } // Attributes - } // end Code - } // Attributes - } // Member - } // methods - - [4] { // Attributes - Attr(#33, 2) { // SourceFile at 0x040D - #34; - } // end SourceFile - ; - Attr(#35, 8) { // Record at 0x0415 - 0x0001000B000C0000; - } // end Record - ; - Attr(#36, 12) { // BootstrapMethods at 0x0423 - [1] { // bootstrap_methods - { // bootstrap_method - #37; // bootstrap_method_ref - [3] { // bootstrap_arguments - #8; // at 0x0431 - #44; // at 0x0433 - #45; // at 0x0435 - } // bootstrap_arguments - } // bootstrap_method - } - } // end BootstrapMethods - ; - Attr(#46, 10) { // InnerClasses at 0x0435 - [1] { // InnerClasses - #47 #49 #51 25; // at 0x0445 - } - } // end InnerClasses - } // Attributes -} // end class recordIgnoredVersion diff --git a/test/hotspot/jtreg/runtime/records/recordReflectionTest.java b/test/hotspot/jtreg/runtime/records/recordReflectionTest.java index bf7f6f5a151..e731398c479 100644 --- a/test/hotspot/jtreg/runtime/records/recordReflectionTest.java +++ b/test/hotspot/jtreg/runtime/records/recordReflectionTest.java @@ -23,8 +23,8 @@ /* * @test - * @compile --enable-preview --source ${jdk.version} recordReflectionTest.java - * @run main/othervm --enable-preview recordReflectionTest + * @bug 8246774 + * @summary testing reflection APIs for record classes */ diff --git a/test/hotspot/jtreg/runtime/records/shortRecordAttribute.jcod b/test/hotspot/jtreg/runtime/records/shortRecordAttribute.jcod index 595cdf38acc..278900dc842 100644 --- a/test/hotspot/jtreg/runtime/records/shortRecordAttribute.jcod +++ b/test/hotspot/jtreg/runtime/records/shortRecordAttribute.jcod @@ -28,7 +28,7 @@ // attribute_count field. It should result in a ClassFormatError exception. class shortRecordAttribute { 0xCAFEBABE; - 65535; // minor version + 0; // minor version 60; // version [69] { // Constant Pool ; // first element is empty diff --git a/test/hotspot/jtreg/runtime/records/superNotJLRecord.jcod b/test/hotspot/jtreg/runtime/records/superNotJLRecord.jcod index 3e279ffec52..770907e8286 100644 --- a/test/hotspot/jtreg/runtime/records/superNotJLRecord.jcod +++ b/test/hotspot/jtreg/runtime/records/superNotJLRecord.jcod @@ -24,11 +24,12 @@ // This test was generated from this source and then modified: // record recordNames(int x, String y) {} -// This test has a Record attribute that is too short but its super class is -// not java.lang.Record. So, the bogus Record attribute should be ignored. +// This test has a Record attribute that is too short and its super class is +// not java.lang.Record. The bad Record attribute should still be detected +// causing a ClassFormatError exception. class superNotJLRecord { 0xCAFEBABE; - 65535; // minor version + 0; // minor version 60; // version [69] { // Constant Pool ; // first element is empty @@ -343,3 +344,329 @@ class superNotJLRecord { } // end Record } // Attributes } // end class superNotJLRecord + + + +// This test was generated from this source and then modified: +// record recordNames(int x, String y) {} +// +// This class has a valid Record attribute but its super class is +// not java.lang.Record. Loading this class should not cause a +// ClassFormatError exception. +class superNotJLRecordOK { + 0xCAFEBABE; + 0; // minor version + 60; // version + [69] { // Constant Pool + ; // first element is empty + Method #2 #3; // #1 at 0x0A + class #4; // #2 at 0x0F + NameAndType #5 #6; // #3 at 0x12 + Utf8 "java/lang/Object"; // #4 at 0x17 + Utf8 ""; // #5 at 0x2A + Utf8 "()V"; // #6 at 0x33 + Field #8 #9; // #7 at 0x39 + class #10; // #8 at 0x3E + NameAndType #11 #12; // #9 at 0x41 + Utf8 "superNotJLRecordOK"; // #10 at 0x46 + Utf8 "x"; // #11 at 0x56 + Utf8 "I"; // #12 at 0x5A + Field #8 #14; // #13 at 0x5E + NameAndType #15 #16; // #14 at 0x63 + Utf8 "y"; // #15 at 0x68 + Utf8 "Ljava/lang/String;"; // #16 at 0x6C + InvokeDynamic 0s #18; // #17 at 0x81 + NameAndType #19 #20; // #18 at 0x86 + Utf8 "toString"; // #19 at 0x8B + Utf8 "(LsuperNotJLRecordOK;)Ljava/lang/String;"; // #20 at 0x96 + InvokeDynamic 0s #22; // #21 at 0xBC + NameAndType #23 #24; // #22 at 0xC1 + Utf8 "hashCode"; // #23 at 0xC6 + Utf8 "(LsuperNotJLRecordOK;)I"; // #24 at 0xD1 + InvokeDynamic 0s #26; // #25 at 0xE6 + NameAndType #27 #28; // #26 at 0xEB + Utf8 "equals"; // #27 at 0xF0 + Utf8 "(LsuperNotJLRecordOK;Ljava/lang/Object;)Z"; // #28 at 0xF9 + Dynamic 1s #30; // #29 at 0x0120 + NameAndType #31 #32; // #30 at 0x0125 + Utf8 "\\%pattern\\%recordExample\\%(ILjava\\|lang\\|String\\?)"; // #31 at 0x012A + Utf8 "Ljava/lang/runtime/PatternHandle;"; // #32 at 0x015F + Utf8 "(ILjava/lang/String;)V"; // #33 at 0x0183 + Utf8 "Code"; // #34 at 0x019C + Utf8 "LineNumberTable"; // #35 at 0x01A3 + Utf8 "MethodParameters"; // #36 at 0x01B5 + Utf8 "()Ljava/lang/String;"; // #37 at 0x01C8 + Utf8 "()I"; // #38 at 0x01DF + Utf8 "(Ljava/lang/Object;)Z"; // #39 at 0x01E5 + Utf8 "()Ljava/lang/runtime/PatternHandle;"; // #40 at 0x01FD + Utf8 "SourceFile"; // #41 at 0x0223 + Utf8 "superNotJLRecordOK.java"; // #42 at 0x0230 + Utf8 "Record"; // #43 at 0x0245 + Utf8 "BootstrapMethods"; // #44 at 0x024E + MethodHandle 6b #46; // #45 at 0x0261 + Method #47 #48; // #46 at 0x0265 + class #49; // #47 at 0x026A + NameAndType #50 #51; // #48 at 0x026D + Utf8 "java/lang/runtime/ObjectMethods"; // #49 at 0x0272 + Utf8 "bootstrap"; // #50 at 0x029A + Utf8 "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/TypeDescriptor;Ljava/lang/Class;Ljava/lang/String;[Ljava/lang/invoke/MethodHandle;)Ljava/lang/Object;"; // #51 at 0x02A6 + String #53; // #52 at 0x035A + Utf8 "x;y"; // #53 at 0x035D + MethodHandle 1b #7; // #54 at 0x0363 + MethodHandle 1b #13; // #55 at 0x0367 + MethodHandle 6b #57; // #56 at 0x036B + Method #58 #59; // #57 at 0x036F + class #60; // #58 at 0x0374 + NameAndType #61 #62; // #59 at 0x0377 + Utf8 "java/lang/runtime/PatternHandles"; // #60 at 0x037C + Utf8 "ofLazyProjection"; // #61 at 0x039F + Utf8 "(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/Class;Ljava/lang/Class;[Ljava/lang/invoke/MethodHandle;)Ljava/lang/runtime/PatternHandle;"; // #62 at 0x03B2 + Utf8 "InnerClasses"; // #63 at 0x0453 + class #65; // #64 at 0x0462 + Utf8 "java/lang/invoke/MethodHandles$Lookup"; // #65 at 0x0465 + class #67; // #66 at 0x048D + Utf8 "java/lang/invoke/MethodHandles"; // #67 at 0x0490 + Utf8 "Lookup"; // #68 at 0x04B1 + } // Constant Pool + + 0x0030; // access [ ACC_SUPER ACC_FINAL ] + #8;// this_cpx + #2;// super_cpx + + [0] { // Interfaces + } // Interfaces + + [2] { // fields + { // Member at 0x04C4 + 0x8012; // access + #11; // name_cpx + #12; // sig_cpx + [0] { // Attributes + } // Attributes + } // Member + ; + { // Member at 0x04CC + 0x8012; // access + #15; // name_cpx + #16; // sig_cpx + [0] { // Attributes + } // Attributes + } // Member + } // fields + + [7] { // methods + { // Member at 0x04D6 + 0x0001; // access + #5; // name_cpx + #33; // sig_cpx + [2] { // Attributes + Attr(#34, 39) { // Code at 0x04DE + 2; // max_stack + 3; // max_locals + Bytes[15]{ + 0x2AB700012A1BB500; + 0x072A2CB5000DB1; + } + [0] { // Traps + } // end Traps + [1] { // Attributes + Attr(#35, 6) { // LineNumberTable at 0x04FF + [1] { // LineNumberTable + 0 1; // at 0x050B + } + } // end LineNumberTable + } // Attributes + } // end Code + ; + Attr(#36, 9) { // MethodParameters at 0x050B + 0x02000B8000000F80; + 0x00; + } // end MethodParameters + } // Attributes + } // Member + ; + { // Member at 0x051A + 0x8001; // access + #19; // name_cpx + #37; // sig_cpx + [1] { // Attributes + Attr(#34, 31) { // Code at 0x0522 + 1; // max_stack + 1; // max_locals + Bytes[7]{ + 0x2ABA00110000B0; + } + [0] { // Traps + } // end Traps + [1] { // Attributes + Attr(#35, 6) { // LineNumberTable at 0x053B + [1] { // LineNumberTable + 0 1; // at 0x0547 + } + } // end LineNumberTable + } // Attributes + } // end Code + } // Attributes + } // Member + ; + { // Member at 0x0547 + 0x8011; // access + #23; // name_cpx + #38; // sig_cpx + [1] { // Attributes + Attr(#34, 31) { // Code at 0x054F + 1; // max_stack + 1; // max_locals + Bytes[7]{ + 0x2ABA00150000AC; + } + [0] { // Traps + } // end Traps + [1] { // Attributes + Attr(#35, 6) { // LineNumberTable at 0x0568 + [1] { // LineNumberTable + 0 1; // at 0x0574 + } + } // end LineNumberTable + } // Attributes + } // end Code + } // Attributes + } // Member + ; + { // Member at 0x0574 + 0x8011; // access + #27; // name_cpx + #39; // sig_cpx + [1] { // Attributes + Attr(#34, 32) { // Code at 0x057C + 2; // max_stack + 2; // max_locals + Bytes[8]{ + 0x2A2BBA00190000AC; + } + [0] { // Traps + } // end Traps + [1] { // Attributes + Attr(#35, 6) { // LineNumberTable at 0x0596 + [1] { // LineNumberTable + 0 1; // at 0x05A2 + } + } // end LineNumberTable + } // Attributes + } // end Code + } // Attributes + } // Member + ; + { // Member at 0x05A2 + 0x8001; // access + #11; // name_cpx + #38; // sig_cpx + [1] { // Attributes + Attr(#34, 29) { // Code at 0x05AA + 1; // max_stack + 1; // max_locals + Bytes[5]{ + 0x2AB40007AC; + } + [0] { // Traps + } // end Traps + [1] { // Attributes + Attr(#35, 6) { // LineNumberTable at 0x05C1 + [1] { // LineNumberTable + 0 1; // at 0x05CD + } + } // end LineNumberTable + } // Attributes + } // end Code + } // Attributes + } // Member + ; + { // Member at 0x05CD + 0x8001; // access + #15; // name_cpx + #37; // sig_cpx + [1] { // Attributes + Attr(#34, 29) { // Code at 0x05D5 + 1; // max_stack + 1; // max_locals + Bytes[5]{ + 0x2AB4000DB0; + } + [0] { // Traps + } // end Traps + [1] { // Attributes + Attr(#35, 6) { // LineNumberTable at 0x05EC + [1] { // LineNumberTable + 0 1; // at 0x05F8 + } + } // end LineNumberTable + } // Attributes + } // end Code + } // Attributes + } // Member + ; + { // Member at 0x05F8 + 0x0009; // access + #31; // name_cpx + #40; // sig_cpx + [1] { // Attributes + Attr(#34, 27) { // Code at 0x0600 + 1; // max_stack + 0; // max_locals + Bytes[3]{ + 0x121DB0; + } + [0] { // Traps + } // end Traps + [1] { // Attributes + Attr(#35, 6) { // LineNumberTable at 0x0615 + [1] { // LineNumberTable + 0 1; // at 0x0621 + } + } // end LineNumberTable + } // Attributes + } // end Code + } // Attributes + } // Member + } // methods + + [4] { // Attributes + Attr(#41, 2) { // SourceFile at 0x0623 + #42; + } // end SourceFile + ; + Attr(#43, 14) { // Record at 0x062B + 0x0002000B000C0000; + 0x000F00100000; + } // end Record + ; + Attr(#44, 24) { // BootstrapMethods at 0x063F + [2] { // bootstrap_methods + { // bootstrap_method + #45; // bootstrap_method_ref + [4] { // bootstrap_arguments + #8; // at 0x064D + #52; // at 0x064F + #54; // at 0x0651 + #55; // at 0x0653 + } // bootstrap_arguments + } // bootstrap_method + ; + { // bootstrap_method + #56; // bootstrap_method_ref + [3] { // bootstrap_arguments + #8; // at 0x0659 + #54; // at 0x065B + #55; // at 0x065D + } // bootstrap_arguments + } // bootstrap_method + } + } // end BootstrapMethods + ; + Attr(#63, 10) { // InnerClasses at 0x065D + [1] { // InnerClasses + #64 #66 #68 25; // at 0x066D + } + } // end InnerClasses + } // Attributes +} // end class superNotJLRecordOK diff --git a/test/hotspot/jtreg/runtime/records/twoRecordAttributes.jcod b/test/hotspot/jtreg/runtime/records/twoRecordAttributes.jcod index 4a7ef78ee69..72e0b4ad2d2 100644 --- a/test/hotspot/jtreg/runtime/records/twoRecordAttributes.jcod +++ b/test/hotspot/jtreg/runtime/records/twoRecordAttributes.jcod @@ -28,7 +28,7 @@ // a ClassFormatError exception. class twoRecordAttributes { 0xCAFEBABE; - 65535; // minor version + 0; // minor version 60; // version [69] { // Constant Pool ; // first element is empty diff --git a/test/hotspot/jtreg/runtime/verifier/OverriderMsg.java b/test/hotspot/jtreg/runtime/verifier/OverriderMsg.java index d90012d0fba..3d36d868115 100644 --- a/test/hotspot/jtreg/runtime/verifier/OverriderMsg.java +++ b/test/hotspot/jtreg/runtime/verifier/OverriderMsg.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2020, 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 @@ -128,7 +128,7 @@ public static void main(String... args) throws Exception { ProcessBuilder pb = ProcessTools.createTestJvm("-cp", ".", "Overrider"); OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldContain( - "java.lang.VerifyError: class Overrider overrides final method HasFinal.m(Ljava/lang/String;)V"); + "java.lang.IncompatibleClassChangeError: class Overrider overrides final method HasFinal.m(Ljava/lang/String;)V"); output.shouldHaveExitValue(1); } diff --git a/test/hotspot/jtreg/vmTestbase/vm/mlvm/anonloader/func/finalSuperclass/TestDescription.java b/test/hotspot/jtreg/vmTestbase/vm/mlvm/anonloader/func/finalSuperclass/TestDescription.java index 19a83c1120c..e6142ebe396 100644 --- a/test/hotspot/jtreg/vmTestbase/vm/mlvm/anonloader/func/finalSuperclass/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/vm/mlvm/anonloader/func/finalSuperclass/TestDescription.java @@ -30,9 +30,9 @@ * VM Testbase keywords: [feature_mlvm] * VM Testbase readme: * DESCRIPTION - * Try to load anonymous class derived from java.lang.System. The verification - * system (split verifier and system class loader) should reject such attempt and - * throw VerifyError. + * Try to load anonymous class derived from java.lang.System. The class file + * loader should reject such attempt and throw IncompatibleClassChangeError + * because java.lang.System is a final class. * * @library /vmTestbase * /test/lib @@ -44,6 +44,6 @@ * @run main/othervm * vm.mlvm.anonloader.share.ReplaceClassParentTest * -newParent java/lang/System - * -requireExceptions java.lang.VerifyError + * -requireExceptions java.lang.IncompatibleClassChangeError */ diff --git a/test/hotspot/jtreg/vmTestbase/vm/runtime/defmeth/ObjectMethodOverridesTest.java b/test/hotspot/jtreg/vmTestbase/vm/runtime/defmeth/ObjectMethodOverridesTest.java index 61564d07380..9858449bb1b 100644 --- a/test/hotspot/jtreg/vmTestbase/vm/runtime/defmeth/ObjectMethodOverridesTest.java +++ b/test/hotspot/jtreg/vmTestbase/vm/runtime/defmeth/ObjectMethodOverridesTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2020, 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 @@ -123,7 +123,7 @@ public void testGetClass() throws Exception { ConcreteClass C = b.clazz("C").implement(I).build(); - b.test().loadClass(I).throws_(VerifyError.class).done() + b.test().loadClass(I).throws_(IncompatibleClassChangeError.class).done() .run(); } @@ -158,7 +158,7 @@ public void testNotify() throws Exception { ConcreteClass C = b.clazz("C").implement(I).build(); - b.test().loadClass(I).throws_(VerifyError.class).done() + b.test().loadClass(I).throws_(IncompatibleClassChangeError.class).done() .run(); } @@ -174,7 +174,7 @@ public void testNotifyAll() throws Exception { ConcreteClass C = b.clazz("C").implement(I).build(); - b.test().loadClass(I).throws_(VerifyError.class).done() + b.test().loadClass(I).throws_(IncompatibleClassChangeError.class).done() .run(); } @@ -208,7 +208,7 @@ public void testWait() throws Exception { ConcreteClass C = b.clazz("C").implement(I).build(); - b.test().loadClass(I).throws_(VerifyError.class).done() + b.test().loadClass(I).throws_(IncompatibleClassChangeError.class).done() .run(); } @@ -224,7 +224,7 @@ public void testTimedWait() throws Exception { ConcreteClass C = b.clazz("C").implement(I).build(); - b.test().loadClass(I).throws_(VerifyError.class).done() + b.test().loadClass(I).throws_(IncompatibleClassChangeError.class).done() .run(); } @@ -240,7 +240,7 @@ public void testTimedWait1() throws Exception { ConcreteClass C = b.clazz("C").implement(I).build(); - b.test().loadClass(I).throws_(VerifyError.class).done() + b.test().loadClass(I).throws_(IncompatibleClassChangeError.class).done() .run(); } } diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 0b617068b33..f2a94d5975d 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -560,6 +560,7 @@ java/beans/XMLEncoder/Test6570354.java 8015593 macosx-all # jdk_foreign java/foreign/TestMismatch.java 8249684 macosx-all +java/foreign/TestMismatch.java 8255270 generic-i586 ############################################################################ @@ -740,12 +741,10 @@ javax/swing/JWindow/ShapedAndTranslucentWindows/TranslucentJComboBox.java 802462 # The next test below is an intermittent failure javax/swing/JComboBox/8033069/bug8033069ScrollBar.java 8163367 generic-all javax/swing/JColorChooser/Test6827032.java 8197825 windows-all -javax/swing/JColorChooser/Test6541987.java 8143021 windows-all,linux-all,macosx-all javax/swing/JTable/4235420/bug4235420.java 8079127 generic-all javax/swing/JSplitPane/4201995/bug4201995.java 8079127 generic-all javax/swing/JTree/DnD/LastNodeLowerHalfDrop.java 8159131 linux-all javax/swing/JTree/4633594/JTreeFocusTest.java 8173125 macosx-all -javax/swing/JFileChooser/8041694/bug8041694.java 8196302 windows-all,macosx-all javax/swing/AbstractButton/6711682/bug6711682.java 8060765 windows-all,macosx-all javax/swing/Action/8133039/bug8133039.java 8196089 windows-all,macosx-all javax/swing/JComboBox/6559152/bug6559152.java 8196090 windows-all,macosx-all @@ -759,60 +758,35 @@ javax/swing/JPopupMenu/6800513/bug6800513.java 7184956 macosx-all javax/swing/JPopupMenu/6675802/bug6675802.java 8196097 windows-all javax/swing/JTabbedPane/8007563/Test8007563.java 8051591 generic-all javax/swing/JTabbedPane/4624207/bug4624207.java 8064922 macosx-all -javax/swing/JTabbedPane/7024235/Test7024235.java 8028281 macosx-all javax/swing/SwingUtilities/TestBadBreak/TestBadBreak.java 8160720 generic-all javax/swing/plaf/basic/Test6984643.java 8198340 windows-all -javax/swing/text/CSSBorder/6796710/bug6796710.java 8196099 windows-all javax/swing/text/DefaultCaret/HidingSelection/HidingSelectionTest.java 8194048 windows-all javax/swing/text/DefaultCaret/HidingSelection/MultiSelectionTest.java 8213562 linux-all javax/swing/text/JTextComponent/5074573/bug5074573.java 8196100 windows-all javax/swing/JFileChooser/6798062/bug6798062.java 8146446 windows-all javax/swing/JComboBox/8182031/ComboPopupTest.java 8196465 linux-all,macosx-all javax/swing/JFileChooser/6738668/bug6738668.java 8194946 generic-all -javax/swing/JFileChooser/8021253/bug8021253.java 8169954 windows-all,linux-all,macosx-all javax/swing/JFileChooser/8062561/bug8062561.java 8196466 linux-all,macosx-all javax/swing/JInternalFrame/Test6325652.java 8224977 macosx-all javax/swing/JInternalFrame/8146321/JInternalFrameIconTest.java 8225045 linux-all javax/swing/JPopupMenu/4870644/bug4870644.java 8194130 macosx-all,linux-all javax/swing/JFileChooser/6868611/bug6868611.java 7059834 windows-all -javax/swing/SwingWorker/6493680/bug6493680.java 8198410 windows-all javax/swing/PopupFactory/6276087/NonOpaquePopupMenuTest.java 8065099,8208565 macosx-all,linux-all -javax/swing/DataTransfer/8059739/bug8059739.java 8199074 generic-all -javax/swing/SwingWorker/6432565/bug6432565.java 8199077 generic-all -javax/swing/SwingWorker/6880336/NestedWorkers.java 8199049 windows-all -javax/swing/text/DefaultCaret/6938583/bug6938583.java 8199058 generic-all -javax/swing/text/html/parser/Parser/6990651/bug6990651.java 8199060 generic-all -javax/swing/text/html/parser/Parser/HtmlCommentTagParseTest/HtmlCommentTagParseTest.java 8199073 generic-all -javax/swing/text/StyledEditorKit/8016833/bug8016833.java 8199055 generic-all -javax/swing/text/Utilities/8134721/bug8134721.java 8199062 generic-all -javax/swing/tree/DefaultTreeCellRenderer/7142955/bug7142955.java 8199076 generic-all javax/swing/UIDefaults/6302464/bug6302464.java 8199079 macosx-all -javax/swing/UIDefaults/8149879/InternalResourceBundle.java 8199054 windows-all javax/swing/PopupFactory/8048506/bug8048506.java 8202660 windows-all -javax/swing/JTextArea/TextViewOOM/TextViewOOM.java 8167355 generic-all javax/swing/JPopupMenu/8075063/ContextMenuScrollTest.java 202880 linux-all javax/swing/dnd/8139050/NativeErrorsInTableDnD.java 8202765 macosx-all,linux-all javax/swing/Popup/TaskbarPositionTest.java 8065097 macosx-all,linux-all javax/swing/JEditorPane/6917744/bug6917744.java 8213124 macosx-all javax/swing/JTree/6263446/bug6263446.java 8213125 macosx-all -javax/swing/ToolTipManager/Test6256140.java 8233560 macosx-all javax/swing/text/View/8014863/bug8014863.java 8233561 macosx-all javax/swing/text/StyledEditorKit/4506788/bug4506788.java 8233562 macosx-all -javax/swing/text/JTextComponent/6361367/bug6361367.java 8233569 macosx-all -javax/swing/text/html/HTMLEditorKit/5043626/bug5043626.java 233570 macosx-all javax/swing/JRootPane/4670486/bug4670486.java 8042381 macosx-all javax/swing/JRadioButton/ButtonGroupFocus/ButtonGroupFocusTest.java 8233555 macosx-all javax/swing/JRadioButton/8075609/bug8075609.java 8233555 macosx-all javax/swing/JRadioButton/8033699/bug8033699.java 8233555 macosx-all -javax/swing/JPopupMenu/6827786/bug6827786.java 8233556 macosx-all -javax/swing/JPopupMenu/6544309/bug6544309.java 8233556 macosx-all -javax/swing/JPopupMenu/4634626/bug4634626.java 8233556 macosx-all -javax/swing/JPopupMenu/4458079/bug4458079.java 8233556 macosx-all -javax/swing/JMenuItem/ActionListenerCalledTwice/ActionListenerCalledTwiceTest.java 8233637 macosx-all +javax/swing/JPopupMenu/4634626/bug4634626.java 8017175 macosx-all javax/swing/JMenuItem/6249972/bug6249972.java 8233640 macosx-all -javax/swing/JMenuItem/4171437/bug4171437.java 8233641 macosx-all -javax/swing/JMenu/4692443/bug4692443.java 8171998 macosx-all -javax/swing/plaf/basic/BasicComboPopup/JComboBoxPopupLocation/JComboBoxPopupLocation.java 8238720 windows-all sanity/client/SwingSet/src/ToolTipDemoTest.java 8225012 windows-all,macosx-all sanity/client/SwingSet/src/ScrollPaneDemoTest.java 8225013 linux-all @@ -890,3 +864,32 @@ jdk/jfr/event/os/TestThreadContextSwitches.java 8247776 windows- tools/jpackage/share/jdk/jpackage/tests/ModulePathTest3.java#id0 8248418 generic-all ############################################################################ + +# Client manual tests + +java/awt/event/MouseEvent/SpuriousExitEnter/SpuriousExitEnter_1.java 7131438,8022539 generic-all +java/awt/event/MouseEvent/SpuriousExitEnter/SpuriousExitEnter_2.java 7131438,8022539 generic-all +java/awt/Modal/WsDisabledStyle/CloseBlocker/CloseBlocker.java 7187741 linux-all,macosx-all +java/awt/Component/UpdatingBootTime/UpdatingBootTime.html 7194219 linux-all +java/awt/xembed/server/TestXEmbedServerJava.java 8001150,8004031 generic-all +java/awt/TextArea/MouseOverScrollbarWhenTyping/Test1.java 8005970 macosx-all,windows-all +javax/swing/JFileChooser/6698013/bug6698013.java 8024419 macosx-all +javax/swing/JColorChooser/8065098/bug8065098.java 8065647 macosx-all +java/awt/Modal/PrintDialogsTest/PrintDialogsTest.java 8068378 generic-all +java/awt/dnd/DnDFileGroupDescriptor/DnDFileGroupDescriptor.html 8080185 macosx-all,linux-all +javax/swing/JTabbedPane/4666224/bug4666224.html 8144124 macosx-all +java/awt/event/MouseEvent/AltGraphModifierTest/AltGraphModifierTest.java 8162380 generic-all +java/awt/Window/TranslucentJAppletTest/TranslucentJAppletTest.java 8163086 macosx-all +java/awt/image/multiresolution/MultiResolutionIcon/IconTest.java 8250804 macosx-all,linux-all +java/awt/image/VolatileImage/VolatileImageConfigurationTest.java 8171069 macosx-all,linux-all +java/awt/Modal/InvisibleParentTest/InvisibleParentTest.java 8172245 linux-all +java/awt/print/Dialog/RestoreActiveWindowTest/RestoreActiveWindowTest.java 8185429 macosx-all +java/awt/TrayIcon/DblClickActionEventTest/DblClickActionEventTest.html 8203867 macosx-all +java/awt/Frame/FrameStateTest/FrameStateTest.html 8203920 macosx-all,linux-all +javax/swing/SwingUtilities/TestTextPosInPrint.java 8227025 windows-all +java/awt/print/PrinterJob/ScaledText/ScaledText.java 8231226 macosx-all +java/awt/font/TextLayout/TestJustification.html 8250791 macosx-all +javax/swing/JTabbedPane/4209065/bug4209065.java 8251177 macosx-all +java/awt/TrayIcon/DragEventSource/DragEventSource.java 8252242 macosx-all + +############################################################################ diff --git a/test/jdk/TEST.ROOT b/test/jdk/TEST.ROOT index 71a3d4795c6..ab63cc78ef6 100644 --- a/test/jdk/TEST.ROOT +++ b/test/jdk/TEST.ROOT @@ -58,7 +58,8 @@ requires.properties= \ vm.hasJFR \ vm.jvmci \ docker.support \ - release.implementor + release.implementor \ + jdk.containerized # Minimum jtreg version requiredVersion=5.1 b1 diff --git a/test/jdk/com/sun/jdi/BadHandshakeTest.java b/test/jdk/com/sun/jdi/BadHandshakeTest.java index 40bac30561d..f2b975ecfcc 100644 --- a/test/jdk/com/sun/jdi/BadHandshakeTest.java +++ b/test/jdk/com/sun/jdi/BadHandshakeTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2020, 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 @@ -112,28 +112,51 @@ public static void main(String args[]) throws Exception { throw error; } - log("cleaning..."); - // Attach to server debuggee and resume it so it can exit + log("final attach..."); + // Attach to server debuggee to ensure it's still available to attach and resume it so it can exit AttachingConnector conn = (AttachingConnector)findConnector("com.sun.jdi.SocketAttach"); - Map conn_args = conn.defaultArguments(); - Connector.IntegerArgument port_arg = - (Connector.IntegerArgument)conn_args.get("port"); - port_arg.setValue(port); - VirtualMachine vm = conn.attach(conn_args); + retryDelay = 20; + for (int retry = 0; retry < 5; retry++) { + if (error != null) { + try { + Thread.sleep(retryDelay); + } catch (InterruptedException ex) { + // ignore + } + retryDelay *= 2; + error = null; + } + try { + log("retry: " + retry); + Map conn_args = conn.defaultArguments(); + Connector.IntegerArgument port_arg = + (Connector.IntegerArgument)conn_args.get("port"); + port_arg.setValue(port); + VirtualMachine vm = conn.attach(conn_args); + + // The first event is always a VMStartEvent, and it is always in + // an EventSet by itself. Wait for it. + EventSet evtSet = vm.eventQueue().remove(); + for (Event event : evtSet) { + if (event instanceof VMStartEvent) { + break; + } + throw new RuntimeException("Test failed - debuggee did not start properly"); + } - // The first event is always a VMStartEvent, and it is always in - // an EventSet by itself. Wait for it. - EventSet evtSet = vm.eventQueue().remove(); - for (Event event : evtSet) { - if (event instanceof VMStartEvent) { + vm.eventRequestManager().deleteAllBreakpoints(); + vm.resume(); break; + } catch (ConnectException ex) { + log("got exception: " + ex.toString()); + error = ex; } - throw new RuntimeException("Test failed - debuggee did not start properly"); + } + if (error != null) { + throw error; } - vm.eventRequestManager().deleteAllBreakpoints(); - vm.resume(); - + // give the debuggee some time to exit before forcibly terminating it debuggee.waitFor(10, TimeUnit.SECONDS); } } diff --git a/test/jdk/com/sun/jdi/EATests.java b/test/jdk/com/sun/jdi/EATests.java index 8b0af830b62..2abba8113bc 100644 --- a/test/jdk/com/sun/jdi/EATests.java +++ b/test/jdk/com/sun/jdi/EATests.java @@ -114,7 +114,7 @@ * * @author Richard Reingruber richard DOT reingruber AT sap DOT com * - * @requires ((vm.compMode == "Xmixed") & vm.jvmci) + * @requires ((vm.compMode == "Xmixed") & vm.graal.enabled) * * @library /test/lib /test/hotspot/jtreg * diff --git a/test/jdk/java/awt/Choice/GetSizeTest/GetSizeTest.java b/test/jdk/java/awt/Choice/GetSizeTest/GetSizeTest.java index 54bb22ccd9e..b44106a28db 100644 --- a/test/jdk/java/awt/Choice/GetSizeTest/GetSizeTest.java +++ b/test/jdk/java/awt/Choice/GetSizeTest/GetSizeTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2020, 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,14 @@ run main GetSizeTest.html */ -import java.awt.*; -import java.awt.event.*; +import java.awt.Choice; +import java.awt.Frame; +import java.awt.Panel; +import java.awt.Point; +import java.awt.Robot; +import java.awt.event.InputEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; public class GetSizeTest { @@ -40,16 +46,15 @@ public class GetSizeTest { "what choices do I have?", "Will I pick the same thing in the future?", }; - static boolean passed = false; - static Robot robot = null; + static volatile boolean passed = false; - public static void main(String args[]) - { + public static void main(String args[]) throws Exception { + Frame f = null; try { - robot = new Robot(); - robot.setAutoDelay(50); + Robot robot = new Robot(); + robot.setAutoDelay(150); - Frame f = new Frame("choice test"); + f = new Frame("choice test"); Panel p = new Panel(); p.setLayout(null); @@ -70,14 +75,7 @@ public void mouseReleased(MouseEvent e) { f.add(p); f.setSize(300, 300); - - f.addWindowListener(new WindowAdapter() { - public void windowClosing(WindowEvent we) { - System.err.println("Test passed"); - passed = true; - } - }); - + f.setLocationRelativeTo(null); f.setVisible(true); c.setSize(200, 200); @@ -88,14 +86,13 @@ public void windowClosing(WindowEvent we) { Point pt = c.getLocationOnScreen(); robot.mouseMove(pt.x + c.getWidth() - 10, pt.y + c.getHeight() / 2); robot.waitForIdle(); - robot.mousePress(InputEvent.BUTTON2_MASK); - robot.mouseRelease(InputEvent.BUTTON2_MASK); + robot.mousePress(InputEvent.BUTTON2_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON2_DOWN_MASK); robot.waitForIdle(); - } catch (Throwable e) { - if (robot == null){ - throw new RuntimeException( "Test failed.Unable to initialize Robot "+e); + } finally { + if (f != null) { + f.dispose(); } - throw new RuntimeException( "Test failed due to thrown exception "+e); } if (!passed) { throw new RuntimeException( "Timeout. Choice component size is not actual size." ); diff --git a/test/jdk/java/awt/color/ICC_ProfileGrayTest.java b/test/jdk/java/awt/color/ICC_ProfileGrayTest.java new file mode 100644 index 00000000000..471d108af48 --- /dev/null +++ b/test/jdk/java/awt/color/ICC_ProfileGrayTest.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.color.ColorSpace; +import java.awt.color.ICC_Profile; +import java.awt.color.ICC_ProfileGray; +import java.awt.color.ProfileDataException; + +/** + * @test + * @bug 8254370 + * @summary Tests basic ICC_ProfileGray functionality + */ +public final class ICC_ProfileGrayTest { + + public static void main(String[] args) throws Exception { + ICC_Profile csProfile = ICC_Profile.getInstance(ColorSpace.CS_GRAY); + ICC_Profile dataProfile = ICC_Profile.getInstance(csProfile.getData()); + ICC_Profile stringProfile = ICC_Profile.getInstance("GRAY.pf"); + test(csProfile); + test(dataProfile); + test(stringProfile); + } + + private static void test(ICC_Profile profile) { + // Gray profile should be implemented as ICC_ProfileGray and includes + // the mediaWhitePointTag and grayTRCTag tags + if (!(profile instanceof ICC_ProfileGray) + || profile.getData(ICC_Profile.icSigMediaWhitePointTag) == null + || profile.getData(ICC_Profile.icSigGrayTRCTag) == null) { + throw new RuntimeException("Wrong profile: " + profile); + } + + ICC_ProfileGray gray = (ICC_ProfileGray) profile; + + int length = gray.getMediaWhitePoint().length; + if (length != 3) { + throw new RuntimeException("Wrong data length: " + length); + } + + // if getTRC() throws an exception then getGamma() should work + boolean trc = false; + try { + gray.getTRC(); + trc = true; + System.out.println("getTRC() works fine"); + } catch (ProfileDataException ignore) { + gray.getGamma(); + } + // if getGamma() throws an exception then getTRC() should work + boolean gamma = false; + try { + gray.getGamma(); + gamma = true; + System.out.println("getGamma() works fine"); + } catch (ProfileDataException ignore) { + gray.getTRC(); + } + + if (gamma == trc) { + // only one should work + throw new RuntimeException("Only one operation should work"); + } + } +} diff --git a/test/jdk/java/awt/color/ICC_ProfileRGBTest.java b/test/jdk/java/awt/color/ICC_ProfileRGBTest.java new file mode 100644 index 00000000000..a1b2562d33e --- /dev/null +++ b/test/jdk/java/awt/color/ICC_ProfileRGBTest.java @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.color.ColorSpace; +import java.awt.color.ICC_Profile; +import java.awt.color.ICC_ProfileRGB; +import java.awt.color.ProfileDataException; +import java.util.Arrays; + +/** + * @test + * @bug 8254370 + * @summary Tests basic ICC_ProfileRGB functionality + */ +public final class ICC_ProfileRGBTest { + + public static void main(String[] args) throws Exception { + ICC_Profile csProfile = ICC_Profile.getInstance(ColorSpace.CS_sRGB); + ICC_Profile dataProfile = ICC_Profile.getInstance(csProfile.getData()); + ICC_Profile string2Profile = ICC_Profile.getInstance("sRGB.pf"); + ICC_Profile string1Profile = ICC_Profile.getInstance("LINEAR_RGB.pf"); + test(csProfile); + test(dataProfile); + test(string1Profile); + test(string2Profile); + } + + private static void test(ICC_Profile profile) { + // RGB profile should be implemented as ICC_ProfileRGB and includes the + // redColorantTag, greenColorantTag, blueColorantTag, redTRCTag, + // greenTRCTag, blueTRCTag, mediaWhitePointTag tags + if (!(profile instanceof ICC_ProfileRGB) + || profile.getData(ICC_Profile.icSigRedColorantTag) == null + || profile.getData(ICC_Profile.icSigGreenColorantTag) == null + || profile.getData(ICC_Profile.icSigBlueColorantTag) == null + || profile.getData(ICC_Profile.icSigRedTRCTag) == null + || profile.getData(ICC_Profile.icSigGreenTRCTag) == null + || profile.getData(ICC_Profile.icSigBlueTRCTag) == null + || profile.getData(ICC_Profile.icSigMediaWhitePointTag) == null) + { + throw new RuntimeException("Wrong profile: " + profile); + } + + ICC_ProfileRGB rgb = (ICC_ProfileRGB) profile; + + int length = rgb.getMediaWhitePoint().length; + if (length != 3) { + throw new RuntimeException("Wrong data length: " + length); + } + + // if getTRC() throws an exception then getGamma() should work + boolean trc = false; + try { + rgb.getTRC(ICC_ProfileRGB.REDCOMPONENT); + rgb.getTRC(ICC_ProfileRGB.GREENCOMPONENT); + rgb.getTRC(ICC_ProfileRGB.BLUECOMPONENT); + trc = true; + System.out.println("getTRC() works fine"); + } catch (ProfileDataException ignore) { + rgb.getGamma(ICC_ProfileRGB.REDCOMPONENT); + rgb.getGamma(ICC_ProfileRGB.GREENCOMPONENT); + rgb.getGamma(ICC_ProfileRGB.BLUECOMPONENT); + } + // if getGamma() throws an exception then getTRC() should work + boolean gamma = false; + try { + rgb.getGamma(ICC_ProfileRGB.REDCOMPONENT); + rgb.getGamma(ICC_ProfileRGB.GREENCOMPONENT); + rgb.getGamma(ICC_ProfileRGB.BLUECOMPONENT); + gamma = true; + System.out.println("getGamma() works fine"); + } catch (ProfileDataException ignore) { + rgb.getTRC(ICC_ProfileRGB.REDCOMPONENT); + rgb.getTRC(ICC_ProfileRGB.GREENCOMPONENT); + rgb.getTRC(ICC_ProfileRGB.BLUECOMPONENT); + } + + if (gamma == trc) { + // only one should work fine + throw new RuntimeException("Only one operation should work"); + } + + // IllegalArgumentException if the component is invalid + try { + rgb.getGamma(10); + throw new RuntimeException("IllegalArgumentException was expected"); + } catch (IllegalArgumentException ignored) {} + try { + rgb.getGamma(-1); + throw new RuntimeException("IllegalArgumentException was expected"); + } catch (IllegalArgumentException ignored) {} + try { + rgb.getTRC(10); + throw new RuntimeException("IllegalArgumentException was expected"); + } catch (IllegalArgumentException ignored) {} + try { + rgb.getTRC(-1); + throw new RuntimeException("IllegalArgumentException was expected"); + } catch (IllegalArgumentException ignored) {} + + // Validates content of ICC_ProfileRGB.getMatrix() + float[][] matrix = rgb.getMatrix(); // current implementation + float[][] old = getMatrix(rgb); // old implementation + if (!Arrays.deepEquals(matrix, old)) { + System.err.println("Expected: " + Arrays.deepToString(old)); + System.err.println("Actual: " + Arrays.deepToString(matrix)); + throw new RuntimeException("Wrong matrix"); + } + } + + /** + * Old implementation of ICC_ProfileRGB.getMatrix(). + */ + private static float[][] getMatrix(ICC_ProfileRGB profile) { + float[] tmpMatrix = getXYZTag(profile, ICC_Profile.icSigRedColorantTag); + float[][] theMatrix = new float[3][3]; + theMatrix[0][0] = tmpMatrix[0]; + theMatrix[1][0] = tmpMatrix[1]; + theMatrix[2][0] = tmpMatrix[2]; + tmpMatrix = getXYZTag(profile, ICC_Profile.icSigGreenColorantTag); + theMatrix[0][1] = tmpMatrix[0]; + theMatrix[1][1] = tmpMatrix[1]; + theMatrix[2][1] = tmpMatrix[2]; + tmpMatrix = getXYZTag(profile, ICC_Profile.icSigBlueColorantTag); + theMatrix[0][2] = tmpMatrix[0]; + theMatrix[1][2] = tmpMatrix[1]; + theMatrix[2][2] = tmpMatrix[2]; + return theMatrix; + } + + private static float[] getXYZTag(ICC_ProfileRGB profile, int theTagSignature) { + byte[] theData = profile.getData(theTagSignature); + float[] theXYZNumber = new float[3]; + for (int i1 = 0, i2 = profile.icXYZNumberX; i1 < 3; i1++, i2 += 4) { + int theS15Fixed16 = intFromBigEndian(theData, i2); + theXYZNumber [i1] = theS15Fixed16 / 65536.0f; + } + return theXYZNumber; + } + + static int intFromBigEndian(byte[] array, int index) { + return (((array[index] & 0xff) << 24) | + ((array[index+1] & 0xff) << 16) | + ((array[index+2] & 0xff) << 8) | + (array[index+3] & 0xff)); + } +} diff --git a/test/jdk/java/awt/datatransfer/ClipboardInterVMTest/ClipboardInterVMTest.java b/test/jdk/java/awt/datatransfer/ClipboardInterVMTest/ClipboardInterVMTest.java index 6cf79322c27..275f8ee446e 100644 --- a/test/jdk/java/awt/datatransfer/ClipboardInterVMTest/ClipboardInterVMTest.java +++ b/test/jdk/java/awt/datatransfer/ClipboardInterVMTest/ClipboardInterVMTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2020, 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 @@ -83,7 +83,7 @@ public void flavorsChanged(FlavorEvent e) { } }); - System.out.println("Starting external clipborad modifier..."); + System.out.println("Starting external clipboard modifier..."); new Thread(() -> runTest(ClipboardInterVMTest.class.getCanonicalName(), "pong")).start(); String content = ""; @@ -106,7 +106,7 @@ public void flavorsChanged(FlavorEvent e) { }; if (!flavorChangedMonitor.await(10, TimeUnit.SECONDS)) { - throw new RuntimeException("No LostOwnership event received."); + throw new RuntimeException("No FlavorsChanged event received."); }; if (!content.equals("pong")) { diff --git a/test/jdk/java/awt/print/bug8023392/bug8023392.java b/test/jdk/java/awt/print/bug8023392/bug8023392.java index 9b7c6bc2313..440de96a061 100644 --- a/test/jdk/java/awt/print/bug8023392/bug8023392.java +++ b/test/jdk/java/awt/print/bug8023392/bug8023392.java @@ -46,6 +46,7 @@ public class bug8023392 extends Applet { static final String[] instructions = { + "Please select the RadioButton for applet size labeled \"variable\" radiobutton in test harness window.", "A Frame containing several pairs of labels ((a) and (b)) is displayed.", "Labels of each pair look the same and are left-aligned (with spaces ", "between chars).", @@ -169,7 +170,9 @@ public int print(Graphics graphics, if (pageIndex >= 1) { return Printable.NO_SUCH_PAGE; } - + double imgX = pageFormat.getImageableX(); + double imgY = pageFormat.getImageableY(); + ((Graphics2D)graphics).translate(imgX, imgY); this.paint(graphics); return Printable.PAGE_EXISTS; } diff --git a/test/jdk/java/io/Serializable/records/AbsentStreamValuesTest.java b/test/jdk/java/io/Serializable/records/AbsentStreamValuesTest.java index 2980b4e4063..153d0a6e995 100644 --- a/test/jdk/java/io/Serializable/records/AbsentStreamValuesTest.java +++ b/test/jdk/java/io/Serializable/records/AbsentStreamValuesTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2020, 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,10 +23,10 @@ /* * @test + * @bug 8246774 * @summary Checks that the appropriate default value is given to the canonical ctr - * @compile --enable-preview -source ${jdk.version} AbsentStreamValuesTest.java - * @run testng/othervm --enable-preview AbsentStreamValuesTest - * @run testng/othervm/java.security.policy=empty_security.policy --enable-preview AbsentStreamValuesTest + * @run testng AbsentStreamValuesTest + * @run testng/othervm/java.security.policy=empty_security.policy AbsentStreamValuesTest */ import java.io.ByteArrayInputStream; diff --git a/test/jdk/java/io/Serializable/records/BadCanonicalCtrTest.java b/test/jdk/java/io/Serializable/records/BadCanonicalCtrTest.java index 4f57f97bf7e..8b0a1ae625b 100644 --- a/test/jdk/java/io/Serializable/records/BadCanonicalCtrTest.java +++ b/test/jdk/java/io/Serializable/records/BadCanonicalCtrTest.java @@ -23,12 +23,12 @@ /* * @test + * @bug 8246774 * @summary InvalidClassException is thrown when the canonical constructor * cannot be found during deserialization. * @library /test/lib * @modules java.base/jdk.internal.org.objectweb.asm - * @compile --enable-preview -source ${jdk.version} BadCanonicalCtrTest.java - * @run testng/othervm --enable-preview BadCanonicalCtrTest + * @run testng BadCanonicalCtrTest */ import java.io.ByteArrayInputStream; @@ -59,7 +59,6 @@ * constructor cannot be found during deserialization. */ public class BadCanonicalCtrTest { - private static final String VERSION = Integer.toString(Runtime.version().feature()); // ClassLoader for creating instances of the records to test with. ClassLoader goodRecordClassLoader; @@ -79,8 +78,7 @@ public class BadCanonicalCtrTest { public void setup() { { byte[] byteCode = InMemoryJavaCompiler.compile("R1", - "public record R1 () implements java.io.Serializable { }", - "--enable-preview", "-source", VERSION); + "public record R1 () implements java.io.Serializable { }"); goodRecordClassLoader = new ByteCodeLoader("R1", byteCode, BadCanonicalCtrTest.class.getClassLoader()); byte[] bc1 = removeConstructor(byteCode); missingCtrClassLoader = new ByteCodeLoader("R1", bc1, BadCanonicalCtrTest.class.getClassLoader()); @@ -89,8 +87,7 @@ public void setup() { } { byte[] byteCode = InMemoryJavaCompiler.compile("R2", - "public record R2 (int x, int y) implements java.io.Serializable { }", - "--enable-preview", "-source", VERSION); + "public record R2 (int x, int y) implements java.io.Serializable { }"); goodRecordClassLoader = new ByteCodeLoader("R2", byteCode, goodRecordClassLoader); byte[] bc1 = removeConstructor(byteCode); missingCtrClassLoader = new ByteCodeLoader("R2", bc1, missingCtrClassLoader); @@ -101,8 +98,7 @@ public void setup() { byte[] byteCode = InMemoryJavaCompiler.compile("R3", "public record R3 (long l) implements java.io.Externalizable {" + " public void writeExternal(java.io.ObjectOutput out) { }" + - " public void readExternal(java.io.ObjectInput in) { } }", - "--enable-preview", "-source", VERSION); + " public void readExternal(java.io.ObjectInput in) { } }"); goodRecordClassLoader = new ByteCodeLoader("R3", byteCode, goodRecordClassLoader); byte[] bc1 = removeConstructor(byteCode); missingCtrClassLoader = new ByteCodeLoader("R3", bc1, missingCtrClassLoader); diff --git a/test/jdk/java/io/Serializable/records/BasicRecordSer.java b/test/jdk/java/io/Serializable/records/BasicRecordSer.java index 4454c804c4b..ee50f630351 100644 --- a/test/jdk/java/io/Serializable/records/BasicRecordSer.java +++ b/test/jdk/java/io/Serializable/records/BasicRecordSer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2020, 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,10 +23,10 @@ /* * @test + * @bug 8246774 * @summary Basic test that serializes and deserializes a number of records - * @compile --enable-preview -source ${jdk.version} BasicRecordSer.java - * @run testng/othervm --enable-preview BasicRecordSer - * @run testng/othervm/java.security.policy=empty_security.policy --enable-preview BasicRecordSer + * @run testng BasicRecordSer + * @run testng/othervm/java.security.policy=empty_security.policy BasicRecordSer */ import java.io.ByteArrayInputStream; diff --git a/test/jdk/java/io/Serializable/records/ConstructorAccessTest.java b/test/jdk/java/io/Serializable/records/ConstructorAccessTest.java index 9624e10987f..c9f2be0e18f 100644 --- a/test/jdk/java/io/Serializable/records/ConstructorAccessTest.java +++ b/test/jdk/java/io/Serializable/records/ConstructorAccessTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,11 +23,11 @@ /* * @test + * @bug 8246774 * @summary Ensures that the serialization implementation can *always* access * the record constructor - * @compile --enable-preview -source ${jdk.version} ConstructorAccessTest.java - * @run testng/othervm --enable-preview ConstructorAccessTest - * @run testng/othervm/java.security.policy=empty_security.policy --enable-preview ConstructorAccessTest + * @run testng ConstructorAccessTest + * @run testng/othervm/java.security.policy=empty_security.policy ConstructorAccessTest */ import java.io.ByteArrayInputStream; diff --git a/test/jdk/java/io/Serializable/records/ConstructorPermissionTest.java b/test/jdk/java/io/Serializable/records/ConstructorPermissionTest.java index d868fffec56..6b0109230b0 100644 --- a/test/jdk/java/io/Serializable/records/ConstructorPermissionTest.java +++ b/test/jdk/java/io/Serializable/records/ConstructorPermissionTest.java @@ -23,10 +23,10 @@ /* * @test + * @bug 8246774 * @summary Verifies that privileged operations performed in the record * constructor throw, when run without the required permissions - * @compile --enable-preview -source ${jdk.version} ConstructorPermissionTest.java - * @run testng/othervm/java.security.policy=empty_security.policy --enable-preview ConstructorPermissionTest + * @run testng/othervm/java.security.policy=empty_security.policy ConstructorPermissionTest */ import java.io.ByteArrayInputStream; diff --git a/test/jdk/java/io/Serializable/records/CycleTest.java b/test/jdk/java/io/Serializable/records/CycleTest.java index 0933303b2ce..9df703c3bc1 100644 --- a/test/jdk/java/io/Serializable/records/CycleTest.java +++ b/test/jdk/java/io/Serializable/records/CycleTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2020, 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,10 +23,10 @@ /* * @test + * @bug 8246774 * @summary Ensures basic behavior of cycles from record components - * @compile --enable-preview -source ${jdk.version} CycleTest.java - * @run testng/othervm --enable-preview CycleTest - * @run testng/othervm/java.security.policy=empty_security.policy --enable-preview CycleTest + * @run testng CycleTest + * @run testng/othervm/java.security.policy=empty_security.policy CycleTest */ import java.io.ByteArrayInputStream; diff --git a/test/jdk/java/io/Serializable/records/DifferentStreamFieldsTest.java b/test/jdk/java/io/Serializable/records/DifferentStreamFieldsTest.java index 1624dce6190..d4101f9894b 100644 --- a/test/jdk/java/io/Serializable/records/DifferentStreamFieldsTest.java +++ b/test/jdk/java/io/Serializable/records/DifferentStreamFieldsTest.java @@ -23,11 +23,11 @@ /* * @test + * @bug 8246774 * @summary Checks that the appropriate value is given to the canonical ctr * @library /test/lib - * @compile --enable-preview -source ${jdk.version} DifferentStreamFieldsTest.java - * @run testng/othervm --enable-preview DifferentStreamFieldsTest - * @run testng/othervm/java.security.policy=empty_security.policy --enable-preview DifferentStreamFieldsTest + * @run testng DifferentStreamFieldsTest + * @run testng/othervm/java.security.policy=empty_security.policy DifferentStreamFieldsTest */ import java.io.ByteArrayInputStream; diff --git a/test/jdk/java/io/Serializable/records/ProhibitedMethods.java b/test/jdk/java/io/Serializable/records/ProhibitedMethods.java index 4863a6054b3..099008b4306 100644 --- a/test/jdk/java/io/Serializable/records/ProhibitedMethods.java +++ b/test/jdk/java/io/Serializable/records/ProhibitedMethods.java @@ -23,11 +23,11 @@ /* * @test + * @bug 8246774 * @summary Basic tests for prohibited magic serialization methods * @library /test/lib * @modules java.base/jdk.internal.org.objectweb.asm - * @compile --enable-preview -source ${jdk.version} ProhibitedMethods.java - * @run testng/othervm --enable-preview ProhibitedMethods + * @run testng ProhibitedMethods */ import java.io.ByteArrayInputStream; @@ -69,7 +69,6 @@ * record objects. */ public class ProhibitedMethods { - private static final String VERSION = Integer.toString(Runtime.version().feature()); public interface ThrowingExternalizable extends Externalizable { default void writeExternal(ObjectOutput out) { @@ -106,8 +105,7 @@ record Wubble (Wobble wobble, Wibble wibble, String s) implements ThrowingExtern public void setup() { { byte[] byteCode = InMemoryJavaCompiler.compile("Foo", - "public record Foo () implements java.io.Serializable { }", - "--enable-preview", "-source", VERSION); + "public record Foo () implements java.io.Serializable { }"); byteCode = addWriteObject(byteCode); byteCode = addReadObject(byteCode); byteCode = addReadObjectNoData(byteCode); @@ -115,8 +113,7 @@ public void setup() { } { byte[] byteCode = InMemoryJavaCompiler.compile("Bar", - "public record Bar (int x, int y) implements java.io.Serializable { }", - "--enable-preview", "-source", VERSION); + "public record Bar (int x, int y) implements java.io.Serializable { }"); byteCode = addWriteObject(byteCode); byteCode = addReadObject(byteCode); byteCode = addReadObjectNoData(byteCode); @@ -125,8 +122,7 @@ public void setup() { { byte[] byteCode = InMemoryJavaCompiler.compile("Baz", "import java.io.Serializable;" + - "public record Baz(U u, V v) implements Serializable { }", - "--enable-preview", "-source", VERSION); + "public record Baz(U u, V v) implements Serializable { }"); byteCode = addWriteObject(byteCode); byteCode = addReadObject(byteCode); byteCode = addReadObjectNoData(byteCode); diff --git a/test/jdk/java/io/Serializable/records/ReadResolveTest.java b/test/jdk/java/io/Serializable/records/ReadResolveTest.java index e5cc24c53c7..725f2cb49ea 100644 --- a/test/jdk/java/io/Serializable/records/ReadResolveTest.java +++ b/test/jdk/java/io/Serializable/records/ReadResolveTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2020, 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,10 +23,10 @@ /* * @test + * @bug 8246774 * @summary Basic tests for readResolve - * @compile --enable-preview -source ${jdk.version} ReadResolveTest.java - * @run testng/othervm --enable-preview ReadResolveTest - * @run testng/othervm/java.security.policy=empty_security.policy --enable-preview ReadResolveTest + * @run testng ReadResolveTest + * @run testng/othervm/java.security.policy=empty_security.policy ReadResolveTest */ import java.io.ByteArrayInputStream; diff --git a/test/jdk/java/io/Serializable/records/RecordClassTest.java b/test/jdk/java/io/Serializable/records/RecordClassTest.java index e101daccec1..6506f9f85e4 100644 --- a/test/jdk/java/io/Serializable/records/RecordClassTest.java +++ b/test/jdk/java/io/Serializable/records/RecordClassTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2020, 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,10 +23,10 @@ /* * @test + * @bug 8246774 * @summary Basic tests for serializing and deserializing record classes - * @compile --enable-preview -source ${jdk.version} RecordClassTest.java - * @run testng/othervm --enable-preview RecordClassTest - * @run testng/othervm/java.security.policy=empty_security.policy --enable-preview RecordClassTest + * @run testng RecordClassTest + * @run testng/othervm/java.security.policy=empty_security.policy RecordClassTest */ import java.io.ByteArrayInputStream; diff --git a/test/jdk/java/io/Serializable/records/SerialPersistentFieldsTest.java b/test/jdk/java/io/Serializable/records/SerialPersistentFieldsTest.java index 186275a201a..0d88074bdbc 100644 --- a/test/jdk/java/io/Serializable/records/SerialPersistentFieldsTest.java +++ b/test/jdk/java/io/Serializable/records/SerialPersistentFieldsTest.java @@ -23,11 +23,11 @@ /* * @test + * @bug 8246774 * @summary Basic tests for prohibited magic serialPersistentFields * @library /test/lib * @modules java.base/jdk.internal.org.objectweb.asm - * @compile --enable-preview -source ${jdk.version} SerialPersistentFieldsTest.java - * @run testng/othervm --enable-preview SerialPersistentFieldsTest + * @run testng SerialPersistentFieldsTest */ import java.io.ByteArrayInputStream; @@ -62,7 +62,6 @@ * Checks that the serialPersistentFields declaration is effectively ignored. */ public class SerialPersistentFieldsTest { - private static final String VERSION = Integer.toString(Runtime.version().feature()); ClassLoader serializableRecordLoader; @@ -83,8 +82,7 @@ public class SerialPersistentFieldsTest { public void setup() { { // R1 byte[] byteCode = InMemoryJavaCompiler.compile("R1", - "public record R1 () implements java.io.Serializable { }", - "--enable-preview", "-source", VERSION); + "public record R1 () implements java.io.Serializable { }"); ObjectStreamField[] serialPersistentFields = { new ObjectStreamField("s", String.class), new ObjectStreamField("i", int.class), @@ -96,8 +94,7 @@ public void setup() { } { // R2 byte[] byteCode = InMemoryJavaCompiler.compile("R2", - "public record R2 (int x) implements java.io.Serializable { }", - "--enable-preview", "-source", VERSION); + "public record R2 (int x) implements java.io.Serializable { }"); ObjectStreamField[] serialPersistentFields = { new ObjectStreamField("s", String.class) }; @@ -106,8 +103,7 @@ public void setup() { } { // R3 byte[] byteCode = InMemoryJavaCompiler.compile("R3", - "public record R3 (int x, int y) implements java.io.Serializable { }", - "--enable-preview", "-source", VERSION); + "public record R3 (int x, int y) implements java.io.Serializable { }"); ObjectStreamField[] serialPersistentFields = new ObjectStreamField[0]; byteCode = addSerialPersistentFields(byteCode, serialPersistentFields); serializableRecordLoader = new ByteCodeLoader("R3", byteCode, serializableRecordLoader); @@ -115,8 +111,7 @@ public void setup() { { // R4 byte[] byteCode = InMemoryJavaCompiler.compile("R4", "import java.io.Serializable;" + - "public record R4(U u, V v) implements Serializable { }", - "--enable-preview", "-source", VERSION); + "public record R4(U u, V v) implements Serializable { }"); ObjectStreamField[] serialPersistentFields = { new ObjectStreamField("v", String.class) }; @@ -132,8 +127,7 @@ public void setup() { " }\n" + " @Override public void readExternal(ObjectInput in) {\n" + " throw new AssertionError(\"should not reach here\");\n" + - " } }", - "--enable-preview", "-source", VERSION); + " } }"); ObjectStreamField[] serialPersistentFields = { new ObjectStreamField("v", String.class) }; diff --git a/test/jdk/java/io/Serializable/records/SerialVersionUIDTest.java b/test/jdk/java/io/Serializable/records/SerialVersionUIDTest.java index 4e76dabd334..d1018c12554 100644 --- a/test/jdk/java/io/Serializable/records/SerialVersionUIDTest.java +++ b/test/jdk/java/io/Serializable/records/SerialVersionUIDTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2020, 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,10 +23,10 @@ /* * @test + * @bug 8246774 * @summary Basic tests for SUID in the serial stream - * @compile --enable-preview -source ${jdk.version} SerialVersionUIDTest.java - * @run testng/othervm --enable-preview SerialVersionUIDTest - * @run testng/othervm/java.security.policy=empty_security.policy --enable-preview SerialVersionUIDTest + * @run testng SerialVersionUIDTest + * @run testng/othervm/java.security.policy=empty_security.policy SerialVersionUIDTest */ import java.io.ByteArrayInputStream; diff --git a/test/jdk/java/io/Serializable/records/StreamRefTest.java b/test/jdk/java/io/Serializable/records/StreamRefTest.java index cb5d5f31557..b0c72ec8a96 100644 --- a/test/jdk/java/io/Serializable/records/StreamRefTest.java +++ b/test/jdk/java/io/Serializable/records/StreamRefTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2020, 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,9 +23,9 @@ /* * @test + * @bug 8246774 * @summary Tests for stream references - * @compile --enable-preview -source ${jdk.version} StreamRefTest.java - * @run testng/othervm --enable-preview StreamRefTest + * @run testng StreamRefTest */ import java.io.ByteArrayInputStream; diff --git a/test/jdk/java/io/Serializable/records/ThrowingConstructorTest.java b/test/jdk/java/io/Serializable/records/ThrowingConstructorTest.java index 63f3436a10b..feb148f5d5c 100644 --- a/test/jdk/java/io/Serializable/records/ThrowingConstructorTest.java +++ b/test/jdk/java/io/Serializable/records/ThrowingConstructorTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2020, 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,10 +23,10 @@ /* * @test + * @bug 8246774 * @summary Tests constructor invocation exceptions are handled appropriately - * @compile --enable-preview -source ${jdk.version} ThrowingConstructorTest.java - * @run testng/othervm --enable-preview ThrowingConstructorTest - * @run testng/othervm/java.security.policy=empty_security.policy --enable-preview ThrowingConstructorTest + * @run testng ThrowingConstructorTest + * @run testng/othervm/java.security.policy=empty_security.policy ThrowingConstructorTest */ import java.io.ByteArrayInputStream; diff --git a/test/jdk/java/io/Serializable/records/UnsharedTest.java b/test/jdk/java/io/Serializable/records/UnsharedTest.java index aac81eef3c4..c96010c83ab 100644 --- a/test/jdk/java/io/Serializable/records/UnsharedTest.java +++ b/test/jdk/java/io/Serializable/records/UnsharedTest.java @@ -23,10 +23,9 @@ /* * @test - * @bug 8238763 + * @bug 8238763 8246774 * @summary ObjectInputStream readUnshared method handling of Records - * @compile --enable-preview -source ${jdk.version} UnsharedTest.java - * @run testng/othervm --enable-preview UnsharedTest + * @run testng UnsharedTest */ import java.io.ByteArrayInputStream; diff --git a/test/jdk/java/io/Serializable/records/WriteReplaceTest.java b/test/jdk/java/io/Serializable/records/WriteReplaceTest.java index 228157bf8a9..8dda381e671 100644 --- a/test/jdk/java/io/Serializable/records/WriteReplaceTest.java +++ b/test/jdk/java/io/Serializable/records/WriteReplaceTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2020, 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,10 +23,10 @@ /* * @test + * @bug 8246774 * @summary Basic tests for writeReplace - * @compile --enable-preview -source ${jdk.version} WriteReplaceTest.java - * @run testng/othervm --enable-preview WriteReplaceTest - * @run testng/othervm/java.security.policy=empty_security.policy --enable-preview WriteReplaceTest + * @run testng WriteReplaceTest + * @run testng/othervm/java.security.policy=empty_security.policy WriteReplaceTest */ import java.io.ByteArrayInputStream; diff --git a/test/jdk/java/io/Serializable/records/migration/AbstractTest.java b/test/jdk/java/io/Serializable/records/migration/AbstractTest.java index 4b0c4547cc8..e0bbc574500 100644 --- a/test/jdk/java/io/Serializable/records/migration/AbstractTest.java +++ b/test/jdk/java/io/Serializable/records/migration/AbstractTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2020, 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 @@ */ public class AbstractTest { - private static final String VERSION = Integer.toString(Runtime.version().feature()); - static final String TEST_SRC = System.getProperty("test.src", "."); static final String TEST_CLASSES = System.getProperty("test.classes", "."); static final Path TEST_CLASSES_DIR = Path.of(TEST_CLASSES); @@ -59,11 +57,9 @@ public class AbstractTest { @BeforeTest public void setup() throws IOException { assertTrue(CompilerUtils.compile(PLAIN_SRC_DIR, PLAIN_DEST_DIR, - "--enable-preview", "-source", VERSION, "--class-path", TEST_CLASSES_DIR.toString())); assertTrue(CompilerUtils.compile(RECORD_SRC_DIR, RECORD_DEST_DIR, - "--enable-preview", "-source", VERSION, "--class-path", TEST_CLASSES_DIR.toString())); } diff --git a/test/jdk/java/io/Serializable/records/migration/AssignableFromTest.java b/test/jdk/java/io/Serializable/records/migration/AssignableFromTest.java index 7c7d6b146a8..6097e2477df 100644 --- a/test/jdk/java/io/Serializable/records/migration/AssignableFromTest.java +++ b/test/jdk/java/io/Serializable/records/migration/AssignableFromTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2020, 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,12 +23,13 @@ /* * @test + * @bug 8246774 * @summary Test for subtype stream field value assign-ability * @library /test/lib * @modules jdk.compiler - * @compile --enable-preview -source ${jdk.version} AssignableFrom.java Point.java - * DefaultValues.java SuperStreamFields.java AssignableFromTest.java - * @run testng/othervm --enable-preview AssignableFromTest + * @compile AssignableFrom.java Point.java + * DefaultValues.java SuperStreamFields.java + * @run testng AssignableFromTest */ import java.math.BigDecimal; diff --git a/test/jdk/java/io/Serializable/records/migration/DefaultValuesTest.java b/test/jdk/java/io/Serializable/records/migration/DefaultValuesTest.java index e7bc63ef559..4af684156c6 100644 --- a/test/jdk/java/io/Serializable/records/migration/DefaultValuesTest.java +++ b/test/jdk/java/io/Serializable/records/migration/DefaultValuesTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2020, 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,12 +23,12 @@ /* * @test + * @bug 8246774 * @summary Checks that the appropriate default value is given to the canonical ctr * @library /test/lib * @modules jdk.compiler - * @compile --enable-preview -source ${jdk.version} AssignableFrom.java Point.java - * DefaultValues.java SuperStreamFields.java DefaultValuesTest.java - * @run testng/othervm --enable-preview DefaultValuesTest + * @compile AssignableFrom.java Point.java DefaultValues.java SuperStreamFields.java + * @run testng DefaultValuesTest */ import java.io.ByteArrayOutputStream; diff --git a/test/jdk/java/io/Serializable/records/migration/SuperStreamFieldsTest.java b/test/jdk/java/io/Serializable/records/migration/SuperStreamFieldsTest.java index 8788dcc939b..6090d71003e 100644 --- a/test/jdk/java/io/Serializable/records/migration/SuperStreamFieldsTest.java +++ b/test/jdk/java/io/Serializable/records/migration/SuperStreamFieldsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2020, 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,12 +23,12 @@ /* * @test + * @bug 8246774 * @summary superclass fields in the stream should be discarded * @library /test/lib * @modules jdk.compiler - * @compile --enable-preview -source ${jdk.version} AssignableFrom.java Point.java - * DefaultValues.java SuperStreamFields.java SuperStreamFieldsTest.java - * @run testng/othervm --enable-preview SuperStreamFieldsTest + * @compile AssignableFrom.java Point.java DefaultValues.java SuperStreamFields.java + * @run testng SuperStreamFieldsTest */ import org.testng.annotations.DataProvider; diff --git a/test/jdk/java/lang/instrument/RedefineRecordAttr/TestRecordAttr.java b/test/jdk/java/lang/instrument/RedefineRecordAttr/TestRecordAttr.java index 349cf1c7534..fddac8812d9 100644 --- a/test/jdk/java/lang/instrument/RedefineRecordAttr/TestRecordAttr.java +++ b/test/jdk/java/lang/instrument/RedefineRecordAttr/TestRecordAttr.java @@ -23,6 +23,7 @@ /* * @test + * @bug 8246774 * @summary Class redefinition must preclude changes to Record attributes * @comment This is a copy of test/jdk/java/lang/instrument/RedefineNestmateAttr/ * @comment modified for records and the Record attribute. @@ -33,15 +34,14 @@ * java.instrument * @compile ../NamedBuffer.java * @run main RedefineClassHelper - * @compile --enable-preview -source ${jdk.version} Host/Host.java - * @compile --enable-preview -source ${jdk.version} TestRecordAttr.java - * @run main/othervm -javaagent:redefineagent.jar --enable-preview -Xlog:redefine+class+record=trace TestRecordAttr Host - * @compile --enable-preview -source ${jdk.version} HostA/Host.java - * @run main/othervm -javaagent:redefineagent.jar --enable-preview -Xlog:redefine+class+record=trace TestRecordAttr HostA - * @compile --enable-preview -source ${jdk.version} HostAB/Host.java - * @run main/othervm -javaagent:redefineagent.jar --enable-preview -Xlog:redefine+class+record=trace TestRecordAttr HostAB - * @compile --enable-preview -source ${jdk.version} HostABC/Host.java - * @run main/othervm -javaagent:redefineagent.jar --enable-preview -Xlog:redefine+class+record=trace TestRecordAttr HostABC + * @compile Host/Host.java + * @run main/othervm -javaagent:redefineagent.jar -Xlog:redefine+class+record=trace TestRecordAttr Host + * @compile HostA/Host.java + * @run main/othervm -javaagent:redefineagent.jar -Xlog:redefine+class+record=trace TestRecordAttr HostA + * @compile HostAB/Host.java + * @run main/othervm -javaagent:redefineagent.jar -Xlog:redefine+class+record=trace TestRecordAttr HostAB + * @compile HostABC/Host.java + * @run main/othervm -javaagent:redefineagent.jar -Xlog:redefine+class+record=trace TestRecordAttr HostABC */ /* Test Description @@ -269,8 +269,6 @@ static void compile(String dir) throws Throwable { " to: " + dst); CompilerUtils.compile(src.toPath(), dst.toPath(), - false /* don't recurse */, - "--enable-preview", - "--source", VERSION); + false /* don't recurse */); } } diff --git a/test/jdk/java/lang/instrument/RedefineRecordAttrGenericSig/TestRecordAttrGenericSig.java b/test/jdk/java/lang/instrument/RedefineRecordAttrGenericSig/TestRecordAttrGenericSig.java index 05362176fdd..af5a6dc4bd2 100644 --- a/test/jdk/java/lang/instrument/RedefineRecordAttrGenericSig/TestRecordAttrGenericSig.java +++ b/test/jdk/java/lang/instrument/RedefineRecordAttrGenericSig/TestRecordAttrGenericSig.java @@ -23,6 +23,7 @@ /* * @test + * @bug 8246774 * @summary Class redefinition must preclude changes to Record attributes * @comment This is a copy of test/jdk/java/lang/instrument/RedefineNestmateAttr/ * @comment modified for records and the Record attribute. @@ -33,11 +34,10 @@ * java.instrument * @compile ../NamedBuffer.java * @run main RedefineClassHelper - * @compile --enable-preview --source ${jdk.version} Host/Host.java - * @compile --enable-preview --source ${jdk.version} TestRecordAttrGenericSig.java - * @run main/othervm -javaagent:redefineagent.jar -Xlog:redefine+class+record=trace --enable-preview TestRecordAttrGenericSig Host - * @compile --enable-preview --source ${jdk.version} HostA/Host.java - * @run main/othervm -javaagent:redefineagent.jar -Xlog:redefine+class+record=trace --enable-preview TestRecordAttrGenericSig HostA + * @compile Host/Host.java + * @run main/othervm -javaagent:redefineagent.jar -Xlog:redefine+class+record=trace TestRecordAttrGenericSig Host + * @compile HostA/Host.java + * @run main/othervm -javaagent:redefineagent.jar -Xlog:redefine+class+record=trace TestRecordAttrGenericSig HostA */ /* Test Description @@ -207,8 +207,6 @@ static void compile(String dir) throws Throwable { " to: " + dst); CompilerUtils.compile(src.toPath(), dst.toPath(), - false /* don't recurse */, - "--enable-preview", - "--source", VERSION); + false /* don't recurse */); } } diff --git a/test/jdk/java/lang/invoke/MethodHandlesPermuteArgumentsTest.java b/test/jdk/java/lang/invoke/MethodHandlesPermuteArgumentsTest.java index 085ff908f60..ff25a14c29a 100644 --- a/test/jdk/java/lang/invoke/MethodHandlesPermuteArgumentsTest.java +++ b/test/jdk/java/lang/invoke/MethodHandlesPermuteArgumentsTest.java @@ -44,7 +44,7 @@ import static org.junit.Assert.*; -public class MethodHandlesPermuteArgumentsTest extends MethodHandlesTest { +public class MethodHandlesPermuteArgumentsTest extends test.java.lang.invoke.MethodHandlesTest { @Test // SLOW public void testPermuteArguments() throws Throwable { @@ -58,6 +58,11 @@ public void testPermuteArguments0() throws Throwable { if (CAN_TEST_LIGHTLY) return; testPermuteArguments(4, Integer.class, 2, String.class, 0); testPermuteArguments(6, Integer.class, 0, null, 30); + + testBadReorderArrayLength(); + testBadReorderIndex(); + testReturnTypeMismatch(); + testReorderTypeMismatch(); } public void testPermuteArguments(int max, Class type1, int t2c, Class type2, int dilution) throws Throwable { @@ -191,4 +196,57 @@ void testPermuteArguments(Object[] args, Class[] types, int[] reorder) throws } assertEquals(expected, result); } + + public void testBadReorderArrayLength() throws Throwable { + MethodHandle mh = MethodHandles.empty(MethodType.methodType(void.class, int.class, int.class, String.class)); + MethodType newType = MethodType.methodType(void.class, int.class, String.class); + assertThrows(() -> MethodHandles.permuteArguments(mh, newType, 0, 1), + IllegalArgumentException.class, ".*old type parameter count and reorder array length do not match.*"); + } + + public void testBadReorderIndex() throws Throwable { + MethodHandle mh = MethodHandles.empty(MethodType.methodType(void.class, int.class, int.class, String.class)); + MethodType newType = MethodType.methodType(void.class, int.class, String.class); + assertThrows(() -> MethodHandles.permuteArguments(mh, newType, 0, 0, 2), + IllegalArgumentException.class, ".*index is out of bounds for new type.*"); + assertThrows(() -> MethodHandles.permuteArguments(mh, newType, 0, 0, -1), + IllegalArgumentException.class, ".*index is out of bounds for new type.*"); + } + + public void testReturnTypeMismatch() throws Throwable { + MethodHandle mh = MethodHandles.empty(MethodType.methodType(void.class, int.class, int.class, String.class)); + MethodType newType = MethodType.methodType(int.class, int.class, String.class); + assertThrows(() -> MethodHandles.permuteArguments(mh, newType, 0, 0, 1), + IllegalArgumentException.class, ".*return types do not match.*"); + } + + public void testReorderTypeMismatch() throws Throwable { + MethodHandle mh = MethodHandles.empty(MethodType.methodType(void.class, int.class, int.class, String.class)); + MethodType newType = MethodType.methodType(void.class, double.class, String.class); + assertThrows(() -> MethodHandles.permuteArguments(mh, newType, 0, 0, 1), + IllegalArgumentException.class, ".*parameter types do not match after reorder.*"); + } + + private interface RunnableX { + void run() throws Throwable; + } + + private static void assertThrows(RunnableX r, Class exceptionClass, String messagePattern) throws Throwable { + try { + r.run(); + fail("Exception expected"); + } catch (Throwable e) { + if (exceptionClass.isInstance(e)) { + assertMatches(e.getMessage(), messagePattern); + } else { + throw e; + } + } + } + + private static void assertMatches(String str, String pattern) { + if (!str.matches(pattern)) { + throw new AssertionError("'" + str + "' did not match the pattern '" + pattern + "'."); + } + } } diff --git a/test/jdk/java/lang/invoke/lambda/superProtectedMethod/SuperMethodTest.java b/test/jdk/java/lang/invoke/lambda/superProtectedMethod/SuperMethodTest.java index 333e87669db..624d2173a35 100644 --- a/test/jdk/java/lang/invoke/lambda/superProtectedMethod/SuperMethodTest.java +++ b/test/jdk/java/lang/invoke/lambda/superProtectedMethod/SuperMethodTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,11 +23,11 @@ /* * @test - * @bug 8227415 - * @run main p.SuperMethodTest + * @bug 8227415 8254975 + * @run testng/othervm p.SuperMethodTest * @summary method reference to a protected method inherited from its - * superclass in a different package must be accessed via - * a bridge method. Lambda proxy class has no access to it. + * superclass in a different runtime package where + * lambda proxy class has no access to it. */ package p; @@ -35,12 +35,24 @@ import q.I; import q.J; +import java.io.IOException; +import java.io.UncheckedIOException; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.net.URL; +import java.net.URLClassLoader; +import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.function.Function; +import org.testng.annotations.Test; +import static org.testng.Assert.*; + public class SuperMethodTest { - public static void main(String... args) { + @Test + public static void remotePackageSameLoader() { Sub_I sub = new Sub_I(); sub.test(Paths.get("test")); } @@ -62,4 +74,68 @@ public void test(Path path) { c.check(path); } } + + @Test + public static void splitPackage() throws Throwable { + ClassLoader parent = new Loader("loader-A", null, A.class); + ClassLoader loader = new Loader("loader-B", parent, B.class); + Class aClass = Class.forName(A.class.getName(), false, loader); + Class bClass = Class.forName(B.class.getName(), false, loader); + assertTrue(aClass.getClassLoader() == parent); + assertTrue(bClass.getClassLoader() == loader); + assertEquals(aClass.getPackageName(), bClass.getPackageName()); + + Object b = bClass.getDeclaredConstructor().newInstance(); + + // verify subclass can access a protected member inherited from + // its superclass in a split package + MethodHandle test = MethodHandles.lookup() + .findVirtual(bClass, "test", MethodType.methodType(void.class)); + test.invoke(b); + + // verify lambda can access a protected member inherited from + // a superclass of the host class where the superclass is in + // a split package (not the same runtime package as the host class) + MethodHandle get = MethodHandles.lookup() + .findVirtual(bClass, "get", MethodType.methodType(Runnable.class)); + ((Runnable) get.invoke(b)).run(); + } + + static class Loader extends URLClassLoader { + static final Path CLASSES_DIR = Paths.get(System.getProperty("test.class.path")); + private final Class c; + Loader(String name, ClassLoader parent, Class c) { + super(name, new URL[]{}, parent); + this.c = c; + } + + @Override + protected Class findClass(String name) throws ClassNotFoundException { + if (name.equals(c.getName())) { + try { + String path = name.replace('.', '/') + ".class"; + byte[] bytes = Files.readAllBytes(CLASSES_DIR.resolve(path)); + return defineClass(name, bytes, 0, bytes.length); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + return super.findClass(name); + } + + } + + public static class A { + protected void func() { } + } + + public static class B extends A { + public Runnable get() { + return this::func; + } + public void test() { + func(); + } + } } diff --git a/test/jdk/java/lang/runtime/ObjectMethodsTest.java b/test/jdk/java/lang/runtime/ObjectMethodsTest.java index f7b008b2400..373e718b45c 100644 --- a/test/jdk/java/lang/runtime/ObjectMethodsTest.java +++ b/test/jdk/java/lang/runtime/ObjectMethodsTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2020, 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,10 +23,10 @@ /* * @test + * @bug 8246774 * @summary Basic tests for ObjectMethods - * @compile --enable-preview -source ${jdk.version} ObjectMethodsTest.java - * @run testng/othervm --enable-preview ObjectMethodsTest - * @run testng/othervm/java.security.policy=empty.policy --enable-preview ObjectMethodsTest + * @run testng ObjectMethodsTest + * @run testng/othervm/java.security.policy=empty.policy ObjectMethodsTest */ import java.lang.invoke.CallSite; diff --git a/test/jdk/java/net/UnixDomainSocketAddress/AddressTest.java b/test/jdk/java/net/UnixDomainSocketAddress/AddressTest.java new file mode 100644 index 00000000000..80bc3ae1033 --- /dev/null +++ b/test/jdk/java/net/UnixDomainSocketAddress/AddressTest.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8231358 + * @compile ../../nio/file/spi/TestProvider.java AddressTest.java + * @run testng/othervm AddressTest + */ + +import java.net.UnixDomainSocketAddress; +import java.net.URI; +import java.nio.file.FileSystems; +import java.nio.file.spi.FileSystemProvider; +import java.nio.file.Path; + +import org.testng.annotations.Test; + +import static org.testng.Assert.assertThrows; + +/** + * Verify that UnixDomainSocketAddress.of(path) throws IAE + * if given a Path that does not originate from system default + * file system. + */ +public class AddressTest { + + // Expected exception + private static final Class IAE = + IllegalArgumentException.class; + + @Test + public static void runTest() throws Exception { + TestProvider prov = new TestProvider(FileSystems.getDefault().provider()); + Path path = prov.getPath(URI.create("file:/")); + assertThrows(IAE, () -> UnixDomainSocketAddress.of(path)); + } +} diff --git a/test/jdk/java/net/UnixDomainSocketAddress/LengthTest.java b/test/jdk/java/net/UnixDomainSocketAddress/LengthTest.java new file mode 100644 index 00000000000..c34c8e001b7 --- /dev/null +++ b/test/jdk/java/net/UnixDomainSocketAddress/LengthTest.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @summary Test UnixDomainSocketAddress constructor + * @library /test/lib + * @run testng/othervm LengthTest + */ + +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +import static java.lang.System.out; +import static java.net.StandardProtocolFamily.UNIX; +import static jdk.test.lib.Asserts.assertTrue; + +import java.net.UnixDomainSocketAddress; +import java.io.IOException; +import java.nio.channels.SocketChannel; +import java.nio.file.Path; + +public class LengthTest { + final int namelen = 100; // length close to max + + @DataProvider(name = "strings") + public Object[][] strings() { + if (namelen == -1) + return new Object[][] {new String[]{""}}; + + return new Object[][]{ + {""}, + {new String(new char[100]).replaceAll("\0", "x")}, + {new String(new char[namelen]).replaceAll("\0", "x")}, + {new String(new char[namelen-1]).replaceAll("\0", "x")}, + }; + } + + @Test(dataProvider = "strings") + public void expectPass(String s) { + var addr = UnixDomainSocketAddress.of(s); + assertTrue(addr.getPath().toString().equals(s), "getPathName.equals(s)"); + var p = Path.of(s); + addr = UnixDomainSocketAddress.of(p); + assertTrue(addr.getPath().equals(p), "getPath.equals(p)"); + } + + @Test + public void expectNPE() { + try { + String s = null; + UnixDomainSocketAddress.of(s); + throw new RuntimeException("Expected NPE"); + } catch (NullPointerException npe) { + out.println("\tCaught expected exception: " + npe); + } + try { + Path p = null; + UnixDomainSocketAddress.of(p); + throw new RuntimeException("Expected NPE"); + } catch (NullPointerException npe) { + out.println("\tCaught expected exception: " + npe); + } + } +} diff --git a/test/jdk/java/net/UnixDomainSocketAddress/UnixDomainSocketAddressSerializationTest.java b/test/jdk/java/net/UnixDomainSocketAddress/UnixDomainSocketAddressSerializationTest.java new file mode 100644 index 00000000000..305b4bee95e --- /dev/null +++ b/test/jdk/java/net/UnixDomainSocketAddress/UnixDomainSocketAddressSerializationTest.java @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import org.testng.annotations.Test; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.InvalidObjectException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.ObjectStreamClass; +import java.io.Serializable; +import java.net.UnixDomainSocketAddress; +import java.nio.file.Path; +import static java.io.ObjectStreamConstants.*; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; +import static org.testng.Assert.expectThrows; + +/* + * @test + * @summary UnixDomainSocketAddress serialization test + * @run testng/othervm UnixDomainSocketAddressSerializationTest + */ + +@Test +public class UnixDomainSocketAddressSerializationTest { + private static final UnixDomainSocketAddress addr = + UnixDomainSocketAddress.of(Path.of("test.sock")); + + public static void test() throws Exception { + assertTrue(addr instanceof Serializable); + + byte[] serialized = serialize(addr); + assertTrue(serialized.length > 0); + + UnixDomainSocketAddress deserialized = + deserialize(serialized, UnixDomainSocketAddress.class); + assertEquals(deserialized.getPath(), addr.getPath()); + assertEquals(deserialized.toString(), addr.toString()); + assertEquals(deserialized.hashCode(), addr.hashCode()); + assertEquals(deserialized, addr); + } + + static final Class IOE = InvalidObjectException.class; + static final Class NPE = NullPointerException.class; + + /** Tests that UnixDomainSocketAddress in the byte-stream is disallowed. */ + public static void testUnixDomainSocketAddressInStream() throws Exception { + long suid = ObjectStreamClass.lookup(UnixDomainSocketAddress.class).getSerialVersionUID(); + byte[] bytes = byteStreamFor(UnixDomainSocketAddress.class.getName(), suid); + expectThrows(IOE, () -> deserialize(bytes, UnixDomainSocketAddress.class)); + } + + /** Tests that SerialProxy with a null/absent path value in the byte-stream is disallowed. */ + public static void testSerialProxyNoStreamValues() throws Exception { + Class c = Class.forName("java.net.UnixDomainSocketAddress$Ser"); + long suid = ObjectStreamClass.lookup(c).getSerialVersionUID(); + byte[] bytes = byteStreamFor(c.getName(), suid); + expectThrows(NPE, () -> deserialize(bytes, UnixDomainSocketAddress.class)); + } + + private static byte[] serialize(T t) + throws IOException { + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(bos); + oos.writeObject(t); + oos.flush(); + oos.close(); + return bos.toByteArray(); + } + + private static T deserialize(byte[] b, Class cl) + throws IOException, ClassNotFoundException { + try (ObjectInputStream ois = + new ObjectInputStream(new ByteArrayInputStream(b))) { + Object o = ois.readObject(); + return cl.cast(o); + } + } + + /** + * Returns a stream with the given classname and suid. The stream will have + * no stream field values. + */ + static byte[] byteStreamFor(String classname, long suid) throws Exception { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + DataOutputStream dos = new DataOutputStream(baos); + dos.writeShort(STREAM_MAGIC); + dos.writeShort(STREAM_VERSION); + dos.writeByte(TC_OBJECT); + dos.writeByte(TC_CLASSDESC); + dos.writeUTF(classname); + dos.writeLong(suid); + dos.writeByte(SC_SERIALIZABLE); + dos.writeShort(0); // number of stream fields + dos.writeByte(TC_ENDBLOCKDATA); // no annotations + dos.writeByte(TC_NULL); // no superclasses + dos.write(TC_ENDBLOCKDATA); // end block - for SC_WRITE_METHOD + dos.close(); + return baos.toByteArray(); + } +} diff --git a/test/jdk/java/nio/channels/DatagramChannel/Connect.java b/test/jdk/java/nio/channels/DatagramChannel/Connect.java index c2d837289b4..a02b5fcf105 100644 --- a/test/jdk/java/nio/channels/DatagramChannel/Connect.java +++ b/test/jdk/java/nio/channels/DatagramChannel/Connect.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2020, 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,7 +24,6 @@ /* @test * @bug 4313882 7183800 * @summary Test DatagramChannel's send and receive methods - * @author Mike McCloskey */ import java.io.*; @@ -32,7 +31,11 @@ import java.nio.*; import java.nio.channels.*; import java.nio.charset.*; - +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionException; +import java.util.stream.Stream; public class Connect { @@ -43,124 +46,127 @@ public static void main(String[] args) throws Exception { } static void test() throws Exception { - Reactor r = new Reactor(); - Actor a = new Actor(r.port()); - invoke(a, r); + ExecutorService threadPool = Executors.newCachedThreadPool(); + try (Reactor r = new Reactor(); + Actor a = new Actor(r.getSocketAddress()) + ) { + invoke(threadPool, a, r); + } finally { + threadPool.shutdown(); + } } - static void invoke(Sprintable reader, Sprintable writer) throws Exception { - - Thread writerThread = new Thread(writer); - writerThread.start(); - - Thread readerThread = new Thread(reader); - readerThread.start(); - - writerThread.join(); - readerThread.join(); - - reader.throwException(); - writer.throwException(); + static void invoke(ExecutorService e, Runnable reader, Runnable writer) throws CompletionException { + CompletableFuture f1 = CompletableFuture.runAsync(writer, e); + CompletableFuture f2 = CompletableFuture.runAsync(reader, e); + wait(f1, f2); } - public interface Sprintable extends Runnable { - public void throwException() throws Exception; - } - public static class Actor implements Sprintable { - final int port; - Exception e = null; + // This method waits for either one of the given futures to complete exceptionally + // or for all of the given futures to complete successfully. + private static void wait(CompletableFuture... futures) throws CompletionException { + CompletableFuture future = CompletableFuture.allOf(futures); + Stream.of(futures) + .forEach(f -> f.exceptionally(ex -> { + future.completeExceptionally(ex); + return null; + })); + future.join(); + } - Actor(int port) { - this.port = port; - } + public static class Actor implements AutoCloseable, Runnable { + final SocketAddress socketAddress; + final DatagramChannel dc; - public void throwException() throws Exception { - if (e != null) - throw e; + Actor(SocketAddress socketAddress) throws IOException { + this.socketAddress = socketAddress; + dc = DatagramChannel.open(); } public void run() { try { - DatagramChannel dc = DatagramChannel.open(); - - // Send a message ByteBuffer bb = ByteBuffer.allocateDirect(256); bb.put("hello".getBytes()); bb.flip(); - InetAddress address = InetAddress.getLocalHost(); - if (address.isLoopbackAddress()) { - address = InetAddress.getLoopbackAddress(); - } - InetSocketAddress isa = new InetSocketAddress(address, port); - dc.connect(isa); + dc.connect(socketAddress); + + // Send a message + log.println("Actor attempting to write to Reactor at " + socketAddress.toString()); dc.write(bb); // Try to send to some other address - address = InetAddress.getLocalHost(); - InetSocketAddress bogus = new InetSocketAddress(address, 3333); try { - dc.send(bb, bogus); - throw new RuntimeException("Allowed bogus send while connected"); + int port = dc.socket().getLocalPort(); + InetAddress loopback = InetAddress.getLoopbackAddress(); + InetSocketAddress otherAddress = new InetSocketAddress(loopback, (port == 3333 ? 3332 : 3333)); + log.println("Testing if Actor throws AlreadyConnectedException" + otherAddress.toString()); + dc.send(bb, otherAddress); + throw new RuntimeException("Actor allowed send to other address while already connected"); } catch (AlreadyConnectedException ace) { // Correct behavior } // Read a reply bb.flip(); + log.println("Actor waiting to read"); dc.read(bb); bb.flip(); - CharBuffer cb = Charset.forName("US-ASCII"). - newDecoder().decode(bb); - log.println("From Reactor: "+isa+ " said " +cb); - - // Clean up - dc.disconnect(); - dc.close(); + CharBuffer cb = StandardCharsets.US_ASCII. + newDecoder().decode(bb); + log.println("Actor received from Reactor at " + socketAddress + ": " + cb); } catch (Exception ex) { - e = ex; + log.println("Actor threw exception: " + ex); + throw new RuntimeException(ex); + } finally { + log.println("Actor finished"); } } + + @Override + public void close() throws IOException { + dc.close(); + } } - public static class Reactor implements Sprintable { + public static class Reactor implements AutoCloseable, Runnable { final DatagramChannel dc; - Exception e = null; Reactor() throws IOException { - dc = DatagramChannel.open().bind(new InetSocketAddress(0)); + dc = DatagramChannel.open().bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0)); } - int port() { - return dc.socket().getLocalPort(); - } - - public void throwException() throws Exception { - if (e != null) - throw e; + SocketAddress getSocketAddress() throws IOException { + return dc.getLocalAddress(); } public void run() { try { // Listen for a message ByteBuffer bb = ByteBuffer.allocateDirect(100); + log.println("Reactor waiting to receive"); SocketAddress sa = dc.receive(bb); bb.flip(); - CharBuffer cb = Charset.forName("US-ASCII"). - newDecoder().decode(bb); - log.println("From Actor: "+sa+ " said " +cb); + CharBuffer cb = StandardCharsets.US_ASCII. + newDecoder().decode(bb); + log.println("Reactor received from Actor at" + sa + ": " + cb); // Reply to sender dc.connect(sa); bb.flip(); + log.println("Reactor attempting to write: " + dc.getRemoteAddress().toString()); dc.write(bb); - - // Clean up - dc.disconnect(); - dc.close(); } catch (Exception ex) { - e = ex; + log.println("Reactor threw exception: " + ex); + throw new RuntimeException(ex); + } finally { + log.println("Reactor finished"); } } + + @Override + public void close() throws IOException { + dc.close(); + } } } diff --git a/test/jdk/java/nio/channels/etc/ProtocolFamilies.java b/test/jdk/java/nio/channels/etc/ProtocolFamilies.java index 0df09571a5d..45226e9a97e 100644 --- a/test/jdk/java/nio/channels/etc/ProtocolFamilies.java +++ b/test/jdk/java/nio/channels/etc/ProtocolFamilies.java @@ -35,6 +35,7 @@ import static java.net.StandardProtocolFamily.INET; import static java.net.StandardProtocolFamily.INET6; import static jdk.test.lib.net.IPSupport.*; +import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertThrows; /* @@ -305,26 +306,30 @@ public void testUoe() { private static SocketChannel openSC(StandardProtocolFamily family) throws IOException { - return family == null ? SocketChannel.open() + SocketChannel sc = family == null ? SocketChannel.open() : SocketChannel.open(family); + return sc; } private static ServerSocketChannel openSSC(StandardProtocolFamily family) throws IOException { - return family == null ? ServerSocketChannel.open() + ServerSocketChannel ssc = family == null ? ServerSocketChannel.open() : ServerSocketChannel.open(family); + return ssc; } private static DatagramChannel openDC(StandardProtocolFamily family) throws IOException { - return family == null ? DatagramChannel.open() + DatagramChannel dc = family == null ? DatagramChannel.open() : DatagramChannel.open(family); + return dc; } private static SocketAddress getSocketAddress(StandardProtocolFamily family) { return family == null ? null : switch (family) { case INET -> new InetSocketAddress(ia4, 0); case INET6 -> new InetSocketAddress(ia6, 0); + default -> throw new RuntimeException("Unexpected protocol family"); }; } diff --git a/test/jdk/java/nio/channels/spi/SelectorProvider/inheritedChannel/CloseTest.java b/test/jdk/java/nio/channels/spi/SelectorProvider/inheritedChannel/CloseTest.java index e42c8ba7ad2..6ea1f34e831 100644 --- a/test/jdk/java/nio/channels/spi/SelectorProvider/inheritedChannel/CloseTest.java +++ b/test/jdk/java/nio/channels/spi/SelectorProvider/inheritedChannel/CloseTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2020, 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,7 @@ * * The test launches the "echo service" with arguments to instruct the * service to close the channel after it receives a small message. The - * service then delays/lingers for 15 seconds before shuting down. To + * service then delays/lingers for 15 seconds before shutting down. To * prove that the close works we check that we see EOF (meaning the * peer has closed the connection) in less than 15 seconds. */ @@ -54,8 +54,7 @@ public static void main(String args[]) throws Exception { service_args[0] = String.valueOf(msg.length()); service_args[1] = String.valueOf( Utils.adjustTimeout(15*1000) ); - - SocketChannel sc = Launcher.launchWithSocketChannel("EchoService", service_args); + SocketChannel sc = Launcher.launchWithInetSocketChannel("EchoService", null, service_args); // send message - service will echo the message and close the connection. diff --git a/test/jdk/java/nio/channels/spi/SelectorProvider/inheritedChannel/EchoTest.java b/test/jdk/java/nio/channels/spi/SelectorProvider/inheritedChannel/EchoTest.java index 6ec6cb730c1..9931f42c458 100644 --- a/test/jdk/java/nio/channels/spi/SelectorProvider/inheritedChannel/EchoTest.java +++ b/test/jdk/java/nio/channels/spi/SelectorProvider/inheritedChannel/EchoTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2020, 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 @@ public class EchoTest { * that it matches the original message. */ private static void TCPEchoTest() throws IOException { - SocketChannel sc = Launcher.launchWithSocketChannel(ECHO_SERVICE, null); + SocketChannel sc = Launcher.launchWithInetSocketChannel(ECHO_SERVICE, null); String msg = "Where's that damn torpedo?"; int repeat = 100; diff --git a/test/jdk/java/nio/channels/spi/SelectorProvider/inheritedChannel/InheritedChannelTest.java b/test/jdk/java/nio/channels/spi/SelectorProvider/inheritedChannel/InheritedChannelTest.java index 389c41c842c..2db3480d4d6 100644 --- a/test/jdk/java/nio/channels/spi/SelectorProvider/inheritedChannel/InheritedChannelTest.java +++ b/test/jdk/java/nio/channels/spi/SelectorProvider/inheritedChannel/InheritedChannelTest.java @@ -85,6 +85,7 @@ public Object[][] testCases() { // These system properties are passed to the launched service as options: // java [-options] class [args...] + { "StateTest run with " + POLICY_PASS, List.of(StateTest.class.getName(), "-Djava.security.manager", "-Djava.security.policy=" diff --git a/test/jdk/java/nio/channels/spi/SelectorProvider/inheritedChannel/Launcher.java b/test/jdk/java/nio/channels/spi/SelectorProvider/inheritedChannel/Launcher.java index fea44e1f685..8e166582819 100644 --- a/test/jdk/java/nio/channels/spi/SelectorProvider/inheritedChannel/Launcher.java +++ b/test/jdk/java/nio/channels/spi/SelectorProvider/inheritedChannel/Launcher.java @@ -1,6 +1,5 @@ - /* - * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2020, 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,9 +28,15 @@ import java.io.IOException; import java.net.InetAddress; import java.net.InetSocketAddress; +import java.net.SocketAddress; +import java.net.StandardProtocolFamily; +import java.net.UnixDomainSocketAddress; import java.nio.channels.DatagramChannel; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; +import java.nio.file.Files; + +import static java.net.StandardProtocolFamily.UNIX; public class Launcher { @@ -63,81 +68,101 @@ private static void launch(String className, String options[], String args[], in launch0(cmdarray, fd); } - /** - * Launch 'java' with specified class using a UnixDomainSocket pair linking calling - * process to the child VM. UnixDomainSocket is a simplified interface to PF_UNIX sockets - * which supports byte a time reads and writes. + * Launch 'java' with specified class. The launched process will inherit + * a connected Unix Domain socket. The remote endpoint will be the + * SocketChannel returned by this method. */ - public static UnixDomainSocket launchWithUnixDomainSocket(String className) throws IOException { - UnixDomainSocket[] socks = UnixDomainSocket.socketpair(); - launch(className, null, null, socks[0].fd()); - socks[0].close(); - return socks[1]; + public static SocketChannel launchWithUnixSocketChannel(String className) + throws IOException + { + UnixDomainSocketAddress addr = null; + try (ServerSocketChannel ssc = ServerSocketChannel.open(UNIX)) { + addr = (UnixDomainSocketAddress)ssc.bind(null).getLocalAddress(); + SocketChannel sc1 = SocketChannel.open(addr); + try (SocketChannel sc2 = ssc.accept()) { + launch(className, null, null, Util.getFD(sc2)); + } + return sc1; + } finally { + if (addr != null) + Files.delete(addr.getPath()); + } } /** - * Launch specified class with an AF_UNIX socket created externally, and one String arg to child VM - */ - public static void launchWithUnixDomainSocket(String className, UnixDomainSocket socket, String arg) throws IOException { - String[] args = new String[1]; - args[0] = arg; - launch(className, null, args, socket.fd()); - } - - /* * Launch 'java' with specified class with the specified arguments (may be null). * The launched process will inherit a connected TCP socket. The remote endpoint * will be the SocketChannel returned by this method. */ - public static SocketChannel launchWithSocketChannel(String className, String options[], String args[]) throws IOException { - ServerSocketChannel ssc = ServerSocketChannel.open(); - ssc.socket().bind(new InetSocketAddress(InetAddress.getLocalHost(), 0)); - InetSocketAddress isa = new InetSocketAddress(InetAddress.getLocalHost(), + public static SocketChannel launchWithInetSocketChannel(String className, + String options[], + String... args) + throws IOException + { + try (ServerSocketChannel ssc = ServerSocketChannel.open()) { + ssc.socket().bind(new InetSocketAddress(InetAddress.getLocalHost(), 0)); + InetSocketAddress isa = new InetSocketAddress(InetAddress.getLocalHost(), ssc.socket().getLocalPort()); - SocketChannel sc1 = SocketChannel.open(isa); - SocketChannel sc2 = ssc.accept(); - launch(className, options, args, Util.getFD(sc2)); - sc2.close(); - ssc.close(); - return sc1; - } - - public static SocketChannel launchWithSocketChannel(String className, String args[]) throws IOException { - return launchWithSocketChannel(className, null, args); + SocketChannel sc1 = SocketChannel.open(isa); + try (SocketChannel sc2 = ssc.accept()) { + launch(className, options, args, Util.getFD(sc2)); + } + return sc1; + } } - public static SocketChannel launchWithSocketChannel(String className) throws IOException { - return launchWithSocketChannel(className, null); + /** + * Launch specified class with a SocketChannel created externally. + */ + public static void launchWithSocketChannel(String className, + SocketChannel sc, + String[] options, + String... args) throws Exception { + launch(className, options, args, Util.getFD(sc)); } - /* + /** * Launch 'java' with specified class with the specified arguments (may be null). * The launched process will inherited a TCP listener socket. * Once launched this method tries to connect to service. If a connection * can be established a SocketChannel, connected to the service, is returned. */ - public static SocketChannel launchWithServerSocketChannel(String className, String options[], String args[]) - throws IOException + public static SocketChannel launchWithInetServerSocketChannel(String className, + String[] options, + String... args) + throws IOException { - ServerSocketChannel ssc = ServerSocketChannel.open(); - ssc.socket().bind(new InetSocketAddress(InetAddress.getLocalHost(), 0)); - int port = ssc.socket().getLocalPort(); - launch(className, options, args, Util.getFD(ssc)); - ssc.close(); - InetSocketAddress isa = new InetSocketAddress(InetAddress.getLocalHost(), port); - return SocketChannel.open(isa); + try (ServerSocketChannel ssc = ServerSocketChannel.open()) { + ssc.socket().bind(new InetSocketAddress(InetAddress.getLocalHost(), 0)); + int port = ssc.socket().getLocalPort(); + launch(className, options, args, Util.getFD(ssc)); + InetSocketAddress isa = new InetSocketAddress(InetAddress.getLocalHost(), port); + return SocketChannel.open(isa); + } } - public static SocketChannel launchWithServerSocketChannel(String className, String args[]) throws IOException { - return launchWithServerSocketChannel(className, null, args); + public static SocketChannel launchWithUnixServerSocketChannel(String className) throws IOException { + ServerSocketChannel ssc = ServerSocketChannel.open(StandardProtocolFamily.UNIX); + ssc.bind(null); + var addr = ssc.getLocalAddress(); + launch(className, null, null, Util.getFD(ssc)); + ssc.close(); + return SocketChannel.open(addr); } - public static SocketChannel launchWithServerSocketChannel(String className) throws IOException { - return launchWithServerSocketChannel(className, null); + /** + * Launch specified class with a ServerSocketChannel created externally. + */ + public static void launchWithServerSocketChannel(String className, + ServerSocketChannel ssc, + String[] options, + String... args) + throws Exception { + launch(className, options, args, Util.getFD(ssc)); } - /* + /** * Launch 'java' with specified class with the specified arguments (may be null). * The launch process will inherited a bound UDP socket. * Once launched this method creates a DatagramChannel and "connects @@ -145,9 +170,10 @@ public static SocketChannel launchWithServerSocketChannel(String className) thro * As it is connected any packets sent from the socket will be * sent to the service. */ - public static DatagramChannel launchWithDatagramChannel(String className, String options[], String args[]) - throws IOException - { + public static DatagramChannel launchWithDatagramChannel(String className, + String[] options, + String... args) + throws IOException { InetAddress address = InetAddress.getLocalHost(); if (address.isLoopbackAddress()) { address = InetAddress.getLoopbackAddress(); @@ -165,12 +191,4 @@ public static DatagramChannel launchWithDatagramChannel(String className, String dc.connect(isa); return dc; } - - public static DatagramChannel launchWithDatagramChannel(String className, String args[]) throws IOException { - return launchWithDatagramChannel(className, null, args); - } - - public static DatagramChannel launchWithDatagramChannel(String className) throws IOException { - return launchWithDatagramChannel(className, null); - } } diff --git a/test/jdk/java/nio/channels/spi/SelectorProvider/inheritedChannel/StateTest.java b/test/jdk/java/nio/channels/spi/SelectorProvider/inheritedChannel/StateTest.java index c8d048eb4e4..8b70defc021 100644 --- a/test/jdk/java/nio/channels/spi/SelectorProvider/inheritedChannel/StateTest.java +++ b/test/jdk/java/nio/channels/spi/SelectorProvider/inheritedChannel/StateTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -170,8 +170,8 @@ public static void main(String args[]) throws IOException { /* * Launch service with a SocketChannel (tcp nowait) */ - System.err.println("launchWithSocketChannel"); - SocketChannel sc = Launcher.launchWithSocketChannel(TEST_SERVICE, options, arg); + System.err.println("launchWithInetSocketChannel"); + SocketChannel sc = Launcher.launchWithInetSocketChannel(TEST_SERVICE, options, arg); System.err.println("Waiting for test results"); waitForTestResult(ssc, expectFail); sc.close(); @@ -181,8 +181,8 @@ public static void main(String args[]) throws IOException { * launchWithServerSocketChannel establishes a connection to the service * and the returned SocketChannel is connected to the service. */ - System.err.println("launchWithServerSocketChannel"); - sc = Launcher.launchWithServerSocketChannel(TEST_SERVICE, options, arg); + System.err.println("launchWithInetServerSocketChannel"); + sc = Launcher.launchWithInetServerSocketChannel(TEST_SERVICE, options, arg); waitForTestResult(ssc, expectFail); sc.close(); diff --git a/test/jdk/java/nio/channels/spi/SelectorProvider/inheritedChannel/StateTestService.java b/test/jdk/java/nio/channels/spi/SelectorProvider/inheritedChannel/StateTestService.java index cfc481b46a2..eac73528709 100644 --- a/test/jdk/java/nio/channels/spi/SelectorProvider/inheritedChannel/StateTestService.java +++ b/test/jdk/java/nio/channels/spi/SelectorProvider/inheritedChannel/StateTestService.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2020, 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,7 @@ * A test service for use in the inetd/System.inheritedChannel unit * tests. * - * The test checks that the channel returned by System.inheritiedChannel + * The test checks that the channel returned by System.inheritedChannel * is in blocking mode and is bound. In addition, in the case of a * SocketChannel checks that the socket is connected. * diff --git a/test/jdk/java/nio/channels/spi/SelectorProvider/inheritedChannel/UnixDomainChannelTest.java b/test/jdk/java/nio/channels/spi/SelectorProvider/inheritedChannel/UnixDomainChannelTest.java index 698d6c5f3d5..fbe5b0ef142 100644 --- a/test/jdk/java/nio/channels/spi/SelectorProvider/inheritedChannel/UnixDomainChannelTest.java +++ b/test/jdk/java/nio/channels/spi/SelectorProvider/inheritedChannel/UnixDomainChannelTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2020, 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 @@ -21,41 +21,50 @@ * questions. */ +import java.io.IOException; +import java.net.SocketAddress; +import java.net.UnixDomainSocketAddress; import java.nio.channels.*; import java.nio.ByteBuffer; -import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; + +import static java.net.StandardProtocolFamily.UNIX; import static java.nio.charset.StandardCharsets.ISO_8859_1; /* - * Make sure that System.inheritedChannel returns null when given a UNIX domain socket + * Make sure that System.inheritedChannel returns the correct type */ public class UnixDomainChannelTest { + private static final UnixDomainSocketAddress SOCK_ADDR = + UnixDomainSocketAddress.of(Path.of("foo.socket")); + + private static boolean passed = true; public static class Child { public static void main(String[] args) throws Exception { - // we just want to make sure that System.inheritedChannel either - // returns a connected channel, or null if it is given a listener + // we want to make sure that System.inheritedChannel either + // returns a ServerSocketChannel or a SocketChannel Channel channel = System.inheritedChannel(); String result = channel == null ? "N" : "Y"; if (args[0].equals("test1") || args[0].equals("test2")) { - // socket is writeable - ByteChannel bc = (ByteChannel)channel; - ByteBuffer buf = ByteBuffer.wrap(result.getBytes(ISO_8859_1)); - bc.write(buf); + if (channel instanceof SocketChannel) { + SocketChannel sc = (SocketChannel) channel; + ByteBuffer buf = ByteBuffer.wrap(result.getBytes(ISO_8859_1)); + sc.write(buf); + } } else { // test3 - // in this case the socket is a listener - // we can't write to it. So, use UnixDatagramSocket - // to accept a writeable socket - UnixDomainSocket listener = new UnixDomainSocket(0); // fd 0 - UnixDomainSocket sock = listener.accept(); - sock.write((int)result.charAt(0)); + if (channel instanceof ServerSocketChannel) { + ServerSocketChannel server = (ServerSocketChannel) channel; + SocketChannel sc = server.accept(); + ByteBuffer buf = ByteBuffer.wrap(result.getBytes(ISO_8859_1)); + sc.write(buf); + } } } } - static boolean passed = true; - public static void main(String args[]) throws Exception { test1(); test2(); @@ -64,54 +73,92 @@ public static void main(String args[]) throws Exception { throw new RuntimeException(); } - private static void closeAll(UnixDomainSocket... sockets) { - for (UnixDomainSocket sock : sockets) { - sock.close(); - } - } - // Test with a named connected socket private static void test1() throws Exception { - UnixDomainSocket listener = new UnixDomainSocket(); - listener.bind("foo.socket"); - UnixDomainSocket sock1 = new UnixDomainSocket(); - sock1.connect("foo.socket"); - UnixDomainSocket sock2 = listener.accept(); - - Launcher.launchWithUnixDomainSocket("UnixDomainChannelTest$Child", sock2, "test1"); - int c = sock1.read(); - if (c != 'Y') { - System.err.printf("test1: failed %d d\n", c ); + ServerSocketChannel listener = ServerSocketChannel.open(UNIX); + listener.bind(SOCK_ADDR); + SocketChannel sock1 = SocketChannel.open(SOCK_ADDR); + SocketChannel sock2 = listener.accept(); + System.out.println("test1: launching child"); + Launcher.launchWithSocketChannel( + "UnixDomainChannelTest$Child", sock2, null, "test1"); + ByteBuffer bb = ByteBuffer.allocate(10); + int c = sock1.read(bb); + if (c != 1) { + System.err.printf("test1: failed " + + "- unexpected number of bytes read %d d\n", c); + passed = false; + } + byte b = bb.get(0); + if (b != 'Y') { + System.err.printf("test1: failed " + + "- unexpected byte read %d d\n", b); passed = false; } closeAll(listener, sock1, sock2); + Files.deleteIfExists(SOCK_ADDR.getPath()); } // Test with unnamed socketpair private static void test2() throws Exception { - UnixDomainSocket[] pair = UnixDomainSocket.socketpair(); + ServerSocketChannel listener = ServerSocketChannel.open(UNIX); + SocketAddress addr = listener.bind(null).getLocalAddress(); + SocketChannel sock1 = SocketChannel.open(addr); + SocketChannel sock2 = listener.accept(); System.out.println("test2: launching child"); - Launcher.launchWithUnixDomainSocket("UnixDomainChannelTest$Child", pair[0], "test2"); - if (pair[1].read() != 'Y') { - System.err.println("test2: failed"); + Launcher.launchWithSocketChannel( + "UnixDomainChannelTest$Child", sock2, null, "test2"); + ByteBuffer bb = ByteBuffer.allocate(10); + int c = sock1.read(bb); + if (c != 1) { + System.err.printf("test3: failed " + + "- unexpected number of bytes read %d d\n", c); + passed = false; + } + byte b = bb.get(0); + if (b != 'Y') { + System.err.printf("test3: failed " + + "- unexpected byte read %d d\n", b); passed = false; } - closeAll(pair[0], pair[1]); + closeAll(listener, sock1, sock2); + Files.deleteIfExists(((UnixDomainSocketAddress)addr).getPath()); } // Test with a named listener private static void test3() throws Exception { - UnixDomainSocket listener = new UnixDomainSocket(); - listener.bind("foo.socket"); - UnixDomainSocket sock1 = new UnixDomainSocket(); + ServerSocketChannel listener = ServerSocketChannel.open(UNIX); + listener.bind(SOCK_ADDR); + SocketChannel sock1 = SocketChannel.open(UNIX); System.out.println("test3: launching child"); - Launcher.launchWithUnixDomainSocket("UnixDomainChannelTest$Child", listener, "test3"); - sock1.connect("foo.socket"); - if (sock1.read() != 'N') { - System.err.println("test3: failed"); + Launcher.launchWithServerSocketChannel( + "UnixDomainChannelTest$Child", listener, null, "test3"); + sock1.connect(SOCK_ADDR); + ByteBuffer bb = ByteBuffer.allocate(10); + int c = sock1.read(bb); + if (c != 1) { + System.err.printf("test3: failed " + + "- unexpected number of bytes read %d d\n", c); + passed = false; + } + byte b = bb.get(0); + if (b != 'Y') { + System.err.printf("test3: failed " + + "- unexpected byte read %d d\n", b); passed = false; } closeAll(listener, sock1); + Files.deleteIfExists(SOCK_ADDR.getPath()); } + private static void closeAll(Channel... channels) { + for (Channel c : channels) { + try { + if (c != null) + c.close(); + } catch (IOException e) { + throw new RuntimeException("Could not close channel " + c); + } + } + } } diff --git a/test/jdk/java/nio/channels/spi/SelectorProvider/inheritedChannel/UnixDomainSocket.java b/test/jdk/java/nio/channels/spi/SelectorProvider/inheritedChannel/UnixDomainSocket.java deleted file mode 100644 index 5ef18fd050c..00000000000 --- a/test/jdk/java/nio/channels/spi/SelectorProvider/inheritedChannel/UnixDomainSocket.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright (c) 2018, 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. - * - * 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. - */ - -/** - * A simplified Unix domain socket which can read and write bytes at a time - * used for simulating external launchers which use UNIX sockets to talk - * the VM. - */ - -import java.io.IOException; - -public class UnixDomainSocket { - - static { - System.loadLibrary("InheritedChannel"); - init(); - } - - private final int fd; - private volatile String name; - - public UnixDomainSocket() throws IOException { - this.fd = create(); - } - - public void bind(String name) throws IOException { - bind0(fd, name); - this.name = name; - } - - public UnixDomainSocket accept() throws IOException { - int newsock = accept0(fd); - return new UnixDomainSocket(newsock); - } - - public UnixDomainSocket(int fd) { - this.fd = fd; - } - - public void connect(String dest) throws IOException { - connect0(fd, dest); - } - - public int read() throws IOException { - return read0(fd); - } - - public String name() { - return name; - } - - public void write(int w) throws IOException { - write0(fd, w); - } - - public void close() { - close0(fd, name); // close0 will unlink name if non-null - } - - public int fd() { - return fd; - } - - public String toString() { - return "UnixDomainSocket: fd=" + Integer.toString(fd); - } - - private static native int create() throws IOException; - private static native void bind0(int fd, String name) throws IOException; - private static native int accept0(int fd) throws IOException; - private static native int connect0(int fd, String name) throws IOException; - - /* read and write bytes with UNIX domain sockets */ - - private static native int read0(int fd) throws IOException; - private static native void write0(int fd, int w) throws IOException; - private static native void close0(int fd, String name); - private static native void init(); - public static native UnixDomainSocket[] socketpair(); -} - diff --git a/test/jdk/java/nio/channels/spi/SelectorProvider/inheritedChannel/UnixSocketTest.java b/test/jdk/java/nio/channels/spi/SelectorProvider/inheritedChannel/UnixSocketTest.java index 7995b5bac79..6f16d8a1dc3 100644 --- a/test/jdk/java/nio/channels/spi/SelectorProvider/inheritedChannel/UnixSocketTest.java +++ b/test/jdk/java/nio/channels/spi/SelectorProvider/inheritedChannel/UnixSocketTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2020, 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 @@ -21,56 +21,68 @@ * questions. */ -/* - * If the platform has IPv6 we spawn a child process simulating the - * effect of being launched from node.js. We check that IPv6 is available in the child - * and report back as appropriate. - */ - -import jdk.test.lib.Utils; -import java.io.*; import java.net.InetAddress; import java.net.Inet6Address; import java.net.NetworkInterface; +import java.net.UnixDomainSocketAddress; +import java.nio.ByteBuffer; +import java.nio.channels.SocketChannel; +import java.nio.channels.ServerSocketChannel; +import java.nio.file.Files; import java.util.Collections; import java.util.Enumeration; +import static java.net.StandardProtocolFamily.UNIX; + public class UnixSocketTest { - static boolean hasIPv6() throws Exception { - Enumeration nets = NetworkInterface.getNetworkInterfaces(); - for (NetworkInterface netint : Collections.list(nets)) { - Enumeration inetAddresses = netint.getInetAddresses(); - for (InetAddress inetAddress : Collections.list(inetAddresses)) { - if (inetAddress instanceof Inet6Address) { - return true; - } - } + public static class Child1 { + public static void main(String[] args) throws Exception { + SocketChannel chan = (SocketChannel)System.inheritedChannel(); + ByteBuffer bb = ByteBuffer.allocate(2); + bb.put((byte)'X'); + bb.put((byte)'Y'); + bb.flip(); + chan.write(bb); + chan.close(); } - return false; } - public static class Child { + public static class Child2 { public static void main(String[] args) throws Exception { - System.out.write('X'); - System.out.flush(); - if (hasIPv6()) { - System.out.println("Y"); // GOOD - } else - System.out.println("N"); // BAD + ServerSocketChannel server = (ServerSocketChannel)System.inheritedChannel(); + SocketChannel chan = server.accept(); + UnixDomainSocketAddress sa = (UnixDomainSocketAddress)server.getLocalAddress(); + Files.delete(sa.getPath()); + server.close(); + ByteBuffer bb = ByteBuffer.allocate(2); + bb.put((byte)'X'); + bb.put((byte)'Y'); + bb.flip(); + chan.write(bb); + chan.close(); } } public static void main(String args[]) throws Exception { - - if (!hasIPv6()) { - return; // can only test if IPv6 is present + SocketChannel sc = Launcher.launchWithUnixSocketChannel("UnixSocketTest$Child1"); + ByteBuffer bb = ByteBuffer.allocate(10); + sc.read(bb); + if (bb.get(0) != 'X') { + System.exit(-2); } - UnixDomainSocket sock = Launcher.launchWithUnixDomainSocket("UnixSocketTest$Child"); - if (sock.read() != 'X') { + if (bb.get(1) != 'Y') { + System.exit(-2); + } + sc.close(); + + sc = Launcher.launchWithUnixServerSocketChannel("UnixSocketTest$Child2"); + bb.clear(); + sc.read(bb); + if (bb.get(0) != 'X') { System.exit(-2); } - if (sock.read() != 'Y') { + if (bb.get(1) != 'Y') { System.exit(-2); } } diff --git a/test/jdk/java/nio/channels/spi/SelectorProvider/inheritedChannel/libInheritedChannel.c b/test/jdk/java/nio/channels/spi/SelectorProvider/inheritedChannel/libInheritedChannel.c index 0ba0986b3a3..c6d493a3e92 100644 --- a/test/jdk/java/nio/channels/spi/SelectorProvider/inheritedChannel/libInheritedChannel.c +++ b/test/jdk/java/nio/channels/spi/SelectorProvider/inheritedChannel/libInheritedChannel.c @@ -29,7 +29,6 @@ #include #include #include -#include #include #include #include @@ -40,9 +39,6 @@ #define CHECK(X) if ((X) == 0) {printf("JNI init error line %d\n", __LINE__); _exit(1);} -static jclass unixSocketClass; -static jmethodID unixSocketCtor; - /* * Throws the exception of the given class name and detail message */ @@ -85,7 +81,6 @@ static char* getString8859_1Chars(JNIEnv *env, jstring jstr) { return result; } - /* * Class: Launcher * Method: launch0 @@ -145,7 +140,7 @@ JNIEXPORT void JNICALL Java_Launcher_launch0 /* * We need to close all file descriptors except for serviceFd. To - * get the list of open file descriptos we read through /proc/self/fd (/dev/fd) + * get the list of open file descriptors we read through /proc/self/fd (/dev/fd) * but to open this requires a file descriptor. We could use a specific * file descriptor and fdopendir but Linux doesn't seem to support * fdopendir. Instead we use opendir and make an assumption on the @@ -184,131 +179,3 @@ JNIEXPORT void JNICALL Java_Launcher_launch0 execvp(cmdv[0], cmdv); _exit(-1); } - -JNIEXPORT void JNICALL Java_UnixDomainSocket_init(JNIEnv *env, jclass cls) { - CHECK(unixSocketClass = (*env)->FindClass(env, "UnixDomainSocket")); - CHECK(unixSocketClass = (*env)->NewGlobalRef(env, unixSocketClass)); - CHECK(unixSocketCtor = (*env)->GetMethodID(env, unixSocketClass, "", "(I)V")); -} - -/* - * Class: UnixDomainSocket - * Method: socketpair - * Signature: ()[LUnixDomainSocket - */ -JNIEXPORT jobjectArray JNICALL Java_UnixDomainSocket_socketpair - (JNIEnv *env, jclass cls) -{ - int fds[2]; - jobject socket; - jobjectArray result = (*env)->NewObjectArray(env, 2, unixSocketClass, 0); - if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) < 0) { - perror("socketpair"); - return result; - } - socket = (*env)->NewObject(env, unixSocketClass, unixSocketCtor, fds[0]); - (*env)->SetObjectArrayElement(env, result, 0, socket); - socket = (*env)->NewObject(env, unixSocketClass, unixSocketCtor, fds[1]); - (*env)->SetObjectArrayElement(env, result, 1, socket); - return result; -} - -JNIEXPORT jint JNICALL Java_UnixDomainSocket_create - (JNIEnv *env, jclass cls) -{ - int sock = socket(AF_UNIX, SOCK_STREAM, 0); - if (sock == -1) { - ThrowException(env, "java/io/IOException", "socket create error"); - } - return sock; -} - -JNIEXPORT void JNICALL Java_UnixDomainSocket_bind0 - (JNIEnv *env, jclass cls, jint sock, jstring name) -{ - struct sockaddr_un addr; - const char *nameUtf = (*env)->GetStringUTFChars(env, name, NULL); - int ret = -1; - int length = sizeof(addr.sun_path); - unlink(nameUtf); - memset(&addr, 0, sizeof(addr)); - addr.sun_family = AF_UNIX; - strncpy(addr.sun_path, nameUtf, length); - addr.sun_path[length - 1] = '\0'; - ret = bind(sock, (const struct sockaddr*)&addr, sizeof(addr)); - if (ret == -1) { - ThrowException(env, "java/io/IOException", "socket bind error"); - } - ret = listen(sock, 5); - if (ret == -1) { - ThrowException(env, "java/io/IOException", "socket bind error"); - } - (*env)->ReleaseStringUTFChars(env, name, nameUtf); -} - -JNIEXPORT jint JNICALL Java_UnixDomainSocket_accept0 - (JNIEnv *env, jclass cls, jint sock) -{ - struct sockaddr_storage addr; - socklen_t len = sizeof(addr); - int ret = accept(sock, (struct sockaddr *)&addr, &len); - if (ret == -1) - ThrowException(env, "java/io/IOException", "socket accept error"); - return ret; -} - -JNIEXPORT void JNICALL Java_UnixDomainSocket_connect0 - (JNIEnv *env, jclass cls, jint fd, jstring name) -{ - struct sockaddr_un addr; - const char *nameUtf = (*env)->GetStringUTFChars(env, name, NULL); - int ret = -1; - int length = sizeof(addr.sun_path); - memset(&addr, 0, sizeof(addr)); - addr.sun_family = AF_UNIX; - strncpy(addr.sun_path, nameUtf, length); - addr.sun_path[length - 1] = '\0'; - ret = connect(fd, (const struct sockaddr*)&addr, sizeof(addr)); - if (ret == -1) { - ThrowException(env, "java/io/IOException", "socket connect error"); - } - (*env)->ReleaseStringUTFChars(env, name, nameUtf); -} - - -JNIEXPORT jint JNICALL Java_UnixDomainSocket_read0 - (JNIEnv *env, jclass cls, jint fd) -{ - int ret; - unsigned char res; - ret = read(fd, &res, 1); - if (ret == 0) - return -1; /* EOF */ - else if (ret < 0) { - ThrowException(env, "java/io/IOException", "read error"); - return -1; - } - return res; -} - -JNIEXPORT void JNICALL Java_UnixDomainSocket_write0 - (JNIEnv *env, jclass cls, jint fd, jint byte) -{ - int ret; - unsigned char w = (unsigned char)byte; - ret = write(fd, &w, 1); - if (ret < 0) { - ThrowException(env, "java/io/IOException", "write error"); - } -} - -JNIEXPORT void JNICALL Java_UnixDomainSocket_close0 - (JNIEnv *env, jclass cls, jint fd, jstring name) -{ - close(fd); - if (name != NULL) { - const char *nameUtf = (*env)->GetStringUTFChars(env, name, NULL); - unlink(nameUtf); - (*env)->ReleaseStringUTFChars(env, name, nameUtf); - } -} diff --git a/test/jdk/java/nio/channels/unixdomain/Bind.java b/test/jdk/java/nio/channels/unixdomain/Bind.java new file mode 100644 index 00000000000..47fc24ae1af --- /dev/null +++ b/test/jdk/java/nio/channels/unixdomain/Bind.java @@ -0,0 +1,329 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8245194 + * @library /test/lib + * @run main/othervm Bind + */ + +import java.io.IOException; +import java.net.*; +import java.nio.channels.*; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Arrays; +import jtreg.SkippedException; + +/** + * Check that all bind variations work + */ +public class Bind { + + static Path spath, cpath; + + static UnixDomainSocketAddress sAddr, cAddr, UNNAMED, nullAddr; + static ServerSocketChannel server; + static SocketChannel client, accept1; + + public static void main(String args[]) throws Exception { + checkSupported(); + spath = Path.of("server.sock"); + cpath = Path.of("client.sock"); + sAddr = UnixDomainSocketAddress.of(spath); + cAddr = UnixDomainSocketAddress.of(cpath); + nullAddr = UnixDomainSocketAddress.of(""); + UNNAMED = nullAddr; + runTests(); + } + + static void checkSupported() { + try { + SocketChannel.open(StandardProtocolFamily.UNIX).close(); + } catch (UnsupportedOperationException e) { + throw new SkippedException("Unix domain channels not supported"); + } catch (Exception e) { + // continue test to see what problem is + } + } + + static interface ThrowingRunnable { + public void run() throws Exception; + } + + static void init() throws IOException { + Files.deleteIfExists(cpath); + Files.deleteIfExists(spath); + client = null; server = null; accept1 = null; + } + + static void checkNormal(ThrowingRunnable r) { + try { + init(); + r.run(); + System.out.println("PASS:"); + } catch (Exception e) { + throw new RuntimeException(e); + } finally { + cleanup(); + } + } + + static void checkException(Class expected, ThrowingRunnable r) { + try { + init(); + r.run(); + throw new RuntimeException("Exception expected"); + } catch (Exception e) { + if (!expected.isAssignableFrom(e.getClass())) { + String msg = "Expected: " + expected + " Got: " + e.getClass(); + throw new RuntimeException(msg); + } + System.out.println("PASS: Got " + e); + } finally { + cleanup(); + } + } + + static void cleanup() { + try { + if (server != null) + server.close(); + if (client != null) + client.close(); + if (accept1 != null) + accept1.close(); + } catch (IOException e) {} + } + + static void assertClientAddress(SocketAddress a) { + assertAddress(a, cAddr, "client"); + } + + static void assertServerAddress(SocketAddress a) { + assertAddress(a, sAddr, "server"); + } + + static void assertAddress(SocketAddress a, UnixDomainSocketAddress a1, String s) { + if (!(a instanceof UnixDomainSocketAddress)) { + throw new RuntimeException("wrong address type"); + } + UnixDomainSocketAddress ua = (UnixDomainSocketAddress)a; + if (!a.equals(a1)) + throw new RuntimeException("this is not the " + s + " address"); + } + + static void assertEquals(Object a, Object b) { + if (!a.equals(b)) + throw new RuntimeException("identity check failed"); + } + + public static void runTests() throws IOException { + checkNormal(() -> { + client = SocketChannel.open(StandardProtocolFamily.UNIX); + client.bind(cAddr); + }); + checkNormal(() -> { + server = ServerSocketChannel.open(StandardProtocolFamily.UNIX); + server.bind(sAddr); + }); + // Repeat first two to make sure they are repeatable + checkNormal(() -> { + client = SocketChannel.open(StandardProtocolFamily.UNIX); + client.bind(cAddr); + }); + checkNormal(() -> { + server = ServerSocketChannel.open(StandardProtocolFamily.UNIX); + server.bind(sAddr); + }); + // address with space should work + checkNormal(() -> { + server = ServerSocketChannel.open(StandardProtocolFamily.UNIX); + UnixDomainSocketAddress usa = UnixDomainSocketAddress.of("with space"); // relative to CWD + Files.deleteIfExists(usa.getPath()); + server.bind(usa); + client = SocketChannel.open(usa); + Files.delete(usa.getPath()); + assertAddress(client.getRemoteAddress(), usa, "address"); + }); + // client bind to null: allowed + checkNormal(() -> { + client = SocketChannel.open(StandardProtocolFamily.UNIX); + client.bind(null); + SocketAddress a = client.getLocalAddress(); + assertAddress(a, nullAddr, "null address"); + assertEquals(a, UNNAMED); + }); + // client bind to UNNAMED: allowed + checkNormal(() -> { + client = SocketChannel.open(StandardProtocolFamily.UNIX); + client.bind(UNNAMED); + SocketAddress a = client.getLocalAddress(); + assertAddress(a, nullAddr, "null address"); + assertEquals(a, UNNAMED); + }); + // server bind to null: should bind to a local address + checkNormal(() -> { + server = ServerSocketChannel.open(StandardProtocolFamily.UNIX); + server.bind(null); + UnixDomainSocketAddress usa = (UnixDomainSocketAddress)server.getLocalAddress(); + if (usa.getPath().toString().isEmpty()) + throw new RuntimeException("expected non zero address length"); + System.out.println("Null server address: " + server.getLocalAddress()); + }); + // server no bind : not allowed + checkException( + NotYetBoundException.class, () -> { + server = ServerSocketChannel.open(StandardProtocolFamily.UNIX); + server.accept(); + } + ); + + // client implicit bind and connect + checkNormal(() -> { + server = ServerSocketChannel.open(StandardProtocolFamily.UNIX); + client = SocketChannel.open(StandardProtocolFamily.UNIX); + server.bind(sAddr); + client.connect(sAddr); + SocketAddress cAddr = client.getLocalAddress(); + assertAddress(cAddr, nullAddr, "null address"); + assertEquals(cAddr, UNNAMED); + assertServerAddress(server.getLocalAddress()); + }); + // client null bind and connect (check all addresses) + checkNormal(() -> { + server = ServerSocketChannel.open(StandardProtocolFamily.UNIX); + client = SocketChannel.open(StandardProtocolFamily.UNIX); + server.bind(sAddr); + client.bind(null); + client.connect(sAddr); + assertAddress(client.getLocalAddress(), UNNAMED, "unnamed address"); + assertServerAddress(server.getLocalAddress()); + }); + // client explicit bind and connect (check all addresses) + checkNormal(() -> { + server = ServerSocketChannel.open(StandardProtocolFamily.UNIX); + client = SocketChannel.open(StandardProtocolFamily.UNIX); + server.bind(sAddr); + client.bind(cAddr); + client.connect(sAddr); + accept1 = server.accept(); + assertClientAddress(client.getLocalAddress()); + assertServerAddress(server.getLocalAddress()); + assertAddress(client.getRemoteAddress(), sAddr, "client's remote server address"); + assertAddress(accept1.getLocalAddress(), sAddr, "accepted local address (server)"); + assertAddress(accept1.getRemoteAddress(), cAddr, "accepted remote address (client)"); + }); + // server multiple bind : not allowed + checkException( + AlreadyBoundException.class, () -> { + server = ServerSocketChannel.open(StandardProtocolFamily.UNIX); + server.bind(sAddr); + server.bind(sAddr); + } + ); + // client multiple bind : not allowed + checkException( + AlreadyBoundException.class, () -> { + client = SocketChannel.open(StandardProtocolFamily.UNIX); + client.bind(cAddr); + client.bind(cAddr); + } + ); + // client multiple bind to different addresses: not allowed + checkException( + AlreadyBoundException.class, () -> { + client = SocketChannel.open(StandardProtocolFamily.UNIX); + client.bind(cAddr); + client.bind(sAddr); + } + ); + // client multiple bind to differnt addresses, incl null: not allowed + checkException( + AlreadyBoundException.class, () -> { + client = SocketChannel.open(StandardProtocolFamily.UNIX); + client.bind(null); + client.bind(cAddr); + } + ); + + // server bind to existing name: not allowed + + checkException( + BindException.class, () -> { + var path = Files.createFile(Path.of("moo.sock")); + var addr = UnixDomainSocketAddress.of(path); + server = ServerSocketChannel.open(StandardProtocolFamily.UNIX); + try { + server.bind(addr); + } finally { + Files.deleteIfExists(path); + } + } + ); + + + // client bind to existing name: not allowed + checkException( + BindException.class, () -> { + var path = Path.of("temp.sock"); + Files.deleteIfExists(path); + Files.createFile(path); + var addr = UnixDomainSocketAddress.of(path); + client = SocketChannel.open(StandardProtocolFamily.UNIX); + try { + client.bind(addr); + } finally { + Files.deleteIfExists(path); + } + } + ); + + // bind and connect to name of close to max size + checkNormal(() -> { + int len = 100; + char[] chars = new char[len]; + Arrays.fill(chars, 'x'); + String name = new String(chars); + UnixDomainSocketAddress address = UnixDomainSocketAddress.of(name); + ServerSocketChannel server = ServerSocketChannel.open(StandardProtocolFamily.UNIX); + server.bind(address); + SocketChannel client = SocketChannel.open(address); + assertAddress(server.getLocalAddress(), address, "server"); + assertAddress(client.getRemoteAddress(), address, "client"); + Files.delete(address.getPath()); + }); + + // implicit server bind + checkNormal(() -> { + server = ServerSocketChannel.open(StandardProtocolFamily.UNIX); + server.bind(null); + UnixDomainSocketAddress usa = (UnixDomainSocketAddress)server.getLocalAddress(); + client = SocketChannel.open(usa); + accept1 = server.accept(); + assertAddress(client.getRemoteAddress(), usa, "server"); + Files.delete(usa.getPath()); + }); + } +} diff --git a/test/jdk/java/nio/channels/unixdomain/IOExchanges.java b/test/jdk/java/nio/channels/unixdomain/IOExchanges.java new file mode 100644 index 00000000000..96478b2b20f --- /dev/null +++ b/test/jdk/java/nio/channels/unixdomain/IOExchanges.java @@ -0,0 +1,1243 @@ +/* + * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8245194 + * @run testng/othervm IOExchanges + */ + +import java.io.IOException; +import java.net.*; +import java.nio.channels.*; +import java.nio.ByteBuffer; +import java.nio.file.Files; + +import org.testng.annotations.BeforeTest; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +import static java.lang.System.out; +import static java.net.StandardProtocolFamily.*; +import static java.nio.channels.SelectionKey.OP_ACCEPT; +import static java.nio.channels.SelectionKey.OP_READ; +import static java.nio.channels.SelectionKey.OP_WRITE; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; + +public class IOExchanges { + static boolean unixDomainSupported = true; + + + @BeforeTest() + public void setup() { + try { + SocketChannel.open(UNIX); + } catch (IOException | UnsupportedOperationException e) { + unixDomainSupported = false; + out.println("Unix domain channels not supported"); + } + } + + static SocketChannel openSocketChannel(ProtocolFamily family) + throws IOException { + return family == UNIX ? SocketChannel.open(family) + : SocketChannel.open(); + } + + static ServerSocketChannel openServerSocketChannel(ProtocolFamily family) + throws IOException { + return family == UNIX ? ServerSocketChannel.open(family) + : ServerSocketChannel.open(); + } + + public static void deleteFile(SocketAddress addr) throws Exception { + if (addr instanceof UnixDomainSocketAddress) { + Files.deleteIfExists(((UnixDomainSocketAddress) addr).getPath()); + } + } + + /* + The following, non-exhaustive set, of tests exercise different combinations + of blocking and non-blocking accept/connect calls along with I/O + operations, that exchange a single byte. The intent it to test a reasonable + set of blocking and non-blocking scenarios. + + The individual test method names follow their test scenario. + [BAccep|SELNBAccep|SPINNBAccep] - Accept either: + blocking, select-non-blocking, spinning-non-blocking + [BConn|NBConn] - blocking connect / non-blocking connect + [BIO|NBIO] - blocking / non-blocking I/O operations (read/write) + [WR|RW] - connecting thread write/accepting thread reads first, and vice-versa + [Id] - unique test Id + + BAccep_BConn_BIO_WR_1 + BAccep_BConn_BIO_RW_2 + SELNBAccep_BConn_BIO_WR_3 + SELNBAccep_BConn_BIO_RW_4 + SPINNBAccep_BConn_BIO_WR_5 + SPINNBAccep_BConn_BIO_RW_6 + BAccep_NBConn_BIO_WR_7 + BAccep_NBConn_BIO_RW_8 + SELNBAccep_NBConn_BIO_WR_9 + SELNBAccep_NBConn_BIO_RW_10 + SPINNBAccep_NBConn_BIO_WR_11 + SPINNBAccep_NBConn_BIO_RW_12 + + BAccep_BConn_NBIO_WR_1a // Non-Blocking I/O + BAccep_BConn_NBIO_RW_2a + SELNBAccep_BConn_NBIO_WR_3a + SELNBAccep_BConn_NBIO_RW_4a + SPINNBAccep_BConn_NBIO_WR_5a + SPINNBAccep_BConn_NBIO_RW_6a + BAccep_NBConn_NBIO_WR_7a + BAccep_NBConn_NBIO_RW_8a + SELNBAccep_NBConn_NBIO_WR_9a + SELNBAccep_NBConn_NBIO_RW_10a + SPINBAccep_NBConn_NBIO_WR_11a + SPINBAccep_NBConn_NBIO_RW_12a + */ + + @DataProvider(name = "family") + public Object[][] family() { + return unixDomainSupported ? + new Object[][] { + { UNIX }, + { INET }} + : new Object[][] { + { INET } + }; + } + + @Test(dataProvider = "family") + public void BAccep_BConn_BIO_WR_1(ProtocolFamily family) + throws Throwable { + try (ServerSocketChannel ssc = openServerSocketChannel(family)) { + ssc.bind(null); + SocketAddress addr = ssc.getLocalAddress(); + + TestThread t = TestThread.of("t1", () -> { + try (SocketChannel sc = openSocketChannel(family)) { + assertTrue(sc.connect(addr)); + ByteBuffer bb = ByteBuffer.allocate(10).put((byte) 0x01).flip(); + assertEquals(sc.write(bb), 1); + out.printf("wrote: 0x%x%n", bb.get(0)); + assertEquals(sc.read(bb.clear()), -1); + } + }); + t.start(); + + try (SocketChannel sc = ssc.accept()) { + ByteBuffer bb = ByteBuffer.allocate(10); + assertEquals(sc.read(bb), 1); + out.printf("read: 0x%x%n", bb.get(0)); + assertEquals(bb.get(0), 0x01); + } + t.awaitCompletion(); + deleteFile(addr); + } + } + + @Test(dataProvider = "family") + public void BAccep_BConn_BIO_RW_2(ProtocolFamily family) + throws Throwable { + try (ServerSocketChannel ssc = openServerSocketChannel(family)) { + ssc.bind(null); + SocketAddress addr = ssc.getLocalAddress(); + + TestThread t = TestThread.of("t2", () -> { + try (SocketChannel sc = openSocketChannel(family)) { + assertTrue(sc.connect(addr)); + ByteBuffer bb = ByteBuffer.allocate(10); + assertEquals(sc.read(bb), 1); + out.printf("read: 0x%x%n", bb.get(0)); + assertEquals(bb.get(0), 0x02); + } + }); + t.start(); + + try (SocketChannel sc = ssc.accept()) { + ByteBuffer bb = ByteBuffer.allocate(10).put((byte) 0x02).flip(); + assertEquals(sc.write(bb), 1); + out.printf("wrote: 0x%x%n", bb.get(0)); + assertEquals(sc.read(bb.clear()), -1); + } + t.awaitCompletion(); + deleteFile(addr); + } + } + + @Test(dataProvider = "family") + public void SELNBAccep_BConn_BIO_WR_3(ProtocolFamily family) + throws Throwable { + try (ServerSocketChannel ssc = openServerSocketChannel(family); + Selector selector = Selector.open()) { + ssc.bind(null); + SocketAddress addr = ssc.getLocalAddress(); + + TestThread t = TestThread.of("t3", () -> { + try (SocketChannel sc = openSocketChannel(family)) { + assertTrue(sc.connect(addr)); + ByteBuffer bb = ByteBuffer.allocate(10).put((byte) 0x03).flip(); + assertEquals(sc.write(bb), 1); + out.printf("wrote: 0x%x%n", bb.get(0)); + assertEquals(sc.read(bb.clear()), -1); + } + }); + t.start(); + + ssc.configureBlocking(false).register(selector, OP_ACCEPT); + assertEquals(selector.select(), 1); + + try (SocketChannel sc = ssc.accept()) { + ByteBuffer bb = ByteBuffer.allocate(10); + assertEquals(sc.read(bb), 1); + out.printf("read: 0x%x%n", bb.get(0)); + assertEquals(bb.get(0), 0x03); + } + t.awaitCompletion(); + deleteFile(addr); + } + } + + @Test(dataProvider = "family") + public void SELNBAccep_BConn_BIO_RW_4(ProtocolFamily family) + throws Throwable { + try (ServerSocketChannel ssc = openServerSocketChannel(family); + Selector selector = Selector.open()) { + ssc.bind(null); + SocketAddress addr = ssc.getLocalAddress(); + + TestThread t = TestThread.of("t4", () -> { + try (SocketChannel sc = openSocketChannel(family)) { + assertTrue(sc.connect(addr)); + ByteBuffer bb = ByteBuffer.allocate(10); + assertEquals(sc.read(bb), 1); + out.printf("read: 0x%x%n", bb.get(0)); + assertEquals(bb.get(0), 0x04); + } + }); + t.start(); + + ssc.configureBlocking(false).register(selector, OP_ACCEPT); + assertEquals(selector.select(), 1); + + try (SocketChannel sc = ssc.accept()) { + ByteBuffer bb = ByteBuffer.allocate(10).put((byte) 0x04).flip(); + assertEquals(sc.write(bb), 1); + out.printf("wrote: 0x%x%n", bb.get(0)); + assertEquals(sc.read(bb.clear()), -1); + + } + t.awaitCompletion(); + deleteFile(addr); + } + } + + @Test(dataProvider = "family") + public void SPINNBAccep_BConn_BIO_WR_5(ProtocolFamily family) + throws Throwable { + try (ServerSocketChannel ssc = openServerSocketChannel(family)) { + ssc.bind(null); + SocketAddress addr = ssc.getLocalAddress(); + + TestThread t = TestThread.of("t5", () -> { + try (SocketChannel sc = openSocketChannel(family)) { + assertTrue(sc.connect(addr)); + ByteBuffer bb = ByteBuffer.allocate(10).put((byte) 0x05).flip(); + assertEquals(sc.write(bb), 1); + out.printf("wrote: 0x%x%n", bb.get(0)); + assertEquals(sc.read(bb.clear()), -1); + } + }); + t.start(); + + SocketChannel accepted; + for (; ; ) { + accepted = ssc.accept(); + if (accepted != null) { + out.println("accepted new connection"); + break; + } + Thread.onSpinWait(); + } + + try (SocketChannel sc = accepted) { + ByteBuffer bb = ByteBuffer.allocate(10); + assertEquals(sc.read(bb), 1); + out.printf("read: 0x%x%n", bb.get(0)); + assertEquals(bb.get(0), 0x05); + } + t.awaitCompletion(); + deleteFile(addr); + } + } + + @Test(dataProvider = "family") + public void SPINNBAccep_BConn_BIO_RW_6(ProtocolFamily family) + throws Throwable { + try (ServerSocketChannel ssc = openServerSocketChannel(family)) { + ssc.bind(null); + SocketAddress addr = ssc.getLocalAddress(); + + TestThread t = TestThread.of("t6", () -> { + try (SocketChannel sc = openSocketChannel(family)) { + assertTrue(sc.connect(addr)); + ByteBuffer bb = ByteBuffer.allocate(10); + assertEquals(sc.read(bb), 1); + out.printf("read: 0x%x%n", bb.get(0)); + assertEquals(bb.get(0), 0x06); + } + }); + t.start(); + + SocketChannel accepted; + for (; ; ) { + accepted = ssc.accept(); + if (accepted != null) { + out.println("accepted new connection"); + break; + } + Thread.onSpinWait(); + } + + try (SocketChannel sc = accepted) { + ByteBuffer bb = ByteBuffer.allocate(10).put((byte) 0x06).flip(); + assertEquals(sc.write(bb), 1); + out.printf("wrote: 0x%x%n", bb.get(0)); + assertEquals(sc.read(bb.clear()), -1); + + } + t.awaitCompletion(); + deleteFile(addr); + } + } + + // Similar to the previous six scenarios, but with same-thread + // non-blocking connect. + + @Test(dataProvider = "family") + public void BAccep_NBConn_BIO_WR_7(ProtocolFamily family) + throws Throwable { + try (ServerSocketChannel ssc = openServerSocketChannel(family)) { + ssc.bind(null); + SocketAddress addr = ssc.getLocalAddress(); + + try (SocketChannel sc = openSocketChannel(family)) { + sc.configureBlocking(false); + sc.connect(addr); + + try (SocketChannel sc2 = ssc.accept()) { + assertTrue(sc.finishConnect()); + sc.configureBlocking(true); + TestThread t = TestThread.of("t7", () -> { + ByteBuffer bb = ByteBuffer.allocate(10).put((byte) 0x07).flip(); + assertEquals(sc.write(bb), 1); + out.printf("wrote: 0x%x%n", bb.get(0)); + assertEquals(sc.read(bb.clear()), -1); + }); + t.start(); + + ByteBuffer bb = ByteBuffer.allocate(10); + assertEquals(sc2.read(bb), 1); + out.printf("read: 0x%x%n", bb.get(0)); + assertEquals(bb.get(0), 0x07); + sc2.shutdownOutput(); + t.awaitCompletion(); + } + } + deleteFile(addr); + } + } + + @Test(dataProvider = "family") + public void BAccep_NBConn_BIO_RW_8(ProtocolFamily family) + throws Throwable { + try (ServerSocketChannel ssc = openServerSocketChannel(family)) { + ssc.bind(null); + SocketAddress addr = ssc.getLocalAddress(); + + try (SocketChannel sc = openSocketChannel(family)) { + sc.configureBlocking(false); + sc.connect(addr); + + try (SocketChannel sc2 = ssc.accept()) { + assertTrue(sc.finishConnect()); + sc.configureBlocking(true); + TestThread t = TestThread.of("t8", () -> { + ByteBuffer bb = ByteBuffer.allocate(10); + assertEquals(sc.read(bb), 1); + out.printf("read: 0x%x%n", bb.get(0)); + assertEquals(bb.get(0), 0x08); + sc.shutdownOutput(); + }); + t.start(); + + ByteBuffer bb = ByteBuffer.allocate(10).put((byte) 0x08).flip(); + assertEquals(sc2.write(bb), 1); + out.printf("wrote: 0x%x%n", bb.get(0)); + assertEquals(sc2.read(bb.clear()), -1); + t.awaitCompletion(); + } + } + deleteFile(addr); + } + } + + @Test(dataProvider = "family") + public void SELNBAccep_NBConn_BIO_WR_9(ProtocolFamily family) + throws Throwable { + try (ServerSocketChannel ssc = openServerSocketChannel(family)) { + ssc.bind(null); + SocketAddress addr = ssc.getLocalAddress(); + + try (SocketChannel sc = openSocketChannel(family); + Selector selector = Selector.open()) { + sc.configureBlocking(false); + sc.connect(addr); + + ssc.configureBlocking(false).register(selector, OP_ACCEPT); + assertEquals(selector.select(), 1); + + try (SocketChannel sc2 = ssc.accept()) { + assertTrue(sc.finishConnect()); + sc.configureBlocking(true); + TestThread t = TestThread.of("t9", () -> { + ByteBuffer bb = ByteBuffer.allocate(10).put((byte) 0x09).flip(); + assertEquals(sc.write(bb), 1); + out.printf("wrote: 0x%x%n", bb.get(0)); + assertEquals(sc.read(bb.clear()), -1); + }); + t.start(); + + ByteBuffer bb = ByteBuffer.allocate(10); + assertEquals(sc2.read(bb), 1); + out.printf("read: 0x%x%n", bb.get(0)); + assertEquals(bb.get(0), 0x09); + sc2.shutdownOutput(); + t.awaitCompletion(); + } + } + deleteFile(addr); + } + } + + @Test(dataProvider = "family") + public void SELNBAccep_NBConn_BIO_RW_10(ProtocolFamily family) + throws Throwable { + try (ServerSocketChannel ssc = openServerSocketChannel(family)) { + ssc.bind(null); + SocketAddress addr = ssc.getLocalAddress(); + + try (SocketChannel sc = openSocketChannel(family); + Selector selector = Selector.open()) { + sc.configureBlocking(false); + sc.connect(addr); + + ssc.configureBlocking(false).register(selector, OP_ACCEPT); + assertEquals(selector.select(), 1); + + try (SocketChannel sc2 = ssc.accept()) { + assertTrue(sc.finishConnect()); + sc.configureBlocking(true); + TestThread t = TestThread.of("t10", () -> { + ByteBuffer bb = ByteBuffer.allocate(10); + assertEquals(sc.read(bb), 1); + out.printf("read: 0x%x%n", bb.get(0)); + assertEquals(bb.get(0), 0x10); + sc.shutdownOutput(); + }); + t.start(); + + ByteBuffer bb = ByteBuffer.allocate(10).put((byte) 0x10).flip(); + assertEquals(sc2.write(bb), 1); + out.printf("wrote: 0x%x%n", bb.get(0)); + assertEquals(sc2.read(bb.clear()), -1); + t.awaitCompletion(); + } + } + deleteFile(addr); + } + } + + @Test(dataProvider = "family") + public void SPINNBAccep_NBConn_BIO_WR_11(ProtocolFamily family) + throws Throwable { + try (ServerSocketChannel ssc = openServerSocketChannel(family)) { + ssc.bind(null); + SocketAddress addr = ssc.getLocalAddress(); + + try (SocketChannel sc = openSocketChannel(family)) { + sc.configureBlocking(false); + sc.connect(addr); + + SocketChannel accepted; + for (; ; ) { + accepted = ssc.accept(); + if (accepted != null) { + out.println("accepted new connection"); + break; + } + Thread.onSpinWait(); + } + + try (SocketChannel sc2 = accepted) { + assertTrue(sc.finishConnect()); + sc.configureBlocking(true); + TestThread t = TestThread.of("t11", () -> { + ByteBuffer bb = ByteBuffer.allocate(10).put((byte) 0x11).flip(); + assertEquals(sc.write(bb), 1); + out.printf("wrote: 0x%x%n", bb.get(0)); + assertEquals(sc.read(bb.clear()), -1); + }); + t.start(); + + ByteBuffer bb = ByteBuffer.allocate(10); + assertEquals(sc2.read(bb), 1); + out.printf("read: 0x%x%n", bb.get(0)); + assertEquals(bb.get(0), 0x11); + sc2.shutdownOutput(); + t.awaitCompletion(); + } + } + deleteFile(addr); + } + } + + @Test(dataProvider = "family") + public void SPINNBAccep_NBConn_BIO_RW_12(ProtocolFamily family) + throws Throwable { + try (ServerSocketChannel ssc = openServerSocketChannel(family)) { + ssc.bind(null); + SocketAddress addr = ssc.getLocalAddress(); + + try (SocketChannel sc = openSocketChannel(family)) { + sc.configureBlocking(false); + sc.connect(addr); + + SocketChannel accepted; + for (; ; ) { + accepted = ssc.accept(); + if (accepted != null) { + out.println("accepted new connection"); + break; + } + Thread.onSpinWait(); + } + + try (SocketChannel sc2 = accepted) { + assertTrue(sc.finishConnect()); + sc.configureBlocking(true); + TestThread t = TestThread.of("t12", () -> { + ByteBuffer bb = ByteBuffer.allocate(10); + assertEquals(sc.read(bb), 1); + out.printf("read: 0x%x%n", bb.get(0)); + assertEquals(bb.get(0), 0x12); + sc.shutdownOutput(); + }); + t.start(); + + ByteBuffer bb = ByteBuffer.allocate(10).put((byte) 0x12).flip(); + assertEquals(sc2.write(bb), 1); + out.printf("wrote: 0x%x%n", bb.get(0)); + assertEquals(sc2.read(bb.clear()), -1); + t.awaitCompletion(); + } + } + deleteFile(addr); + } + } + + // --- + // Similar to the previous twelve scenarios but with non-blocking IO + // --- + + @Test(dataProvider = "family") + public void BAccep_BConn_NBIO_WR_1a(ProtocolFamily family) + throws Throwable { + try (ServerSocketChannel ssc = openServerSocketChannel(family)) { + ssc.bind(null); + SocketAddress addr = ssc.getLocalAddress(); + + TestThread t = TestThread.of("t1a", () -> { + try (SocketChannel sc = openSocketChannel(family); + Selector selector = Selector.open()) { + assertTrue(sc.connect(addr)); + ByteBuffer bb = ByteBuffer.allocate(10).put((byte) 0x1A).flip(); + sc.configureBlocking(false); + SelectionKey k = sc.register(selector, OP_WRITE); + selector.select(); + int c; + while ((c = sc.write(bb)) < 1) ; + assertEquals(c, 1); + out.printf("wrote: 0x%x%n", bb.get(0)); + k.interestOps(OP_READ); + selector.select(); + bb.clear(); + while ((c = sc.read(bb)) == 0) ; + assertEquals(c, -1); + } + }); + t.start(); + + try (SocketChannel sc = ssc.accept(); + Selector selector = Selector.open()) { + ByteBuffer bb = ByteBuffer.allocate(10); + sc.configureBlocking(false); + sc.register(selector, OP_READ); + selector.select(); + int c; + while ((c = sc.read(bb)) == 0) ; + assertEquals(c, 1); + out.printf("read: 0x%x%n", bb.get(0)); + assertEquals(bb.get(0), 0x1A); + } + t.awaitCompletion(); + deleteFile(addr); + } + } + + @Test(dataProvider = "family") + public void BAccep_BConn_NBIO_RW_2a(ProtocolFamily family) + throws Throwable { + try (ServerSocketChannel ssc = openServerSocketChannel(family)) { + ssc.bind(null); + SocketAddress addr = ssc.getLocalAddress(); + + TestThread t = TestThread.of("t2a", () -> { + try (SocketChannel sc = openSocketChannel(family); + Selector selector = Selector.open()) { + assertTrue(sc.connect(addr)); + ByteBuffer bb = ByteBuffer.allocate(10); + sc.configureBlocking(false); + sc.register(selector, OP_READ); + selector.select(); + int c; + while ((c = sc.read(bb)) == 0) ; + assertEquals(c, 1); + out.printf("read: 0x%x%n", bb.get(0)); + assertEquals(bb.get(0), 0x2A); + } + }); + t.start(); + + try (SocketChannel sc = ssc.accept(); + Selector selector = Selector.open()) { + ByteBuffer bb = ByteBuffer.allocate(10).put((byte) 0x2A).flip(); + sc.configureBlocking(false); + SelectionKey k = sc.register(selector, OP_WRITE); + selector.select(); + int c; + while ((c = sc.write(bb)) < 1) ; + assertEquals(c, 1); + out.printf("wrote: 0x%x%n", bb.get(0)); + k.interestOps(OP_READ); + selector.select(); + bb.clear(); + while ((c = sc.read(bb)) == 0) ; + assertEquals(c, -1); + } + t.awaitCompletion(); + deleteFile(addr); + } + } + + @Test(dataProvider = "family") + public void SELNBAccep_BConn_NBIO_WR_3a(ProtocolFamily family) + throws Throwable { + try (ServerSocketChannel ssc = openServerSocketChannel(family); + Selector aselector = Selector.open()) { + ssc.bind(null); + SocketAddress addr = ssc.getLocalAddress(); + + TestThread t = TestThread.of("t3a", () -> { + try (SocketChannel sc = openSocketChannel(family); + Selector selector = Selector.open()) { + assertTrue(sc.connect(addr)); + ByteBuffer bb = ByteBuffer.allocate(10).put((byte) 0x3A).flip(); + sc.configureBlocking(false); + SelectionKey k = sc.register(selector, OP_WRITE); + selector.select(); + int c; + while ((c = sc.write(bb)) < 1) ; + assertEquals(c, 1); + out.printf("wrote: 0x%x%n", bb.get(0)); + k.interestOps(OP_READ); + selector.select(); + bb.clear(); + while ((c = sc.read(bb)) == 0) ; + assertEquals(c, -1); + } + }); + t.start(); + + ssc.configureBlocking(false).register(aselector, OP_ACCEPT); + assertEquals(aselector.select(), 1); + + try (SocketChannel sc = ssc.accept(); + Selector selector = Selector.open()) { + ByteBuffer bb = ByteBuffer.allocate(10); + sc.configureBlocking(false); + sc.register(selector, OP_READ); + selector.select(); + int c; + while ((c = sc.read(bb)) == 0) ; + assertEquals(c, 1); + out.printf("read: 0x%x%n", bb.get(0)); + assertEquals(bb.get(0), 0x3A); + } + t.awaitCompletion(); + deleteFile(addr); + } + } + + @Test(dataProvider = "family") + public void SELNBAccep_BConn_NBIO_RW_4a(ProtocolFamily family) + throws Throwable { + try (ServerSocketChannel ssc = openServerSocketChannel(family); + Selector aselector = Selector.open()) { + ssc.bind(null); + SocketAddress addr = ssc.getLocalAddress(); + + TestThread t = TestThread.of("t4a", () -> { + try (SocketChannel sc = openSocketChannel(family); + Selector selector = Selector.open()) { + assertTrue(sc.connect(addr)); + ByteBuffer bb = ByteBuffer.allocate(10); + sc.configureBlocking(false); + sc.register(selector, OP_READ); + selector.select(); + int c; + while ((c = sc.read(bb)) == 0) ; + assertEquals(c, 1); + out.printf("read: 0x%x%n", bb.get(0)); + assertEquals(bb.get(0), 0x4A); + } + }); + t.start(); + + ssc.configureBlocking(false).register(aselector, OP_ACCEPT); + assertEquals(aselector.select(), 1); + + try (SocketChannel sc = ssc.accept(); + Selector selector = Selector.open()) { + ByteBuffer bb = ByteBuffer.allocate(10).put((byte) 0x4A).flip(); + sc.configureBlocking(false); + SelectionKey k = sc.register(selector, OP_WRITE); + selector.select(); + int c; + while ((c = sc.write(bb)) < 1) ; + assertEquals(c, 1); + out.printf("wrote: 0x%x%n", bb.get(0)); + k.interestOps(OP_READ); + selector.select(); + bb.clear(); + while ((c = sc.read(bb)) == 0) ; + assertEquals(c, -1); + } + t.awaitCompletion(); + deleteFile(addr); + } + } + + @Test(dataProvider = "family") + public void SPINNBAccep_BConn_NBIO_WR_5a(ProtocolFamily family) + throws Throwable { + try (ServerSocketChannel ssc = openServerSocketChannel(family)) { + ssc.bind(null); + SocketAddress addr = ssc.getLocalAddress(); + + TestThread t = TestThread.of("t5a", () -> { + try (SocketChannel sc = openSocketChannel(family); + Selector selector = Selector.open()) { + assertTrue(sc.connect(addr)); + ByteBuffer bb = ByteBuffer.allocate(10).put((byte) 0x5A).flip(); + sc.configureBlocking(false); + SelectionKey k = sc.register(selector, OP_WRITE); + selector.select(); + int c; + while ((c = sc.write(bb)) < 1) ; + assertEquals(c, 1); + out.printf("wrote: 0x%x%n", bb.get(0)); + k.interestOps(OP_READ); + selector.select(); + bb.clear(); + while ((c = sc.read(bb)) == 0) ; + assertEquals(c, -1); + } + }); + t.start(); + + SocketChannel accepted; + for (; ; ) { + accepted = ssc.accept(); + if (accepted != null) { + out.println("accepted new connection"); + break; + } + Thread.onSpinWait(); + } + + try (SocketChannel sc = accepted; + Selector selector = Selector.open()) { + ByteBuffer bb = ByteBuffer.allocate(10); + sc.configureBlocking(false); + sc.register(selector, OP_READ); + selector.select(); + int c; + while ((c = sc.read(bb)) == 0) ; + assertEquals(c, 1); + out.printf("read: 0x%x%n", bb.get(0)); + assertEquals(bb.get(0), 0x5A); + } + t.awaitCompletion(); + deleteFile(addr); + } + } + + @Test(dataProvider = "family") + public void SPINNBAccep_BConn_NBIO_RW_6a(ProtocolFamily family) + throws Throwable { + try (ServerSocketChannel ssc = openServerSocketChannel(family)) { + ssc.bind(null); + SocketAddress addr = ssc.getLocalAddress(); + + TestThread t = TestThread.of("t6a", () -> { + try (SocketChannel sc = openSocketChannel(family); + Selector selector = Selector.open()) { + assertTrue(sc.connect(addr)); + ByteBuffer bb = ByteBuffer.allocate(10); + sc.configureBlocking(false); + sc.register(selector, OP_READ); + selector.select(); + int c; + while ((c = sc.read(bb)) == 0) ; + assertEquals(c, 1); + out.printf("read: 0x%x%n", bb.get(0)); + assertEquals(bb.get(0), 0x6A); + } + }); + t.start(); + + SocketChannel accepted; + for (; ; ) { + accepted = ssc.accept(); + if (accepted != null) { + out.println("accepted new connection"); + break; + } + Thread.onSpinWait(); + } + + try (SocketChannel sc = accepted; + Selector selector = Selector.open()) { + ByteBuffer bb = ByteBuffer.allocate(10).put((byte) 0x6A).flip(); + sc.configureBlocking(false); + SelectionKey k = sc.register(selector, OP_WRITE); + selector.select(); + int c; + while ((c = sc.write(bb)) < 1) ; + assertEquals(c, 1); + out.printf("wrote: 0x%x%n", bb.get(0)); + k.interestOps(OP_READ); + selector.select(); + bb.clear(); + while ((c = sc.read(bb)) == 0) ; + assertEquals(c, -1); + + } + t.awaitCompletion(); + deleteFile(addr); + } + } + + // Similar to the previous six scenarios but with same-thread + // non-blocking connect. + + @Test(dataProvider = "family") + public void BAccep_NBConn_NBIO_WR_7a(ProtocolFamily family) + throws Throwable { + try (ServerSocketChannel ssc = openServerSocketChannel(family)) { + ssc.bind(null); + SocketAddress addr = ssc.getLocalAddress(); + + try (SocketChannel sc = openSocketChannel(family)) { + sc.configureBlocking(false); + sc.connect(addr); + + try (SocketChannel sc2 = ssc.accept()) { + assertTrue(sc.finishConnect()); + TestThread t = TestThread.of("t7a", () -> { + try (Selector selector = Selector.open()) { + ByteBuffer bb = ByteBuffer.allocate(10).put((byte) 0x7A).flip(); + sc.configureBlocking(false); + SelectionKey k = sc.register(selector, OP_WRITE); + selector.select(); + int c; + while ((c = sc.write(bb)) < 1) ; + assertEquals(c, 1); + out.printf("wrote: 0x%x%n", bb.get(0)); + k.interestOps(OP_READ); + selector.select(); + bb.clear(); + while ((c = sc.read(bb)) == 0) ; + assertEquals(c, -1); + } + }); + t.start(); + + ByteBuffer bb = ByteBuffer.allocate(10); + sc2.configureBlocking(false); + try (Selector selector = Selector.open()) { + sc2.register(selector, OP_READ); + selector.select(); + int c; + while ((c = sc2.read(bb)) == 0) ; + assertEquals(c, 1); + out.printf("read: 0x%x%n", bb.get(0)); + assertEquals(bb.get(0), 0x7A); + sc2.shutdownOutput(); + } + t.awaitCompletion(); + } + } + deleteFile(addr); + } + } + + @Test(dataProvider = "family") + public void BAccep_NBConn_NBIO_RW_8a(ProtocolFamily family) + throws Throwable { + try (ServerSocketChannel ssc = openServerSocketChannel(family)) { + ssc.bind(null); + SocketAddress addr = ssc.getLocalAddress(); + + try (SocketChannel sc = openSocketChannel(family)) { + sc.configureBlocking(false); + sc.connect(addr); + + try (SocketChannel sc2 = ssc.accept()) { + assertTrue(sc.finishConnect()); + TestThread t = TestThread.of("t8a", () -> { + try (Selector selector = Selector.open()) { + ByteBuffer bb = ByteBuffer.allocate(10); + sc.register(selector, OP_READ); + selector.select(); + int c; + while ((c = sc.read(bb)) == 0) ; + assertEquals(c, 1); + out.printf("read: 0x%x%n", bb.get(0)); + assertEquals(bb.get(0), (byte) 0x8A); + sc.shutdownOutput(); + } + }); + t.start(); + + ByteBuffer bb = ByteBuffer.allocate(10).put((byte) 0x8A).flip(); + sc2.configureBlocking(false); + try (Selector selector = Selector.open()) { + SelectionKey k = sc2.register(selector, OP_WRITE); + selector.select(); + int c; + while ((c = sc2.write(bb)) < 1) ; + assertEquals(c, 1); + out.printf("wrote: 0x%x%n", bb.get(0)); + k.interestOps(OP_READ); + selector.select(); + bb.clear(); + while ((c = sc2.read(bb)) == 0) ; + assertEquals(c, -1); + } + t.awaitCompletion(); + } + } + deleteFile(addr); + } + } + + @Test(dataProvider = "family") + public void SELNBAccep_NBConn_NBIO_WR_9a(ProtocolFamily family) + throws Throwable { + try (ServerSocketChannel ssc = openServerSocketChannel(family)) { + ssc.bind(null); + SocketAddress addr = ssc.getLocalAddress(); + + try (SocketChannel sc = openSocketChannel(family)) { + sc.configureBlocking(false); + sc.connect(addr); + + Selector aselector = Selector.open(); + ssc.configureBlocking(false).register(aselector, OP_ACCEPT); + assertEquals(aselector.select(), 1); + + try (SocketChannel sc2 = ssc.accept()) { + assertTrue(sc.finishConnect()); + TestThread t = TestThread.of("t9a", () -> { + try (Selector selector = Selector.open()) { + ByteBuffer bb = ByteBuffer.allocate(10).put((byte) 0x9A).flip(); + sc.configureBlocking(false); + SelectionKey k = sc.register(selector, OP_WRITE); + selector.select(); + int c; + while ((c = sc.write(bb)) < 1) ; + assertEquals(c, 1); + out.printf("wrote: 0x%x%n", bb.get(0)); + k.interestOps(OP_READ); + selector.select(); + bb.clear(); + while ((c = sc.read(bb)) == 0) ; + assertEquals(c, -1); + } + }); + t.start(); + + ByteBuffer bb = ByteBuffer.allocate(10); + sc2.configureBlocking(false); + try (Selector selector = Selector.open()) { + sc2.register(selector, OP_READ); + selector.select(); + int c; + while ((c = sc2.read(bb)) == 0) ; + assertEquals(c, 1); + out.printf("read: 0x%x%n", bb.get(0)); + assertEquals(bb.get(0), (byte) 0x9A); + sc2.shutdownOutput(); + } + t.awaitCompletion(); + } + } + deleteFile(addr); + } + } + + @Test(dataProvider = "family") + public void SELNBAccep_NBConn_NBIO_RW_10a(ProtocolFamily family) + throws Throwable { + try (ServerSocketChannel ssc = openServerSocketChannel(family)) { + ssc.bind(null); + SocketAddress addr = ssc.getLocalAddress(); + + try (SocketChannel sc = openSocketChannel(family)) { + sc.configureBlocking(false); + sc.connect(addr); + + Selector aselector = Selector.open(); + ssc.configureBlocking(false).register(aselector, OP_ACCEPT); + assertEquals(aselector.select(), 1); + + try (SocketChannel sc2 = ssc.accept()) { + assertTrue(sc.finishConnect()); + TestThread t = TestThread.of("t10a", () -> { + try (Selector selector = Selector.open()) { + ByteBuffer bb = ByteBuffer.allocate(10); + sc.register(selector, OP_READ); + selector.select(); + int c; + while ((c = sc.read(bb)) == 0) ; + assertEquals(c, 1); + out.printf("read: 0x%x%n", bb.get(0)); + assertEquals(bb.get(0), (byte) 0xAA); + sc.shutdownOutput(); + } + }); + t.start(); + + ByteBuffer bb = ByteBuffer.allocate(10).put((byte) 0xAA).flip(); + sc2.configureBlocking(false); + try (Selector selector = Selector.open()) { + SelectionKey k = sc2.register(selector, OP_WRITE); + selector.select(); + int c; + while ((c = sc2.write(bb)) < 1) ; + assertEquals(c, 1); + out.printf("wrote: 0x%x%n", bb.get(0)); + k.interestOps(OP_READ); + selector.select(); + bb.clear(); + while ((c = sc2.read(bb)) == 0) ; + assertEquals(c, -1); + } + t.awaitCompletion(); + } + } + deleteFile(addr); + } + } + + @Test(dataProvider = "family") + public void SPINBAccep_NBConn_NBIO_WR_11a(ProtocolFamily family) + throws Throwable { + try (ServerSocketChannel ssc = openServerSocketChannel(family)) { + ssc.bind(null); + SocketAddress addr = ssc.getLocalAddress(); + + try (SocketChannel sc = openSocketChannel(family)) { + sc.configureBlocking(false); + sc.connect(addr); + + SocketChannel accepted; + for (; ; ) { + accepted = ssc.accept(); + if (accepted != null) { + out.println("accepted new connection"); + break; + } + Thread.onSpinWait(); + } + + try (SocketChannel sc2 = accepted) { + assertTrue(sc.finishConnect()); + TestThread t = TestThread.of("t11a", () -> { + try (Selector selector = Selector.open()) { + ByteBuffer bb = ByteBuffer.allocate(10).put((byte) 0xBA).flip(); + sc.configureBlocking(false); + SelectionKey k = sc.register(selector, OP_WRITE); + selector.select(); + int c; + while ((c = sc.write(bb)) < 1) ; + assertEquals(c, 1); + out.printf("wrote: 0x%x%n", bb.get(0)); + k.interestOps(OP_READ); + selector.select(); + bb.clear(); + while ((c = sc.read(bb)) == 0) ; + assertEquals(c, -1); + } + }); + t.start(); + + ByteBuffer bb = ByteBuffer.allocate(10); + sc2.configureBlocking(false); + try (Selector selector = Selector.open()) { + sc2.register(selector, OP_READ); + selector.select(); + int c; + while ((c = sc2.read(bb)) == 0) ; + assertEquals(c, 1); + out.printf("read: 0x%x%n", bb.get(0)); + assertEquals(bb.get(0), (byte) 0xBA); + sc2.shutdownOutput(); + } + t.awaitCompletion(); + } + } + deleteFile(addr); + } + } + + @Test(dataProvider = "family") + public void SPINBAccep_NBConn_NBIO_RW_12a(ProtocolFamily family) + throws Throwable { + try (ServerSocketChannel ssc = openServerSocketChannel(family)) { + ssc.bind(null); + SocketAddress addr = ssc.getLocalAddress(); + + try (SocketChannel sc = openSocketChannel(family)) { + sc.configureBlocking(false); + sc.connect(addr); + + SocketChannel accepted; + for (; ; ) { + accepted = ssc.accept(); + if (accepted != null) { + out.println("accepted new connection"); + break; + } + Thread.onSpinWait(); + } + + try (SocketChannel sc2 = accepted) { + assertTrue(sc.finishConnect()); + TestThread t = TestThread.of("t10a", () -> { + try (Selector selector = Selector.open()) { + ByteBuffer bb = ByteBuffer.allocate(10); + sc.register(selector, OP_READ); + selector.select(); + int c; + while ((c = sc.read(bb)) == 0) ; + assertEquals(c, 1); + out.printf("read: 0x%x%n", bb.get(0)); + assertEquals(bb.get(0), (byte) 0xCA); + sc.shutdownOutput(); + } + }); + t.start(); + + ByteBuffer bb = ByteBuffer.allocate(10).put((byte) 0xCA).flip(); + sc2.configureBlocking(false); + try (Selector selector = Selector.open()) { + SelectionKey k = sc2.register(selector, OP_WRITE); + selector.select(); + int c; + while ((c = sc2.write(bb)) < 1) ; + assertEquals(c, 1); + out.printf("wrote: 0x%x%n", bb.get(0)); + k.interestOps(OP_READ); + selector.select(); + bb.clear(); + while ((c = sc2.read(bb)) == 0) ; + assertEquals(c, -1); + } + t.awaitCompletion(); + } + } + deleteFile(addr); + } + } + + // -- + + static class TestThread extends Thread { + private final UncheckedRunnable runnable; + private volatile Throwable throwable; + + TestThread(UncheckedRunnable runnable, String name) { + super(name); + this.runnable = runnable; + } + + @Override + public void run() { + try { + runnable.run(); + } catch (Throwable t) { + out.printf("[%s] caught unexpected: %s%n", getName(), t); + throwable = t; + } + } + + interface UncheckedRunnable { + void run() throws Throwable; + } + + static TestThread of(String name, UncheckedRunnable runnable) { + return new TestThread(runnable, name); + } + + void awaitCompletion() throws Throwable { + this.join(); + if (throwable != null) + throw throwable; + } + } +} diff --git a/test/jdk/java/nio/channels/unixdomain/NonBlockingAccept.java b/test/jdk/java/nio/channels/unixdomain/NonBlockingAccept.java new file mode 100644 index 00000000000..62b21a98d60 --- /dev/null +++ b/test/jdk/java/nio/channels/unixdomain/NonBlockingAccept.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8245194 + * @library /test/lib + * @run main/othervm NonBlockingAccept + */ + +import java.net.StandardProtocolFamily; +import java.nio.channels.ServerSocketChannel; +import java.nio.channels.SocketChannel; +import jtreg.SkippedException; + +public class NonBlockingAccept { + + static void checkSupported() { + try { + SocketChannel.open(StandardProtocolFamily.UNIX).close(); + } catch (UnsupportedOperationException e) { + throw new SkippedException("Unix domain sockets not supported"); + } catch (Exception e) { + // continue + } + } + + public static void main(String[] args) throws Exception { + + checkSupported(); + + try (ServerSocketChannel serverSocketChannel = + ServerSocketChannel.open(StandardProtocolFamily.UNIX)) { + //non blocking mode + serverSocketChannel.configureBlocking(false); + serverSocketChannel.bind(null); + SocketChannel socketChannel = serverSocketChannel.accept(); + System.out.println("The socketChannel is : expected Null " + socketChannel); + if (socketChannel != null) + throw new RuntimeException("expected null"); + // or exception could be thrown otherwise + } + } +} + diff --git a/test/jdk/java/nio/channels/unixdomain/NullTest.java b/test/jdk/java/nio/channels/unixdomain/NullTest.java new file mode 100644 index 00000000000..ed96cfdecc9 --- /dev/null +++ b/test/jdk/java/nio/channels/unixdomain/NullTest.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8245194 + * @run testng NullTest + */ + +import java.net.ProtocolFamily; +import java.net.SocketAddress; +import java.net.UnixDomainSocketAddress; +import java.nio.channels.*; +import java.nio.file.Path; +import org.testng.annotations.Test; +import static org.testng.Assert.assertThrows; + +/** + * Check for NPE + */ +public class NullTest { + + // Expected exception + private static final Class NPE = + NullPointerException.class; + + @Test + public static void runTest() throws Exception { + assertThrows(NPE, () -> SocketChannel.open((ProtocolFamily)null)); + assertThrows(NPE, () -> SocketChannel.open((SocketAddress)null)); + assertThrows(NPE, () -> ServerSocketChannel.open((ProtocolFamily)null)); + assertThrows(NPE, () -> UnixDomainSocketAddress.of((Path)null)); + assertThrows(NPE, () -> UnixDomainSocketAddress.of((String)null)); + } + +} diff --git a/test/jdk/java/nio/channels/unixdomain/Security.java b/test/jdk/java/nio/channels/unixdomain/Security.java new file mode 100644 index 00000000000..2bba0e32af3 --- /dev/null +++ b/test/jdk/java/nio/channels/unixdomain/Security.java @@ -0,0 +1,196 @@ +/* + * 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. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8245194 + * @run main/othervm/java.security.policy=policy1 Security policy1 + * @run main/othervm/java.security.policy=policy2 Security policy2 + * @run main/othervm Security policy3 + * @summary Security test for Unix Domain socket and server socket channels + */ + +import java.io.File; +import java.io.IOException; +import java.net.SocketAddress; +import java.net.UnixDomainSocketAddress; +import java.nio.channels.*; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Comparator; + +import static java.net.StandardProtocolFamily.UNIX; + +/** + * Tests required all with security manager + */ + +public class Security { + + static interface Command { + public void run() throws Exception; + } + + static void call(Command r, Class expectedException) { + boolean threw = false; + try { + r.run(); + } catch (Throwable t) { + if (expectedException == null) { + t.printStackTrace(); + throw new RuntimeException("an exception was thrown but was not expected"); + } + threw = true; + if (!(expectedException.isAssignableFrom(t.getClass()))) { + throw new RuntimeException("wrong exception type thrown " + t.toString()); + } + } + if (expectedException != null && !threw) { + // should have thrown + throw new RuntimeException("% was expected".formatted(expectedException.getName())); + } + } + + + public static void main(String[] args) throws Exception { + try { + SocketChannel.open(UNIX); + } catch (UnsupportedOperationException e) { + System.out.println("Unix domain not supported"); + return; + } + + String policy = args[0]; + switch (policy) { + case "policy1": + testPolicy1(); + break; + case "policy2": + testPolicy2(); + break; + case "policy3": + testPolicy3(); + break; + } + } + + static void setSecurityManager(String policy) { + String testSrc = System.getProperty("test.src"); + // Three /// required for Windows below + String policyURL = "file:///" + testSrc + File.separator + policy; + System.out.println("POLICY: " + policyURL); + System.setProperty("java.security.policy", policyURL); + System.setSecurityManager(new SecurityManager()); + } + + static void close(NetworkChannel... channels) { + + for (NetworkChannel chan : channels) { + try { + chan.close(); + } catch (Exception e) { + } + } + } + + private static final Class SE = SecurityException.class; + private static final Class IOE = IOException.class; + + // No permission + + public static void testPolicy1() throws Exception { + Path servername = Path.of("sock"); + Files.deleteIfExists(servername); + // Permission exists to bind a ServerSocketChannel + final UnixDomainSocketAddress saddr = UnixDomainSocketAddress.of(servername); + try (final ServerSocketChannel server = ServerSocketChannel.open(UNIX)) { + try (final SocketChannel client = SocketChannel.open(UNIX)) { + call(() -> { + server.bind(saddr); + }, SE); + call(() -> { + client.connect(saddr); + }, SE); + } + } finally { + Files.deleteIfExists(servername); + } + } + + // All permissions + + public static void testPolicy2() throws Exception { + Path servername = Path.of("sock"); + Files.deleteIfExists(servername); + final UnixDomainSocketAddress saddr = UnixDomainSocketAddress.of(servername); + try (final ServerSocketChannel server = ServerSocketChannel.open(UNIX)) { + try (final SocketChannel client = SocketChannel.open(UNIX)) { + call(() -> { + server.bind(saddr); + }, null); + call(() -> { + client.connect(saddr); + }, null); + } + } finally { + Files.deleteIfExists(servername); + } + } + + public static void testPolicy3() throws Exception { + Path sock1 = Path.of("sock3"); + Files.deleteIfExists(sock1); + final UnixDomainSocketAddress saddr = UnixDomainSocketAddress.of(sock1); + try (var s1 = ServerSocketChannel.open(UNIX)) { + s1.bind(saddr); + try (var s2 = ServerSocketChannel.open(UNIX)) { + s2.bind(null); + var add2 = (UnixDomainSocketAddress)s2.getLocalAddress(); + saddr.getPath().toFile().deleteOnExit(); + add2.getPath().toFile().deleteOnExit(); + + // Now set security manager and check if we can see addresses + + setSecurityManager("policy3"); + + if (((UnixDomainSocketAddress)s1 + .getLocalAddress()) + .getPath() + .toString() + .length() != 0) + { + throw new RuntimeException("address should have been empty"); + } + + if (((UnixDomainSocketAddress)s2 + .getLocalAddress()) + .getPath() + .toString() + .length() != 0) + { + throw new RuntimeException("address should have been empty"); + } + } + } + } +} diff --git a/test/jdk/java/nio/channels/unixdomain/Shutdown.java b/test/jdk/java/nio/channels/unixdomain/Shutdown.java new file mode 100644 index 00000000000..acdd9978528 --- /dev/null +++ b/test/jdk/java/nio/channels/unixdomain/Shutdown.java @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8245194 + * @run main/othervm Shutdown + */ + +import java.io.Closeable; +import java.io.IOException; +import java.net.*; +import java.nio.ByteBuffer; +import java.nio.channels.*; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.util.Arrays; + +/** + * Check that half close works + */ +public class Shutdown { + + public static void main(String args[]) throws Exception { + if (!supported()) { + System.out.println("Unix domain channels not supported"); + return; + } + runTest(); + } + + static boolean supported() { + try { + SocketChannel.open(StandardProtocolFamily.UNIX).close(); + } catch (UnsupportedOperationException e) { + return false; + } catch (Exception e) { + return true; // continue test to see what problem is + } + return true; + } + + static void assertTrue(boolean condition, String error) { + if (!condition) + throw new RuntimeException(error); + } + + public static void runTest() throws IOException { + ServerSocketChannel server = null; + SocketChannel client = null; + SocketChannel acceptee = null; + UnixDomainSocketAddress usa = null; + + try { + server = ServerSocketChannel.open(StandardProtocolFamily.UNIX); + server.bind(null); + usa = (UnixDomainSocketAddress)server.getLocalAddress(); + System.out.println("Local address " + usa); + client = SocketChannel.open(usa); + acceptee = server.accept(); + ByteBuffer buf = ByteBuffer.wrap("Hello world".getBytes(StandardCharsets.ISO_8859_1)); + ByteBuffer rx = ByteBuffer.allocate(buf.capacity()); + client.write(buf); + buf.rewind(); + while (rx.hasRemaining()) + acceptee.read(rx); + + assertTrue(Arrays.equals(buf.array(), rx.array()), "array contents not equal"); + + client.shutdownOutput(); + try { + client.write(buf); + throw new RuntimeException("shutdown error"); + } catch (ClosedChannelException e) { + } + + rx.clear(); + int c = acceptee.read(rx); + assertTrue(c == -1, "read after remote shutdown"); + + client.configureBlocking(false); + c = client.read(rx); + assertTrue(c == 0, "expected c == 0"); + client.shutdownInput(); + c = client.read(rx); + assertTrue(c == -1, "expected c == -1"); + } finally { + close(server); + close(client); + close(acceptee); + if (usa != null) + Files.delete(usa.getPath()); + } + System.out.println("OK"); + } + + static void close(Closeable c) { + try { + if (c != null) + c.close(); + } catch (IOException e) {} + } +} diff --git a/test/jdk/java/nio/channels/unixdomain/SocketOptions.java b/test/jdk/java/nio/channels/unixdomain/SocketOptions.java new file mode 100644 index 00000000000..f275b519394 --- /dev/null +++ b/test/jdk/java/nio/channels/unixdomain/SocketOptions.java @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @bug 8245194 + * @run main/othervm SocketOptions + */ + +import java.io.IOException; +import java.net.*; +import java.nio.ByteBuffer; +import java.nio.channels.*; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Set; +import jdk.net.UnixDomainPrincipal; +import static jdk.net.ExtendedSocketOptions.SO_PEERCRED; + +/** + * Check that all supported options can actually be set and got + */ +public class SocketOptions { + + public static void main(String args[]) throws Exception { + if (!supported()) { + System.out.println("Unix domain channels not supported"); + return; + } + test(ServerSocketChannel.open(StandardProtocolFamily.UNIX)); + test(SocketChannel.open(StandardProtocolFamily.UNIX)); + testPeerCred(); + } + + static void testPeerCred() throws Exception { + UnixDomainSocketAddress addr = null; + UnixDomainPrincipal p; + try (ServerSocketChannel s = ServerSocketChannel.open(StandardProtocolFamily.UNIX)) { + s.bind(null); + addr = (UnixDomainSocketAddress)s.getLocalAddress(); + try (SocketChannel c = SocketChannel.open(addr)) { + if (!c.supportedOptions().contains(SO_PEERCRED)) { + return; + } + Files.deleteIfExists(addr.getPath()); + p = c.getOption(SO_PEERCRED); + String s1 = p.user().getName(); + System.out.println(s1); + System.out.println(p.group().getName()); + String s2 = System.getProperty("user.name"); + + // Check returned user name + + if (!s1.equals(s2)) { + throw new RuntimeException("wrong username"); + } + + // Try setting the option: Read only + + try { + c.setOption(SO_PEERCRED, p); + throw new RuntimeException("should have thrown SocketException"); + } catch (SocketException e) {} + } + } finally { + if (addr != null) + Files.deleteIfExists(addr.getPath()); + } + + // Try getting from unconnected socket + + try (var c = SocketChannel.open(StandardProtocolFamily.UNIX)) { + try { + p = c.getOption(SO_PEERCRED); + System.out.println(p.user()); + throw new RuntimeException("should have thrown SocketException"); + } catch (SocketException e) {} + } + + // Try getting from ServerSocketChannel + + try (var server = ServerSocketChannel.open(StandardProtocolFamily.UNIX)) { + try { + p = server.getOption(SO_PEERCRED); + System.out.println(p.user()); + throw new RuntimeException("should have thrown USE"); + } catch (UnsupportedOperationException e) {} + } + } + + static boolean supported() { + try { + SocketChannel.open(StandardProtocolFamily.UNIX).close(); + } catch (UnsupportedOperationException e) { + return false; + } catch (Exception e) { + return true; // continue test to see what problem is + } + return true; + } + + @SuppressWarnings("unchecked") + public static void test(NetworkChannel chan) throws IOException { + System.out.println("Checking: " + chan.getClass()); + Set> supported = chan.supportedOptions(); + for (SocketOption option : supported) { + String name = option.name(); + System.out.println("Checking option " + name); + if (option.type() == Boolean.class) { + chan.setOption((SocketOption)option, true); + chan.setOption((SocketOption)option, false); + chan.getOption(option); + } else if (option.type() == Integer.class) { + chan.setOption((SocketOption)option, 10); + chan.getOption(option); + } + } + } +} diff --git a/test/jdk/java/nio/channels/unixdomain/policy1 b/test/jdk/java/nio/channels/unixdomain/policy1 new file mode 100644 index 00000000000..ccfe2ef15a7 --- /dev/null +++ b/test/jdk/java/nio/channels/unixdomain/policy1 @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +grant { + // No permission + permission java.io.FilePermission "sock", "delete"; +}; diff --git a/test/jdk/java/nio/channels/unixdomain/policy2 b/test/jdk/java/nio/channels/unixdomain/policy2 new file mode 100644 index 00000000000..00643294155 --- /dev/null +++ b/test/jdk/java/nio/channels/unixdomain/policy2 @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +grant { + // permission to bind a SocketChannel in sockets directory + permission java.net.NetPermission "accessUnixDomainSocket"; + + permission java.io.FilePermission "sock", "delete"; +}; diff --git a/test/jdk/java/nio/channels/unixdomain/policy3 b/test/jdk/java/nio/channels/unixdomain/policy3 new file mode 100644 index 00000000000..ccfe2ef15a7 --- /dev/null +++ b/test/jdk/java/nio/channels/unixdomain/policy3 @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +grant { + // No permission + permission java.io.FilePermission "sock", "delete"; +}; diff --git a/test/jdk/java/nio/file/Files/Misc.java b/test/jdk/java/nio/file/Files/Misc.java index 553f8910a1d..0bfc0c410dc 100644 --- a/test/jdk/java/nio/file/Files/Misc.java +++ b/test/jdk/java/nio/file/Files/Misc.java @@ -22,7 +22,7 @@ */ /* @test - * @bug 4313887 6838333 8005566 8032220 8215467 + * @bug 4313887 6838333 8005566 8032220 8215467 8255576 * @summary Unit test for miscellenous methods in java.nio.file.Files * @library .. */ @@ -87,6 +87,9 @@ static void testCreateDirectories(Path tmpdir) throws IOException { * Tests isHidden */ static void testIsHidden(Path tmpdir) throws IOException { + // passing an empty path must not throw any runtime exception + assertTrue(!isHidden(Path.of(""))); + assertTrue(!isHidden(tmpdir)); Path file = tmpdir.resolve(".foo"); diff --git a/test/jdk/java/text/Bidi/BidiConformance.java b/test/jdk/java/text/Bidi/BidiConformance.java index 45e49cb632f..7fc7e61cd2e 100644 --- a/test/jdk/java/text/Bidi/BidiConformance.java +++ b/test/jdk/java/text/Bidi/BidiConformance.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2020, 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,7 +23,7 @@ /* * @test - * @bug 6850113 8032446 + * @bug 6850113 8032446 8255242 * @summary confirm the behavior of new Bidi implementation. (Backward compatibility) * @modules java.desktop */ @@ -1246,6 +1246,11 @@ private void testMethod_reorderVisually2() { "when levelStart is -1."); } catch (IllegalArgumentException e) { + if (!e.getMessage().equals( + "Value levelStart -1 is out of range 0 to " + (llen - 1))) { + errorHandling("reorderVisually() should throw an IAE" + + " mentioning levelStart is beyond the levels range. Message: " + e.getMessage()); + } } catch (ArrayIndexOutOfBoundsException e) { errorHandling("reorderVisually() should not throw an AIOoBE " + @@ -1258,6 +1263,11 @@ private void testMethod_reorderVisually2() { "when levelStart is 6(levels.length)."); } catch (IllegalArgumentException e) { + if (!e.getMessage().equals( + "Value levelStart " + llen + " is out of range 0 to " + (llen - 1))) { + errorHandling("reorderVisually() should throw an IAE" + + " mentioning levelStart is beyond the levels range. Message: " + e.getMessage()); + } } catch (ArrayIndexOutOfBoundsException e) { errorHandling("reorderVisually() should not throw an AIOoBE " + @@ -1278,6 +1288,11 @@ private void testMethod_reorderVisually2() { " when objectStart is -1."); } catch (IllegalArgumentException e) { + if (!e.getMessage().equals( + "Value objectStart -1 is out of range 0 to " + (olen - 1))) { + errorHandling("reorderVisually() should throw an IAE" + + " mentioning objectStart is beyond the objects range. Message: " + e.getMessage()); + } } catch (ArrayIndexOutOfBoundsException e) { errorHandling("reorderVisually() should not throw an AIOoBE " + @@ -1290,6 +1305,11 @@ private void testMethod_reorderVisually2() { "when objectStart is 6(objects.length)."); } catch (IllegalArgumentException e) { + if (!e.getMessage().equals( + "Value objectStart 6 is out of range 0 to " + (olen - 1))) { + errorHandling("reorderVisually() should throw an IAE" + + " mentioning objectStart is beyond the objects range. Message: " + e.getMessage()); + } } try { @@ -1298,6 +1318,12 @@ private void testMethod_reorderVisually2() { "when count is -1."); } catch (IllegalArgumentException e) { + if (!e.getMessage().equals( + "Value count -1 is less than zero, or objectStart + count " + + "is beyond objects length " + olen)) { + errorHandling("reorderVisually() should throw an IAE" + + " mentioning objectStart/count is beyond the objects range. Message: " + e.getMessage()); + } } catch (NegativeArraySizeException e) { errorHandling("reorderVisually() should not throw an NASE " + @@ -1310,6 +1336,12 @@ private void testMethod_reorderVisually2() { "when count is 7(objects.length+1)."); } catch (IllegalArgumentException e) { + if (!e.getMessage().equals( + "Value count " + (count + 1) + " is less than zero, or objectStart + count " + + "is beyond objects length " + olen)) { + errorHandling("reorderVisually() should throw an IAE" + + " mentioning objectStart/count is beyond the objects range. Message: " + e.getMessage()); + } } catch (ArrayIndexOutOfBoundsException e) { errorHandling("reorderVisually() should not throw an AIOoBE " + @@ -1397,6 +1429,12 @@ private void testMethod_requiresBidi() { " when limit is textLength+1(too large)."); } catch (IllegalArgumentException e) { + if (!e.getMessage().equals( + "Value start 0 is out of range 0 to " + (textLength + 1) + + ", or limit " + (textLength + 1) + " is beyond the text length " + textLength)) { + errorHandling("requiresBidi() should throw an IAE" + + " mentioning limit is beyond the text length. Message: " + e.getMessage()); + } } catch (ArrayIndexOutOfBoundsException e) { errorHandling("requiresBidi() should not throw an AIOoBE " + diff --git a/test/jdk/java/util/stream/test/org/openjdk/tests/java/util/stream/SegmentTestDataProvider.java b/test/jdk/java/util/stream/test/org/openjdk/tests/java/util/stream/SegmentTestDataProvider.java index 2d2d33d0ab7..c5410865a2b 100644 --- a/test/jdk/java/util/stream/test/org/openjdk/tests/java/util/stream/SegmentTestDataProvider.java +++ b/test/jdk/java/util/stream/test/org/openjdk/tests/java/util/stream/SegmentTestDataProvider.java @@ -40,12 +40,12 @@ public class SegmentTestDataProvider { static VarHandle BYTE_HANDLE = MemoryLayouts.JAVA_BYTE.varHandle(byte.class); - static VarHandle CHAR_HANDLE = MemoryLayouts.JAVA_CHAR.varHandle(char.class); - static VarHandle SHORT_HANDLE = MemoryLayouts.JAVA_SHORT.varHandle(short.class); - static VarHandle INT_HANDLE = MemoryLayouts.JAVA_INT.varHandle(int.class); - static VarHandle LONG_HANDLE = MemoryLayouts.JAVA_LONG.varHandle(long.class); - static VarHandle FLOAT_HANDLE = MemoryLayouts.JAVA_FLOAT.varHandle(float.class); - static VarHandle DOUBLE_HANDLE = MemoryLayouts.JAVA_DOUBLE.varHandle(double.class); + static VarHandle CHAR_HANDLE = MemoryLayouts.JAVA_CHAR.withBitAlignment(8).varHandle(char.class); + static VarHandle SHORT_HANDLE = MemoryLayouts.JAVA_SHORT.withBitAlignment(8).varHandle(short.class); + static VarHandle INT_HANDLE = MemoryLayouts.JAVA_INT.withBitAlignment(8).varHandle(int.class); + static VarHandle LONG_HANDLE = MemoryLayouts.JAVA_LONG.withBitAlignment(8).varHandle(long.class); + static VarHandle FLOAT_HANDLE = MemoryLayouts.JAVA_FLOAT.withBitAlignment(8).varHandle(float.class); + static VarHandle DOUBLE_HANDLE = MemoryLayouts.JAVA_DOUBLE.withBitAlignment(8).varHandle(double.class); static boolean compareSegmentsByte(Collection segments1, Collection segments2, boolean isOrdered) { Function mapper = segment -> (byte)BYTE_HANDLE.get(segment.baseAddress()); diff --git a/test/jdk/javax/swing/JColorChooser/Test6541987.java b/test/jdk/javax/swing/JColorChooser/Test6541987.java index 84053cd1b8f..79e78e993bf 100644 --- a/test/jdk/javax/swing/JColorChooser/Test6541987.java +++ b/test/jdk/javax/swing/JColorChooser/Test6541987.java @@ -42,24 +42,33 @@ public class Test6541987 implements Runnable { private static Robot robot; + private static JFrame frame; - public static void main(String[] args) throws AWTException { - robot = new Robot(); - // test escape after selection - start(); - click(KeyEvent.VK_ESCAPE); - robot.waitForIdle(); - // test double escape after editing - start(); - click(KeyEvent.VK_1); - click(KeyEvent.VK_0); - click(KeyEvent.VK_ESCAPE); - click(KeyEvent.VK_ESCAPE); - robot.waitForIdle(); - // all windows should be closed - for (Window window : Window.getWindows()) { - if (window.isVisible()) { - throw new Error("found visible window: " + window.getName()); + public static void main(String[] args) throws Exception { + try { + robot = new Robot(); + robot.setAutoDelay(100); + // test escape after selection + start(); + click(KeyEvent.VK_ESCAPE); + robot.waitForIdle(); + // test double escape after editing + start(); + click(KeyEvent.VK_1); + click(KeyEvent.VK_0); + click(KeyEvent.VK_ESCAPE); + click(KeyEvent.VK_ESCAPE); + robot.waitForIdle(); + robot.delay(500); + // all windows should be closed + for (Window window : Window.getWindows()) { + if (window.isVisible()) { + throw new Error("found visible window: " + window.getName()); + } + } + } finally { + if (frame != null) { + SwingUtilities.invokeAndWait(frame::dispose); } } } @@ -85,7 +94,8 @@ private static void click(int...keys) { public void run() { String title = getClass().getName(); - JFrame frame = new JFrame(title); + frame = new JFrame(title); + frame.setLocationRelativeTo(null); frame.setVisible(true); Color color = JColorChooser.showDialog(frame, title, Color.BLACK); diff --git a/test/jdk/javax/swing/JFileChooser/8021253/bug8021253.java b/test/jdk/javax/swing/JFileChooser/8021253/bug8021253.java index 831711b260f..35750d506b6 100644 --- a/test/jdk/javax/swing/JFileChooser/8021253/bug8021253.java +++ b/test/jdk/javax/swing/JFileChooser/8021253/bug8021253.java @@ -47,34 +47,41 @@ public class bug8021253 { private static volatile boolean defaultKeyPressed; private static JFileChooser fileChooser; private static File file; + private static JFrame frame; public static void main(String[] args) throws Exception { + try { + Robot robot = new Robot(); + robot.setAutoDelay(100); - Robot robot = new Robot(); - robot.setAutoDelay(50); - - SwingUtilities.invokeAndWait(new Runnable() { - public void run() { - createAndShowGUI(); - } - }); + SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + createAndShowGUI(); + } + }); - robot.waitForIdle(); + robot.waitForIdle(); + robot.delay(1000); - SwingUtilities.invokeAndWait(new Runnable() { - public void run() { - fileChooser.setSelectedFile(file); - } - }); + SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + fileChooser.setSelectedFile(file); + } + }); - robot.waitForIdle(); + robot.waitForIdle(); - robot.keyPress(KeyEvent.VK_ENTER); - robot.keyRelease(KeyEvent.VK_ENTER); - robot.waitForIdle(); + robot.keyPress(KeyEvent.VK_ENTER); + robot.keyRelease(KeyEvent.VK_ENTER); + robot.waitForIdle(); - if (!defaultKeyPressed) { - throw new RuntimeException("Default button is not pressed"); + if (!defaultKeyPressed) { + throw new RuntimeException("Default button is not pressed"); + } + } finally { + if (frame != null) { + SwingUtilities.invokeAndWait(frame::dispose); + } } } @@ -82,7 +89,7 @@ private static void createAndShowGUI() { file = getTempFile(); - final JFrame frame = new JFrame("Test"); + frame = new JFrame("Test"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setSize(200, 300); @@ -97,6 +104,7 @@ public void actionPerformed(ActionEvent e) { frame.getContentPane().add(BorderLayout.CENTER, fileChooser); frame.setSize(fileChooser.getPreferredSize()); + frame.setLocationRelativeTo(null); frame.setVisible(true); } diff --git a/test/jdk/javax/swing/JFileChooser/8041694/bug8041694.java b/test/jdk/javax/swing/JFileChooser/8041694/bug8041694.java index 311f19a44a1..3e3cb3b9658 100644 --- a/test/jdk/javax/swing/JFileChooser/8041694/bug8041694.java +++ b/test/jdk/javax/swing/JFileChooser/8041694/bug8041694.java @@ -57,6 +57,7 @@ private static void runTest() { // Set Metal L&F to make the test compatible with OS X. UIManager.setLookAndFeel(new MetalLookAndFeel()); Robot robot = new Robot(); + robot.setAutoDelay(100); dir1 = Files.createTempDirectory("bug8041694").toFile(); if (Platform.isWindows()) { @@ -83,15 +84,17 @@ public void run() { } }); - robot.setAutoDelay(50); robot.delay(1000); robot.waitForIdle(); robot.keyPress(KeyEvent.VK_D); robot.keyRelease(KeyEvent.VK_D); + robot.waitForIdle(); robot.keyPress(KeyEvent.VK_SPACE); robot.keyRelease(KeyEvent.VK_SPACE); + robot.waitForIdle(); robot.keyPress(KeyEvent.VK_ENTER); robot.keyRelease(KeyEvent.VK_ENTER); + robot.waitForIdle(); fChooserClosedSignal.await(); if (selectedDir == null) { diff --git a/test/jdk/javax/swing/JMenu/4692443/bug4692443.java b/test/jdk/javax/swing/JMenu/4692443/bug4692443.java index d61da32dc8f..70a007cf51b 100644 --- a/test/jdk/javax/swing/JMenu/4692443/bug4692443.java +++ b/test/jdk/javax/swing/JMenu/4692443/bug4692443.java @@ -50,6 +50,7 @@ public static void main(String args[]) throws Throwable { pass = new PassedListener(); passed = false; Robot robo = new Robot(); + robo.setAutoDelay(100); SwingUtilities.invokeAndWait(new Runnable() { public void run() { @@ -58,9 +59,9 @@ public void run() { }); robo.waitForIdle(); + robo.delay(1000); int altKey = java.awt.event.KeyEvent.VK_ALT; - robo.setAutoDelay(100); Util.hitMnemonics(robo, KeyEvent.VK_F); // Enter File menu robo.keyPress(KeyEvent.VK_S); // Enter submenu robo.keyRelease(KeyEvent.VK_S); @@ -79,6 +80,7 @@ public void run() { } } + private static void createAndShowGUI() { mainFrame = new JFrame("Bug 4692443"); JMenuBar mbar = new JMenuBar(); @@ -109,7 +111,7 @@ public void menuCanceled(MenuEvent e) { mainFrame.setJMenuBar(mbar); mainFrame.setSize(200, 200); - mainFrame.setLocation(200, 200); + mainFrame.setLocationRelativeTo(null); mainFrame.setVisible(true); mainFrame.toFront(); } diff --git a/test/jdk/javax/swing/JMenuItem/4171437/bug4171437.java b/test/jdk/javax/swing/JMenuItem/4171437/bug4171437.java index 3bac95fad72..da2e8dccdc3 100644 --- a/test/jdk/javax/swing/JMenuItem/4171437/bug4171437.java +++ b/test/jdk/javax/swing/JMenuItem/4171437/bug4171437.java @@ -44,21 +44,21 @@ public class bug4171437 { public static void main(String[] args) throws Exception { try { + Robot robot = new Robot(); + robot.setAutoDelay(100); SwingUtilities.invokeAndWait(new Runnable() { public void run() { createAndShowGUI(); } }); - Robot robot = new Robot(); - robot.setAutoDelay(50); robot.waitForIdle(); + robot.delay(1000); Util.hitMnemonics(robot, KeyEvent.VK_F); Util.hitKeys(robot, KeyEvent.VK_C); robot.waitForIdle(); - Thread.sleep(1000); if (!closeActivated || customActivated) { throw new RuntimeException("Didn't pass the muster"); @@ -109,6 +109,7 @@ public void menuCanceled(MenuEvent e) {} frame.setSize(300, 300); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.pack(); + frame.setLocationRelativeTo(null); frame.setVisible(true); } } diff --git a/test/jdk/javax/swing/JMenuItem/ActionListenerCalledTwice/ActionListenerCalledTwiceTest.java b/test/jdk/javax/swing/JMenuItem/ActionListenerCalledTwice/ActionListenerCalledTwiceTest.java index 141eb204a4f..800c7693206 100644 --- a/test/jdk/javax/swing/JMenuItem/ActionListenerCalledTwice/ActionListenerCalledTwiceTest.java +++ b/test/jdk/javax/swing/JMenuItem/ActionListenerCalledTwice/ActionListenerCalledTwiceTest.java @@ -63,13 +63,15 @@ public static void main(String[] args) throws Exception { } try { + Robot robot = new Robot(); + robot.setAutoDelay(100); System.setProperty("apple.laf.useScreenMenuBar", "true"); SwingUtilities.invokeAndWait( ActionListenerCalledTwiceTest::createAndShowGUI); - Robot robot = new Robot(); - robot.setAutoDelay(100); + robot.waitForIdle(); + robot.delay(1000); testForTwice(robot, ""); @@ -99,6 +101,7 @@ private static void createAndShowGUI() { frame.setJMenuBar(bar); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.pack(); + frame.setLocationRelativeTo(null); frame.setVisible(true); } diff --git a/test/jdk/javax/swing/JPopupMenu/4458079/bug4458079.java b/test/jdk/javax/swing/JPopupMenu/4458079/bug4458079.java index c68841a1c11..c0d93699a93 100644 --- a/test/jdk/javax/swing/JPopupMenu/4458079/bug4458079.java +++ b/test/jdk/javax/swing/JPopupMenu/4458079/bug4458079.java @@ -44,9 +44,10 @@ public class bug4458079 extends JFrame implements PopupMenuListener { static volatile boolean itemASelected = false; public static void main(String[] args) throws Exception { Robot robot = new Robot(); - robot.waitForIdle(); + robot.setAutoDelay(100); // move mouse outside menu to prevent auto selection robot.mouseMove(100,100); + robot.waitForIdle(); SwingUtilities.invokeAndWait(new Runnable() { public void run() { @@ -54,18 +55,16 @@ public void run() { } }); - robot.setAutoDelay(50); - + robot.waitForIdle(); + robot.delay(1000); Util.hitMnemonics(robot, KeyEvent.VK_M); robot.waitForIdle(); - Thread.sleep(1000); Util.hitKeys(robot, KeyEvent.VK_DOWN); Util.hitKeys(robot, KeyEvent.VK_ENTER); robot.waitForIdle(); - Thread.sleep(1000); if (!itemASelected) { throw new RuntimeException("Test failed: arrow key traversal in JMenu broken!"); diff --git a/test/jdk/javax/swing/JPopupMenu/6544309/bug6544309.java b/test/jdk/javax/swing/JPopupMenu/6544309/bug6544309.java index fa0968ff77c..df5178e320c 100644 --- a/test/jdk/javax/swing/JPopupMenu/6544309/bug6544309.java +++ b/test/jdk/javax/swing/JPopupMenu/6544309/bug6544309.java @@ -22,16 +22,13 @@ */ /* @test - @key headful + @key headful @bug 6544309 @summary Checks that 'Select Input Method' popup menu allows to select items with keyboard. - @author Mikhail Lapshin - @library /lib/client - @build ExtendedRobot @run main bug6544309 */ - +import java.awt.Robot; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; @@ -44,12 +41,15 @@ public class bug6544309 { private JDialog dialog; private boolean passed; - private static ExtendedRobot robot; + private static Robot robot; public static void main(String[] args) throws Exception { - robot = new ExtendedRobot(); + robot = new Robot(); + robot.setAutoDelay(100); // move mouse outside menu to prevent auto selection robot.mouseMove(100,100); + robot.waitForIdle(); + final bug6544309 test = new bug6544309(); try { SwingUtilities.invokeAndWait(new Runnable() { @@ -57,6 +57,8 @@ public void run() { test.setupUI(); } }); + robot.waitForIdle(); + robot.delay(1000); test.test(); System.out.println("Test passed"); } finally { @@ -95,13 +97,16 @@ private void test() throws Exception { private void testImpl() throws Exception { robot.waitForIdle(); System.out.println("Pressing DOWN ARROW"); - robot.type(KeyEvent.VK_DOWN); + robot.keyPress(KeyEvent.VK_DOWN); + robot.keyRelease(KeyEvent.VK_DOWN); robot.waitForIdle(); System.out.println("Pressing DOWN ARROW"); - robot.type(KeyEvent.VK_DOWN); + robot.keyPress(KeyEvent.VK_DOWN); + robot.keyRelease(KeyEvent.VK_DOWN); robot.waitForIdle(); System.out.println("Pressing SPACE"); - robot.type(KeyEvent.VK_SPACE); + robot.keyPress(KeyEvent.VK_SPACE); + robot.keyRelease(KeyEvent.VK_SPACE); } private void checkResult() { diff --git a/test/jdk/javax/swing/JPopupMenu/6827786/bug6827786.java b/test/jdk/javax/swing/JPopupMenu/6827786/bug6827786.java index 7d046b6123e..3f2d58edcad 100644 --- a/test/jdk/javax/swing/JPopupMenu/6827786/bug6827786.java +++ b/test/jdk/javax/swing/JPopupMenu/6827786/bug6827786.java @@ -49,9 +49,10 @@ public class bug6827786 { public static void main(String[] args) throws Exception { try { Robot robot = new Robot(); - robot.setAutoDelay(50); + robot.setAutoDelay(100); // move mouse outside menu to prevent auto selection - robot.mouseMove(100,100); + robot.mouseMove(100,100); + robot.waitForIdle(); SwingUtilities.invokeAndWait(new Runnable() { @@ -61,6 +62,7 @@ public void run() { }); robot.waitForIdle(); + robot.delay(1000); SwingUtilities.invokeAndWait(new Runnable() { diff --git a/test/jdk/javax/swing/JSpinner/SerializationTest.java b/test/jdk/javax/swing/JSpinner/SerializationTest.java new file mode 100644 index 00000000000..40467a679c6 --- /dev/null +++ b/test/jdk/javax/swing/JSpinner/SerializationTest.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.EventQueue; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; + +import javax.swing.JSpinner; +import javax.swing.UIManager; +import javax.swing.UnsupportedLookAndFeelException; + +import static javax.swing.UIManager.getInstalledLookAndFeels; + +/** + * @test + * @bug 7124397 + * @summary Verifies that JSpinner can be serialized/deserialized correctly. + */ +public final class SerializationTest { + + public static void main(String[] argv) throws Exception { + for (UIManager.LookAndFeelInfo laf : getInstalledLookAndFeels()) { + EventQueue.invokeAndWait(() -> setLookAndFeel(laf)); + EventQueue.invokeAndWait(() -> { + JSpinner spinner = new JSpinner(); + JSpinner firstCopy = (JSpinner) createCopy(spinner); + JSpinner secondCopy = (JSpinner) createCopy(firstCopy); + }); + } + } + + private static Object createCopy(Serializable objectToCopy) { + try { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(baos); + oos.writeObject(objectToCopy); + InputStream bais = new ByteArrayInputStream(baos.toByteArray()); + ObjectInputStream ois = new ObjectInputStream(bais); + return ois.readObject(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + private static void setLookAndFeel(UIManager.LookAndFeelInfo laf) { + try { + UIManager.setLookAndFeel(laf.getClassName()); + } catch (UnsupportedLookAndFeelException ignored) { + System.out.println("Unsupported LookAndFeel: " + laf.getClassName()); + } catch (Exception e) { + throw new RuntimeException(e); + } + } +} diff --git a/test/jdk/javax/swing/JTabbedPane/7024235/Test7024235.java b/test/jdk/javax/swing/JTabbedPane/7024235/Test7024235.java index 090c47e2808..5cd1019a835 100644 --- a/test/jdk/javax/swing/JTabbedPane/7024235/Test7024235.java +++ b/test/jdk/javax/swing/JTabbedPane/7024235/Test7024235.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2020, 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 @@ -22,16 +22,14 @@ */ import java.awt.BorderLayout; - import java.awt.Container; import java.awt.Rectangle; -import java.awt.Toolkit; +import java.awt.Robot; import javax.swing.JButton; import javax.swing.JCheckBox; -import javax.swing.JTabbedPane; - import javax.swing.JFrame; +import javax.swing.JTabbedPane; import javax.swing.SwingUtilities; import javax.swing.UIManager; import javax.swing.UIManager.LookAndFeelInfo; @@ -41,9 +39,6 @@ * @key headful * @bug 7024235 * @summary Tests JFrame.pack() with the JTabbedPane - * @library /lib/client/ - * @build ExtendedRobot - * @author Sergey Malenkov * @run main Test7024235 */ @@ -54,12 +49,15 @@ public class Test7024235 implements Runnable { public static void main(String[] args) throws Exception { Test7024235 test = new Test7024235(); for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) { - UIManager.setLookAndFeel(info.getClassName()); + String className = info.getClassName(); + System.out.println("className = " + className); + UIManager.setLookAndFeel(className); test.test(); try { - ExtendedRobot robot = new ExtendedRobot(); - robot.waitForIdle(1000); + Robot robot = new Robot(); + robot.waitForIdle(); + robot.delay(1000); }catch(Exception ex) { ex.printStackTrace(); throw new Error("Unexpected Failure"); @@ -81,6 +79,7 @@ public void run() { JFrame frame = new JFrame(); frame.add(BorderLayout.WEST, this.pane); frame.pack(); + frame.setLocationRelativeTo(null); frame.setVisible(true); test("first"); @@ -105,6 +104,9 @@ private void test(String step) { this.passed = true; for (int index = 0; index < this.pane.getTabCount(); index++) { Rectangle bounds = this.pane.getBoundsAt(index); + if (bounds == null) { + continue; + } int centerX = bounds.x + bounds.width / 2; int centerY = bounds.y + bounds.height / 2; int actual = this.pane.indexAtLocation(centerX, centerY); diff --git a/test/jdk/javax/swing/SpringLayout/4726194/bug4726194.java b/test/jdk/javax/swing/SpringLayout/4726194/bug4726194.java index 5199be566c2..048961089c4 100644 --- a/test/jdk/javax/swing/SpringLayout/4726194/bug4726194.java +++ b/test/jdk/javax/swing/SpringLayout/4726194/bug4726194.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,13 +25,22 @@ * @test * @bug 4726194 7124209 * @summary Tests for 4726194 - * @author Phil Milne */ -import java.awt.*; -import java.lang.reflect.InvocationTargetException; -import java.util.*; + +import java.awt.Font; +import java.util.ArrayList; +import java.util.Arrays; import java.util.List; -import javax.swing.*; + +import javax.swing.BorderFactory; +import javax.swing.JTextField; +import javax.swing.Spring; +import javax.swing.SpringLayout; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; +import javax.swing.UnsupportedLookAndFeelException; + +import static javax.swing.UIManager.getInstalledLookAndFeels; public class bug4726194 { @@ -40,22 +49,29 @@ public class bug4726194 { private static int[] FAIL = new int[3]; private static boolean TEST_DUPLICATES = false; - public static void main(String[] args) { - try { - SwingUtilities.invokeAndWait(new Runnable() { - @Override - public void run() { - int minLevel = 2; - int maxLevel = 2; - for (int i = minLevel; i <= maxLevel; i++) { - test(i, true); - test(i, false); - } + public static void main(String[] args) throws Exception { + for (final UIManager.LookAndFeelInfo laf : getInstalledLookAndFeels()) { + SwingUtilities.invokeAndWait(() -> setLookAndFeel(laf)); + SwingUtilities.invokeAndWait(() -> { + int minLevel = 2; + int maxLevel = 2; + for (int i = minLevel; i <= maxLevel; i++) { + test(i, true); + test(i, false); } }); - } catch (InterruptedException | InvocationTargetException ex) { - ex.printStackTrace(); - throw new RuntimeException("FAILED: SwingUtilities.invokeAndWait method failed!"); + } + } + + private static void setLookAndFeel(UIManager.LookAndFeelInfo laf) { + try { + System.out.println("LookAndFeel: " + laf.getClassName()); + UIManager.setLookAndFeel(laf.getClassName()); + } catch (UnsupportedLookAndFeelException ignored){ + System.out.println("Unsupported LookAndFeel: " + laf.getClassName()); + } catch (ClassNotFoundException | InstantiationException | + IllegalAccessException e) { + throw new RuntimeException(e); } } @@ -64,6 +80,7 @@ public static void test(int level, boolean horizontal) { String[] constraints = horizontal ? hConstraints : vConstraints; test(level, constraints, result, Arrays.asList(new Object[level])); JTextField tf = new JTextField(""); + tf.setBorder(BorderFactory.createEmptyBorder()); tf.setFont(new Font("Dialog", Font.PLAIN, 6)); System.out.print("\t\t"); for (int j = 0; j < constraints.length; j++) { diff --git a/test/jdk/javax/swing/ToolTipManager/Test6256140.java b/test/jdk/javax/swing/ToolTipManager/Test6256140.java index 3456c0ecec8..641d58ac09e 100644 --- a/test/jdk/javax/swing/ToolTipManager/Test6256140.java +++ b/test/jdk/javax/swing/ToolTipManager/Test6256140.java @@ -40,49 +40,58 @@ public class Test6256140 { private final static String initialText = "value"; private final static JLabel toolTipLabel = new JLabel("tip"); + private static JFrame frame; public static void main(String[] args) throws Exception { - - Robot robot = new Robot(); - robot.setAutoDelay(10); - - SwingUtilities.invokeAndWait(new Runnable() { - public void run() { - createAndShowGUI(); + try { + Robot robot = new Robot(); + robot.setAutoDelay(100); + + SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + createAndShowGUI(); + } + }); + robot.waitForIdle(); + robot.delay(1000); + + Point point = ft.getLocationOnScreen(); + robot.mouseMove(point.x, point.y); + robot.waitForIdle(); + robot.mouseMove(point.x + 3, point.y + 3); + robot.waitForIdle(); + + robot.keyPress(KeyEvent.VK_A); + robot.keyRelease(KeyEvent.VK_A); + robot.waitForIdle(); + + if (!isTooltipShowning()) { + throw new RuntimeException("Tooltip is not shown"); } - }); - robot.waitForIdle(); - - Point point = ft.getLocationOnScreen(); - robot.mouseMove(point.x, point.y); - robot.mouseMove(point.x + 3, point.y + 3); - robot.keyPress(KeyEvent.VK_A); - robot.keyRelease(KeyEvent.VK_A); - robot.waitForIdle(); - - if (!isTooltipShowning()) { - throw new RuntimeException("Tooltip is not shown"); - } + robot.keyPress(KeyEvent.VK_ESCAPE); + robot.keyRelease(KeyEvent.VK_ESCAPE); + robot.waitForIdle(); - robot.keyPress(KeyEvent.VK_ESCAPE); - robot.keyRelease(KeyEvent.VK_ESCAPE); - robot.waitForIdle(); - - if (isTooltipShowning()) { - throw new RuntimeException("Tooltip must be hidden now"); - } + if (isTooltipShowning()) { + throw new RuntimeException("Tooltip must be hidden now"); + } - if (isTextEqual()) { - throw new RuntimeException("FormattedTextField must *not* cancel the updated value this time"); - } + if (isTextEqual()) { + throw new RuntimeException("FormattedTextField must *not* cancel the updated value this time"); + } - robot.keyPress(KeyEvent.VK_ESCAPE); - robot.keyRelease(KeyEvent.VK_ESCAPE); - robot.waitForIdle(); + robot.keyPress(KeyEvent.VK_ESCAPE); + robot.keyRelease(KeyEvent.VK_ESCAPE); + robot.waitForIdle(); - if (!isTextEqual()) { - throw new RuntimeException("FormattedTextField must cancel the updated value"); + if (!isTextEqual()) { + throw new RuntimeException("FormattedTextField must cancel the updated value"); + } + } finally { + if (frame != null) { + SwingUtilities.invokeAndWait(frame::dispose); + } } } @@ -116,7 +125,7 @@ private static void createAndShowGUI() { ToolTipManager.sharedInstance().setDismissDelay(Integer.MAX_VALUE); ToolTipManager.sharedInstance().setInitialDelay(0); - final JFrame frame = new JFrame(); + frame = new JFrame(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setLayout(new FlowLayout()); diff --git a/test/jdk/javax/swing/text/CSSBorder/6796710/bug6796710.java b/test/jdk/javax/swing/text/CSSBorder/6796710/bug6796710.java index e492a62c7de..c8945c761fd 100644 --- a/test/jdk/javax/swing/text/CSSBorder/6796710/bug6796710.java +++ b/test/jdk/javax/swing/text/CSSBorder/6796710/bug6796710.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,12 +28,23 @@ * @summary Html content in JEditorPane is overlapping on swing components while resizing the application. * @library ../../../regtesthelpers * @build Util - @run main bug6796710 + * @run main/othervm -Dsun.java2d.uiScale=1 bug6796710 */ -import java.awt.*; +import java.awt.BorderLayout; +import java.awt.Rectangle; +import java.awt.Robot; import java.awt.image.BufferedImage; -import javax.swing.*; +import java.io.File; + +import javax.imageio.ImageIO; +import javax.swing.JButton; +import javax.swing.JEditorPane; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.SwingUtilities; public class bug6796710 { // The page is inlined because we want to be sure that the JEditorPane filled synchronously @@ -89,6 +100,7 @@ public void run() { frame.setContentPane(pnContent); frame.setSize(400, 600); + frame.setLocationRelativeTo(null); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setVisible(true); } @@ -113,7 +125,10 @@ public void run() { // On Linux platforms realSync doesn't guaranties setSize completion Thread.sleep(1000); - if (!Util.compareBufferedImages(bufferedImage, getPnBottomImage())) { + BufferedImage pnBottomImage = getPnBottomImage(); + if (!Util.compareBufferedImages(bufferedImage, pnBottomImage)) { + ImageIO.write(bufferedImage, "png", new File("bufferedImage.png")); + ImageIO.write(pnBottomImage, "png", new File("pnBottomImage.png")); throw new RuntimeException("The test failed"); } diff --git a/test/jdk/javax/swing/text/DefaultEditorKit/4278839/bug4278839.java b/test/jdk/javax/swing/text/DefaultEditorKit/4278839/bug4278839.java index a4c7c2d8641..e67d2ddb588 100644 --- a/test/jdk/javax/swing/text/DefaultEditorKit/4278839/bug4278839.java +++ b/test/jdk/javax/swing/text/DefaultEditorKit/4278839/bug4278839.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2020, 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 @@ -62,12 +62,6 @@ public void run() { robo.waitForIdle(); area.setCaretPosition(0); - - if ("Aqua".equals(UIManager.getLookAndFeel().getID())) { - Util.hitKeys(robo, KeyEvent.VK_HOME); - } else { - Util.hitKeys(robo, KeyEvent.VK_CONTROL, KeyEvent.VK_HOME); - } robo.waitForIdle(); passed &= moveCaret(true) == 1; @@ -152,6 +146,7 @@ private static void createAndShowGUI() { frame = new JFrame(); frame.setTitle("Bug# 4278839"); frame.setSize(200, 200); + frame.setLocationRelativeTo(null); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); area = new JTextArea("\naaa bbb\nccc ddd\n"); frame.getContentPane().add(new JScrollPane(area)); diff --git a/test/jdk/javax/swing/text/JTextComponent/6361367/bug6361367.java b/test/jdk/javax/swing/text/JTextComponent/6361367/bug6361367.java index 153e6c7d655..0c00e561bcd 100644 --- a/test/jdk/javax/swing/text/JTextComponent/6361367/bug6361367.java +++ b/test/jdk/javax/swing/text/JTextComponent/6361367/bug6361367.java @@ -79,7 +79,7 @@ public JTextComponent call() throws Exception { waitForFocus(textComponent); Robot robot = new Robot(); robot.setAutoWaitForIdle(true); - robot.setAutoDelay(250); + robot.setAutoDelay(100); robot.keyPress(KeyEvent.VK_END); robot.keyRelease(KeyEvent.VK_END); robot.keyPress(KeyEvent.VK_SHIFT); diff --git a/test/jdk/javax/swing/text/html/HTMLEditorKit/5043626/bug5043626.java b/test/jdk/javax/swing/text/html/HTMLEditorKit/5043626/bug5043626.java index 8184b6a9562..cdce0dab584 100644 --- a/test/jdk/javax/swing/text/html/HTMLEditorKit/5043626/bug5043626.java +++ b/test/jdk/javax/swing/text/html/HTMLEditorKit/5043626/bug5043626.java @@ -26,9 +26,6 @@ * @key headful * @bug 5043626 * @summary Tests pressing Home or Ctrl+Home set cursor to invisible element - * @author Alexander Potochkin - * @library ../../../../regtesthelpers - * @build Util * @run main bug5043626 */ @@ -43,38 +40,51 @@ public class bug5043626 { private static Document doc; private static Robot robot; + private static JFrame frame; public static void main(String[] args) throws Exception { - robot = new Robot(); + try { + robot = new Robot(); + robot.setAutoDelay(100); - SwingUtilities.invokeAndWait(new Runnable() { - public void run() { - createAndShowGUI(); - } - }); + SwingUtilities.invokeAndWait(new Runnable() { + public void run() { + createAndShowGUI(); + } + }); - robot.waitForIdle(); + robot.waitForIdle(); + robot.delay(1000); - Util.hitKeys(robot, KeyEvent.VK_HOME); - Util.hitKeys(robot, KeyEvent.VK_1); + robot.keyPress(KeyEvent.VK_HOME); + robot.keyRelease(KeyEvent.VK_HOME); + robot.keyPress(KeyEvent.VK_1); + robot.keyRelease(KeyEvent.VK_1); - robot.waitForIdle(); + robot.waitForIdle(); - String test = getText(); + String test = getText(); - if (!"1test".equals(test)) { - throw new RuntimeException("Begin line action set cursor inside tag"); - } + if (!"1test".equals(test)) { + throw new RuntimeException("Begin line action set cursor inside tag"); + } - Util.hitKeys(robot, KeyEvent.VK_HOME); - Util.hitKeys(robot, KeyEvent.VK_2); + robot.keyPress(KeyEvent.VK_HOME); + robot.keyRelease(KeyEvent.VK_HOME); + robot.keyPress(KeyEvent.VK_2); + robot.keyRelease(KeyEvent.VK_2); - robot.waitForIdle(); + robot.waitForIdle(); - test = getText(); + test = getText(); - if (!"21test".equals(test)) { - throw new RuntimeException("Begin action set cursor inside tag"); + if (!"21test".equals(test)) { + throw new RuntimeException("Begin action set cursor inside tag"); + } + } finally { + if (frame != null) { + SwingUtilities.invokeAndWait(frame::dispose); + } } } @@ -95,7 +105,7 @@ public void run() { } private static void createAndShowGUI() { - JFrame frame = new JFrame(); + frame = new JFrame(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); JEditorPane editorPane = new JEditorPane(); @@ -104,6 +114,7 @@ private static void createAndShowGUI() { editorPane.setEditable(true); frame.add(editorPane); frame.pack(); + frame.setLocationRelativeTo(null); frame.setVisible(true); doc = editorPane.getDocument(); editorPane.setCaretPosition(doc.getLength()); diff --git a/test/jdk/jdk/incubator/vector/VectorReshapeTests.java b/test/jdk/jdk/incubator/vector/VectorReshapeTests.java index 08d85f02bd3..83e86ea3736 100644 --- a/test/jdk/jdk/incubator/vector/VectorReshapeTests.java +++ b/test/jdk/jdk/incubator/vector/VectorReshapeTests.java @@ -800,20 +800,41 @@ static byte[] castByteArrayData(byte[] data, Class atype, Class btype) { int count = data.length / asize; assert(data.length == count * asize); byte[] result = new byte[count * bsize]; - int rp = 0, dp = 0; + int minsize = Math.min(asize, bsize); + int size_diff = bsize - asize; + ByteOrder bo = ByteOrder.nativeOrder(); + int rp = 0, dp = 0; for (int i = 0; i < count; i++) { - int nextrp = rp + bsize; + if (bo == ByteOrder.BIG_ENDIAN) { + if (size_diff > 0) { + byte sign = (byte)(data[dp] >> 7); // sign extend + for (int j = 0; j < size_diff; j++) { + result[rp++] = sign; + } + } else { + dp -= size_diff; // step forward if needed + } + } byte b = 0; - for (int j = 0; j < asize; j++) { + for (int j = 0; j < minsize; j++) { b = data[dp++]; - if (j < minsize) result[rp++] = b; + result[rp++] = b; + } + if (bo == ByteOrder.LITTLE_ENDIAN) { + if (size_diff > 0) { + byte sign = (byte)(b >> 7); // sign extend + for (int j = 0; j < size_diff; j++) { + result[rp++] = sign; + } + } else { + dp -= size_diff; // step forward if needed + } } - b >>= 7; // sign extend - while (rp < nextrp) result[rp++] = b; } assert(dp == data.length); assert(rp == result.length); + return result; } diff --git a/test/jdk/jdk/internal/platform/cgroup/TestCgroupSubsystemFactory.java b/test/jdk/jdk/internal/platform/cgroup/TestCgroupSubsystemFactory.java index e8597bb4dd8..62b3d70ca58 100644 --- a/test/jdk/jdk/internal/platform/cgroup/TestCgroupSubsystemFactory.java +++ b/test/jdk/jdk/internal/platform/cgroup/TestCgroupSubsystemFactory.java @@ -50,6 +50,8 @@ public class TestCgroupSubsystemFactory { private Path existingDirectory; + private Path cgroupv1CgroupsJoinControllers; + private Path cgroupv1MountInfoJoinControllers; private Path cgroupv1CgInfoZeroHierarchy; private Path cgroupv1MntInfoZeroHierarchy; private Path cgroupv2CgInfoZeroHierarchy; @@ -57,7 +59,24 @@ public class TestCgroupSubsystemFactory { private Path cgroupv1CgInfoNonZeroHierarchy; private Path cgroupv1MntInfoNonZeroHierarchy; private Path cgroupv1MntInfoSystemdOnly; + private Path cgroupv1MntInfoDoubleCpusets; + private Path cgroupv1MntInfoDoubleCpusets2; private String mntInfoEmpty = ""; + private String cgroupsNonZeroJoinControllers = + "#subsys_name hierarchy num_cgroups enabled\n" + + "cpuset\t3\t1\t1\n" + + "cpu\t4\t153\t1\n" + + "cpuacct\t4\t153\t1\n" + + "blkio\t7\t87\t1\n" + + "memory\t4\t153\t1\n" + + "devices\t6\t87\t1\n" + + "freezer\t9\t1\t1\n" + + "net_cls\t4\t153\t1\n" + + "perf_event\t2\t1\t1\n" + + "net_prio\t4\t153\t1\n" + + "hugetlb\t4\t153\t1\n" + + "pids\t5\t95\t1\n" + + "rdma\t8\t1\t1\n"; private String cgroupsZeroHierarchy = "#subsys_name hierarchy num_cgroups enabled\n" + "cpuset 0 1 1\n" + @@ -71,18 +90,30 @@ public class TestCgroupSubsystemFactory { "perf_event 0 1 1 "; private String mntInfoHybrid = "30 23 0:26 / /sys/fs/cgroup ro,nosuid,nodev,noexec shared:4 - tmpfs tmpfs ro,seclabel,mode=755\n" + - "31 30 0:27 / /sys/fs/cgroup/unified rw,nosuid,nodev,noexec,relatime shared:5 - cgroup2 cgroup2 rw,seclabel,nsdelegate\n" + - "32 30 0:28 / /sys/fs/cgroup/systemd rw,nosuid,nodev,noexec,relatime shared:6 - cgroup cgroup rw,seclabel,xattr,name=systemd\n" + - "35 30 0:31 / /sys/fs/cgroup/memory rw,nosuid,nodev,noexec,relatime shared:7 - cgroup cgroup rw,seclabel,memory\n" + - "36 30 0:32 / /sys/fs/cgroup/pids rw,nosuid,nodev,noexec,relatime shared:8 - cgroup cgroup rw,seclabel,pids\n" + - "37 30 0:33 / /sys/fs/cgroup/perf_event rw,nosuid,nodev,noexec,relatime shared:9 - cgroup cgroup rw,seclabel,perf_event\n" + - "38 30 0:34 / /sys/fs/cgroup/net_cls,net_prio rw,nosuid,nodev,noexec,relatime shared:10 - cgroup cgroup rw,seclabel,net_cls,net_prio\n" + - "39 30 0:35 / /sys/fs/cgroup/hugetlb rw,nosuid,nodev,noexec,relatime shared:11 - cgroup cgroup rw,seclabel,hugetlb\n" + - "40 30 0:36 / /sys/fs/cgroup/cpu,cpuacct rw,nosuid,nodev,noexec,relatime shared:12 - cgroup cgroup rw,seclabel,cpu,cpuacct\n" + - "41 30 0:37 / /sys/fs/cgroup/devices rw,nosuid,nodev,noexec,relatime shared:13 - cgroup cgroup rw,seclabel,devices\n" + - "42 30 0:38 / /sys/fs/cgroup/cpuset rw,nosuid,nodev,noexec,relatime shared:14 - cgroup cgroup rw,seclabel,cpuset\n" + - "43 30 0:39 / /sys/fs/cgroup/blkio rw,nosuid,nodev,noexec,relatime shared:15 - cgroup cgroup rw,seclabel,blkio\n" + - "44 30 0:40 / /sys/fs/cgroup/freezer rw,nosuid,nodev,noexec,relatime shared:16 - cgroup cgroup rw,seclabel,freezer"; + "31 30 0:27 / /sys/fs/cgroup/unified rw,nosuid,nodev,noexec,relatime shared:5 - cgroup2 none rw,seclabel,nsdelegate\n" + + "32 30 0:28 / /sys/fs/cgroup/systemd rw,nosuid,nodev,noexec,relatime shared:6 - cgroup none rw,seclabel,xattr,name=systemd\n" + + "35 30 0:31 / /sys/fs/cgroup/memory rw,nosuid,nodev,noexec,relatime shared:7 - cgroup none rw,seclabel,memory\n" + + "36 30 0:32 / /sys/fs/cgroup/pids rw,nosuid,nodev,noexec,relatime shared:8 - cgroup none rw,seclabel,pids\n" + + "37 30 0:33 / /sys/fs/cgroup/perf_event rw,nosuid,nodev,noexec,relatime shared:9 - cgroup none rw,seclabel,perf_event\n" + + "38 30 0:34 / /sys/fs/cgroup/net_cls,net_prio rw,nosuid,nodev,noexec,relatime shared:10 - cgroup none rw,seclabel,net_cls,net_prio\n" + + "39 30 0:35 / /sys/fs/cgroup/hugetlb rw,nosuid,nodev,noexec,relatime shared:11 - cgroup none rw,seclabel,hugetlb\n" + + "40 30 0:36 / /sys/fs/cgroup/cpu,cpuacct rw,nosuid,nodev,noexec,relatime shared:12 - cgroup none rw,seclabel,cpu,cpuacct\n" + + "41 30 0:37 / /sys/fs/cgroup/devices rw,nosuid,nodev,noexec,relatime shared:13 - cgroup none rw,seclabel,devices\n" + + "42 30 0:38 / /sys/fs/cgroup/cpuset rw,nosuid,nodev,noexec,relatime shared:14 - cgroup none rw,seclabel,cpuset\n" + + "43 30 0:39 / /sys/fs/cgroup/blkio rw,nosuid,nodev,noexec,relatime shared:15 - cgroup none rw,seclabel,blkio\n" + + "44 30 0:40 / /sys/fs/cgroup/freezer rw,nosuid,nodev,noexec,relatime shared:16 - cgroup none rw,seclabel,freezer\n"; + private String mntInfoCgroupv1JoinControllers = + "31 22 0:26 / /sys/fs/cgroup ro,nosuid,nodev,noexec shared:9 - tmpfs tmpfs ro,mode=755\n" + + "32 31 0:27 / /sys/fs/cgroup/unified rw,nosuid,nodev,noexec,relatime shared:10 - cgroup2 cgroup2 rw,nsdelegate\n" + + "33 31 0:28 / /sys/fs/cgroup/systemd rw,nosuid,nodev,noexec,relatime shared:11 - cgroup cgroup rw,xattr,name=systemd\n" + + "36 31 0:31 / /sys/fs/cgroup/perf_event rw,nosuid,nodev,noexec,relatime shared:15 - cgroup cgroup rw,perf_event\n" + + "37 31 0:32 / /sys/fs/cgroup/cpuset rw,nosuid,nodev,noexec,relatime shared:16 - cgroup cgroup rw,cpuset\n" + + "38 31 0:33 / /sys/fs/cgroup/cpu,cpuacct,net_cls,net_prio,hugetlb,memory rw,nosuid,nodev,noexec,relatime shared:17 - cgroup cgroup rw,cpu,cpuacct,memory,net_cls,net_prio,hugetlb\n" + + "39 31 0:34 / /sys/fs/cgroup/pids rw,nosuid,nodev,noexec,relatime shared:18 - cgroup cgroup rw,pids\n" + + "40 31 0:35 / /sys/fs/cgroup/devices rw,nosuid,nodev,noexec,relatime shared:19 - cgroup cgroup rw,devices\n" + + "41 31 0:36 / /sys/fs/cgroup/blkio rw,nosuid,nodev,noexec,relatime shared:20 - cgroup cgroup rw,blkio\n" + + "42 31 0:37 / /sys/fs/cgroup/rdma rw,nosuid,nodev,noexec,relatime shared:21 - cgroup cgroup rw,rdma\n" + + "43 31 0:38 / /sys/fs/cgroup/freezer rw,nosuid,nodev,noexec,relatime shared:22 - cgroup cgroup rw,freezer\n"; private String cgroupsNonZeroHierarchy = "#subsys_name hierarchy num_cgroups enabled\n" + "cpuset 9 1 1\n" + @@ -98,10 +129,13 @@ public class TestCgroupSubsystemFactory { "hugetlb 6 1 1\n" + "pids 3 80 1"; private String mntInfoCgroupsV2Only = - "28 21 0:25 / /sys/fs/cgroup rw,nosuid,nodev,noexec,relatime shared:4 - cgroup2 cgroup2 rw,seclabel,nsdelegate"; + "28 21 0:25 / /sys/fs/cgroup rw,nosuid,nodev,noexec,relatime shared:4 - cgroup2 none rw,seclabel,nsdelegate"; private String mntInfoCgroupsV1SystemdOnly = "35 26 0:26 / /sys/fs/cgroup/systemd rw,nosuid,nodev,noexec,relatime - cgroup systemd rw,name=systemd\n" + "26 18 0:19 / /sys/fs/cgroup rw,relatime - tmpfs none rw,size=4k,mode=755\n"; + private String mntInfoCgroupv1MoreCpusetLine = "121 32 0:37 / /cpuset rw,relatime shared:69 - cgroup none rw,cpuset\n"; + private String mntInfoCgroupsV1DoubleCpuset = mntInfoHybrid + mntInfoCgroupv1MoreCpusetLine; + private String mntInfoCgroupsV1DoubleCpuset2 = mntInfoCgroupv1MoreCpusetLine + mntInfoHybrid; @Before public void setup() { @@ -125,6 +159,18 @@ public void setup() { cgroupv1MntInfoSystemdOnly = Paths.get(existingDirectory.toString(), "mountinfo_cgroupv1_systemd_only"); Files.writeString(cgroupv1MntInfoSystemdOnly, mntInfoCgroupsV1SystemdOnly); + + cgroupv1MntInfoDoubleCpusets = Paths.get(existingDirectory.toString(), "mountinfo_cgroupv1_double_cpuset"); + Files.writeString(cgroupv1MntInfoDoubleCpusets, mntInfoCgroupsV1DoubleCpuset); + + cgroupv1MntInfoDoubleCpusets2 = Paths.get(existingDirectory.toString(), "mountinfo_cgroupv1_double_cpuset2"); + Files.writeString(cgroupv1MntInfoDoubleCpusets2, mntInfoCgroupsV1DoubleCpuset2); + + cgroupv1CgroupsJoinControllers = Paths.get(existingDirectory.toString(), "cgroups_cgv1_join_controllers"); + Files.writeString(cgroupv1CgroupsJoinControllers, cgroupsNonZeroJoinControllers); + + cgroupv1MountInfoJoinControllers = Paths.get(existingDirectory.toString(), "mntinfo_cgv1_join_controllers"); + Files.writeString(cgroupv1MountInfoJoinControllers, mntInfoCgroupv1JoinControllers); } catch (IOException e) { throw new RuntimeException(e); } @@ -139,6 +185,17 @@ public void teardown() { } } + @Test + public void testCgroupv1JoinControllerCombo() throws IOException { + String cgroups = cgroupv1CgroupsJoinControllers.toString(); + String mountInfo = cgroupv1MountInfoJoinControllers.toString(); + Optional result = CgroupSubsystemFactory.determineType(mountInfo, cgroups); + + assertTrue("Expected non-empty cgroup result", result.isPresent()); + CgroupTypeResult res = result.get(); + assertFalse("Join controller combination expected as cgroups v1", res.isCgroupV2()); + } + @Test public void testCgroupv1SystemdOnly() throws IOException { String cgroups = cgroupv1CgInfoZeroHierarchy.toString(); @@ -148,6 +205,22 @@ public void testCgroupv1SystemdOnly() throws IOException { assertTrue("zero hierarchy ids with no *relevant* controllers mounted", result.isEmpty()); } + @Test + public void testCgroupv1MultipleCpusetMounts() throws IOException { + doMultipleCpusetMountsTest(cgroupv1MntInfoDoubleCpusets); + doMultipleCpusetMountsTest(cgroupv1MntInfoDoubleCpusets2); + } + + private void doMultipleCpusetMountsTest(Path info) throws IOException { + String cgroups = cgroupv1CgInfoNonZeroHierarchy.toString(); + String mountInfo = info.toString(); + Optional result = CgroupSubsystemFactory.determineType(mountInfo, cgroups); + + assertTrue("Expected non-empty cgroup result", result.isPresent()); + CgroupTypeResult res = result.get(); + assertFalse("Duplicate cpusets should not influence detection heuristic", res.isCgroupV2()); + } + @Test public void testHybridCgroupsV1() throws IOException { String cgroups = cgroupv1CgInfoNonZeroHierarchy.toString(); diff --git a/test/jdk/jdk/security/jarsigner/Properties.java b/test/jdk/jdk/security/jarsigner/Properties.java index c96a6c3731e..05c50c16979 100644 --- a/test/jdk/jdk/security/jarsigner/Properties.java +++ b/test/jdk/jdk/security/jarsigner/Properties.java @@ -75,15 +75,10 @@ public static void main(String[] args) throws Exception { Asserts.assertTrue(sf.startsWith("Signature-Version")); // There is a SignedAttributes - byte[] d0 = sign(jsb.setProperty("directsign", "false")); + byte[] d0 = sign(jsb); Asserts.assertTrue(DerUtils.innerDerValue(d0, "10403") .isContextSpecific((byte)0)); - // There is no SignedAttributes - byte[] d1 = sign(jsb.setProperty("directsign", "true")); - Asserts.assertFalse(DerUtils.innerDerValue(d1, "10403") - .isContextSpecific((byte)0)); - // Has a hash for the whole manifest byte[] s0 = sign(jsb.setProperty("sectionsonly", "false")); sf = new String(DerUtils.innerDerValue(s0, "10210").getOctetString()); diff --git a/test/jdk/jdk/security/jarsigner/Spec.java b/test/jdk/jdk/security/jarsigner/Spec.java index ae18236d217..b089f4af929 100644 --- a/test/jdk/jdk/security/jarsigner/Spec.java +++ b/test/jdk/jdk/security/jarsigner/Spec.java @@ -23,7 +23,7 @@ /** * @test - * @bug 8056174 8242068 + * @bug 8056174 8242068 8255536 * @summary Make sure JarSigner impl conforms to spec * @library /test/lib * @modules java.base/sun.security.tools.keytool @@ -70,6 +70,9 @@ public static void main(String[] args) throws Exception { sun.security.tools.keytool.Main.main( ("-keystore ks -storepass changeit -keypass changeit -dname" + " CN=DSA -alias d -genkeypair -keyalg dsa").split(" ")); + sun.security.tools.keytool.Main.main( + ("-keystore ks -storepass changeit -keypass changeit -dname" + + " CN=Ed25519 -alias e -genkeypair -keyalg Ed25519").split(" ")); char[] pass = "changeit".toCharArray(); @@ -127,8 +130,6 @@ public static void main(String[] args) throws Exception { iae(()->b1.setProperty("sectionsonly", "OK")); npe(()->b1.setProperty("sectionsonly", null)); npe(()->b1.setProperty("altsigner", null)); - iae(()->b1.setProperty("directsign", "OK")); - npe(()->b1.setProperty("directsign", null)); npe(()->b1.eventHandler(null)); // default values @@ -146,7 +147,6 @@ public static void main(String[] args) throws Exception { assertTrue(js2.getProperty("tsapolicyid") == null); assertTrue(js2.getProperty("internalsf").equals("false")); assertTrue(js2.getProperty("sectionsonly").equals("false")); - assertTrue(js2.getProperty("directsign").equals("false")); assertTrue(js2.getProperty("altsigner") == null); uoe(()->js2.getProperty("invalid")); @@ -163,7 +163,6 @@ public static void main(String[] args) throws Exception { .setProperty("tsapolicyid", "1.2.3.4") .setProperty("internalsf", "true") .setProperty("sectionsonly", "true") - .setProperty("directsign", "true") .setProperty("altsigner", "MyContentSigner") .eventHandler(myeh); JarSigner js3 = b3.build(); @@ -176,7 +175,6 @@ public static void main(String[] args) throws Exception { assertTrue(js3.getProperty("tsapolicyid").equals("1.2.3.4")); assertTrue(js3.getProperty("internalsf").equals("true")); assertTrue(js3.getProperty("sectionsonly").equals("true")); - assertTrue(js3.getProperty("directsign").equals("true")); assertTrue(js3.getProperty("altsigner").equals("MyContentSigner")); assertTrue(js3.getProperty("altsignerpath") == null); @@ -208,6 +206,14 @@ public static void main(String[] args) throws Exception { assertTrue(JarSigner.Builder .getDefaultSignatureAlgorithm(kpg.generateKeyPair().getPrivate()) .equals("SHA512withECDSA")); + + // altsigner does not support modern algorithms + JarSigner.Builder b4 = new JarSigner.Builder( + (PrivateKey)ks.getKey("e", pass), + CertificateFactory.getInstance("X.509") + .generateCertPath(Arrays.asList(ks.getCertificateChain("e")))); + b4.setProperty("altsigner", "MyContentSigner"); + iae(() -> b4.build()); } interface RunnableWithException { diff --git a/test/jdk/sun/net/ftp/TestFtpTimeValue.java b/test/jdk/sun/net/ftp/TestFtpTimeValue.java new file mode 100644 index 00000000000..e51837db238 --- /dev/null +++ b/test/jdk/sun/net/ftp/TestFtpTimeValue.java @@ -0,0 +1,194 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8255078 + * @summary verify that datetime in MDTM and MLSD responses are properly parsed + * @library /test/lib + * @modules java.base/sun.net.ftp + * @build jdk.test.lib.Asserts + * @run main/othervm -Duser.timezone=UTC TestFtpTimeValue + * @run main/othervm -Duser.timezone=America/Los_Angeles TestFtpTimeValue + */ + +import jdk.test.lib.Asserts; +import sun.net.ftp.FtpClient; + +import java.io.*; +import java.net.*; +import java.util.Calendar; +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.TimeZone; + + +public class TestFtpTimeValue { + private enum TestCase { + AmTimeNoMilli(2019, 4, 20, 10, 57, 13, 0), + AmTimeWithMilli(2019, 4, 20, 10, 57, 13, 50), + PmTimeNoMilli(2019, 4, 20, 22, 57, 13, 0), + PmTimeWithMilli(2019, 4, 20, 22, 57, 13, 50), + ; + + public final Date expectedCreated; + public final Date expectedModified; + public final String create; + public final String modify; + + TestCase(int year, int month, int day, int hrs, int min, int sec, int milliseconds) { + var calendar = GregorianCalendar.getInstance(TimeZone.getTimeZone("GMT")); + // month is 0-based in Calendar + calendar.set(year, month - 1, day, hrs, min, sec); + calendar.set(Calendar.MILLISECOND, milliseconds); + expectedCreated = calendar.getTime(); + var s = String.format("%4d%02d%02d%02d%02d%02d", year, month, day, hrs, min, sec); + if (milliseconds != 0) { + s += "." + String.format("%03d", milliseconds); + } + create = s; + + calendar.add(GregorianCalendar.SECOND, 1); + expectedModified = calendar.getTime(); + s = String.format("%4d%02d%02d%02d%02d%02d", year, month, day, hrs, min, sec + 1); + if (milliseconds != 0) { + s += "." + String.format("%03d", milliseconds); + } + modify = s; + } + } + + public static void main(String[] args) throws Exception { + System.out.println("user.timezone: " + System.getProperty("user.timezone")); + try (FtpServer server = new FtpServer(); + FtpClient client = FtpClient.create()) { + (new Thread(server)).start(); + int port = server.getPort(); + var loopback = InetAddress.getLoopbackAddress(); + client.connect(new InetSocketAddress(loopback, port)); + client.enablePassiveMode(true); + for (var testCase : TestCase.values()) { + Asserts.assertEQ(testCase.expectedModified, client.getLastModified(testCase.name()), + "wrong modified date from MDTM for " + testCase); + } + for (var it = client.listFiles(null); it.hasNext(); ) { + var e = it.next(); + Asserts.assertEQ(TestCase.valueOf(e.getName()).expectedCreated, e.getCreated(), + "wrong created date from MLSD for " + e.getName()); + Asserts.assertEQ(TestCase.valueOf(e.getName()).expectedModified, e.getLastModified(), + "wrong modified date from MLSD for " + e.getName()); + } + } + } + + private static class FtpServer implements AutoCloseable, Runnable { + private final ServerSocket serverSocket; + private final ServerSocket pasv; + + FtpServer() throws IOException { + var loopback = InetAddress.getLoopbackAddress(); + serverSocket = new ServerSocket(); + serverSocket.bind(new InetSocketAddress(loopback, 0)); + pasv = new ServerSocket(); + pasv.bind(new InetSocketAddress(loopback, 0)); + } + + public void handleClient(Socket client) throws IOException { + String str; + + client.setSoTimeout(2000); + BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream())); + PrintWriter out = new PrintWriter(client.getOutputStream(), true); + out.println("220 FTP serverSocket is ready."); + boolean done = false; + while (!done) { + try { + str = in.readLine(); + } catch (SocketException e) { + done = true; + continue; + } + String cmd = str.substring(0, str.indexOf(" ") > 0 ? str.indexOf(" ") : str.length()); + String args = (cmd.equals(str)) ? "" : str.substring(str.indexOf(" ") + 1); + System.err.println("C> " + str); + switch (cmd) { + case "QUIT": + out.println("221 Goodbye."); + System.err.println("S> 221"); + done = true; + break; + case "MDTM": { + var testCase = TestCase.valueOf(args); + out.println("213 " + testCase.modify); + System.err.println("S> 213"); + break; + } + case "MLSD": + try (var socket = pasv.accept(); + var dout = new PrintWriter(socket.getOutputStream(), true)) { + out.println("150 MLSD start"); + System.err.println("S> 150"); + for (var testCase : TestCase.values()) { + dout.printf("modify=%s;create=%s; %s%n", + testCase.modify, testCase.create, testCase.name()); + } + } + out.println("226 MLSD done."); + System.err.println("S> 226"); + break; + case "EPSV": + if ("all".equalsIgnoreCase(args)) { + out.println("200 EPSV ALL command successful."); + System.err.println("S> 200"); + continue; + } + out.println("229 Entering Extended Passive Mode (|||" + pasv.getLocalPort() + "|)"); + System.err.println("S> 229"); + break; + default: + System.err.println("S> 500"); + out.println("500 unsupported command: " + str); + } + } + } + + public int getPort() { + return serverSocket.getLocalPort(); + } + + public void close() throws IOException { + serverSocket.close(); + pasv.close(); + } + + @Override + public void run() { + try (Socket client = serverSocket.accept()) { + handleClient(client); + } catch (Throwable t) { + t.printStackTrace(); + throw new RuntimeException("Problem in test execution", t); + } + } + } +} diff --git a/test/jdk/sun/security/mscapi/VeryLongAlias.java b/test/jdk/sun/security/mscapi/VeryLongAlias.java index dfdf5eb508b..b7649f8eaf4 100644 --- a/test/jdk/sun/security/mscapi/VeryLongAlias.java +++ b/test/jdk/sun/security/mscapi/VeryLongAlias.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2020, 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,7 +23,7 @@ /* * @test - * @bug 8223063 + * @bug 8223063 8153005 * @requires os.family == "windows" * @library /test/lib * @summary Support CNG RSA keys @@ -48,7 +48,11 @@ public class VeryLongAlias { public static void main(String[] args) throws Throwable { - SecurityTools.keytool("-genkeypair -storetype pkcs12 -keystore ks" + // Using the old algorithms to make sure the file is recognized + // by the certutil command on old versions of Windows. + SecurityTools.keytool( + "-J-Dkeystore.pkcs12.legacy" + + " -genkeypair -storetype pkcs12 -keystore ks" + " -storepass changeit -keyalg RSA -dname CN=A -alias " + alias); String id = ((X509Certificate)KeyStore.getInstance( diff --git a/test/jdk/sun/security/pkcs/pkcs7/TwoHash.java b/test/jdk/sun/security/pkcs/pkcs7/TwoHash.java new file mode 100644 index 00000000000..6aaf7825c26 --- /dev/null +++ b/test/jdk/sun/security/pkcs/pkcs7/TwoHash.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8255494 + * @summary Make sure the signature algorithm to verify a PKCS7 block is + * DIGwithENC instead of HASHwithENC. + * @modules java.base/sun.security.pkcs + * java.base/sun.security.tools.keytool + * java.base/sun.security.x509 + */ + +import sun.security.pkcs.PKCS7; +import sun.security.tools.keytool.CertAndKeyGen; +import sun.security.x509.X500Name; + +import java.nio.charset.StandardCharsets; +import java.security.cert.X509Certificate; + +public class TwoHash { + public static void main(String[] args) throws Exception { + + byte[] content = "Hello You fool I love you".getBytes(); + + CertAndKeyGen cak = new CertAndKeyGen("EC", "SHA512withECDSA"); + cak.generate("secp256r1"); + byte[] signature = PKCS7.generateNewSignedData( + "SHA256withECDSA", + null, + cak.getPrivateKey(), + new X509Certificate[] {cak.getSelfCertificate(new X500Name("CN=Me"), 1000)}, + content, + false, + true, // direct sign, so that RFC 6211 check is not possible + null); + + // The original signature should verify. + if (new PKCS7(signature).verify(content) == null) { + throw new RuntimeException("Should be verified"); + } + + // Modify the SHA256withECDSA signature algorithm (OID encoded as + // "06 08 2A 86 48 CE 3D 04 03 02") to SHA384withECDSA (OID encoded as + // "06 08 2A 86 48 CE 3D 04 03 03"). ISO_8859_1 charset is chosen + // because it's a strictly one byte per char encoding. + String s = new String(signature, StandardCharsets.ISO_8859_1); + String s1 = s.replace( + "\u0006\u0008\u002A\u0086\u0048\u00CE\u003D\u0004\u0003\u0002", + "\u0006\u0008\u002A\u0086\u0048\u00CE\u003D\u0004\u0003\u0003"); + byte[] modified = s1.getBytes(StandardCharsets.ISO_8859_1); + + // The modified signature should still verify because the HASH + // part of signature algorithm is ignored. + if (new PKCS7(modified).verify(content) == null) { + throw new RuntimeException("Should be verified"); + } + } +} diff --git a/test/jdk/sun/security/pkcs12/P12SecretKey.java b/test/jdk/sun/security/pkcs12/P12SecretKey.java index 39f95d5e0b1..34c90d638c8 100644 --- a/test/jdk/sun/security/pkcs12/P12SecretKey.java +++ b/test/jdk/sun/security/pkcs12/P12SecretKey.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2020, 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,8 +23,11 @@ /* * @test - * @bug 8149411 + * @bug 8149411 8007632 * @summary Get AES key from keystore (uses SecretKeySpec not SecretKeyFactory) + * @run main P12SecretKey pkcs12 AES 128 + * @run main P12SecretKey pkcs12 DES 56 + * @run main P12SecretKey pkcs12 DESede 168 */ import java.io.File; @@ -43,20 +46,19 @@ public class P12SecretKey { public static void main(String[] args) throws Exception { P12SecretKey testp12 = new P12SecretKey(); - String keystoreType = "pkcs12"; - if (args != null && args.length > 0) { - keystoreType = args[0]; - } - testp12.run(keystoreType); + String keystoreType = args[0]; + String algName = args[1]; + int keySize = Integer.parseInt(args[2]); + testp12.run(keystoreType, algName, keySize); } - private void run(String keystoreType) throws Exception { + private void run(String keystoreType, String algName, int keySize) throws Exception { char[] pw = "password".toCharArray(); KeyStore ks = KeyStore.getInstance(keystoreType); ks.load(null, pw); - KeyGenerator kg = KeyGenerator.getInstance("AES"); - kg.init(128); + KeyGenerator kg = KeyGenerator.getInstance(algName); + kg.init(keySize); SecretKey key = kg.generateKey(); KeyStore.SecretKeyEntry ske = new KeyStore.SecretKeyEntry(key); diff --git a/test/jdk/sun/security/pkcs12/ParamsPreferences.java b/test/jdk/sun/security/pkcs12/ParamsPreferences.java index 3c87e045120..06f066897d0 100644 --- a/test/jdk/sun/security/pkcs12/ParamsPreferences.java +++ b/test/jdk/sun/security/pkcs12/ParamsPreferences.java @@ -22,217 +22,247 @@ */ import jdk.test.lib.SecurityTools; -import sun.security.util.ObjectIdentifier; +import sun.security.util.KnownOIDs; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; import java.util.List; +import java.util.Map; import static jdk.test.lib.security.DerUtils.*; -import static sun.security.pkcs.ContentInfo.DATA_OID; -import static sun.security.pkcs.ContentInfo.ENCRYPTED_DATA_OID; -import sun.security.util.ObjectIdentifier; -import sun.security.util.KnownOIDs; +import static sun.security.util.KnownOIDs.*; /* * @test - * @bug 8076190 8242151 + * @bug 8076190 8242151 8153005 * @library /test/lib * @modules java.base/sun.security.pkcs * java.base/sun.security.util - * @summary Checks the preferences order of pkcs12 params + * @summary Checks the preferences order of pkcs12 params, whether it's + * a system property or a security property, whether the name has + * "pkcs12" or "PKCS12", whether the legacy property is set. */ public class ParamsPreferences { public static final void main(String[] args) throws Exception { int c = 0; - // with storepass - test(c++, "-", "-", - oid(KnownOIDs.PBEWithSHA1AndRC2_40), 50000, - oid(KnownOIDs.PBEWithSHA1AndDESede), 50000, - oid(KnownOIDs.SHA_1), 100000); + // default + test(c++, + Map.of(), + Map.of(), + PBES2, HmacSHA256, AES_256$CBC$NoPadding, 10000, + PBES2, HmacSHA256, AES_256$CBC$NoPadding, 10000, + SHA_256, 10000); + + // legacy settings + test(c++, + Map.of("keystore.pkcs12.legacy", ""), + Map.of(), + PBEWithSHA1AndRC2_40, 50000, + PBEWithSHA1AndDESede, 50000, + SHA_1, 100000); + + // legacy override everything else + test(c++, + Map.of("keystore.pkcs12.legacy", "", + "keystore.pkcs12.certProtectionAlgorithm", "PBEWithHmacSHA256AndAES_128", + "keystore.pkcs12.certPbeIterationCount", 3000, + "keystore.pkcs12.keyProtectionAlgorithm", "PBEWithHmacSHA256AndAES_128", + "keystore.pkcs12.keyPbeIterationCount", 4000, + "keystore.pkcs12.macAlgorithm", "HmacPBESHA384", + "keystore.pkcs12.macIterationCount", 2000), + Map.of(), + PBEWithSHA1AndRC2_40, 50000, + PBEWithSHA1AndDESede, 50000, + SHA_1, 100000); // password-less with system property - test(c++, "keystore.pkcs12.certProtectionAlgorithm", "NONE", - "keystore.pkcs12.macAlgorithm", "NONE", - "-", "-", - null, 0, - oid(KnownOIDs.PBEWithSHA1AndDESede), 50000, - null, 0); + test(c++, + Map.of("keystore.pkcs12.certProtectionAlgorithm", "NONE", + "keystore.pkcs12.macAlgorithm", "NONE"), + Map.of(), + null, + PBES2, HmacSHA256, AES_256$CBC$NoPadding, 10000, + null); // password-less with security property - test(c++, "-", - "keystore.pkcs12.certProtectionAlgorithm", "NONE", - "keystore.pkcs12.macAlgorithm", "NONE", - "-", - null, 0, - oid(KnownOIDs.PBEWithSHA1AndDESede), 50000, - null, 0); + test(c++, + Map.of(), + Map.of("keystore.pkcs12.certProtectionAlgorithm", "NONE", + "keystore.pkcs12.macAlgorithm", "NONE"), + null, + PBES2, HmacSHA256, AES_256$CBC$NoPadding, 10000, + null); // back to with storepass by overriding security property with system property - test(c++, "keystore.pkcs12.certProtectionAlgorithm", "PBEWithSHA1AndDESede", - "keystore.pkcs12.macAlgorithm", "HmacPBESHA256", - "-", - "keystore.pkcs12.certProtectionAlgorithm", "NONE", - "keystore.pkcs12.macAlgorithm", "NONE", - "-", - oid(KnownOIDs.PBEWithSHA1AndDESede), 50000, - oid(KnownOIDs.PBEWithSHA1AndDESede), 50000, - oid(KnownOIDs.SHA_256), 100000); + test(c++, + Map.of("keystore.pkcs12.certProtectionAlgorithm", "PBEWithSHA1AndDESede", + "keystore.pkcs12.macAlgorithm", "HmacPBESHA256"), + Map.of("keystore.pkcs12.certProtectionAlgorithm", "NONE", + "keystore.pkcs12.macAlgorithm", "NONE"), + PBEWithSHA1AndDESede, 10000, + PBES2, HmacSHA256, AES_256$CBC$NoPadding, 10000, + SHA_256, 10000); // back to with storepass by using "" to force hardcoded default - test(c++, "keystore.pkcs12.certProtectionAlgorithm", "", - "keystore.pkcs12.keyProtectionAlgorithm", "", - "keystore.pkcs12.macAlgorithm", "", - "-", - "keystore.pkcs12.certProtectionAlgorithm", "NONE", - "keystore.pkcs12.keyProtectionAlgorithm", "PBEWithSHA1AndRC2_40", - "keystore.pkcs12.macAlgorithm", "NONE", - "-", - oid(KnownOIDs.PBEWithSHA1AndRC2_40), 50000, - oid(KnownOIDs.PBEWithSHA1AndDESede), 50000, - oid(KnownOIDs.SHA_1), 100000); + test(c++, + Map.of("keystore.pkcs12.certProtectionAlgorithm", "", + "keystore.pkcs12.keyProtectionAlgorithm", "", + "keystore.pkcs12.macAlgorithm", ""), + Map.of("keystore.pkcs12.certProtectionAlgorithm", "NONE", + "keystore.pkcs12.keyProtectionAlgorithm", "PBEWithSHA1AndRC2_40", + "keystore.pkcs12.macAlgorithm", "NONE"), + PBES2, HmacSHA256, AES_256$CBC$NoPadding, 10000, + PBES2, HmacSHA256, AES_256$CBC$NoPadding, 10000, + SHA_256, 10000); // change everything with system property - test(c++, "keystore.pkcs12.certProtectionAlgorithm", "PBEWithSHA1AndDESede", - "keystore.pkcs12.certPbeIterationCount", 3000, - "keystore.pkcs12.keyProtectionAlgorithm", "PBEWithSHA1AndRC2_40", - "keystore.pkcs12.keyPbeIterationCount", 4000, - "keystore.pkcs12.macAlgorithm", "HmacPBESHA256", - "keystore.pkcs12.macIterationCount", 2000, - "-", "-", - oid(KnownOIDs.PBEWithSHA1AndDESede), 3000, - oid(KnownOIDs.PBEWithSHA1AndRC2_40), 4000, - oid(KnownOIDs.SHA_256), 2000); + test(c++, + Map.of("keystore.pkcs12.certProtectionAlgorithm", "PBEWithSHA1AndDESede", + "keystore.pkcs12.certPbeIterationCount", 3000, + "keystore.pkcs12.keyProtectionAlgorithm", "PBEWithSHA1AndRC2_40", + "keystore.pkcs12.keyPbeIterationCount", 4000, + "keystore.pkcs12.macAlgorithm", "HmacPBESHA256", + "keystore.pkcs12.macIterationCount", 2000), + Map.of(), + PBEWithSHA1AndDESede, 3000, + PBEWithSHA1AndRC2_40, 4000, + SHA_256, 2000); // change everything with security property - test(c++, "-", - "keystore.pkcs12.certProtectionAlgorithm", "PBEWithSHA1AndDESede", - "keystore.pkcs12.certPbeIterationCount", 3000, - "keystore.pkcs12.keyProtectionAlgorithm", "PBEWithSHA1AndRC2_40", - "keystore.pkcs12.keyPbeIterationCount", 4000, - "keystore.pkcs12.macAlgorithm", "HmacPBESHA256", - "keystore.pkcs12.macIterationCount", 2000, - "-", - oid(KnownOIDs.PBEWithSHA1AndDESede), 3000, - oid(KnownOIDs.PBEWithSHA1AndRC2_40), 4000, - oid(KnownOIDs.SHA_256), 2000); + test(c++, + Map.of(), + Map.of("keystore.pkcs12.certProtectionAlgorithm", "PBEWithSHA1AndDESede", + "keystore.pkcs12.certPbeIterationCount", 3000, + "keystore.pkcs12.keyProtectionAlgorithm", "PBEWithSHA1AndRC2_40", + "keystore.pkcs12.keyPbeIterationCount", 4000, + "keystore.pkcs12.macAlgorithm", "HmacPBESHA256", + "keystore.pkcs12.macIterationCount", 2000), + PBEWithSHA1AndDESede, 3000, + PBEWithSHA1AndRC2_40, 4000, + SHA_256, 2000); // override security property with system property - test(c++, "keystore.pkcs12.certProtectionAlgorithm", "PBEWithSHA1AndDESede", - "keystore.pkcs12.certPbeIterationCount", 13000, - "keystore.pkcs12.keyProtectionAlgorithm", "PBEWithSHA1AndRC2_40", - "keystore.pkcs12.keyPbeIterationCount", 14000, - "keystore.pkcs12.macAlgorithm", "HmacPBESHA256", - "keystore.pkcs12.macIterationCount", 12000, - "-", - "keystore.pkcs12.certProtectionAlgorithm", "PBEWithSHA1AndRC2_40", - "keystore.pkcs12.certPbeIterationCount", 3000, - "keystore.pkcs12.keyProtectionAlgorithm", "PBEWithSHA1AndDESede", - "keystore.pkcs12.keyPbeIterationCount", 4000, - "keystore.pkcs12.macAlgorithm", "HmacPBESHA1", - "keystore.pkcs12.macIterationCount", 2000, - "-", - oid(KnownOIDs.PBEWithSHA1AndDESede), 13000, - oid(KnownOIDs.PBEWithSHA1AndRC2_40), 14000, - oid(KnownOIDs.SHA_256), 12000); + test(c++, + Map.of("keystore.pkcs12.certProtectionAlgorithm", "PBEWithSHA1AndDESede", + "keystore.pkcs12.certPbeIterationCount", 13000, + "keystore.pkcs12.keyProtectionAlgorithm", "PBEWithSHA1AndRC2_40", + "keystore.pkcs12.keyPbeIterationCount", 14000, + "keystore.pkcs12.macAlgorithm", "HmacPBESHA256", + "keystore.pkcs12.macIterationCount", 12000), + Map.of("keystore.pkcs12.certProtectionAlgorithm", "PBEWithSHA1AndRC2_40", + "keystore.pkcs12.certPbeIterationCount", 3000, + "keystore.pkcs12.keyProtectionAlgorithm", "PBEWithSHA1AndDESede", + "keystore.pkcs12.keyPbeIterationCount", 4000, + "keystore.pkcs12.macAlgorithm", "HmacPBESHA1", + "keystore.pkcs12.macIterationCount", 2000), + PBEWithSHA1AndDESede, 13000, + PBEWithSHA1AndRC2_40, 14000, + SHA_256, 12000); // check keyProtectionAlgorithm old behavior. Preferences of // 4 different settings. - test(c++, "-", - "keystore.PKCS12.keyProtectionAlgorithm", "PBEWithSHA1AndRC2_128", - "-", - oid(KnownOIDs.PBEWithSHA1AndRC2_40), 50000, - oid(KnownOIDs.PBEWithSHA1AndRC2_128), 50000, - oid(KnownOIDs.SHA_1), 100000); - test(c++, "-", - "keystore.PKCS12.keyProtectionAlgorithm", "PBEWithSHA1AndRC2_128", - "keystore.pkcs12.keyProtectionAlgorithm", "PBEWithSHA1AndRC2_40", - "-", - oid(KnownOIDs.PBEWithSHA1AndRC2_40), 50000, - oid(KnownOIDs.PBEWithSHA1AndRC2_40), 50000, - oid(KnownOIDs.SHA_1), 100000); test(c++, - "keystore.PKCS12.keyProtectionAlgorithm", "PBEWithSHA1AndRC4_128", - "-", - "keystore.PKCS12.keyProtectionAlgorithm", "PBEWithSHA1AndRC2_128", - "keystore.pkcs12.keyProtectionAlgorithm", "PBEWithSHA1AndRC2_40", - "-", - oid(KnownOIDs.PBEWithSHA1AndRC2_40), 50000, - oid(KnownOIDs.PBEWithSHA1AndRC4_128), 50000, - oid(KnownOIDs.SHA_1), 100000); + Map.of(), + Map.of("keystore.PKCS12.keyProtectionAlgorithm", "PBEWithSHA1AndRC2_128"), + PBES2, HmacSHA256, AES_256$CBC$NoPadding, 10000, + PBEWithSHA1AndRC2_128, 10000, + SHA_256, 10000); test(c++, - "keystore.PKCS12.keyProtectionAlgorithm", "PBEWithSHA1AndRC4_128", - "keystore.pkcs12.keyProtectionAlgorithm", "PBEWithSHA1AndRC4_40", - "-", - "keystore.PKCS12.keyProtectionAlgorithm", "PBEWithSHA1AndRC2_128", - "keystore.pkcs12.keyProtectionAlgorithm", "PBEWithSHA1AndRC2_40", - "-", - oid(KnownOIDs.PBEWithSHA1AndRC2_40), 50000, - oid(KnownOIDs.PBEWithSHA1AndRC4_40), 50000, - oid(KnownOIDs.SHA_1), 100000); - } - - private static ObjectIdentifier oid(KnownOIDs o) { - return ObjectIdentifier.of(o); + Map.of(), + Map.of("keystore.PKCS12.keyProtectionAlgorithm", "PBEWithSHA1AndRC2_128", + "keystore.pkcs12.keyProtectionAlgorithm", "PBEWithSHA1AndRC2_40"), + PBES2, HmacSHA256, AES_256$CBC$NoPadding, 10000, + PBEWithSHA1AndRC2_40, 10000, + SHA_256, 10000); + test(c++, + Map.of("keystore.PKCS12.keyProtectionAlgorithm", "PBEWithSHA1AndRC4_128"), + Map.of("keystore.PKCS12.keyProtectionAlgorithm", "PBEWithSHA1AndRC2_128", + "keystore.pkcs12.keyProtectionAlgorithm", "PBEWithSHA1AndRC2_40"), + PBES2, HmacSHA256, AES_256$CBC$NoPadding, 10000, + PBEWithSHA1AndRC4_128, 10000, + SHA_256, 10000); + test(c++, + Map.of("keystore.PKCS12.keyProtectionAlgorithm", "PBEWithSHA1AndRC4_128", + "keystore.pkcs12.keyProtectionAlgorithm", "PBEWithSHA1AndRC4_40"), + Map.of("keystore.PKCS12.keyProtectionAlgorithm", "PBEWithSHA1AndRC2_128", + "keystore.pkcs12.keyProtectionAlgorithm", "PBEWithSHA1AndRC2_40"), + PBES2, HmacSHA256, AES_256$CBC$NoPadding, 10000, + PBEWithSHA1AndRC4_40, 10000, + SHA_256, 10000); } /** * Run once. * - * @param args an array containing system properties and values, "-", - * security properties and values, "-", expected certPbeAlg, - * certPbeIC, keyPbeAlg, keyPbeIc, macAlg, macIC. + * @param sysProps system properties + * @param secProps security properties + * @param args an array expected certPbeAlg (sub algs), certPbeIC, + * keyPbeAlg (sub algs), keyPbeIc, macAlg, macIC. */ - static void test(int n, Object... args) throws Exception { - boolean isSysProp = true; + static void test(int n, Map sysProps, + Map secProps, + Object... args) throws Exception { + String cmd = "-keystore ks" + n + " -genkeypair -keyalg EC " + "-alias a -dname CN=A -storepass changeit " + "-J-Djava.security.properties=" + n + ".conf"; + + for (var p : sysProps.entrySet()) { + cmd += " -J-D" + p.getKey() + "=" + p.getValue(); + } + List jsConf = new ArrayList<>(); - for (int i = 0; i < args.length; i++) { - if (isSysProp) { - if (args[i].equals("-")) { - isSysProp = false; - } else { - cmd += " -J-D" + args[i] + "=" + args[++i]; - } + for (var p : secProps.entrySet()) { + jsConf.add(p.getKey() + "=" + p.getValue()); + } + Files.write(Path.of(n + ".conf"), jsConf); + System.out.println("--------- test starts ----------"); + System.out.println(jsConf); + SecurityTools.keytool(cmd).shouldHaveExitValue(0); + + int i = 0; + byte[] data = Files.readAllBytes(Path.of("ks" + n)); + + // cert pbe alg + ic + KnownOIDs certAlg = (KnownOIDs)args[i++]; + if (certAlg == null) { + checkAlg(data, "110c10", Data); + } else { + checkAlg(data, "110c10", EncryptedData); + checkAlg(data, "110c110110", certAlg); + if (certAlg == PBES2) { + checkAlg(data, "110c11011100", PBKDF2WithHmacSHA1); + checkAlg(data, "110c1101110130", args[i++]); + checkAlg(data, "110c11011110", args[i++]); + checkInt(data, "110c110111011", (int) args[i++]); } else { - if (args[i] == "-") { - Files.write(Path.of(n + ".conf"), jsConf); - System.out.println("--------- test starts ----------"); - System.out.println(jsConf); - SecurityTools.keytool(cmd).shouldHaveExitValue(0); - - byte[] data = Files.readAllBytes(Path.of("ks" + n)); - - // cert pbe alg + ic - if (args[i+1] == null) { - checkAlg(data, "110c10", DATA_OID); - } else { - checkAlg(data, "110c10", ENCRYPTED_DATA_OID); - checkAlg(data, "110c110110", (ObjectIdentifier)args[i+1]); - checkInt(data, "110c1101111", (int)args[i+2]); - } - - // key pbe alg + ic - checkAlg(data, "110c010c01000", (ObjectIdentifier)args[i+3]); - checkInt(data, "110c010c010011", (int)args[i+4]); - - // mac alg + ic - if (args[i+5] == null) { - shouldNotExist(data, "2"); - } else { - checkAlg(data, "2000", (ObjectIdentifier)args[i+5]); - checkInt(data, "22", (int)args[i+6]); - } - } else { - jsConf.add(args[i] + "=" + args[++i]); - } + checkInt(data, "110c1101111", (int) args[i++]); } } + + // key pbe alg + ic + KnownOIDs keyAlg = (KnownOIDs)args[i++]; + checkAlg(data, "110c010c01000", keyAlg); + if (keyAlg == PBES2) { + checkAlg(data, "110c010c0100100", PBKDF2WithHmacSHA1); + checkAlg(data, "110c010c010010130", args[i++]); + checkAlg(data, "110c010c0100110", args[i++]); + checkInt(data, "110c010c01001011", (int) args[i++]); + } else { + checkInt(data, "110c010c010011", (int) args[i++]); + } + + // mac alg + ic + KnownOIDs macAlg = (KnownOIDs)args[i++]; + if (macAlg == null) { + shouldNotExist(data, "2"); + } else { + checkAlg(data, "2000", macAlg); + checkInt(data, "22", (int) args[i++]); + } } } diff --git a/test/jdk/sun/security/pkcs12/ParamsTest.java b/test/jdk/sun/security/pkcs12/ParamsTest.java index 54910f47cb6..d292a7e563e 100644 --- a/test/jdk/sun/security/pkcs12/ParamsTest.java +++ b/test/jdk/sun/security/pkcs12/ParamsTest.java @@ -23,7 +23,7 @@ /* * @test - * @bug 8076190 8242151 + * @bug 8076190 8242151 8153005 * @library /test/lib * @modules java.base/sun.security.pkcs * java.base/sun.security.util @@ -41,6 +41,7 @@ import java.io.InputStream; import java.io.OutputStream; import java.io.UncheckedIOException; +import java.nio.file.DirectoryStream; import java.nio.file.Files; import java.nio.file.Path; import java.security.KeyStore; @@ -48,8 +49,7 @@ import java.util.Objects; import static jdk.test.lib.security.DerUtils.*; -import sun.security.util.ObjectIdentifier; -import sun.security.util.KnownOIDs; +import static sun.security.util.KnownOIDs.*; import static sun.security.pkcs.ContentInfo.*; public class ParamsTest { @@ -57,15 +57,18 @@ public class ParamsTest { public static void main(String[] args) throws Throwable { // De-BASE64 textual files in ./params to `pwd` - Files.newDirectoryStream(Path.of(System.getProperty("test.src"), "params")) - .forEach(p -> { - try (InputStream is = Files.newInputStream(p); - OutputStream os = Files.newOutputStream(p.getFileName())){ - Base64.getMimeDecoder().wrap(is).transferTo(os); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - }); + try (DirectoryStream stream = Files.newDirectoryStream( + Path.of(System.getProperty("test.src"), "params"), + p -> !p.getFileName().toString().equals("README"))) { + stream.forEach(p -> { + try (InputStream is = Files.newInputStream(p); + OutputStream os = Files.newOutputStream(p.getFileName())) { + Base64.getMimeDecoder().wrap(is).transferTo(os); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + }); + } byte[] data; @@ -100,34 +103,44 @@ public static void main(String[] args) throws Throwable { // Current default pkcs12 setting keytool("-importkeystore -srckeystore ks -srcstorepass changeit " + "-destkeystore ksnormal -deststorepass changeit"); + data = Files.readAllBytes(Path.of("ksnormal")); - checkInt(data, "22", 100000); // Mac ic - checkAlg(data, "2000", oid(KnownOIDs.SHA_1)); // Mac alg - checkAlg(data, "110c010c01000", oid(KnownOIDs.PBEWithSHA1AndDESede)); // key alg - checkInt(data, "110c010c010011", 50000); // key ic + checkInt(data, "22", 10000); // Mac ic + checkAlg(data, "2000", SHA_256); // Mac alg + checkAlg(data, "110c010c01000", PBES2); // key alg + checkInt(data, "110c010c01001011", 10000); // key ic checkAlg(data, "110c10", ENCRYPTED_DATA_OID); - checkAlg(data, "110c110110", oid(KnownOIDs.PBEWithSHA1AndRC2_40)); // cert alg - checkInt(data, "110c1101111", 50000); // cert ic - + checkAlg(data, "110c110110", PBES2); // cert alg check("ksnormal", "a", "changeit", "changeit", true, true, true); check("ksnormal", "a", null, "changeit", true, false, true); check("ksnormal", "a", "wrongpass", "-", IOException.class, "-", "-"); + // Import it into a new keystore with legacy algorithms + keytool("-importkeystore -srckeystore ksnormal -srcstorepass changeit " + + "-destkeystore kslegacyimp -deststorepass changeit " + + "-J-Dkeystore.pkcs12.legacy"); + data = Files.readAllBytes(Path.of("kslegacyimp")); + checkInt(data, "22", 100000); // Mac ic + checkAlg(data, "2000", SHA_1); // Mac alg + checkAlg(data, "110c010c01000", PBEWithSHA1AndDESede); // key alg + checkInt(data, "110c010c010011", 50000); // key ic + checkAlg(data, "110c110110", PBEWithSHA1AndRC2_40); // cert alg + checkInt(data, "110c1101111", 50000); // cert ic + // Add a new entry with password-less settings, still has a storepass keytool("-keystore ksnormal -genkeypair -keyalg DSA " + "-storepass changeit -alias b -dname CN=b " + "-J-Dkeystore.pkcs12.certProtectionAlgorithm=NONE " + "-J-Dkeystore.pkcs12.macAlgorithm=NONE"); data = Files.readAllBytes(Path.of("ksnormal")); - checkInt(data, "22", 100000); // Mac ic - checkAlg(data, "2000", oid(KnownOIDs.SHA_1)); // Mac alg - checkAlg(data, "110c010c01000", oid(KnownOIDs.PBEWithSHA1AndDESede)); // key alg - checkInt(data, "110c010c010011", 50000); // key ic - checkAlg(data, "110c010c11000", oid(KnownOIDs.PBEWithSHA1AndDESede)); // new key alg - checkInt(data, "110c010c110011", 50000); // new key ic + checkInt(data, "22", 10000); // Mac ic + checkAlg(data, "2000", SHA_256); // Mac alg + checkAlg(data, "110c010c01000", PBES2); // key alg + checkInt(data, "110c010c01001011", 10000); // key ic + checkAlg(data, "110c010c11000", PBES2); // new key alg + checkInt(data, "110c010c11001011", 10000); // new key ic checkAlg(data, "110c10", ENCRYPTED_DATA_OID); - checkAlg(data, "110c110110", oid(KnownOIDs.PBEWithSHA1AndRC2_40)); // cert alg - checkInt(data, "110c1101111", 50000); // cert ic + checkAlg(data, "110c110110", PBES2); // cert alg check("ksnormal", "b", null, "changeit", true, false, true); check("ksnormal", "b", "changeit", "changeit", true, true, true); @@ -139,8 +152,8 @@ public static void main(String[] args) throws Throwable { + "-J-Dkeystore.pkcs12.macAlgorithm=NONE"); data = Files.readAllBytes(Path.of("ksnopass")); shouldNotExist(data, "2"); // no Mac - checkAlg(data, "110c010c01000", oid(KnownOIDs.PBEWithSHA1AndRC4_128)); - checkInt(data, "110c010c010011", 50000); + checkAlg(data, "110c010c01000", PBEWithSHA1AndRC4_128); + checkInt(data, "110c010c010011", 10000); checkAlg(data, "110c10", DATA_OID); check("ksnopass", "a", null, "changeit", true, true, true); check("ksnopass", "a", "changeit", "changeit", true, true, true); @@ -151,10 +164,10 @@ public static void main(String[] args) throws Throwable { + "-storepass changeit -alias b -dname CN=B"); data = Files.readAllBytes(Path.of("ksnopass")); shouldNotExist(data, "2"); // no Mac - checkAlg(data, "110c010c01000", oid(KnownOIDs.PBEWithSHA1AndRC4_128)); - checkInt(data, "110c010c010011", 50000); - checkAlg(data, "110c010c11000", oid(KnownOIDs.PBEWithSHA1AndDESede)); - checkInt(data, "110c010c110011", 50000); + checkAlg(data, "110c010c01000", PBEWithSHA1AndRC4_128); + checkInt(data, "110c010c010011", 10000); + checkAlg(data, "110c010c11000", PBES2); + checkInt(data, "110c010c11001011", 10000); checkAlg(data, "110c10", DATA_OID); check("ksnopass", "a", null, "changeit", true, true, true); check("ksnopass", "b", null, "changeit", true, true, true); @@ -166,11 +179,11 @@ public static void main(String[] args) throws Throwable { + "-J-Dkeystore.pkcs12.keyPbeIterationCount=7777"); data = Files.readAllBytes(Path.of("ksnewic")); checkInt(data, "22", 5555); // Mac ic - checkAlg(data, "2000", oid(KnownOIDs.SHA_1)); // Mac alg - checkAlg(data, "110c010c01000", oid(KnownOIDs.PBEWithSHA1AndDESede)); // key alg - checkInt(data, "110c010c010011", 7777); // key ic - checkAlg(data, "110c110110", oid(KnownOIDs.PBEWithSHA1AndRC2_40)); // cert alg - checkInt(data, "110c1101111", 6666); // cert ic + checkAlg(data, "2000", SHA_256); // Mac alg + checkAlg(data, "110c010c01000", PBES2); // key alg + checkInt(data, "110c010c01001011", 7777); // key ic + checkAlg(data, "110c110110", PBES2); // cert alg + checkInt(data, "110c110111011", 6666); // cert ic // keypbe alg cannot be NONE keytool("-keystore ksnewic -genkeypair -keyalg DSA " @@ -185,13 +198,13 @@ public static void main(String[] args) throws Throwable { + "-J-Dkeystore.pkcs12.keyProtectionAlgorithm=PBEWithSHA1AndRC4_128"); data = Files.readAllBytes(Path.of("ksnewic")); checkInt(data, "22", 5555); // Mac ic - checkAlg(data, "2000", oid(KnownOIDs.SHA_1)); // Mac alg - checkAlg(data, "110c010c01000", oid(KnownOIDs.PBEWithSHA1AndDESede)); // key alg - checkInt(data, "110c010c010011", 7777); // key ic - checkAlg(data, "110c010c11000", oid(KnownOIDs.PBEWithSHA1AndRC4_128)); // new key alg - checkInt(data, "110c010c110011", 50000); // new key ic - checkAlg(data, "110c110110", oid(KnownOIDs.PBEWithSHA1AndRC2_40)); // cert alg - checkInt(data, "110c1101111", 6666); // cert ic + checkAlg(data, "2000", SHA_256); // Mac alg + checkAlg(data, "110c010c01000", PBES2); // key alg + checkInt(data, "110c010c01001011", 7777); // key ic + checkAlg(data, "110c010c11000", PBEWithSHA1AndRC4_128); // new key alg + checkInt(data, "110c010c110011", 10000); // new key ic + checkAlg(data, "110c110110", PBES2); // cert alg + checkInt(data, "110c110111011", 6666); // cert ic // Check KeyStore loading multiple keystores KeyStore ks = KeyStore.getInstance("pkcs12"); @@ -201,15 +214,15 @@ public static void main(String[] args) throws Throwable { ks.store(fos, "changeit".toCharArray()); } data = Files.readAllBytes(Path.of("ksnormaldup")); - checkInt(data, "22", 100000); // Mac ic - checkAlg(data, "2000", oid(KnownOIDs.SHA_1)); // Mac alg - checkAlg(data, "110c010c01000", oid(KnownOIDs.PBEWithSHA1AndDESede)); // key alg - checkInt(data, "110c010c010011", 50000); // key ic - checkAlg(data, "110c010c11000", oid(KnownOIDs.PBEWithSHA1AndDESede)); // new key alg - checkInt(data, "110c010c110011", 50000); // new key ic + checkInt(data, "22", 10000); // Mac ic + checkAlg(data, "2000", SHA_256); // Mac alg + checkAlg(data, "110c010c01000", PBES2); // key alg + checkInt(data, "110c010c01001011", 10000); // key ic + checkAlg(data, "110c010c11000", PBES2); // new key alg + checkInt(data, "110c010c11001011", 10000); // new key ic checkAlg(data, "110c10", ENCRYPTED_DATA_OID); - checkAlg(data, "110c110110", oid(KnownOIDs.PBEWithSHA1AndRC2_40)); // cert alg - checkInt(data, "110c1101111", 50000); // cert ic + checkAlg(data, "110c110110", PBES2); // cert alg + checkInt(data, "110c110111011", 10000); // cert ic try (FileInputStream fis = new FileInputStream("ksnopass"); FileOutputStream fos = new FileOutputStream("ksnopassdup")) { @@ -218,10 +231,10 @@ public static void main(String[] args) throws Throwable { } data = Files.readAllBytes(Path.of("ksnopassdup")); shouldNotExist(data, "2"); // no Mac - checkAlg(data, "110c010c01000", oid(KnownOIDs.PBEWithSHA1AndRC4_128)); - checkInt(data, "110c010c010011", 50000); - checkAlg(data, "110c010c11000", oid(KnownOIDs.PBEWithSHA1AndDESede)); - checkInt(data, "110c010c110011", 50000); + checkAlg(data, "110c010c01000", PBEWithSHA1AndRC4_128); + checkInt(data, "110c010c010011", 10000); + checkAlg(data, "110c010c11000", PBES2); + checkInt(data, "110c010c11001011", 10000); checkAlg(data, "110c10", DATA_OID); try (FileInputStream fis = new FileInputStream("ksnewic"); @@ -231,13 +244,13 @@ public static void main(String[] args) throws Throwable { } data = Files.readAllBytes(Path.of("ksnewicdup")); checkInt(data, "22", 5555); // Mac ic - checkAlg(data, "2000", oid(KnownOIDs.SHA_1)); // Mac alg - checkAlg(data, "110c010c01000", oid(KnownOIDs.PBEWithSHA1AndDESede)); // key alg - checkInt(data, "110c010c010011", 7777); // key ic - checkAlg(data, "110c010c11000", oid(KnownOIDs.PBEWithSHA1AndRC4_128)); // new key alg - checkInt(data, "110c010c110011", 50000); // new key ic - checkAlg(data, "110c110110", oid(KnownOIDs.PBEWithSHA1AndRC2_40)); // cert alg - checkInt(data, "110c1101111", 6666); // cert ic + checkAlg(data, "2000", SHA_256); // Mac alg + checkAlg(data, "110c010c01000", PBES2); // key alg + checkInt(data, "110c010c01001011", 7777); // key ic + checkAlg(data, "110c010c11000", PBEWithSHA1AndRC4_128); // new key alg + checkInt(data, "110c010c110011", 10000); // new key ic + checkAlg(data, "110c110110", PBES2); // cert alg + checkInt(data, "110c110111011", 6666); // cert ic // Check keytool behavior @@ -434,10 +447,6 @@ private static void check( Asserts.assertEQ(expectedKey, actualKey, label + "-key"); } - private static ObjectIdentifier oid(KnownOIDs o) { - return ObjectIdentifier.of(o); - } - static OutputAnalyzer keytool(String s) throws Throwable { return SecurityTools.keytool(s); } diff --git a/test/jdk/sun/security/pkcs12/params/README b/test/jdk/sun/security/pkcs12/params/README index 0fcd17d7c05..eca9e1b8d8a 100644 --- a/test/jdk/sun/security/pkcs12/params/README +++ b/test/jdk/sun/security/pkcs12/params/README @@ -1,8 +1,10 @@ 1. Preparing data in this directory +Do not use OpenSSL 3.0.0. The default algorithms for pkcs12 are changed. +( mkdir tmp cd tmp -keytool -keystore ks -genkeypair -storepass changeit -alias a -dname CN=A +keytool -keystore ks -keyalg ec -genkeypair -storepass changeit -alias a -dname CN=A openssl pkcs12 -in ks -nodes -out kandc -passin pass:changeit openssl pkcs12 -export -in kandc -out os2 -name a -passout pass:changeit \ -certpbe NONE -nomac @@ -17,37 +19,38 @@ for a in *; do done cd .. rm -rf tmp +) 2. After running the test, we can go to the scratch directory and run the following commands to check keytool -> openssl interoperability. OpenSSL 1.1.0i is used here. Earlier versions might generate different info. ( -openssl pkcs12 -in ks2 -passin pass:changeit -info -nokeys -nocerts 2> t2 || exit 20 -grep "MAC:sha1 Iteration 100000" t2 || exit 21 -grep "Shrouded Keybag: pbeWithSHA1And3-KeyTripleDES-CBC, Iteration 50000" t2 || exit 23 -grep "PKCS7 Encrypted data: pbeWithSHA1And40BitRC2-CBC, Iteration 50000" t2 || exit 24 +openssl pkcs12 -in ksnormal -passin pass:changeit -info -nokeys -nocerts 2> t2 || exit 20 +grep "MAC: sha256, Iteration 10000" t2 || exit 21 +grep "Shrouded Keybag: PBES2, PBKDF2, AES-256-CBC, Iteration 10000, PRF hmacWithSHA256" t2 || exit 23 +grep "PKCS7 Encrypted data: PBES2, PBKDF2, AES-256-CBC, Iteration 10000, PRF hmacWithSHA256" t2 || exit 24 -openssl pkcs12 -in ks22 -passin pass:changeit -info -nokeys -nocerts 2> t22 || exit 25 +openssl pkcs12 -in ksnormaldup -passin pass:changeit -info -nokeys -nocerts 2> t22 || exit 25 diff t2 t22 || exit 26 -openssl pkcs12 -in ks3 -passin pass:changeit -info -nokeys -nocerts && exit 30 +openssl pkcs12 -in ksnopass -passin pass:changeit -info -nokeys -nocerts && exit 30 -openssl pkcs12 -in ks3 -passin pass:changeit -info -nokeys -nocerts -nomacver 2> t3 || exit 31 +openssl pkcs12 -in ksnopass -passin pass:changeit -info -nokeys -nocerts -nomacver 2> t3 || exit 31 grep "PKCS7 Encrypted data:" t3 && exit 33 -grep "Shrouded Keybag: pbeWithSHA1And3-KeyTripleDES-CBC, Iteration 50000" t3 || exit 34 -grep "Shrouded Keybag: pbeWithSHA1And128BitRC4, Iteration 50000" t3 || exit 35 +grep "Shrouded Keybag: PBES2, PBKDF2, AES-256-CBC, Iteration 10000, PRF hmacWithSHA256" t3 || exit 34 +grep "Shrouded Keybag: pbeWithSHA1And128BitRC4, Iteration 10000" t3 || exit 35 -openssl pkcs12 -in ks33 -passin pass:changeit -info -nokeys -nocerts -nomacver 2> t33 || exit 36 +openssl pkcs12 -in ksnopassdup -passin pass:changeit -info -nokeys -nocerts -nomacver 2> t33 || exit 36 diff t3 t33 || exit 37 -openssl pkcs12 -in ks4 -passin pass:changeit -info -nokeys -nocerts 2> t4 || exit 40 -grep "MAC:sha1 Iteration 5555" t4 || exit 41 -grep "Shrouded Keybag: pbeWithSHA1And3-KeyTripleDES-CBC, Iteration 7777" t4 || exit 43 -grep "Shrouded Keybag: pbeWithSHA1And128BitRC4, Iteration 50000" t4 || exit 44 -grep "PKCS7 Encrypted data: pbeWithSHA1And40BitRC2-CBC, Iteration 6666" t4 || exit 45 +openssl pkcs12 -in ksnewic -passin pass:changeit -info -nokeys -nocerts 2> t4 || exit 40 +grep "MAC: sha256, Iteration 5555" t4 || exit 41 +grep "Shrouded Keybag: PBES2, PBKDF2, AES-256-CBC, Iteration 7777, PRF hmacWithSHA256" t4 || exit 43 +grep "Shrouded Keybag: pbeWithSHA1And128BitRC4, Iteration 10000" t4 || exit 44 +grep "PKCS7 Encrypted data: PBES2, PBKDF2, AES-256-CBC, Iteration 6666, PRF hmacWithSHA256" t4 || exit 45 -openssl pkcs12 -in ks44 -passin pass:changeit -info -nokeys -nocerts 2> t44 || exit 46 +openssl pkcs12 -in ksnewicdup -passin pass:changeit -info -nokeys -nocerts 2> t44 || exit 46 diff t4 t44 || exit 47 echo Succeed diff --git a/test/jdk/sun/security/tools/keytool/GenerateAll.java b/test/jdk/sun/security/tools/keytool/GenerateAll.java index 84fbd0e0d5d..4efc3b0ebc6 100644 --- a/test/jdk/sun/security/tools/keytool/GenerateAll.java +++ b/test/jdk/sun/security/tools/keytool/GenerateAll.java @@ -108,10 +108,9 @@ public void eddsaTest(String keyAlg, String sigAlg, String expected) oa.shouldHaveExitValue(0); kt("-alias " + alias + " -export -file " + alias + ".crt"); byte[] crt = Files.readAllBytes(Path.of(alias + ".crt")); - ObjectIdentifier oid = oid(expected); - DerUtils.checkAlg(crt, "020", oid); // tbsCertificate.signature - DerUtils.checkAlg(crt, "0600", oid); // tbsCertificate.subjectPublicKeyInfo.algorithm - DerUtils.checkAlg(crt, "10", oid); // signatureAlgorithm + DerUtils.checkAlg(crt, "020", expected); // tbsCertificate.signature + DerUtils.checkAlg(crt, "0600", expected); // tbsCertificate.subjectPublicKeyInfo.algorithm + DerUtils.checkAlg(crt, "10", expected); // signatureAlgorithm } } @@ -179,18 +178,18 @@ public void test(String alias, String keyAlg, String sigAlg, String ext, } byte[] crt = read(alias + ".self"); - DerUtils.checkAlg(crt, "020", oid(sigAlg)); // tbsCertificate.signature - DerUtils.checkAlg(crt, "0600", oid(keyAlg)); // tbsCertificate.subjectPublicKeyInfo.algorithm + DerUtils.checkAlg(crt, "020", sigAlg); // tbsCertificate.signature + DerUtils.checkAlg(crt, "0600", keyAlg); // tbsCertificate.subjectPublicKeyInfo.algorithm assertEquals( DerUtils.innerDerValue(crt, "02"), // tbsCertificate.signature DerUtils.innerDerValue(crt, "1")); // signatureAlgorithm byte[] req = read(alias + ".req"); - DerUtils.checkAlg(req, "10", oid(sigAlg)); // signatureAlgorithm - DerUtils.checkAlg(req, "0200", oid(keyAlg)); // certificationRequestInfo.subjectPKInfo.algorithm + DerUtils.checkAlg(req, "10", sigAlg); // signatureAlgorithm + DerUtils.checkAlg(req, "0200", keyAlg); // certificationRequestInfo.subjectPKInfo.algorithm byte[] crl = read(alias + ".crl"); - DerUtils.checkAlg(crl, "000", oid(sigAlg)); // tbsCertList.signature + DerUtils.checkAlg(crl, "000", sigAlg); // tbsCertList.signature assertEquals( DerUtils.innerDerValue(crl, "00"), // tbsCertList.signature DerUtils.innerDerValue(crl, "1")); // signatureAlgorithm @@ -200,13 +199,13 @@ public void test(String alias, String keyAlg, String sigAlg, String ext, "META-INF/" + alias.toUpperCase() + "." + ext); byte[] p7 = jf.getInputStream(je).readAllBytes(); // SignerInfo.digestAlgorithm - DerUtils.checkAlg(p7, "104020", oid(expDigAlg)); + DerUtils.checkAlg(p7, "104020", expDigAlg); // SignerInfo.signatureAlgorithm if (DerUtils.innerDerValue(p7, "10403").isContextSpecific()) { // SignerInfo has signedAttributes at 104030 - DerUtils.checkAlg(p7, "104040", oid(expEncAlg)); + DerUtils.checkAlg(p7, "104040", expEncAlg); } else { - DerUtils.checkAlg(p7, "104030", oid(expEncAlg)); + DerUtils.checkAlg(p7, "104030", expEncAlg); } } } @@ -216,14 +215,6 @@ public void afterTest() throws Exception { js("-verify a.jar -verbose -certs"); } - static ObjectIdentifier oid(String name) { - return ObjectIdentifier.of(KnownOIDs.findMatch(name)); - } - - static ObjectIdentifier oid(KnownOIDs ko) { - return ObjectIdentifier.of(ko); - } - static byte[] read(String f) throws IOException { try (var v = Files.lines(Path.of(f))) { return Base64.getDecoder().decode(v.filter(s -> !s.startsWith("-----")) diff --git a/test/jdk/sun/security/util/DerValue/Indefinite.java b/test/jdk/sun/security/util/DerValue/Indefinite.java index 17270c6642f..989ad4abe02 100644 --- a/test/jdk/sun/security/util/DerValue/Indefinite.java +++ b/test/jdk/sun/security/util/DerValue/Indefinite.java @@ -25,7 +25,7 @@ * @test * @bug 6731685 8249783 * @summary CertificateFactory.generateCertificates throws IOException on PKCS7 cert chain - * @modules java.base/sun.security.util + * @modules java.base/sun.security.util:+open * @library /test/lib */ @@ -35,7 +35,6 @@ import jdk.test.lib.Asserts; import jdk.test.lib.Utils; -import jdk.test.lib.hexdump.HexPrinter; import sun.security.util.*; public class Indefinite { diff --git a/test/jtreg-ext/requires/VMProps.java b/test/jtreg-ext/requires/VMProps.java index 1c58ec654cb..7dae9191b01 100644 --- a/test/jtreg-ext/requires/VMProps.java +++ b/test/jtreg-ext/requires/VMProps.java @@ -118,6 +118,7 @@ public Map call() { map.put("vm.musl", this::isMusl); map.put("release.implementor", this::implementor); map.put("test.vm.gc.nvdimm", this::isNvdimmTestEnabled); + map.put("jdk.containerized", this::jdkContainerized); vmGC(map); // vm.gc.X = true/false vmOptFinalFlags(map); @@ -545,6 +546,11 @@ private String isNvdimmTestEnabled() { return "" + "true".equalsIgnoreCase(isEnabled); } + private String jdkContainerized() { + String isEnabled = System.getenv("TEST_JDK_CONTAINERIZED"); + return "" + "true".equalsIgnoreCase(isEnabled); + } + /** * Dumps the map to the file if the file name is given as the property. * This functionality could be helpful to know context in the real diff --git a/test/langtools/jdk/javadoc/doclet/testRecordLinks/TestRecordLinks.java b/test/langtools/jdk/javadoc/doclet/testRecordLinks/TestRecordLinks.java index 706ec613f04..d35298134b9 100644 --- a/test/langtools/jdk/javadoc/doclet/testRecordLinks/TestRecordLinks.java +++ b/test/langtools/jdk/javadoc/doclet/testRecordLinks/TestRecordLinks.java @@ -23,12 +23,11 @@ /* * @test - * @bug 8236539 + * @bug 8236539 8246774 * @summary Relative link tags in record javadoc don't resolve * @library /tools/lib ../../lib * @modules jdk.javadoc/jdk.javadoc.internal.tool * @build toolbox.ToolBox javadoc.tester.* - * @compile TestRecordLinks.java * @run main TestRecordLinks */ @@ -74,7 +73,6 @@ public void bar() { } javadoc("-d", base.resolve("out").toString(), "-sourcepath", src.toString(), - "--enable-preview", "--source", thisRelease, "example"); checkExit(Exit.OK); diff --git a/test/langtools/jdk/javadoc/doclet/testRecordTypes/TestRecordTypes.java b/test/langtools/jdk/javadoc/doclet/testRecordTypes/TestRecordTypes.java index 830bee551d7..2390eb8b383 100644 --- a/test/langtools/jdk/javadoc/doclet/testRecordTypes/TestRecordTypes.java +++ b/test/langtools/jdk/javadoc/doclet/testRecordTypes/TestRecordTypes.java @@ -23,13 +23,12 @@ /* * @test - * @bug 8225055 8239804 + * @bug 8225055 8239804 8246774 * @summary Record types * @library /tools/lib ../../lib * @modules jdk.javadoc/jdk.javadoc.internal.tool * @build toolbox.ToolBox javadoc.tester.* - * @compile --enable-preview --source ${jdk.version} TestRecordTypes.java - * @run main/othervm --enable-preview TestRecordTypes + * @run main TestRecordTypes */ @@ -69,7 +68,6 @@ public void testRecordKeywordUnnamedPackage(Path base) throws IOException { javadoc("-d", base.resolve("out").toString(), "-quiet", "-noindex", "-sourcepath", src.toString(), - "--enable-preview", "--source", thisRelease, src.resolve("R.java").toString()); checkExit(Exit.OK); @@ -91,7 +89,6 @@ public void testRecordKeywordNamedPackage(Path base) throws IOException { javadoc("-d", base.resolve("out").toString(), "-quiet", "-noindex", "-sourcepath", src.toString(), - "--enable-preview", "--source", thisRelease, "p"); checkExit(Exit.OK); @@ -113,7 +110,6 @@ public void testEmptyRecord(Path base) throws IOException { javadoc("-d", base.resolve("out").toString(), "-quiet", "-noindex", "-sourcepath", src.toString(), - "--enable-preview", "--source", thisRelease, "p"); checkExit(Exit.OK); @@ -139,7 +135,6 @@ public record R(int r1) { }"""); javadoc("-d", base.resolve("out").toString(), "-quiet", "-noindex", "-sourcepath", src.toString(), - "--enable-preview", "--source", thisRelease, "p"); checkExit(Exit.OK); @@ -171,7 +166,6 @@ public record R(int r1) { }"""); javadoc("-d", base.resolve("out").toString(), "-quiet", "-noindex", "-sourcepath", src.toString(), - "--enable-preview", "--source", thisRelease, "p"); checkExit(Exit.OK); @@ -204,7 +198,6 @@ public record R(int r1) { }"""); javadoc("-d", base.resolve("out").toString(), "-quiet", "-noindex", "-sourcepath", src.toString(), - "--enable-preview", "--source", thisRelease, "p"); checkExit(Exit.OK); @@ -268,7 +261,6 @@ public record R(int r1) { }"""); "-quiet", "-noindex", "-sourcepath", src.toString(), "-linkoffline", externalDocs, localDocs, - "--enable-preview", "--source", thisRelease, "p"); checkExit(Exit.OK); @@ -349,7 +341,6 @@ public record R(""" + comps + ") { }"); "-quiet", "-noindex", "--no-platform-links", "-sourcepath", src.toString(), - "--enable-preview", "--source", thisRelease, "p"); checkExit(Exit.OK); @@ -375,7 +366,6 @@ public record R(int r1) { javadoc("-d", base.resolve("out").toString(), "-quiet", "-noindex", "-sourcepath", src.toString(), - "--enable-preview", "--source", thisRelease, "p"); checkExit(Exit.OK); @@ -406,7 +396,6 @@ public void testExamples(Path base) throws IOException { "-quiet", "-noindex", "-sourcepath", testSrc.toString(), "-linksource", - "--enable-preview", "--source", thisRelease, "examples"); checkExit(Exit.OK); @@ -415,13 +404,11 @@ public void testExamples(Path base) throws IOException { "-sourcepath", testSrc.toString(), "-linksource", "-linkoffline", externalDocs, localDocs, - "--enable-preview", "--source", thisRelease, "examples"); checkExit(Exit.OK); } @Test - @SuppressWarnings("preview") public void testAnnotations(Path base) throws IOException { ElementType[] types = { ElementType.FIELD, @@ -468,7 +455,6 @@ void testAnnotations(Path base, Set types) throws IOException { "--no-platform-links", "-sourcepath", src.toString(), "-private", - "--enable-preview", "--source", thisRelease, "p"); checkExit(Exit.OK); diff --git a/test/langtools/jdk/javadoc/tool/api/basic/GetTask_DiagListenerTest.java b/test/langtools/jdk/javadoc/tool/api/basic/GetTask_DiagListenerTest.java index bbead5a206f..8e51bdbc50e 100644 --- a/test/langtools/jdk/javadoc/tool/api/basic/GetTask_DiagListenerTest.java +++ b/test/langtools/jdk/javadoc/tool/api/basic/GetTask_DiagListenerTest.java @@ -23,7 +23,7 @@ /* * @test - * @bug 6493690 + * @bug 6493690 8246774 * @summary javadoc should have a javax.tools.Tool service provider * @modules java.compiler * jdk.compiler @@ -78,7 +78,7 @@ public void testDiagListener() throws Exception { } List expect = Arrays.asList( "javadoc.note.msg", // Loading source file - "compiler.err.expected3", // class, interface, enum, or __datum expected + "compiler.err.expected4", // class, interface, enum, or record expected "javadoc.note.msg"); // 1 error if (!diagCodes.equals(expect)) throw new Exception("unexpected diagnostics occurred"); diff --git a/test/langtools/jdk/jshell/CompletenessTest.java b/test/langtools/jdk/jshell/CompletenessTest.java index 6ff4ce4d55a..97e165abb7a 100644 --- a/test/langtools/jdk/jshell/CompletenessTest.java +++ b/test/langtools/jdk/jshell/CompletenessTest.java @@ -23,7 +23,7 @@ /* * @test - * @bug 8149524 8131024 8165211 8080071 8130454 8167343 8129559 8114842 8182268 8223782 8235474 + * @bug 8149524 8131024 8165211 8080071 8130454 8167343 8129559 8114842 8182268 8223782 8235474 8246774 * @summary Test SourceCodeAnalysis * @build KullaTesting TestingInputStream * @run testng CompletenessTest @@ -379,10 +379,4 @@ public void testMiscSource() { assertStatus("int[] m = {1, 2}, n = new int[0]; int i;", COMPLETE, "int[] m = {1, 2}, n = new int[0];"); } - - @BeforeMethod - public void setUp() { - setUp(b -> b.compilerOptions("--enable-preview", "-source", String.valueOf(SourceVersion.latest().ordinal()))); - } - } diff --git a/test/langtools/jdk/jshell/RecordsTest.java b/test/langtools/jdk/jshell/RecordsTest.java index bdca879edde..69aaae8e46f 100644 --- a/test/langtools/jdk/jshell/RecordsTest.java +++ b/test/langtools/jdk/jshell/RecordsTest.java @@ -23,7 +23,7 @@ /* * @test - * @bug 8235474 8236715 + * @bug 8235474 8236715 8246774 * @summary Tests for evalution of records * @modules jdk.jshell * @build KullaTesting TestingInputStream ExpectedDiagnostic @@ -76,10 +76,4 @@ public void testRecordMethod() { assertEval("record(\"r\")", "\"rr\""); assertEval("record(\"r\").length()", "2"); } - - @BeforeMethod - public void setUp() { - setUp(b -> b.compilerOptions("--enable-preview", "-source", String.valueOf(SourceVersion.latest().ordinal())) - .remoteVMOptions("--enable-preview")); - } } diff --git a/test/langtools/jdk/jshell/ToolSimpleTest.java b/test/langtools/jdk/jshell/ToolSimpleTest.java index 6f38ad6fc0e..6a50d9bc9f1 100644 --- a/test/langtools/jdk/jshell/ToolSimpleTest.java +++ b/test/langtools/jdk/jshell/ToolSimpleTest.java @@ -23,14 +23,14 @@ /* * @test - * @bug 8153716 8143955 8151754 8150382 8153920 8156910 8131024 8160089 8153897 8167128 8154513 8170015 8170368 8172102 8172103 8165405 8173073 8173848 8174041 8173916 8174028 8174262 8174797 8177079 8180508 8177466 8172154 8192979 8191842 8198573 8198801 8210596 8210959 8215099 8199623 8236715 8239536 8247456 + * @bug 8153716 8143955 8151754 8150382 8153920 8156910 8131024 8160089 8153897 8167128 8154513 8170015 8170368 8172102 8172103 8165405 8173073 8173848 8174041 8173916 8174028 8174262 8174797 8177079 8180508 8177466 8172154 8192979 8191842 8198573 8198801 8210596 8210959 8215099 8199623 8236715 8239536 8247456 8246774 * @summary Simple jshell tool tests * @modules jdk.compiler/com.sun.tools.javac.api * jdk.compiler/com.sun.tools.javac.main * jdk.jdeps/com.sun.tools.javap * jdk.jshell/jdk.internal.jshell.tool * @build KullaTesting TestingInputStream - * @run testng/othervm ToolSimpleTest + * @run testng ToolSimpleTest */ import java.util.ArrayList; @@ -917,7 +917,7 @@ public void testUpdateFalsePositive() { @Test public void testRecords() { - test(new String[] {"--enable-preview"}, + test(new String[] {}, (a) -> assertCommandOutputContains(a, "record R(int i) { public int g() { return j; } }", "| created record R, however, it cannot be instantiated or its methods invoked until variable j is declared"), (a) -> assertCommandOutputContains(a, "new R(0)", diff --git a/test/langtools/tools/javac/IllegalAnnotation.java b/test/langtools/tools/javac/IllegalAnnotation.java index 164d1786146..79c4194d0c5 100644 --- a/test/langtools/tools/javac/IllegalAnnotation.java +++ b/test/langtools/tools/javac/IllegalAnnotation.java @@ -1,10 +1,9 @@ /** * @test /nodynamiccopyright/ - * @bug 5012028 6384539 8074364 8250741 + * @bug 5012028 6384539 8074364 8250741 8246774 * @summary javac crash when declare an annotation type illegally * * @compile/fail/ref=IllegalAnnotation.out -XDrawDiagnostics IllegalAnnotation.java - * @compile/fail/ref=IllegalAnnotation.out -XDrawDiagnostics --enable-preview -source ${jdk.version} IllegalAnnotation.java */ class IllegalAnnotation { { diff --git a/test/langtools/tools/javac/IllegalAnnotation.out b/test/langtools/tools/javac/IllegalAnnotation.out index 6b99a40d084..00d7fd4e2a3 100644 --- a/test/langtools/tools/javac/IllegalAnnotation.out +++ b/test/langtools/tools/javac/IllegalAnnotation.out @@ -1,2 +1,2 @@ -IllegalAnnotation.java:11:10: compiler.err.annotation.decl.not.allowed.here +IllegalAnnotation.java:10:10: compiler.err.annotation.decl.not.allowed.here 1 error diff --git a/test/langtools/tools/javac/LocalInterface.java b/test/langtools/tools/javac/LocalInterface.java index 13c2d56bdf1..818bb69ceab 100644 --- a/test/langtools/tools/javac/LocalInterface.java +++ b/test/langtools/tools/javac/LocalInterface.java @@ -1,9 +1,9 @@ /** * @test /nodynamiccopyright/ - * @bug 8242478 + * @bug 8242478 8246774 * @summary test for local interfaces - * @compile/fail/ref=LocalInterface.out -XDrawDiagnostics LocalInterface.java - * @compile --enable-preview -source ${jdk.version} LocalInterface.java + * @compile/fail/ref=LocalInterface.out -XDrawDiagnostics -source 15 LocalInterface.java + * @compile LocalInterface.java */ class LocalInterface { void m() { diff --git a/test/langtools/tools/javac/LocalInterface.out b/test/langtools/tools/javac/LocalInterface.out index 2ad6d4011d9..98524edadc0 100644 --- a/test/langtools/tools/javac/LocalInterface.out +++ b/test/langtools/tools/javac/LocalInterface.out @@ -1,2 +1,4 @@ +- compiler.warn.source.no.system.modules.path: 15 LocalInterface.java:10:9: compiler.err.intf.not.allowed.here 1 error +1 warning diff --git a/test/langtools/tools/javac/LocalRecord.java b/test/langtools/tools/javac/LocalRecord.java index 9dda54e04d6..b4053bb1fe3 100644 --- a/test/langtools/tools/javac/LocalRecord.java +++ b/test/langtools/tools/javac/LocalRecord.java @@ -23,9 +23,9 @@ /* * @test - * @bug 8242478 + * @bug 8242478 8246774 * @summary test local records - * @compile --enable-preview -source ${jdk.version} LocalRecord.java + * @compile LocalRecord.java */ class LocalRecord { void m() { diff --git a/test/langtools/tools/javac/annotations/ApplicableAnnotationsOnRecords.java b/test/langtools/tools/javac/annotations/ApplicableAnnotationsOnRecords.java index 05845700903..da5c6746047 100644 --- a/test/langtools/tools/javac/annotations/ApplicableAnnotationsOnRecords.java +++ b/test/langtools/tools/javac/annotations/ApplicableAnnotationsOnRecords.java @@ -24,12 +24,11 @@ /* * @test * @summary test for com.sun.tools.javac.comp.Check::validateAnnotation, com.sun.tools.javac.code.SymbolMetadata::removeDeclarationMetadata and ::removeFromCompoundList - * @bug 8241312 + * @bug 8241312 8246774 * @library /tools/lib * @modules jdk.compiler/com.sun.tools.javac.util * jdk.jdeps/com.sun.tools.classfile - * @compile --enable-preview -source ${jdk.version} ApplicableAnnotationsOnRecords.java - * @run main/othervm --enable-preview ApplicableAnnotationsOnRecords + * @run main ApplicableAnnotationsOnRecords */ import com.sun.tools.classfile.*; import com.sun.tools.javac.util.Assert; diff --git a/test/langtools/tools/javac/annotations/repeatingAnnotations/combo/TargetAnnoCombo.java b/test/langtools/tools/javac/annotations/repeatingAnnotations/combo/TargetAnnoCombo.java index b22b3d10638..bf03407f754 100644 --- a/test/langtools/tools/javac/annotations/repeatingAnnotations/combo/TargetAnnoCombo.java +++ b/test/langtools/tools/javac/annotations/repeatingAnnotations/combo/TargetAnnoCombo.java @@ -23,7 +23,7 @@ /* * @test - * @bug 7151010 8006547 8007766 8029017 + * @bug 7151010 8006547 8007766 8029017 8246774 * @summary Default test cases for running combinations for Target values * @modules jdk.compiler * @build Helper @@ -204,25 +204,22 @@ public static void main(String args[]) throws Exception { } } - // options to be passed if all targets, including RECORD_COMPONENTS, are to be considered - List previewOptions = List.of( - "--enable-preview", - "-source", Integer.toString(Runtime.version().feature()) - ); + // options to be passed if target RECORD_COMPONENT can't be considered + List source8 = List.of("-source", "8"); private void generate() { // Adding test cases to run. testCases.addAll(Arrays.asList( // No base target against no container target. - new TestCase(noSet, noSet), + /* 0*/ new TestCase(noSet, noSet), // No base target against empty container target. - new TestCase(noSet, empty), + /* 1*/ new TestCase(noSet, empty), // No base target against TYPE_USE only container target. - new TestCase(noSet, less(jdk8, TYPE_PARAMETER)), + new TestCase(noSet, less(jdk8, TYPE_PARAMETER), source8), // No base target against TYPE_PARAMETER only container target. - new TestCase(noSet, less(jdk8, TYPE_USE)), + new TestCase(noSet, less(jdk8, TYPE_USE), source8), // No base target against TYPE_USE + TYPE_PARAMETER only container target. - new TestCase(noSet, jdk8), + new TestCase(noSet, jdk8, source8), // No base target against TYPE_USE + some selection of jdk7 targets. new TestCase(noSet, plus(EnumSet.range(TYPE, LOCAL_VARIABLE), TYPE_USE)), @@ -233,7 +230,7 @@ private void generate() { new TestCase(noSet, plus(empty, TYPE)), new TestCase(noSet, plus(empty, PARAMETER)), new TestCase(noSet, plus(empty, PACKAGE)), - new TestCase(noSet, plus(empty, METHOD)), + /* 10*/ new TestCase(noSet, plus(empty, METHOD)), new TestCase(noSet, plus(empty, LOCAL_VARIABLE)), new TestCase(noSet, plus(empty, FIELD)), new TestCase(noSet, plus(empty, CONSTRUCTOR)), @@ -246,32 +243,32 @@ private void generate() { new TestCase(empty, plus(empty, TYPE)), new TestCase(empty, plus(empty, PARAMETER)), new TestCase(empty, plus(empty, PACKAGE)), - new TestCase(empty, plus(empty, METHOD)), + /* 20*/ new TestCase(empty, plus(empty, METHOD)), new TestCase(empty, plus(empty, LOCAL_VARIABLE)), new TestCase(empty, plus(empty, FIELD)), new TestCase(empty, plus(empty, CONSTRUCTOR)), new TestCase(empty, plus(empty, ANNOTATION_TYPE)), - new TestCase(empty, less(jdk8, TYPE_USE)), - new TestCase(empty, less(jdk8, TYPE_PARAMETER)), + new TestCase(empty, less(jdk8, TYPE_USE), source8), + new TestCase(empty, less(jdk8, TYPE_PARAMETER), source8), // No container target against all all-but one jdk7 targets. - new TestCase(less(jdk7, TYPE), noSet), - new TestCase(less(jdk7, PARAMETER), noSet), - new TestCase(less(jdk7, PACKAGE), noSet), - new TestCase(less(jdk7, METHOD), noSet), - new TestCase(less(jdk7, LOCAL_VARIABLE), noSet), - new TestCase(less(jdk7, FIELD), noSet), - new TestCase(less(jdk7, CONSTRUCTOR), noSet), - new TestCase(less(jdk7, ANNOTATION_TYPE), noSet), + new TestCase(less(jdk7, TYPE), noSet, source8), + new TestCase(less(jdk7, PARAMETER), noSet, source8), + new TestCase(less(jdk7, PACKAGE), noSet, source8), + /* 30*/ new TestCase(less(jdk7, METHOD), noSet, source8), + new TestCase(less(jdk7, LOCAL_VARIABLE), noSet, source8), + new TestCase(less(jdk7, FIELD), noSet, source8), + new TestCase(less(jdk7, CONSTRUCTOR), noSet, source8), + new TestCase(less(jdk7, ANNOTATION_TYPE), noSet, source8), // No container against all but TYPE and ANNOTATION_TYPE new TestCase(less(jdk7, TYPE, ANNOTATION_TYPE), noSet), // No container against jdk7 targets. - new TestCase(jdk7, noSet), + new TestCase(jdk7, noSet, source8), // No container against jdk7 targets plus one or both of TYPE_USE, TYPE_PARAMETER - new TestCase(plus(jdk7, TYPE_USE), noSet), - new TestCase(plus(jdk7, TYPE_PARAMETER), noSet), - new TestCase(allTargets, noSet, previewOptions), + new TestCase(plus(jdk7, TYPE_USE), noSet, source8), + new TestCase(plus(jdk7, TYPE_PARAMETER), noSet, source8), + new TestCase(allTargets, noSet, null), // Empty container target against any lone target. - new TestCase(plus(empty, TYPE), empty), + /* 40*/ new TestCase(plus(empty, TYPE), empty), new TestCase(plus(empty, PARAMETER), empty), new TestCase(plus(empty, PACKAGE), empty), new TestCase(plus(empty, METHOD), empty), @@ -282,34 +279,34 @@ private void generate() { new TestCase(plus(empty, TYPE_USE), empty), new TestCase(plus(empty, TYPE_PARAMETER), empty), // All base targets against all container targets. - new TestCase(allTargets, allTargets, previewOptions), + /* 50*/ new TestCase(allTargets, allTargets), // All base targets against all but one container targets. - new TestCase(allTargets, less(allTargets, TYPE), previewOptions), - new TestCase(allTargets, less(allTargets, PARAMETER), previewOptions), - new TestCase(allTargets, less(allTargets, PACKAGE), previewOptions), - new TestCase(allTargets, less(allTargets, METHOD), previewOptions), - new TestCase(allTargets, less(allTargets, LOCAL_VARIABLE), previewOptions), - new TestCase(allTargets, less(allTargets, FIELD), previewOptions), - new TestCase(allTargets, less(allTargets, CONSTRUCTOR), previewOptions), - new TestCase(allTargets, less(allTargets, ANNOTATION_TYPE), previewOptions), - new TestCase(allTargets, less(allTargets, TYPE_USE), previewOptions), - new TestCase(allTargets, less(allTargets, TYPE_PARAMETER), previewOptions), + new TestCase(allTargets, less(allTargets, TYPE)), + new TestCase(allTargets, less(allTargets, PARAMETER)), + new TestCase(allTargets, less(allTargets, PACKAGE)), + new TestCase(allTargets, less(allTargets, METHOD)), + new TestCase(allTargets, less(allTargets, LOCAL_VARIABLE)), + new TestCase(allTargets, less(allTargets, FIELD)), + new TestCase(allTargets, less(allTargets, CONSTRUCTOR)), + new TestCase(allTargets, less(allTargets, ANNOTATION_TYPE)), + new TestCase(allTargets, less(allTargets, TYPE_USE)), + /* 60*/ new TestCase(allTargets, less(allTargets, TYPE_PARAMETER)), // All container targets against all but one base targets. - new TestCase(less(allTargets, TYPE), allTargets, previewOptions), - new TestCase(less(allTargets, PARAMETER), allTargets, previewOptions), - new TestCase(less(allTargets, PACKAGE), allTargets, previewOptions), - new TestCase(less(allTargets, METHOD), allTargets, previewOptions), - new TestCase(less(allTargets, LOCAL_VARIABLE), allTargets, previewOptions), - new TestCase(less(allTargets, FIELD), allTargets, previewOptions), - new TestCase(less(allTargets, CONSTRUCTOR), allTargets, previewOptions), - new TestCase(less(allTargets, ANNOTATION_TYPE), allTargets, previewOptions), - new TestCase(less(allTargets, TYPE_USE), allTargets, previewOptions), - new TestCase(less(allTargets, TYPE_PARAMETER), allTargets, previewOptions))); + new TestCase(less(allTargets, TYPE), allTargets), + new TestCase(less(allTargets, PARAMETER), allTargets), + new TestCase(less(allTargets, PACKAGE), allTargets), + new TestCase(less(allTargets, METHOD), allTargets), + new TestCase(less(allTargets, LOCAL_VARIABLE), allTargets), + new TestCase(less(allTargets, FIELD), allTargets), + new TestCase(less(allTargets, CONSTRUCTOR), allTargets), + new TestCase(less(allTargets, ANNOTATION_TYPE), allTargets), + new TestCase(less(allTargets, TYPE_USE), allTargets), + /* 70*/ new TestCase(less(allTargets, TYPE_PARAMETER), allTargets))); // Generates 100 test cases for any lone base target contained in Set // allTargets against any lone container target. for (ElementType b : allTargets) { for (ElementType c : allTargets) { - testCases.add(new TestCase(plus(empty, b), plus(empty, c), previewOptions)); + testCases.add(new TestCase(plus(empty, b), plus(empty, c))); } } } @@ -456,7 +453,7 @@ private boolean getCompileResult(String className, boolean shouldCompile, if (allDiagnostics.stream().noneMatch(d -> d.getKind() == javax.tools.Diagnostic.Kind.ERROR)) { ok = true; } else { - errMesg = "Test failed, compiled unexpectedly."; + errMesg = "Test failed, should have compiled successfully."; ok = false; } } else { diff --git a/test/langtools/tools/javac/annotations/typeAnnotations/TypeAnnotationsPositionsOnRecords.java b/test/langtools/tools/javac/annotations/typeAnnotations/TypeAnnotationsPositionsOnRecords.java index 17b94730e54..551bd981c21 100644 --- a/test/langtools/tools/javac/annotations/typeAnnotations/TypeAnnotationsPositionsOnRecords.java +++ b/test/langtools/tools/javac/annotations/typeAnnotations/TypeAnnotationsPositionsOnRecords.java @@ -23,6 +23,7 @@ /* * @test + * @bug 8246774 * @summary Verify location of type annotations on records * @library /tools/lib * @modules @@ -32,8 +33,7 @@ * jdk.compiler/com.sun.tools.javac.code * jdk.compiler/com.sun.tools.javac.util * @build toolbox.ToolBox toolbox.JavacTask - * @compile --enable-preview -source ${jdk.version} TypeAnnotationsPositionsOnRecords.java - * @run main/othervm --enable-preview TypeAnnotationsPositionsOnRecords + * @run main TypeAnnotationsPositionsOnRecords */ import java.util.List; @@ -105,7 +105,6 @@ void run() throws Exception { void compileTestClass() throws Exception { new JavacTask(tb) .sources(src) - .options("--enable-preview", "-source", Integer.toString(Runtime.version().feature())) .run(); } diff --git a/test/langtools/tools/javac/annotations/typeAnnotations/failures/AnnotatedImport.out b/test/langtools/tools/javac/annotations/typeAnnotations/failures/AnnotatedImport.out index 91589d9252e..301f7335520 100644 --- a/test/langtools/tools/javac/annotations/typeAnnotations/failures/AnnotatedImport.out +++ b/test/langtools/tools/javac/annotations/typeAnnotations/failures/AnnotatedImport.out @@ -1,7 +1,7 @@ AnnotatedImport.java:10:13: compiler.err.expected: token.identifier -AnnotatedImport.java:10:16: compiler.err.expected3: class, interface, enum +AnnotatedImport.java:10:16: compiler.err.expected4: class, interface, enum, record AnnotatedImport.java:11:7: compiler.err.expected: token.identifier -AnnotatedImport.java:11:11: compiler.err.expected3: class, interface, enum +AnnotatedImport.java:11:11: compiler.err.expected4: class, interface, enum, record AnnotatedImport.java:12:18: compiler.err.expected: token.identifier -AnnotatedImport.java:12:21: compiler.err.expected3: class, interface, enum +AnnotatedImport.java:12:21: compiler.err.expected4: class, interface, enum, record 6 errors diff --git a/test/langtools/tools/javac/annotations/typeAnnotations/failures/AnnotatedPackage1.out b/test/langtools/tools/javac/annotations/typeAnnotations/failures/AnnotatedPackage1.out index b2c1770b3b5..cb2e66ca6db 100644 --- a/test/langtools/tools/javac/annotations/typeAnnotations/failures/AnnotatedPackage1.out +++ b/test/langtools/tools/javac/annotations/typeAnnotations/failures/AnnotatedPackage1.out @@ -1,3 +1,3 @@ AnnotatedPackage1.java:9:14: compiler.err.expected: token.identifier -AnnotatedPackage1.java:9:17: compiler.err.expected3: class, interface, enum +AnnotatedPackage1.java:9:17: compiler.err.expected4: class, interface, enum, record 2 errors diff --git a/test/langtools/tools/javac/annotations/typeAnnotations/failures/AnnotatedPackage2.out b/test/langtools/tools/javac/annotations/typeAnnotations/failures/AnnotatedPackage2.out index 77b25afc5e0..c511caf6546 100644 --- a/test/langtools/tools/javac/annotations/typeAnnotations/failures/AnnotatedPackage2.out +++ b/test/langtools/tools/javac/annotations/typeAnnotations/failures/AnnotatedPackage2.out @@ -1,3 +1,3 @@ AnnotatedPackage2.java:9:8: compiler.err.expected: token.identifier -AnnotatedPackage2.java:9:12: compiler.err.expected3: class, interface, enum +AnnotatedPackage2.java:9:12: compiler.err.expected4: class, interface, enum, record 2 errors diff --git a/test/langtools/tools/javac/api/TestGetScopeResult.java b/test/langtools/tools/javac/api/TestGetScopeResult.java index b2a2e500e03..60913ac0050 100644 --- a/test/langtools/tools/javac/api/TestGetScopeResult.java +++ b/test/langtools/tools/javac/api/TestGetScopeResult.java @@ -23,13 +23,12 @@ /* * @test - * @bug 8205418 8207229 8207230 8230847 8245786 8247334 8248641 8240658 + * @bug 8205418 8207229 8207230 8230847 8245786 8247334 8248641 8240658 8246774 * @summary Test the outcomes from Trees.getScope * @modules jdk.compiler/com.sun.tools.javac.api * jdk.compiler/com.sun.tools.javac.comp * jdk.compiler/com.sun.tools.javac.tree * jdk.compiler/com.sun.tools.javac.util - * @compile TestGetScopeResult.java */ import java.io.IOException; @@ -559,9 +558,7 @@ public String getCharContent(boolean ignoreEncodingErrors) { } Context ctx = new Context(); TestAnalyzer.preRegister(ctx); - List options = List.of("--enable-preview", - "-source", System.getProperty("java.specification.version")); - JavacTask t = (JavacTask) c.getTask(null, fm, null, options, null, + JavacTask t = (JavacTask) c.getTask(null, fm, null, null, null, List.of(new MyFileObject()), ctx); CompilationUnitTree cut = t.parse().iterator().next(); t.analyze(); @@ -636,9 +633,7 @@ public String getCharContent(boolean ignoreEncodingErrors) { } Context ctx = new Context(); TestAnalyzer.preRegister(ctx); - List options = List.of("--enable-preview", - "-source", System.getProperty("java.specification.version")); - JavacTask t = (JavacTask) c.getTask(null, fm, null, options, null, + JavacTask t = (JavacTask) c.getTask(null, fm, null, null, null, List.of(new MyFileObject()), ctx); CompilationUnitTree cut = t.parse().iterator().next(); t.analyze(); diff --git a/test/langtools/tools/javac/diags/examples/AccessorCantBeGeneric.java b/test/langtools/tools/javac/diags/examples/AccessorCantBeGeneric.java index 9594b5a561a..8027475b90b 100644 --- a/test/langtools/tools/javac/diags/examples/AccessorCantBeGeneric.java +++ b/test/langtools/tools/javac/diags/examples/AccessorCantBeGeneric.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2020, 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,9 +23,6 @@ // key: compiler.err.invalid.accessor.method.in.record // key: compiler.misc.accessor.method.must.not.be.generic -// key: compiler.note.preview.filename -// key: compiler.note.preview.recompile -// options: --enable-preview -source ${jdk.version} record R(int i) { public int i() { diff --git a/test/langtools/tools/javac/diags/examples/AccessorCantThrowException.java b/test/langtools/tools/javac/diags/examples/AccessorCantThrowException.java index f4dcbf305a7..47e2566348e 100644 --- a/test/langtools/tools/javac/diags/examples/AccessorCantThrowException.java +++ b/test/langtools/tools/javac/diags/examples/AccessorCantThrowException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2020, 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,9 +23,6 @@ // key: compiler.err.invalid.accessor.method.in.record // key: compiler.misc.accessor.method.cant.throw.exception -// key: compiler.note.preview.filename -// key: compiler.note.preview.recompile -// options: --enable-preview -source ${jdk.version} record R(int i) { public int i() throws ArithmeticException { diff --git a/test/langtools/tools/javac/diags/examples/AccessorMethodCantBeStatic.java b/test/langtools/tools/javac/diags/examples/AccessorMethodCantBeStatic.java index 7299c746207..868a4dd1821 100644 --- a/test/langtools/tools/javac/diags/examples/AccessorMethodCantBeStatic.java +++ b/test/langtools/tools/javac/diags/examples/AccessorMethodCantBeStatic.java @@ -23,9 +23,6 @@ // key: compiler.err.invalid.accessor.method.in.record // key: compiler.misc.accessor.method.must.not.be.static -// key: compiler.note.preview.filename -// key: compiler.note.preview.recompile -// options: --enable-preview -source ${jdk.version} record R(int x) { static final int j = 0; diff --git a/test/langtools/tools/javac/diags/examples/AccessorReturnTypeDoesntMatch.java b/test/langtools/tools/javac/diags/examples/AccessorReturnTypeDoesntMatch.java index b8af12cc6f9..a11c79b9161 100644 --- a/test/langtools/tools/javac/diags/examples/AccessorReturnTypeDoesntMatch.java +++ b/test/langtools/tools/javac/diags/examples/AccessorReturnTypeDoesntMatch.java @@ -23,9 +23,6 @@ // key: compiler.err.invalid.accessor.method.in.record // key: compiler.misc.accessor.return.type.doesnt.match -// key: compiler.note.preview.filename -// key: compiler.note.preview.recompile -// options: --enable-preview -source ${jdk.version} import java.util.List; record R(List x) { diff --git a/test/langtools/tools/javac/diags/examples/CanonicalCantHaveStrongerAccessPrivileges.java b/test/langtools/tools/javac/diags/examples/CanonicalCantHaveStrongerAccessPrivileges.java index 7364e698543..2104d3a9287 100644 --- a/test/langtools/tools/javac/diags/examples/CanonicalCantHaveStrongerAccessPrivileges.java +++ b/test/langtools/tools/javac/diags/examples/CanonicalCantHaveStrongerAccessPrivileges.java @@ -23,10 +23,7 @@ // key: compiler.err.invalid.canonical.constructor.in.record // key: compiler.misc.canonical.must.not.have.stronger.access -// key: compiler.note.preview.filename -// key: compiler.note.preview.recompile // key: compiler.misc.canonical -// options: --enable-preview -source ${jdk.version} public record CanonicalCantHaveStrongerAccessPrivileges() { private CanonicalCantHaveStrongerAccessPrivileges {} diff --git a/test/langtools/tools/javac/diags/examples/CanonicalCantInvokeOtherConstructor.java b/test/langtools/tools/javac/diags/examples/CanonicalCantInvokeOtherConstructor.java index 89dc304bcfc..1c62e2ede88 100644 --- a/test/langtools/tools/javac/diags/examples/CanonicalCantInvokeOtherConstructor.java +++ b/test/langtools/tools/javac/diags/examples/CanonicalCantInvokeOtherConstructor.java @@ -23,10 +23,7 @@ // key: compiler.err.invalid.canonical.constructor.in.record // key: compiler.misc.canonical.must.not.contain.explicit.constructor.invocation -// key: compiler.note.preview.filename -// key: compiler.note.preview.recompile // key: compiler.misc.canonical -// options: --enable-preview -source ${jdk.version} record R(int x) { public R(int x) { super(); this.x = x; } diff --git a/test/langtools/tools/javac/diags/examples/CanonicalConstructorArgumentMismatch.java b/test/langtools/tools/javac/diags/examples/CanonicalConstructorArgumentMismatch.java index 91d7fcb9881..621d26dbdd6 100644 --- a/test/langtools/tools/javac/diags/examples/CanonicalConstructorArgumentMismatch.java +++ b/test/langtools/tools/javac/diags/examples/CanonicalConstructorArgumentMismatch.java @@ -23,10 +23,7 @@ // key: compiler.err.invalid.canonical.constructor.in.record // key: compiler.misc.canonical.with.name.mismatch -// key: compiler.note.preview.filename -// key: compiler.note.preview.recompile // key: compiler.misc.canonical -// options: --enable-preview -source ${jdk.version} record R(int x) { public R(int _x) { this.x = _x; } diff --git a/test/langtools/tools/javac/diags/examples/CanonicalConstructorCantHaveReturn.java b/test/langtools/tools/javac/diags/examples/CanonicalConstructorCantHaveReturn.java index 0033ac8761d..6f86a867bd7 100644 --- a/test/langtools/tools/javac/diags/examples/CanonicalConstructorCantHaveReturn.java +++ b/test/langtools/tools/javac/diags/examples/CanonicalConstructorCantHaveReturn.java @@ -23,10 +23,7 @@ // key: compiler.err.invalid.canonical.constructor.in.record // key: compiler.misc.canonical.cant.have.return.statement -// key: compiler.note.preview.filename -// key: compiler.note.preview.recompile // key: compiler.misc.compact -// options: --enable-preview -source ${jdk.version} record R() { public R { diff --git a/test/langtools/tools/javac/diags/examples/CanonicalConstructorCantHaveThrowsClause.java b/test/langtools/tools/javac/diags/examples/CanonicalConstructorCantHaveThrowsClause.java index 6c3e165ead9..26003a3a1a7 100644 --- a/test/langtools/tools/javac/diags/examples/CanonicalConstructorCantHaveThrowsClause.java +++ b/test/langtools/tools/javac/diags/examples/CanonicalConstructorCantHaveThrowsClause.java @@ -23,10 +23,7 @@ // key: compiler.err.invalid.canonical.constructor.in.record // key: compiler.misc.throws.clause.not.allowed.for.canonical.constructor -// key: compiler.note.preview.filename -// key: compiler.note.preview.recompile // key: compiler.misc.canonical -// options: --enable-preview -source ${jdk.version} record R(int i) { public R(int i) throws Exception { diff --git a/test/langtools/tools/javac/diags/examples/CanonicalMustNotDeclareTypeVariables.java b/test/langtools/tools/javac/diags/examples/CanonicalMustNotDeclareTypeVariables.java index 5ab9185a7ed..1060955d102 100644 --- a/test/langtools/tools/javac/diags/examples/CanonicalMustNotDeclareTypeVariables.java +++ b/test/langtools/tools/javac/diags/examples/CanonicalMustNotDeclareTypeVariables.java @@ -23,10 +23,7 @@ // key: compiler.err.invalid.canonical.constructor.in.record // key: compiler.misc.canonical.must.not.declare.type.variables -// key: compiler.note.preview.filename -// key: compiler.note.preview.recompile // key: compiler.misc.canonical -// options: --enable-preview -source ${jdk.version} record R(int i) { public R(int i) { diff --git a/test/langtools/tools/javac/diags/examples/ConstructorWithSameErasureAsCanonical.java b/test/langtools/tools/javac/diags/examples/ConstructorWithSameErasureAsCanonical.java index dcccae65d66..28d485c48ef 100644 --- a/test/langtools/tools/javac/diags/examples/ConstructorWithSameErasureAsCanonical.java +++ b/test/langtools/tools/javac/diags/examples/ConstructorWithSameErasureAsCanonical.java @@ -23,10 +23,7 @@ // key: compiler.err.invalid.canonical.constructor.in.record // key: compiler.misc.type.must.be.identical.to.corresponding.record.component.type -// key: compiler.note.preview.filename -// key: compiler.note.preview.recompile // key: compiler.misc.canonical -// options: --enable-preview -source ${jdk.version} import java.util.List; diff --git a/test/langtools/tools/javac/diags/examples/Expected3.java b/test/langtools/tools/javac/diags/examples/Expected3.java index 72fd7d7c43c..2b1ec325618 100644 --- a/test/langtools/tools/javac/diags/examples/Expected3.java +++ b/test/langtools/tools/javac/diags/examples/Expected3.java @@ -22,5 +22,7 @@ */ // key: compiler.err.expected3 +// key: compiler.warn.source.no.system.modules.path +// options: -source 15 int Expected3; diff --git a/test/langtools/tools/javac/diags/examples/FirstInvocationMustBeAnotherConstructor.java b/test/langtools/tools/javac/diags/examples/FirstInvocationMustBeAnotherConstructor.java index 2fdb1c4f5ae..e2478244cc9 100644 --- a/test/langtools/tools/javac/diags/examples/FirstInvocationMustBeAnotherConstructor.java +++ b/test/langtools/tools/javac/diags/examples/FirstInvocationMustBeAnotherConstructor.java @@ -22,9 +22,6 @@ */ // key: compiler.err.first.statement.must.be.call.to.another.constructor -// key: compiler.note.preview.filename -// key: compiler.note.preview.recompile -// options: --enable-preview -source ${jdk.version} record R(int x) { public R(int x, int y) { this.x = x; } diff --git a/test/langtools/tools/javac/diags/examples/IllegalRecordComponentName.java b/test/langtools/tools/javac/diags/examples/IllegalRecordComponentName.java index 483ac93a7e7..45a7a153839 100644 --- a/test/langtools/tools/javac/diags/examples/IllegalRecordComponentName.java +++ b/test/langtools/tools/javac/diags/examples/IllegalRecordComponentName.java @@ -22,8 +22,5 @@ */ // key: compiler.err.illegal.record.component.name -// key: compiler.note.preview.filename -// key: compiler.note.preview.recompile -// options: --enable-preview -source ${jdk.version} record R(int hashCode) {} diff --git a/test/langtools/tools/javac/diags/examples/IncorrectRecordDeclaration.java b/test/langtools/tools/javac/diags/examples/IncorrectRecordDeclaration.java index acaecb37755..dc1dd8af632 100644 --- a/test/langtools/tools/javac/diags/examples/IncorrectRecordDeclaration.java +++ b/test/langtools/tools/javac/diags/examples/IncorrectRecordDeclaration.java @@ -22,8 +22,5 @@ */ // key: compiler.err.record.header.expected -// key: compiler.note.preview.filename -// key: compiler.note.preview.recompile -// options: --enable-preview -source ${jdk.version} record R {} diff --git a/test/langtools/tools/javac/diags/examples/InstanceInitializersNotAllowedInRecords.java b/test/langtools/tools/javac/diags/examples/InstanceInitializersNotAllowedInRecords.java index 6b57276d865..b12c26ba0a5 100644 --- a/test/langtools/tools/javac/diags/examples/InstanceInitializersNotAllowedInRecords.java +++ b/test/langtools/tools/javac/diags/examples/InstanceInitializersNotAllowedInRecords.java @@ -22,9 +22,6 @@ */ // key: compiler.err.instance.initializer.not.allowed.in.records -// key: compiler.note.preview.filename -// key: compiler.note.preview.recompile -// options: --enable-preview -source ${jdk.version} record R(int x) { {} diff --git a/test/langtools/tools/javac/diags/examples/InterfaceNotAllowed.java b/test/langtools/tools/javac/diags/examples/InterfaceNotAllowed.java index 3c3feb692d4..a72e7ef12bd 100644 --- a/test/langtools/tools/javac/diags/examples/InterfaceNotAllowed.java +++ b/test/langtools/tools/javac/diags/examples/InterfaceNotAllowed.java @@ -22,6 +22,8 @@ */ // key: compiler.err.intf.not.allowed.here +// key: compiler.warn.source.no.system.modules.path +// options: -source 15 class InterfaceNotAllowed { void m() { diff --git a/test/langtools/tools/javac/diags/examples/InvalidSuperTypeRecord.java b/test/langtools/tools/javac/diags/examples/InvalidSuperTypeRecord.java index 8e8b0599c13..d12665681bf 100644 --- a/test/langtools/tools/javac/diags/examples/InvalidSuperTypeRecord.java +++ b/test/langtools/tools/javac/diags/examples/InvalidSuperTypeRecord.java @@ -22,7 +22,6 @@ */ // key: compiler.err.invalid.supertype.record -// options: --enable-preview -source ${jdk.version} @SuppressWarnings("preview") class R extends Record {} diff --git a/test/langtools/tools/javac/diags/examples/KindnameRecord.java b/test/langtools/tools/javac/diags/examples/KindnameRecord.java index 3ee2450e9ed..056e43a0205 100644 --- a/test/langtools/tools/javac/diags/examples/KindnameRecord.java +++ b/test/langtools/tools/javac/diags/examples/KindnameRecord.java @@ -27,10 +27,6 @@ // key: compiler.misc.kindname.method // key: compiler.err.already.defined // key: compiler.err.error -// key: compiler.note.preview.filename -// key: compiler.note.preview.recompile -// key: compiler.note.note // run: backdoor -// options: --enable-preview -source ${jdk.version} record R(int i, int i) {} diff --git a/test/langtools/tools/javac/diags/examples/LocalEnum.java b/test/langtools/tools/javac/diags/examples/LocalEnum.java index 431d6d931e9..fdf875c9697 100644 --- a/test/langtools/tools/javac/diags/examples/LocalEnum.java +++ b/test/langtools/tools/javac/diags/examples/LocalEnum.java @@ -22,6 +22,8 @@ */ // key: compiler.err.local.enum +// key: compiler.warn.source.no.system.modules.path +// options: -source 15 class LocalEnum { void m() { diff --git a/test/langtools/tools/javac/diags/examples/MethodMustBePublic.java b/test/langtools/tools/javac/diags/examples/MethodMustBePublic.java index c104261d361..fb48b1d7578 100644 --- a/test/langtools/tools/javac/diags/examples/MethodMustBePublic.java +++ b/test/langtools/tools/javac/diags/examples/MethodMustBePublic.java @@ -23,9 +23,6 @@ // key: compiler.err.invalid.accessor.method.in.record // key: compiler.misc.method.must.be.public -// key: compiler.note.preview.filename -// key: compiler.note.preview.recompile -// options: --enable-preview -source ${jdk.version} record R(int x) { private int x() { return x; } diff --git a/test/langtools/tools/javac/diags/examples/Records.java b/test/langtools/tools/javac/diags/examples/Records.java index 65b2c380cd6..9acc44d0f43 100644 --- a/test/langtools/tools/javac/diags/examples/Records.java +++ b/test/langtools/tools/javac/diags/examples/Records.java @@ -22,7 +22,8 @@ */ // key: compiler.misc.feature.records -// key: compiler.warn.preview.feature.use.plural -// options: --enable-preview -source ${jdk.version} -Xlint:preview +// key: compiler.err.feature.not.supported.in.source.plural +// key: compiler.warn.source.no.system.modules.path +// options: -source 15 record R() {} diff --git a/test/langtools/tools/javac/diags/examples/RecordsCanNotDeclareInstanceFields.java b/test/langtools/tools/javac/diags/examples/RecordsCanNotDeclareInstanceFields.java index 20f9ab1ccf0..d98bcae9911 100644 --- a/test/langtools/tools/javac/diags/examples/RecordsCanNotDeclareInstanceFields.java +++ b/test/langtools/tools/javac/diags/examples/RecordsCanNotDeclareInstanceFields.java @@ -22,9 +22,6 @@ */ // key: compiler.err.record.cannot.declare.instance.fields -// key: compiler.note.preview.filename -// key: compiler.note.preview.recompile -// options: --enable-preview -source ${jdk.version} record R(int i) { private final int y = 0; diff --git a/test/langtools/tools/javac/diags/examples/RecordsCantDeclareComponentModifiers.java b/test/langtools/tools/javac/diags/examples/RecordsCantDeclareComponentModifiers.java index 3fda0742cf4..2bf01b9e7a3 100644 --- a/test/langtools/tools/javac/diags/examples/RecordsCantDeclareComponentModifiers.java +++ b/test/langtools/tools/javac/diags/examples/RecordsCantDeclareComponentModifiers.java @@ -22,8 +22,5 @@ */ // key: compiler.err.record.cant.declare.field.modifiers -// key: compiler.note.preview.filename -// key: compiler.note.preview.recompile -// options: --enable-preview -source ${jdk.version} record R(final int x) {} diff --git a/test/langtools/tools/javac/diags/examples/RecordsComponentsCanNotDeclareCStyleArrays.java b/test/langtools/tools/javac/diags/examples/RecordsComponentsCanNotDeclareCStyleArrays.java index 6d2d5186e24..dcc06349038 100644 --- a/test/langtools/tools/javac/diags/examples/RecordsComponentsCanNotDeclareCStyleArrays.java +++ b/test/langtools/tools/javac/diags/examples/RecordsComponentsCanNotDeclareCStyleArrays.java @@ -22,8 +22,5 @@ */ // key: compiler.err.record.component.and.old.array.syntax -// key: compiler.note.preview.filename -// key: compiler.note.preview.recompile -// options: --enable-preview -source ${jdk.version} record R(int i[]) {} diff --git a/test/langtools/tools/javac/diags/examples/RecordsNotAllowedInInnerClasses.java b/test/langtools/tools/javac/diags/examples/RecordsNotAllowedInInnerClasses.java index 99000219c42..1016a874e00 100644 --- a/test/langtools/tools/javac/diags/examples/RecordsNotAllowedInInnerClasses.java +++ b/test/langtools/tools/javac/diags/examples/RecordsNotAllowedInInnerClasses.java @@ -22,9 +22,6 @@ */ // key: compiler.err.static.declaration.not.allowed.in.inner.classes -// key: compiler.note.preview.filename -// key: compiler.note.preview.recompile -// options: --enable-preview -source ${jdk.version} class Outer { class Inner { diff --git a/test/langtools/tools/javac/enum/FauxEnum3.java b/test/langtools/tools/javac/enum/FauxEnum3.java index 83bb06f80ee..ec53aeb5951 100644 --- a/test/langtools/tools/javac/enum/FauxEnum3.java +++ b/test/langtools/tools/javac/enum/FauxEnum3.java @@ -5,7 +5,6 @@ * @author Joseph D. Darcy * * @compile/fail/ref=FauxEnum3.out -XDrawDiagnostics FauxEnum3.java - * @compile/fail/ref=FauxEnum3.out -XDrawDiagnostics --enable-preview -source ${jdk.version} FauxEnum3.java */ public final class FauxEnum3 extends SpecializedEnum {} diff --git a/test/langtools/tools/javac/enum/FauxEnum3.out b/test/langtools/tools/javac/enum/FauxEnum3.out index aaf4855e215..885154d073a 100644 --- a/test/langtools/tools/javac/enum/FauxEnum3.out +++ b/test/langtools/tools/javac/enum/FauxEnum3.out @@ -1,2 +1,2 @@ -FauxEnum3.java:11:14: compiler.err.enum.types.not.extensible -1 error \ No newline at end of file +FauxEnum3.java:10:14: compiler.err.enum.types.not.extensible +1 error diff --git a/test/langtools/tools/javac/enum/LocalEnum.java b/test/langtools/tools/javac/enum/LocalEnum.java index 0cbb0bf438c..331992b3565 100644 --- a/test/langtools/tools/javac/enum/LocalEnum.java +++ b/test/langtools/tools/javac/enum/LocalEnum.java @@ -1,10 +1,10 @@ /* * @test /nodynamiccopyright/ - * @bug 5019609 + * @bug 5019609 8246774 * @summary javac fails to reject local enums * @author gafter - * @compile/fail/ref=LocalEnum.out -XDrawDiagnostics LocalEnum.java - * @compile --enable-preview -source ${jdk.version} LocalEnum.java + * @compile/fail/ref=LocalEnum.out -XDrawDiagnostics -source 15 LocalEnum.java + * @compile LocalEnum.java */ public class LocalEnum { diff --git a/test/langtools/tools/javac/enum/LocalEnum.out b/test/langtools/tools/javac/enum/LocalEnum.out index ee4cc2d10f5..a01b8555456 100644 --- a/test/langtools/tools/javac/enum/LocalEnum.out +++ b/test/langtools/tools/javac/enum/LocalEnum.out @@ -1,2 +1,4 @@ +- compiler.warn.source.no.system.modules.path: 15 LocalEnum.java:12:9: compiler.err.local.enum 1 error +1 warning diff --git a/test/langtools/tools/javac/launcher/SourceLauncherTest.java b/test/langtools/tools/javac/launcher/SourceLauncherTest.java index 76082210850..1f622e0fefc 100644 --- a/test/langtools/tools/javac/launcher/SourceLauncherTest.java +++ b/test/langtools/tools/javac/launcher/SourceLauncherTest.java @@ -23,7 +23,7 @@ /* * @test - * @bug 8192920 8204588 + * @bug 8192920 8204588 8246774 * @summary Test source launcher * @library /tools/lib * @modules jdk.compiler/com.sun.tools.javac.api @@ -299,7 +299,7 @@ public void testHelloWorldWithShebangJava(Path base) throws IOException { file + ":1: error: illegal character: '#'\n" + "#!/usr/bin/java --source " + thisVersion + "\n" + "^\n" + - file + ":1: error: class, interface, or enum expected\n" + + file + ":1: error: class, interface, enum, or record expected\n" + "#!/usr/bin/java --source " + thisVersion + "\n" + " ^\n" + "2 errors\n", @@ -505,7 +505,7 @@ public void testBadShebang(Path base) throws IOException { file + ":1: error: illegal character: '#'\n" + "#/usr/bin/java --source " + thisVersion + "\n" + "^\n" + - file + ":1: error: class, interface, or enum expected\n" + + file + ":1: error: class, interface, enum, or record expected\n" + "#/usr/bin/java --source " + thisVersion + "\n" + " ^\n" + "2 errors\n", diff --git a/test/langtools/tools/javac/modules/AnnotationProcessing.java b/test/langtools/tools/javac/modules/AnnotationProcessing.java index f134c417c5b..68e0794e8eb 100644 --- a/test/langtools/tools/javac/modules/AnnotationProcessing.java +++ b/test/langtools/tools/javac/modules/AnnotationProcessing.java @@ -23,7 +23,7 @@ /** * @test - * @bug 8133884 8162711 8133896 8172158 8172262 8173636 8175119 8189747 + * @bug 8133884 8162711 8133896 8172158 8172262 8173636 8175119 8189747 8236842 * @summary Verify that annotation processing works. * @library /tools/lib * @modules @@ -46,6 +46,7 @@ import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; +import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Objects; @@ -53,7 +54,6 @@ import java.util.concurrent.Callable; import java.util.function.Consumer; import java.util.function.Function; -import java.util.regex.Pattern; import java.util.stream.Collectors; import javax.annotation.processing.AbstractProcessor; @@ -80,11 +80,8 @@ import javax.tools.FileObject; import javax.tools.JavaCompiler; import javax.tools.JavaCompiler.CompilationTask; -import javax.tools.JavaFileManager; -import javax.tools.JavaFileManager.Location; import javax.tools.JavaFileObject; import javax.tools.StandardJavaFileManager; -import javax.tools.StandardLocation; import javax.tools.ToolProvider; import toolbox.JavacTask; @@ -1299,6 +1296,440 @@ private static void writeFile(String content, Path base, String... pathElements) } } + @Test + public void testUnboundLookupNew(Path base) throws Exception { + Path moduleSrc = base.resolve("module-src"); + Path m1 = moduleSrc.resolve("m1x"); + Path m2 = moduleSrc.resolve("m2x"); + Path m3 = moduleSrc.resolve("m3x"); + Path m4 = moduleSrc.resolve("m4x"); + + Path src = base.resolve("src"); + + Path classes = base.resolve("classes"); + Path srcClasses = base.resolve("src-classes"); + + Files.createDirectories(classes); + Files.createDirectories(srcClasses); + Files.createDirectories(moduleSrc); + + { + tb.cleanDirectory(classes); + tb.cleanDirectory(moduleSrc); + + tb.writeJavaFiles(m1, + "module m1x { exports api; }", + "package test; public class Test { }", + "package api; public class API {}"); + + tb.writeJavaFiles(m2, + "module m2x { requires m1x; }", + "package test; public class Test { }", + "package api.impl; public class Impl { }"); + + new JavacTask(tb) + .options("--module-source-path", moduleSrc.toString()) + .outdir(classes) + .files(findJavaFiles(moduleSrc)) + .run() + .writeAll() + .getOutputLines(OutputKind.DIRECT); + + List log = new JavacTask(tb) + .options("--module-source-path", moduleSrc.toString(), + "-processorpath", System.getProperty("test.class.path"), + "-processor", UnboundLookupNew.class.getName(), + "-AlookupClass=+test.Test", + "-AlookupPackage=+test,+api", + "-XDrawDiagnostics") + .outdir(classes) + .files(findJavaFiles(m2)) + .run() + .writeAll() + .getOutputLines(OutputKind.DIRECT); + + List expected = Arrays.asList("- compiler.note.proc.messager: test.Test found in module: m2x", + "- compiler.note.proc.messager: test found in module: m2x", + "- compiler.note.proc.messager: api found in module: m1x", + "- compiler.note.proc.messager: test.Test found in module: m2x", + "- compiler.note.proc.messager: test found in module: m2x", + "- compiler.note.proc.messager: api found in module: m1x" + ); + + if (!expected.equals(log)) { + throw new AssertionError("Expected output not found: " + log); + } + } + + { + tb.cleanDirectory(classes); + tb.cleanDirectory(moduleSrc); + + tb.writeJavaFiles(m1, + "module m1x { exports test; }", + "package test; public class Test { }"); + + tb.writeJavaFiles(m2, + "module m2x { requires m1x; }", + "package test; public class Test { }"); + + List log = new JavacTask(tb) + .options("--module-source-path", moduleSrc.toString(), + "-processorpath", System.getProperty("test.class.path"), + "-processor", UnboundLookupNew.class.getName(), + "-AlookupClass=+test.Test", + "-AlookupPackage=+test", + "-XDrawDiagnostics", + "-XDshould-stop.at=FLOW") + .outdir(classes) + .files(findJavaFiles(m2)) + .run(Task.Expect.FAIL) + .writeAll() + .getOutputLines(OutputKind.DIRECT); + + List expected = Arrays.asList( + "Test.java:1:1: compiler.err.package.in.other.module: m1x", + "- compiler.note.proc.messager: test.Test found in module: m2x", + "- compiler.note.proc.messager: test found in module: m1x", + "- compiler.note.proc.messager: test.Test found in module: m2x", + "- compiler.note.proc.messager: test found in module: m1x", + "1 error"); + + if (!expected.equals(log)) { + throw new AssertionError("Expected output not found: " + log); + } + } + + { + tb.cleanDirectory(classes); + tb.cleanDirectory(moduleSrc); + + tb.writeJavaFiles(m1, + "module m1x { }", + "package test; public class Test { }"); + + tb.writeJavaFiles(m2, + "module m2x { requires m1x; requires m3x; }", + "package test; public class Test { }"); + + tb.writeJavaFiles(m3, + "module m3x { }", + "package test; public class Test { }"); + + new JavacTask(tb) + .options("--module-source-path", moduleSrc.toString()) + .outdir(classes) + .files(findJavaFiles(moduleSrc)) + .run() + .writeAll() + .getOutputLines(OutputKind.DIRECT); + + List log = new JavacTask(tb) + .options("--module-source-path", moduleSrc.toString(), + "-processorpath", System.getProperty("test.class.path"), + "-processor", UnboundLookupNew.class.getName(), + "-AlookupClass=+test.Test", + "-AlookupPackage=+test", + "-XDrawDiagnostics") + .outdir(classes) + .files(findJavaFiles(m2)) + .run() + .writeAll() + .getOutputLines(OutputKind.DIRECT); + + List expected = Arrays.asList( + "- compiler.note.proc.messager: test.Test found in module: m2x", + "- compiler.note.proc.messager: test found in module: m2x", + "- compiler.note.proc.messager: test.Test found in module: m2x", + "- compiler.note.proc.messager: test found in module: m2x" + ); + + if (!expected.equals(log)) { + throw new AssertionError("Expected output not found: " + log); + } + } + + { + tb.cleanDirectory(classes); + tb.cleanDirectory(moduleSrc); + + tb.writeJavaFiles(m1, + "module m1x { exports test; }", + "package test; public class Test { }"); + + tb.writeJavaFiles(m2, + "module m2x { requires m1x; requires m3x; }"); + + tb.writeJavaFiles(m3, + "module m3x { exports test; }", + "package test; public class Test { }"); + + tb.writeJavaFiles(m4, + "module m4x { }", + "package test; public class Test { }"); + + { + List log = new JavacTask(tb) + .options("--module-source-path", moduleSrc.toString(), + "-processorpath", System.getProperty("test.class.path"), + "-processor", UnboundLookupNew.class.getName(), + "-AlookupClass=+test.Test", + "-AlookupPackage=+test", + "-XDrawDiagnostics", + "-XDshould-stop.at=FLOW") + .outdir(classes) + .files(findJavaFiles(m2)) + .run(Task.Expect.FAIL) + .writeAll() + .getOutputLines(OutputKind.DIRECT); + + List> expected = Arrays.asList( + variants("module-info.java:1:1: compiler.err.package.clash.from.requires: m2x, test, m1x, m3x"), + variants("- compiler.note.proc.messager: test.Test found in module: m1x"), + variants("- compiler.note.proc.messager: test found in module: m1x"), + variants("- compiler.note.proc.messager: test.Test found in module: m1x"), + variants("- compiler.note.proc.messager: test found in module: m1x"), + variants("1 error")); + + assertErrorsWithVariants(expected, log); + } + + { + List log = new JavacTask(tb) + .options("--module-source-path", moduleSrc.toString(), + "-processorpath", System.getProperty("test.class.path"), + "-processor", UnboundLookupNew.class.getName(), + "-AlookupClass=-test.Test", + "-AlookupPackage=-test", + "-XDrawDiagnostics", + "-XDshould-stop.at=FLOW") + .outdir(classes) + .files(findJavaFiles(m2, m4)) + .run(Task.Expect.FAIL) + .writeAll() + .getOutputLines(OutputKind.DIRECT); + + List expected = Arrays.asList( + "module-info.java:1:1: compiler.err.package.clash.from.requires: m2x, test, m1x, m3x", + "- compiler.note.multiple.elements: getTypeElement, test.Test, m1x, m4x", + "- compiler.note.multiple.elements: getPackageElement, test, m1x, m4x", + "1 error"); + + if (!expected.equals(log)) { + throw new AssertionError("Expected output not found: " + log); + } + } + } + + { + tb.cleanDirectory(classes); + tb.cleanDirectory(moduleSrc); + + tb.writeJavaFiles(m1, + "module m1x { exports test; }", + "package test; public class Test { }"); + + tb.writeJavaFiles(m2, + "module m2x { requires m1x; }"); + + tb.writeJavaFiles(src, + "package test; public class Test { }"); + + new JavacTask(tb) + .options("--module-source-path", moduleSrc.toString()) + .outdir(classes) + .files(findJavaFiles(moduleSrc)) + .run() + .writeAll() + .getOutputLines(OutputKind.DIRECT); + + List log = new JavacTask(tb) + .options("--module-source-path", moduleSrc.toString(), + "--source-path", src.toString(), + "-processorpath", System.getProperty("test.class.path"), + "-processor", UnboundLookupNew.class.getName(), + "-AlookupClass=+test.Test", + "-AlookupPackage=+test", + "-XDrawDiagnostics") + .outdir(classes) + .files(findJavaFiles(m2)) + .run() + .writeAll() + .getOutputLines(OutputKind.DIRECT); + + List expected = Arrays.asList( + "- compiler.note.proc.messager: test.Test found in module: m1x", + "- compiler.note.proc.messager: test found in module: m1x", + "- compiler.note.proc.messager: test.Test found in module: m1x", + "- compiler.note.proc.messager: test found in module: m1x" + ); + + if (!expected.equals(log)) { + throw new AssertionError("Expected output not found: " + log); + } + } + + { + tb.cleanDirectory(classes); + tb.cleanDirectory(moduleSrc); + + tb.writeJavaFiles(m1, + "module m1x { exports test; }", + "package test; public class Test { }"); + + tb.writeJavaFiles(m2, + "module m2x { requires m1x; }"); + + tb.writeJavaFiles(src, + "package test; public class Test { }"); + + new JavacTask(tb) + .options("--module-source-path", moduleSrc.toString()) + .outdir(classes) + .files(findJavaFiles(moduleSrc)) + .run() + .writeAll() + .getOutputLines(OutputKind.DIRECT); + + List log = new JavacTask(tb) + .options("--module-source-path", moduleSrc.toString(), + "--source-path", src.toString(), + "--add-reads=m2x=ALL-UNNAMED", + "-processorpath", System.getProperty("test.class.path"), + "-processor", UnboundLookupNew.class.getName(), + "-AlookupClass=+test.Test", + "-AlookupPackage=+test", + "-XDrawDiagnostics") + .outdir(classes) + .files(findJavaFiles(m2)) + .run() + .writeAll() + .getOutputLines(OutputKind.DIRECT); + + List expected = Arrays.asList( + "- compiler.note.proc.messager: test.Test found in module: m1x", + "- compiler.note.proc.messager: test found in module: m1x", + "- compiler.note.proc.messager: test.Test found in module: m1x", + "- compiler.note.proc.messager: test found in module: m1x" + ); + + if (!expected.equals(log)) { + throw new AssertionError("Expected output not found: " + log); + } + } + + { + tb.cleanDirectory(classes); + tb.cleanDirectory(srcClasses); + tb.cleanDirectory(moduleSrc); + + tb.writeJavaFiles(m1, + "module m1x { exports test; }", + "package test; public class Test { }"); + + tb.writeJavaFiles(m2, + "module m2x { requires m1x; }"); + + tb.writeJavaFiles(src, + "package test; public class Test { }"); + + new JavacTask(tb) + .options("--module-source-path", moduleSrc.toString()) + .outdir(classes) + .files(findJavaFiles(moduleSrc)) + .run() + .writeAll() + .getOutputLines(OutputKind.DIRECT); + + List log = new JavacTask(tb) + .options("--module-path", classes.toString(), + "--source-path", src.toString(), + "-processorpath", System.getProperty("test.class.path"), + "-processor", UnboundLookupNew.class.getName(), + "-AlookupClass=+test.Test", + "-AlookupPackage=+test", + "--add-modules=m2x", + "-XDshould-stop.at=ATTR", + "-XDrawDiagnostics") + .outdir(srcClasses) + .files(findJavaFiles(src)) + .run(Task.Expect.FAIL) + .writeAll() + .getOutputLines(OutputKind.DIRECT); + + List expected = Arrays.asList("Test.java:1:1: compiler.err.package.in.other.module: m1x", + "- compiler.note.proc.messager: test.Test found in module: unnamed module", + "- compiler.note.proc.messager: test found in module: m1x", + "- compiler.note.proc.messager: test.Test found in module: unnamed module", + "- compiler.note.proc.messager: test found in module: m1x", + "1 error" + ); + + if (!expected.equals(log)) { + throw new AssertionError("Expected output not found: " + log); + } + } + } + + private Set variants(String... expected) { + return new HashSet<>(Arrays.asList(expected)); + } + + private void assertErrorsWithVariants(List> expectedVariants, List actual) { + assertEquals(expectedVariants.size(), actual.size()); + Iterator> expIt = expectedVariants.iterator(); + Iterator actIt = actual.iterator(); + + while (expIt.hasNext() && actIt.hasNext()) { + Set exp = expIt.next(); + String act = actIt.next(); + + if (!exp.contains(act)) { + throw new AssertionError("Expected: " + exp + ", actual: " + act); + } + } + } + + @SupportedAnnotationTypes("*") + @SupportedOptions({"lookupClass", "lookupPackage"}) + public static final class UnboundLookupNew extends AbstractProcessor { + + @Override + public boolean process(Set annotations, RoundEnvironment roundEnv) { + performLookup("lookupClass", processingEnv.getElementUtils()::getTypeElement); + performLookup("lookupPackage", processingEnv.getElementUtils()::getPackageElement); + + return false; + } + + private void performLookup(String optionName, Function name2Element) { + String[] lookupList = processingEnv.getOptions().get(optionName).split(","); + for (String lookup : lookupList) { + boolean shouldExists = lookup.charAt(0) == '+'; + String name = lookup.substring(1); + Element type = name2Element.apply(name); + + if (shouldExists) { + if (type == null) { + throw new AssertionError("Did not find the expected type."); + } else { + processingEnv.getMessager().printMessage(Kind.NOTE, name + " found in module: " + processingEnv.getElementUtils().getModuleOf(type)); + } + } else { + if (type != null) { + throw new AssertionError("Found the unexpected type."); + } + } + } + } + + @Override + public SourceVersion getSupportedSourceVersion() { + return SourceVersion.latest(); + } + + } + @Test public void testUnboundLookup(Path base) throws Exception { Path src = base.resolve("src"); @@ -1333,7 +1764,7 @@ public void testUnboundLookup(Path base) throws Exception { "package nested.pack; public class Impl { }"); //from source: - String log = new JavacTask(tb) + new JavacTask(tb) .options("--module-source-path", moduleSrc.toString(), "--source-path", src.toString(), "-processorpath", System.getProperty("test.class.path"), @@ -1345,20 +1776,6 @@ public void testUnboundLookup(Path base) throws Exception { .writeAll() .getOutput(OutputKind.DIRECT); - String moduleImplConflictString = - "- compiler.note.multiple.elements: getTypeElement, impl.conflict.module.Impl, m2x, m1x"; - String srcConflictString = - "- compiler.note.multiple.elements: getTypeElement, impl.conflict.src.Impl, m1x, unnamed module"; - - if (!log.contains(moduleImplConflictString) || - !log.contains(srcConflictString)) { - throw new AssertionError("Expected output not found: " + log); - } - - if (log.split(Pattern.quote(moduleImplConflictString)).length > 2) { - throw new AssertionError("Too many warnings in: " + log); - } - new JavacTask(tb) .options("--source-path", src.toString()) .outdir(cpClasses) @@ -1373,7 +1790,8 @@ public void testUnboundLookup(Path base) throws Exception { "--add-modules", "m1x,m2x", "-processorpath", System.getProperty("test.class.path"), "-processor", UnboundLookup.class.getName(), - "-proc:only") + "-proc:only", + "-Aunnamedmodule") .classes("java.lang.Object") .run() .writeAll(); @@ -1405,6 +1823,7 @@ public void testUnboundLookup(Path base) throws Exception { } @SupportedAnnotationTypes("*") + @SupportedOptions("unnamedmodule") public static final class UnboundLookup extends AbstractProcessor { @Override @@ -1422,8 +1841,8 @@ public boolean process(Set annotations, RoundEnvironment assertTypeElementNotFound("impl.conflict.module.Impl"); assertTypeElementNotFound("impl.conflict.module.Impl"); //check that the warning/note is produced only once assertPackageElementNotFound("impl.conflict.module"); - assertTypeElementNotFound("impl.conflict.src.Impl"); - assertPackageElementNotFound("impl.conflict.src"); + assertTypeElementExists("impl.conflict.src.Impl", processingEnv.getOptions().containsKey("unnamedmodule") ? "" : "m1x"); + assertPackageElementExists("impl.conflict.src", processingEnv.getOptions().containsKey("unnamedmodule") ? "" : "m1x"); assertTypeElementNotFound("impl.conflict.clazz.pkg"); assertPackageElementNotFound("unique"); //do not return packages without members in module mode assertTypeElementNotFound("nested"); //cannot distinguish between m1x and m2x diff --git a/test/langtools/tools/javac/parser/JavacParserTest.java b/test/langtools/tools/javac/parser/JavacParserTest.java index cb7b8d01382..e12e40ce4c4 100644 --- a/test/langtools/tools/javac/parser/JavacParserTest.java +++ b/test/langtools/tools/javac/parser/JavacParserTest.java @@ -23,7 +23,7 @@ /* * @test - * @bug 7073631 7159445 7156633 8028235 8065753 8205418 8205913 8228451 8237041 8253584 + * @bug 7073631 7159445 7156633 8028235 8065753 8205418 8205913 8228451 8237041 8253584 8246774 * @summary tests error and diagnostics positions * @author Jan Lahoda * @modules jdk.compiler/com.sun.tools.javac.api @@ -999,7 +999,7 @@ void testVoidLambdaParameter() throws IOException { @Test //JDK-8065753 void testWrongFirstToken() throws IOException { String code = "<"; - String expectedErrors = "Test.java:1:1: compiler.err.expected3: class, interface, enum\n" + + String expectedErrors = "Test.java:1:1: compiler.err.expected4: class, interface, enum, record\n" + "1 error\n"; StringWriter out = new StringWriter(); JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(out, fm, null, diff --git a/test/langtools/tools/javac/parser/SingleCommaAnnotationValueFail.out b/test/langtools/tools/javac/parser/SingleCommaAnnotationValueFail.out index 8c8f0566d15..3748ccfeb97 100644 --- a/test/langtools/tools/javac/parser/SingleCommaAnnotationValueFail.out +++ b/test/langtools/tools/javac/parser/SingleCommaAnnotationValueFail.out @@ -1,3 +1,3 @@ SingleCommaAnnotationValueFail.java:34:12: compiler.err.expected: '}' -SingleCommaAnnotationValueFail.java:34:14: compiler.err.expected3: class, interface, enum +SingleCommaAnnotationValueFail.java:34:14: compiler.err.expected4: class, interface, enum, record 2 errors diff --git a/test/langtools/tools/javac/processing/model/element/JavaxLangModelForRecords.java b/test/langtools/tools/javac/processing/model/element/JavaxLangModelForRecords.java index 85fa3b90435..9bc06ce6d42 100644 --- a/test/langtools/tools/javac/processing/model/element/JavaxLangModelForRecords.java +++ b/test/langtools/tools/javac/processing/model/element/JavaxLangModelForRecords.java @@ -23,6 +23,7 @@ /* * @test + * @bug 8246774 * @summary Verify that annotation processing works for records * @library /tools/lib /tools/javac/lib * @modules @@ -67,7 +68,6 @@ public class JavaxLangModelForRecords extends TestRunner { } public static void main(String... args) throws Exception { - System.out.println(System.getProperties()); new JavaxLangModelForRecords().runTests(); } @@ -105,17 +105,13 @@ public void testQualifiedClassForProcessing(Path base) throws Exception { tb.writeJavaFiles(r, "record R(int i) {}"); - List expected = List.of("Note: field: i", - "Note: record component: i", - "Note: testQualifiedClassForProcessing" + File.separator + "src" + File.separator - + "R" + File.separator + "R.java uses preview language features.", - "Note: Recompile with -Xlint:preview for details."); + List expected = List.of( + "Note: field: i", + "Note: record component: i"); for (Mode mode : new Mode[] {Mode.API}) { List log = new JavacTask(tb, mode) - .options("-processor", QualifiedClassForProcessing.class.getName(), - "--enable-preview", - "-source", Integer.toString(Runtime.version().feature())) + .options("-processor", QualifiedClassForProcessing.class.getName()) .files(findJavaFiles(src)) .outdir(classes) .run() diff --git a/test/langtools/tools/javac/records/ElementFilterRecordComponentTest.java b/test/langtools/tools/javac/records/ElementFilterRecordComponentTest.java index 062de5b5392..3ca306ed34f 100644 --- a/test/langtools/tools/javac/records/ElementFilterRecordComponentTest.java +++ b/test/langtools/tools/javac/records/ElementFilterRecordComponentTest.java @@ -23,7 +23,7 @@ /* * @test - * @bug 8241312 + * @bug 8241312 8246774 * @summary test for javax.lang.model.util.ElementFilter::recordComponentsIn * @modules jdk.compiler/com.sun.tools.javac.util */ @@ -47,8 +47,7 @@ public class ElementFilterRecordComponentTest { public static void main(String... args) throws IOException { JavaCompiler c = ToolProvider.getSystemJavaCompiler(); - JavacTask t = (JavacTask) c.getTask(null, null, null, - List.of("--enable-preview", "-source", Integer.toString(Runtime.version().feature())), null, + JavacTask t = (JavacTask) c.getTask(null, null, null, null, null, List.of(new SimpleJavaFileObject(URI.create("TestClass.java"), JavaFileObject.Kind.SOURCE) { @Override public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException { diff --git a/test/langtools/tools/javac/records/LocalStaticDeclarations.java b/test/langtools/tools/javac/records/LocalStaticDeclarations.java index 1b8519bc7b9..53dd9854231 100644 --- a/test/langtools/tools/javac/records/LocalStaticDeclarations.java +++ b/test/langtools/tools/javac/records/LocalStaticDeclarations.java @@ -23,15 +23,14 @@ /* * @test - * @bug 8242293 + * @bug 8242293 8246774 * @summary allow for local interfaces and enums plus nested records, interfaces and enums * @library /tools/javac/lib * @modules jdk.compiler/com.sun.tools.javac.api * jdk.compiler/com.sun.tools.javac.file * jdk.compiler/com.sun.tools.javac.util * @build combo.ComboTestHelper - * @compile --enable-preview -source ${jdk.version} LocalStaticDeclarations.java - * @run main/othervm --enable-preview LocalStaticDeclarations + * @run main LocalStaticDeclarations */ import javax.lang.model.element.Element; @@ -175,7 +174,6 @@ public static void main(String... args) throws Exception { @Override public void doWork() throws Throwable { newCompilationTask() - .withOptions(new String[]{"--enable-preview", "-source", Integer.toString(Runtime.version().feature())}) .withSourceFromTemplate("Test", sourceTemplate) .generate(this::check); } diff --git a/test/langtools/tools/javac/records/MapAccessorToComponent.java b/test/langtools/tools/javac/records/MapAccessorToComponent.java index e8f2bcac492..9927d0ddb76 100644 --- a/test/langtools/tools/javac/records/MapAccessorToComponent.java +++ b/test/langtools/tools/javac/records/MapAccessorToComponent.java @@ -23,6 +23,7 @@ /* * @test + * @bug 8246774 * @summary test for javax.lang.model.util.Elements::recordComponentFor * @modules jdk.compiler */ @@ -51,8 +52,7 @@ public static void main(String... args) throws IOException { public void run() throws IOException { String code = "record R(int val1, int val2) {}"; JavaCompiler c = ToolProvider.getSystemJavaCompiler(); - JavacTask t = (JavacTask) c.getTask(null, null, null, - List.of("--enable-preview", "-source", Integer.toString(Runtime.version().feature())), null, + JavacTask t = (JavacTask) c.getTask(null, null, null, null, null, List.of(new MyFileObject(code))); TypeElement record = (TypeElement) t.analyze().iterator().next(); for (RecordComponentElement rce : ElementFilter.recordComponentsIn(record.getEnclosedElements())) { diff --git a/test/langtools/tools/javac/records/RecordCompilationTests.java b/test/langtools/tools/javac/records/RecordCompilationTests.java index 279ded7443d..ee9c99a8e7b 100644 --- a/test/langtools/tools/javac/records/RecordCompilationTests.java +++ b/test/langtools/tools/javac/records/RecordCompilationTests.java @@ -26,7 +26,8 @@ /** * RecordCompilationTests * - * @test 8250629 8252307 8247352 8241151 + * @test + * @bug 8250629 8252307 8247352 8241151 8246774 * @summary Negative compilation tests, and positive compilation (smoke) tests for records * @library /lib/combo /tools/lib /tools/javac/lib * @modules @@ -35,9 +36,8 @@ * jdk.compiler/com.sun.tools.javac.util * jdk.jdeps/com.sun.tools.classfile * @build JavacTestingAbstractProcessor - * @compile --enable-preview -source ${jdk.version} RecordCompilationTests.java - * @run testng/othervm -DuseAP=false --enable-preview RecordCompilationTests - * @run testng/othervm -DuseAP=true --enable-preview RecordCompilationTests + * @run testng/othervm -DuseAP=false RecordCompilationTests + * @run testng/othervm -DuseAP=true RecordCompilationTests */ import java.io.File; @@ -119,17 +119,7 @@ @Test public class RecordCompilationTests extends CompilationTestCase { - // @@@ When records become a permanent feature, we don't need these any more - private static String[] PREVIEW_OPTIONS = { - "--enable-preview", - "-source", Integer.toString(Runtime.version().feature()) - }; - - private static String[] PREVIEW_OPTIONS_WITH_AP = { - "--enable-preview", - "-source", Integer.toString(Runtime.version().feature()), - "-processor", SimplestAP.class.getName() - }; + private static String[] OPTIONS_WITH_AP = {"-processor", SimplestAP.class.getName()}; private static final List BAD_COMPONENT_NAMES = List.of( "clone", "finalize", "getClass", "hashCode", @@ -150,7 +140,9 @@ public boolean process(Set annotations, RoundEnvironment public RecordCompilationTests() { useAP = System.getProperty("useAP", "false").equals("true"); setDefaultFilename("R.java"); - setCompileOptions(useAP ? PREVIEW_OPTIONS_WITH_AP : PREVIEW_OPTIONS); + if (useAP) { + setCompileOptions(OPTIONS_WITH_AP); + } System.out.println(useAP ? "running all tests using an annotation processor" : "running all tests without annotation processor"); } @@ -1010,7 +1002,7 @@ public void testAcceptRecordId() { String[] previousOptions = getCompileOptions(); String[] testOptions = {/* no options */}; setCompileOptions(testOptions); - assertOKWithWarning("compiler.warn.restricted.type.not.allowed.preview", + assertFail("compiler.err.illegal.start.of.type", "class R {\n" + " record RR(int i) {\n" + " return null;\n" + @@ -1062,8 +1054,6 @@ record R(@Anno String s) {} ); String[] generalOptions = { - "--enable-preview", - "-source", Integer.toString(Runtime.version().feature()), "-processor", Processor.class.getName(), "-Atargets=" }; diff --git a/test/langtools/tools/javac/records/RecordMemberTests.java b/test/langtools/tools/javac/records/RecordMemberTests.java index 85d9434ffb6..a754f294723 100644 --- a/test/langtools/tools/javac/records/RecordMemberTests.java +++ b/test/langtools/tools/javac/records/RecordMemberTests.java @@ -24,11 +24,10 @@ */ /** - * RecordMemberTests - * * @test - * @compile --enable-preview -source ${jdk.version} RecordMemberTests.java - * @run testng/othervm --enable-preview RecordMemberTests + * @bug 8246774 + * @summary test several assertions on record classes members + * @run testng RecordMemberTests */ import java.lang.reflect.Constructor; diff --git a/test/langtools/tools/javac/records/VarargsRecordsTest.java b/test/langtools/tools/javac/records/VarargsRecordsTest.java index 2151db278ac..2e60ec810ea 100644 --- a/test/langtools/tools/javac/records/VarargsRecordsTest.java +++ b/test/langtools/tools/javac/records/VarargsRecordsTest.java @@ -33,11 +33,10 @@ import static org.testng.Assert.*; /** - * VarargsRecordsTest - * * @test - * @compile --enable-preview -source ${jdk.version} VarargsRecordsTest.java - * @run testng/othervm --enable-preview VarargsRecordsTest + * @bug 8246774 + * @summary test for varargs record components + * @run testng VarargsRecordsTest */ @Test public class VarargsRecordsTest { diff --git a/test/langtools/tools/javac/records/mandated_members/CheckRecordMembers.java b/test/langtools/tools/javac/records/mandated_members/CheckRecordMembers.java index e862ec42538..f0aab5985d5 100644 --- a/test/langtools/tools/javac/records/mandated_members/CheckRecordMembers.java +++ b/test/langtools/tools/javac/records/mandated_members/CheckRecordMembers.java @@ -25,6 +25,7 @@ * CheckRecordMembers * * @test + * @bug 8246774 * @summary check that the accessors, equals, hashCode and toString methods * work as expected * @library /tools/javac/lib @@ -32,7 +33,7 @@ * jdk.compiler/com.sun.tools.javac.api * jdk.compiler/com.sun.tools.javac.util * @build combo.ComboTestHelper - * @run main/othervm --enable-preview CheckRecordMembers + * @run main CheckRecordMembers */ import java.lang.reflect.Constructor; @@ -102,7 +103,6 @@ public static void main(String... args) throws Exception { @Override public void doWork() throws Throwable { newCompilationTask() - .withOptions(new String[]{"--enable-preview", "-source", Integer.toString(Runtime.version().feature())}) .withSourceFromTemplate("Data", sourceTemplate) .generate(this::check); } diff --git a/test/langtools/tools/javac/records/writeread/WriteReadTest.java b/test/langtools/tools/javac/records/writeread/WriteReadTest.java index 2d6430ee7ae..e7d75a852f4 100644 --- a/test/langtools/tools/javac/records/writeread/WriteReadTest.java +++ b/test/langtools/tools/javac/records/writeread/WriteReadTest.java @@ -23,9 +23,10 @@ /* * @test + * @bug 8246774 * @summary Verify javac can read record classfiles it writes - * @compile --enable-preview -source ${jdk.version} Record.java - * @compile --enable-preview -source ${jdk.version} WriteReadTest.java + * @compile Record.java + * @compile WriteReadTest.java */ public class WriteReadTest { Record1 r1; diff --git a/test/langtools/tools/javac/tree/TreePosTest.java b/test/langtools/tools/javac/tree/TreePosTest.java index ba5876bb9d9..add1db72e29 100644 --- a/test/langtools/tools/javac/tree/TreePosTest.java +++ b/test/langtools/tools/javac/tree/TreePosTest.java @@ -79,6 +79,7 @@ import com.sun.tools.javac.tree.JCTree.JCAnnotatedType; import com.sun.tools.javac.tree.JCTree.JCCase; import com.sun.tools.javac.tree.JCTree.JCCompilationUnit; +import com.sun.tools.javac.tree.JCTree.JCMethodDecl; import com.sun.tools.javac.tree.JCTree.JCNewClass; import com.sun.tools.javac.tree.JCTree.JCVariableDecl; import com.sun.tools.javac.tree.TreeInfo; @@ -419,6 +420,14 @@ private boolean isAnnotatedArray(JCTree tree) { ((JCAnnotatedType)tree).underlyingType.hasTag(TYPEARRAY); } + @Override + public void visitMethodDef(JCMethodDecl tree) { + // ignore compact record constructors + if ((tree.mods.flags & Flags.COMPACT_RECORD_CONSTRUCTOR) == 0) { + super.visitMethodDef(tree); + } + } + @Override public void visitVarDef(JCVariableDecl tree) { // enum member declarations are desugared in the parser and have diff --git a/test/langtools/tools/sjavac/PubApisTest.java b/test/langtools/tools/sjavac/PubApisTest.java index 2192aeee531..c62166fb793 100644 --- a/test/langtools/tools/sjavac/PubApisTest.java +++ b/test/langtools/tools/sjavac/PubApisTest.java @@ -23,13 +23,12 @@ /* * @test - * @bug 8241312 + * @bug 8241312 8246774 * @summary test for com.sun.tools.sjavac.comp.PubAPIs and com.sun.tools.sjavac.comp.PubapiVisitor * @library /tools/lib * @modules jdk.compiler/com.sun.tools.javac.util * jdk.compiler/com.sun.tools.sjavac.comp * jdk.compiler/com.sun.tools.sjavac.pubapi - * @run main PubApisTest */ import com.sun.source.util.JavacTask; import com.sun.tools.javac.util.Context; @@ -48,8 +47,7 @@ public class PubApisTest { public static void main(String[] args) throws Throwable { javax.tools.JavaCompiler c = ToolProvider.getSystemJavaCompiler(); - JavacTask t = (JavacTask) c.getTask(null, null, null, - List.of("--enable-preview", "-source", Integer.toString(Runtime.version().feature())), null, + JavacTask t = (JavacTask) c.getTask(null, null, null, null, null, List.of(new SimpleJavaFileObject(URI.create("TestClass.java"), JavaFileObject.Kind.SOURCE) { @Override public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException { diff --git a/test/lib-test/jdk/test/lib/hexdump/ASN1FormatterTest.java b/test/lib-test/jdk/test/lib/hexdump/ASN1FormatterTest.java index 01887fa8baa..c7622d4b9b4 100644 --- a/test/lib-test/jdk/test/lib/hexdump/ASN1FormatterTest.java +++ b/test/lib-test/jdk/test/lib/hexdump/ASN1FormatterTest.java @@ -39,6 +39,7 @@ /* * @test * @summary ASN.1 formatting + * @modules java.base/sun.security.util * @library /test/lib * @compile ASN1FormatterTest.java * @run testng jdk.test.lib.hexdump.ASN1FormatterTest diff --git a/test/lib/jdk/test/lib/hexdump/ASN1Formatter.java b/test/lib/jdk/test/lib/hexdump/ASN1Formatter.java index fb9486c3f95..086aa81e471 100644 --- a/test/lib/jdk/test/lib/hexdump/ASN1Formatter.java +++ b/test/lib/jdk/test/lib/hexdump/ASN1Formatter.java @@ -412,7 +412,6 @@ private static String oidName(byte[] bytes) { // Look up the OID; if the class is not accessible just return the numeric form Class cl = Class.forName("sun.security.util.KnownOIDs"); Method findMatch = cl.getDeclaredMethod("findMatch", String.class); - findMatch.setAccessible(true); Object oid = findMatch.invoke(null, noid); return (oid == null) ? noid : noid + " (" + oid.toString() + ")"; } catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { diff --git a/test/lib/jdk/test/lib/security/DerUtils.java b/test/lib/jdk/test/lib/security/DerUtils.java index c2efaf91503..06e6ece738f 100644 --- a/test/lib/jdk/test/lib/security/DerUtils.java +++ b/test/lib/jdk/test/lib/security/DerUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2020, 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,6 +25,7 @@ import jdk.test.lib.Asserts; import sun.security.util.DerInputStream; import sun.security.util.DerValue; +import sun.security.util.KnownOIDs; import sun.security.util.ObjectIdentifier; import java.io.IOException; @@ -95,8 +96,18 @@ public static DerValue innerDerValue(byte[] data, String location) * Ensures that the inner DerValue is the expected ObjectIdentifier. */ public static void checkAlg(byte[] der, String location, - ObjectIdentifier expected) throws Exception { - Asserts.assertEQ(innerDerValue(der, location).getOID(), expected); + Object expected) throws Exception { + ObjectIdentifier oid; + if (expected instanceof ObjectIdentifier) { + oid = (ObjectIdentifier)expected; + } else if (expected instanceof KnownOIDs) { + oid = ObjectIdentifier.of((KnownOIDs) expected); + } else if (expected instanceof String) { + oid = ObjectIdentifier.of(KnownOIDs.findMatch((String)expected)); + } else { + throw new IllegalArgumentException(expected.toString()); + } + Asserts.assertEQ(innerDerValue(der, location).getOID(), oid); } /** diff --git a/test/micro/org/openjdk/bench/java/io/RecordDeserialization.java b/test/micro/org/openjdk/bench/java/io/RecordDeserialization.java index b2dbefe3c05..f119ce37b2b 100644 --- a/test/micro/org/openjdk/bench/java/io/RecordDeserialization.java +++ b/test/micro/org/openjdk/bench/java/io/RecordDeserialization.java @@ -82,7 +82,7 @@ @Measurement(iterations = 10, time = 1) @OutputTimeUnit(TimeUnit.MICROSECONDS) @State(Scope.Thread) -@Fork(value = 1, warmups = 0, jvmArgsAppend = "--enable-preview") +@Fork(value = 1, warmups = 0) public class RecordDeserialization { public record PointR(int x, int y) implements Serializable {} diff --git a/test/micro/org/openjdk/bench/java/lang/StringIndexOfChar.java b/test/micro/org/openjdk/bench/java/lang/StringIndexOfChar.java index 245789ae10a..adc3c296460 100644 --- a/test/micro/org/openjdk/bench/java/lang/StringIndexOfChar.java +++ b/test/micro/org/openjdk/bench/java/lang/StringIndexOfChar.java @@ -25,10 +25,13 @@ import java.util.Random; import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; +import org.openjdk.jmh.annotations.Param; import org.openjdk.jmh.annotations.OutputTimeUnit; import org.openjdk.jmh.annotations.Mode; +import org.openjdk.jmh.annotations.Setup; import org.openjdk.jmh.annotations.Scope; import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.infra.Blackhole; import java.util.concurrent.TimeUnit; @@ -41,18 +44,37 @@ @OutputTimeUnit(TimeUnit.NANOSECONDS) @State(Scope.Thread) public class StringIndexOfChar { - private static final int loops = 100000; - private static final Random rng = new Random(1999); - private static final int pathCnt = 1000; - private static final String [] latn1_short = new String[pathCnt]; - private static final String [] latn1_sse4 = new String[pathCnt]; - private static final String [] latn1_avx2 = new String[pathCnt]; - private static final String [] latn1_mixedLength = new String[pathCnt]; - private static final String [] utf16_short = new String[pathCnt]; - private static final String [] utf16_sse4 = new String[pathCnt]; - private static final String [] utf16_avx2 = new String[pathCnt]; - private static final String [] utf16_mixedLength = new String[pathCnt]; - static { + @Param("100000") + private int loops; + + @Param("1000") + private int pathCnt; + + @Param("1999") + private int rngSeed; + + private Random rng; + private String[] latn1_short; + private String[] latn1_sse4; + private String[] latn1_avx2; + private String[] latn1_mixedLength; + private String[] utf16_short; + private String[] utf16_sse4; + private String[] utf16_avx2; + private String[] utf16_mixedLength; + + @Setup + public void setup() { + rng = new Random(rngSeed); + latn1_short = new String[pathCnt]; + latn1_sse4 = new String[pathCnt]; + latn1_avx2 = new String[pathCnt]; + latn1_mixedLength = new String[pathCnt]; + utf16_short = new String[pathCnt]; + utf16_sse4 = new String[pathCnt]; + utf16_avx2 = new String[pathCnt]; + utf16_mixedLength = new String[pathCnt]; + for (int i = 0; i < pathCnt; i++) { latn1_short[i] = makeRndString(false, 15); latn1_sse4[i] = makeRndString(false, 16); @@ -65,7 +87,7 @@ public class StringIndexOfChar { } } - private static String makeRndString(boolean isUtf16, int length) { + private String makeRndString(boolean isUtf16, int length) { StringBuilder sb = new StringBuilder(length); if(length > 0){ sb.append(isUtf16?'\u2026':'b'); // ... @@ -81,141 +103,116 @@ private static String makeRndString(boolean isUtf16, int length) { @Benchmark - public void latin1_mixed_char() { - int ret = 0; + public void latin1_mixed_char(Blackhole bh) { for (String what : latn1_mixedLength) { - ret += what.indexOf('a'); + bh.consume(what.indexOf('a')); } } @Benchmark - public void utf16_mixed_char() { - int ret = 0; + public void utf16_mixed_char(Blackhole bh) { for (String what : utf16_mixedLength) { - ret += what.indexOf('a'); + bh.consume(what.indexOf('a')); } } @Benchmark - public void latin1_mixed_String() { - int ret = 0; + public void latin1_mixed_String(Blackhole bh) { for (String what : latn1_mixedLength) { - ret += what.indexOf("a"); + bh.consume(what.indexOf("a")); } } @Benchmark - public void utf16_mixed_String() { - int ret = 0; + public void utf16_mixed_String(Blackhole bh) { for (String what : utf16_mixedLength) { - ret += what.indexOf("a"); + bh.consume(what.indexOf("a")); } } ////////// more detailed code path dependent tests ////////// @Benchmark - public void latin1_Short_char() { - int ret = 0; + public void latin1_Short_char(Blackhole bh) { for (String what : latn1_short) { - ret += what.indexOf('a'); + bh.consume(what.indexOf('a')); } } @Benchmark - public void latin1_SSE4_char() { - int ret = 0; + public void latin1_SSE4_char(Blackhole bh) { for (String what : latn1_sse4) { - ret += what.indexOf('a'); + bh.consume(what.indexOf('a')); } } @Benchmark - public void latin1_AVX2_char() { - int ret = 0; + public void latin1_AVX2_char(Blackhole bh) { for (String what : latn1_avx2) { - ret += what.indexOf('a'); + bh.consume(what.indexOf('a')); } } @Benchmark - public int utf16_Short_char() { - int ret = 0; + public void utf16_Short_char(Blackhole bh) { for (String what : utf16_short) { - ret += what.indexOf('a'); + bh.consume(what.indexOf('a')); } - return ret; } @Benchmark - public int utf16_SSE4_char() { - int ret = 0; + public void utf16_SSE4_char(Blackhole bh) { for (String what : utf16_sse4) { - ret += what.indexOf('a'); + bh.consume(what.indexOf('a')); } - return ret; } @Benchmark - public int utf16_AVX2_char() { - int ret = 0; + public void utf16_AVX2_char(Blackhole bh) { for (String what : utf16_avx2) { - ret += what.indexOf('a'); + bh.consume(what.indexOf('a')); } - return ret; } @Benchmark - public int latin1_Short_String() { - int ret = 0; + public void latin1_Short_String(Blackhole bh) { for (String what : latn1_short) { - ret += what.indexOf("a"); + bh.consume(what.indexOf("a")); } - return ret; } @Benchmark - public int latin1_SSE4_String() { - int ret = 0; + public void latin1_SSE4_String(Blackhole bh) { for (String what : latn1_sse4) { - ret += what.indexOf("a"); + bh.consume(what.indexOf("a")); } - return ret; } @Benchmark - public int latin1_AVX2_String() { - int ret = 0; + public void latin1_AVX2_String(Blackhole bh) { for (String what : latn1_avx2) { - ret += what.indexOf("a"); + bh.consume(what.indexOf("a")); } - return ret; } @Benchmark - public int utf16_Short_String() { - int ret = 0; + public void utf16_Short_String(Blackhole bh) { for (String what : utf16_short) { - ret += what.indexOf("a"); + bh.consume(what.indexOf("a")); } - return ret; } @Benchmark - public int utf16_SSE4_String() { - int ret = 0; + public void utf16_SSE4_String(Blackhole bh) { for (String what : utf16_sse4) { - ret += what.indexOf("a"); + bh.consume(what.indexOf("a")); } - return ret; } @Benchmark - public int utf16_AVX2_String() { - int ret = 0; + public void utf16_AVX2_String(Blackhole bh) { for (String what : utf16_avx2) { - ret += what.indexOf("a"); + bh.consume(what.indexOf("a")); } - return ret; } } diff --git a/test/micro/org/openjdk/bench/java/math/BigIntegers.java b/test/micro/org/openjdk/bench/java/math/BigIntegers.java index 8b26b47cf1c..d3a20a3ee5e 100644 --- a/test/micro/org/openjdk/bench/java/math/BigIntegers.java +++ b/test/micro/org/openjdk/bench/java/math/BigIntegers.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2020, 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 @@ -34,6 +34,7 @@ import org.openjdk.jmh.annotations.Scope; import org.openjdk.jmh.annotations.Setup; import org.openjdk.jmh.annotations.State; +import org.openjdk.jmh.annotations.Param; import org.openjdk.jmh.infra.Blackhole; import java.math.BigInteger; @@ -45,11 +46,14 @@ @State(Scope.Thread) public class BigIntegers { - private BigInteger[] hugeArray, largeArray, smallArray, shiftArray; + private BigInteger[] hugeArray, largeArray, smallArray, shiftArray, smallShiftArray; public String[] dummyStringArray; public Object[] dummyArr; private static final int TESTSIZE = 1000; + @Param({"32", "64", "96", "128", "160", "192", "224", "256"}) + private int maxNumbits; + @Setup public void setup() { Random r = new Random(1123); @@ -72,6 +76,9 @@ public void setup() { * Each array entry is atmost 16k bits * in size */ + smallShiftArray = new BigInteger[TESTSIZE]; /* + * Small numbers, bits count in range [maxNumbits - 31, maxNumbits] + */ dummyStringArray = new String[TESTSIZE]; dummyArr = new Object[TESTSIZE]; @@ -84,6 +91,7 @@ public void setup() { largeArray[i] = new BigInteger("" + ((long) value + (long) Integer.MAX_VALUE)); smallArray[i] = new BigInteger("" + ((long) value / 1000)); shiftArray[i] = new BigInteger(numbits, r); + smallShiftArray[i] = new BigInteger(Math.max(maxNumbits - value % 32, 0), r); } } @@ -177,4 +185,30 @@ public void testRightShift(Blackhole bh) { } bh.consume(tmp); } + + /** Invokes the shiftLeft method of small BigInteger with different values. */ + @Benchmark + @OperationsPerInvocation(TESTSIZE) + public void testSmallLeftShift(Blackhole bh) { + Random rand = new Random(); + int shift = rand.nextInt(30) + 1; + BigInteger tmp = null; + for (BigInteger s : smallShiftArray) { + tmp = s.shiftLeft(shift); + bh.consume(tmp); + } + } + + /** Invokes the shiftRight method of small BigInteger with different values. */ + @Benchmark + @OperationsPerInvocation(TESTSIZE) + public void testSmallRightShift(Blackhole bh) { + Random rand = new Random(); + int shift = rand.nextInt(30) + 1; + BigInteger tmp = null; + for (BigInteger s : smallShiftArray) { + tmp = s.shiftRight(shift); + bh.consume(tmp); + } + } } diff --git a/test/micro/org/openjdk/bench/java/net/SocketChannelCompare.java b/test/micro/org/openjdk/bench/java/net/SocketChannelCompare.java new file mode 100644 index 00000000000..2d67bed5f23 --- /dev/null +++ b/test/micro/org/openjdk/bench/java/net/SocketChannelCompare.java @@ -0,0 +1,193 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.bench.java.net; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.StandardProtocolFamily; +import java.net.UnixDomainSocketAddress; +import java.nio.ByteBuffer; +import java.nio.channels.ClosedChannelException; +import java.nio.channels.ServerSocketChannel; +import java.nio.channels.SocketChannel; +import java.nio.file.*; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + +import org.openjdk.jmh.annotations.*; +import org.openjdk.jmh.runner.Runner; +import org.openjdk.jmh.runner.RunnerException; +import org.openjdk.jmh.runner.options.Options; +import org.openjdk.jmh.runner.options.OptionsBuilder; + +/** + * Tests sending a 128 byte message on a second, to a thread which + * echo's it back and received by the original thread. + * Benchmark is performed for "inet" channels over TCP/IP + * and "unix" domain channels. + */ +@BenchmarkMode(Mode.Throughput) +@OutputTimeUnit(TimeUnit.MILLISECONDS) +@State(Scope.Thread) +public class SocketChannelCompare { + + static final int BUFSIZE = 128; // message size sent and received + private ServerSocketChannel ssc; + private SocketChannel s1, s2; + private EchoThread rt; + private ByteBuffer bb = ByteBuffer.allocate(BUFSIZE); + + private static volatile String tempDir; + private static final AtomicInteger count = new AtomicInteger(0); + private volatile Path socket; + + @Param({"inet", "unix"}) + private volatile String family; + + static { + try { + Path p = Files.createTempDirectory("readWriteTest"); + tempDir = p.toString(); + } catch (IOException e) { + tempDir = null; + } + } + + private ServerSocketChannel getServerSocketChannel() throws IOException { + if (family.equals("inet")) + return getInetServerSocketChannel(); + else if (family.equals("unix")) + return getUnixServerSocketChannel(); + throw new InternalError(); + } + + + private ServerSocketChannel getInetServerSocketChannel() throws IOException { + InetAddress iaddr = InetAddress.getLoopbackAddress(); + return ServerSocketChannel.open().bind(null); + } + + private ServerSocketChannel getUnixServerSocketChannel() throws IOException { + int next = count.incrementAndGet(); + socket = Paths.get(tempDir, Integer.toString(next)); + UnixDomainSocketAddress addr = UnixDomainSocketAddress.of(socket); + return ServerSocketChannel.open(StandardProtocolFamily.UNIX).bind(addr); + } + + @Setup(Level.Trial) + public void beforeRun() throws IOException { + ssc = getServerSocketChannel(); + s1 = SocketChannel.open(ssc.getLocalAddress()); + s2 = ssc.accept(); + + rt = new EchoThread(s2); + rt.start(); + } + + @TearDown(Level.Trial) + public void afterRun() throws IOException, InterruptedException { + s1.close(); + s2.close(); + ssc.close(); + if (family.equals("unix")) { + Files.delete(socket); + Files.delete(Path.of(tempDir)); + } + rt.join(); + } + + @Benchmark + public void test() throws IOException { + bb.position(0).limit(BUFSIZE); + s1.write(bb); + bb.clear(); + readFully(s1, bb); + } + + // read until buf is full, or EOF. Always returns number of bytes read + + static int readFully(SocketChannel chan, ByteBuffer buf) throws IOException { + int n = buf.remaining(); + int count = 0; + while (n > 0) { + int c = chan.read(buf); + if (c == -1) + return count; + n -= c; + count += c; + } + return count; + } + + static class EchoThread extends Thread { + private SocketChannel sc; + + public EchoThread(SocketChannel s2) { + this.sc = s2; + } + + public void run() { + try { + ByteBuffer bb = ByteBuffer.allocate(BUFSIZE); + while (true) { + bb.clear(); + int c = readFully(sc, bb); + if (c == 0) { + sc.close(); + return; + } + bb.flip(); + sc.write(bb); + } + } catch (ClosedChannelException ex) { + // shutdown time + } catch (IOException ioex) { + ioex.printStackTrace(); + } + } + } + + public static void main(String[] args) throws RunnerException { + Options opt = new OptionsBuilder() + .include(org.openjdk.bench.java.net.SocketChannelCompare.class.getSimpleName()) + .warmupForks(1) + .warmupIterations(2) + .measurementIterations(2) + .forks(2) + .build(); + + new Runner(opt).run(); + + opt = new OptionsBuilder() + .include(org.openjdk.bench.java.net.SocketChannelCompare.class.getSimpleName()) + .warmupForks(1) + .warmupIterations(2) + .measurementIterations(2) + .jvmArgsPrepend("-Djdk.net.useFastTcpLoopback=true") + .forks(3) + .build(); + + new Runner(opt).run(); + } +} diff --git a/test/micro/org/openjdk/bench/java/net/SocketChannelConnectionSetup.java b/test/micro/org/openjdk/bench/java/net/SocketChannelConnectionSetup.java new file mode 100644 index 00000000000..965c8d41c79 --- /dev/null +++ b/test/micro/org/openjdk/bench/java/net/SocketChannelConnectionSetup.java @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.bench.java.net; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.StandardProtocolFamily; +import java.net.UnixDomainSocketAddress; +import java.nio.channels.ClosedChannelException; +import java.nio.channels.ServerSocketChannel; +import java.nio.channels.SocketChannel; +import java.nio.file.*; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + +import org.openjdk.jmh.annotations.*; +import org.openjdk.jmh.runner.Runner; +import org.openjdk.jmh.runner.RunnerException; +import org.openjdk.jmh.runner.options.Options; +import org.openjdk.jmh.runner.options.OptionsBuilder; + +/** + * Measures connection setup times + */ +@BenchmarkMode(Mode.SingleShotTime) +@OutputTimeUnit(TimeUnit.MILLISECONDS) +@State(Scope.Thread) +public class SocketChannelConnectionSetup { + + private ServerSocketChannel ssc; + private SocketChannel s1, s2; + + private static volatile String tempDir; + private static final AtomicInteger count = new AtomicInteger(0); + private volatile Path socket; + + @Param({"inet", "unix"}) + private volatile String family; + + static { + try { + Path p = Files.createTempDirectory("readWriteTest"); + tempDir = p.toString(); + } catch (IOException e) { + tempDir = null; + } + } + + private ServerSocketChannel getServerSocketChannel() throws IOException { + if (family.equals("inet")) + return getInetServerSocketChannel(); + else if (family.equals("unix")) + return getUnixServerSocketChannel(); + throw new InternalError(); + } + + + private ServerSocketChannel getInetServerSocketChannel() throws IOException { + InetAddress iaddr = InetAddress.getLoopbackAddress(); + return ServerSocketChannel.open().bind(null); + } + + private ServerSocketChannel getUnixServerSocketChannel() throws IOException { + int next = count.incrementAndGet(); + socket = Paths.get(tempDir, Integer.toString(next)); + UnixDomainSocketAddress addr = UnixDomainSocketAddress.of(socket); + return ServerSocketChannel.open(StandardProtocolFamily.UNIX).bind(addr); + } + + @Setup(Level.Trial) + public void beforeRun() throws IOException { + ssc = getServerSocketChannel(); + } + + @TearDown(Level.Trial) + public void afterRun() throws IOException, InterruptedException { + ssc.close(); + if (family.equals("unix")) { + Files.delete(socket); + Files.delete(Path.of(tempDir)); + } + } + + @Benchmark + @Measurement(iterations = 5, batchSize=200) + public void test() throws IOException { + s1 = SocketChannel.open(ssc.getLocalAddress()); + s2 = ssc.accept(); + s1.close(); + s2.close(); + } + + public static void main(String[] args) throws RunnerException { + Options opt = new OptionsBuilder() + .include(org.openjdk.bench.java.net.SocketChannelConnectionSetup.class.getSimpleName()) + .warmupForks(1) + .forks(2) + .build(); + + new Runner(opt).run(); + + opt = new OptionsBuilder() + .include(org.openjdk.bench.java.net.SocketChannelConnectionSetup.class.getSimpleName()) + .jvmArgsPrepend("-Djdk.net.useFastTcpLoopback=true") + .warmupForks(1) + .forks(2) + .build(); + + new Runner(opt).run(); + } +} diff --git a/test/micro/org/openjdk/bench/java/net/UnixSocketChannelReadWrite.java b/test/micro/org/openjdk/bench/java/net/UnixSocketChannelReadWrite.java new file mode 100644 index 00000000000..9e75b0d556c --- /dev/null +++ b/test/micro/org/openjdk/bench/java/net/UnixSocketChannelReadWrite.java @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package org.openjdk.bench.java.net; + +import java.io.IOException; +import java.net.StandardProtocolFamily; +import java.net.UnixDomainSocketAddress; +import java.nio.ByteBuffer; +import java.nio.channels.ClosedChannelException; +import java.nio.channels.ServerSocketChannel; +import java.nio.channels.SocketChannel; +import java.nio.file.*; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + +import org.openjdk.jmh.annotations.*; + +/** + * Tests the overheads of I/O API. + * This test is known to depend heavily on network conditions and paltform. + */ +@BenchmarkMode(Mode.Throughput) +@OutputTimeUnit(TimeUnit.MILLISECONDS) +@State(Scope.Thread) +public class UnixSocketChannelReadWrite { + + private ServerSocketChannel ssc; + private SocketChannel s1, s2; + private ReadThread rt; + private ByteBuffer bb = ByteBuffer.allocate(1); + + private static volatile String tempDir; + private static final AtomicInteger count = new AtomicInteger(0); + private volatile Path socket; + + static { + try { + Path p = Files.createTempDirectory("readWriteTest"); + tempDir = p.toString(); + } catch (IOException e) { + tempDir = null; + } + } + + private ServerSocketChannel getServerSocketChannel() throws IOException { + int next = count.incrementAndGet(); + socket = Paths.get(tempDir, Integer.toString(next)); + UnixDomainSocketAddress addr = UnixDomainSocketAddress.of(socket); + ServerSocketChannel c = ServerSocketChannel.open(StandardProtocolFamily.UNIX); + c.bind(addr); + return c; + } + + @Setup(Level.Trial) + public void beforeRun() throws IOException { + ssc = getServerSocketChannel(); + s1 = SocketChannel.open(ssc.getLocalAddress()); + s2 = ssc.accept(); + + rt = new ReadThread(s2); + rt.start(); + + bb.put((byte) 47); + bb.flip(); + } + + @TearDown(Level.Trial) + public void afterRun() throws IOException, InterruptedException { + s1.close(); + s2.close(); + ssc.close(); + Files.delete(socket); + Files.delete(Path.of(tempDir)); + rt.join(); + } + + @Benchmark + public void test() throws IOException { + s1.write(bb); + bb.flip(); + } + + static class ReadThread extends Thread { + private SocketChannel sc; + + public ReadThread(SocketChannel s2) { + this.sc = s2; + } + + public void run() { + try { + ByteBuffer bb = ByteBuffer.allocate(1); + while (sc.read(bb) > 0) { + bb.flip(); + } + } catch (ClosedChannelException ex) { + // shutdown time + } catch (IOException e) { + e.printStackTrace(); + } + } + } + +}