diff --git a/.github/scripts/gen-test-results.sh b/.github/scripts/gen-test-results.sh index 73edb8b3d11..9e85eef4dc0 100644 --- a/.github/scripts/gen-test-results.sh +++ b/.github/scripts/gen-test-results.sh @@ -1,6 +1,6 @@ #!/bin/bash # -# Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2022, 2024, 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,8 @@ for test in $failures $errors; do base_path="$(echo "$test" | tr '#' '_')" report_file="$report_dir/$base_path.jtr" hs_err_files=$(ls $report_dir/$base_path/hs_err*.log 2> /dev/null || true) + replay_files=$(ls $report_dir/$base_path/replay*.log 2> /dev/null || true) echo "#### $test" - echo '
View test results' echo '' echo '```' @@ -73,6 +73,20 @@ for test in $failures $errors; do echo '' fi + if [[ "$replay_files" != "" ]]; then + echo '
View HotSpot replay file' + echo '' + for replay in $replay_files; do + echo '```' + echo "$replay:" + echo '' + cat "$replay" + echo '```' + done + + echo '
' + echo '' + fi done >> $GITHUB_STEP_SUMMARY # With many failures, the summary can easily exceed 1024 kB, the limit set by Github diff --git a/.github/scripts/gen-test-summary.sh b/.github/scripts/gen-test-summary.sh index d016cb38649..a612bed5527 100644 --- a/.github/scripts/gen-test-summary.sh +++ b/.github/scripts/gen-test-summary.sh @@ -42,6 +42,7 @@ error_count=$(echo $errors | wc -w || true) if [[ "$failures" = "" && "$errors" = "" ]]; then # We know something went wrong, but not what + echo 'failure=true' >> $GITHUB_OUTPUT echo 'error-message=Unspecified test suite failure. Please see log for job for details.' >> $GITHUB_OUTPUT exit 0 fi diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index b3590166264..8808ab80d0e 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -63,6 +63,7 @@ jobs: - 'hs/tier1 compiler part 1' - 'hs/tier1 compiler part 2' - 'hs/tier1 compiler part 3' + - 'hs/tier1 compiler not-xcomp' - 'hs/tier1 gc' - 'hs/tier1 runtime' - 'hs/tier1 serviceability' @@ -90,13 +91,17 @@ jobs: debug-suffix: -debug - test-name: 'hs/tier1 compiler part 2' - test-suite: 'test/hotspot/jtreg/:tier1_compiler_2 test/hotspot/jtreg/:tier1_compiler_not_xcomp' + test-suite: 'test/hotspot/jtreg/:tier1_compiler_2' debug-suffix: -debug - test-name: 'hs/tier1 compiler part 3' test-suite: 'test/hotspot/jtreg/:tier1_compiler_3' debug-suffix: -debug + - test-name: 'hs/tier1 compiler not-xcomp' + test-suite: 'test/hotspot/jtreg/:tier1_compiler_not_xcomp' + debug-suffix: -debug + - test-name: 'hs/tier1 gc' test-suite: 'test/hotspot/jtreg/:tier1_gc' debug-suffix: -debug diff --git a/.jcheck/conf b/.jcheck/conf index 9d53db9f996..0548a905b42 100644 --- a/.jcheck/conf +++ b/.jcheck/conf @@ -1,7 +1,7 @@ [general] -project=jdk +project=jdk-updates jbs=JDK -version=22 +version=22.0.1 [checks] error=author,committer,reviewers,merge,issues,executable,symlink,message,hg-tag,whitespace,problemlists diff --git a/make/Main.gmk b/make/Main.gmk index e904235ff3f..f01b3e21006 100644 --- a/make/Main.gmk +++ b/make/Main.gmk @@ -962,20 +962,28 @@ else jdk.jdeps-gendata: java - # The ct.sym generation uses all the moduleinfos as input - jdk.compiler-gendata: $(GENSRC_MODULEINFO_TARGETS) $(JAVA_TARGETS) - # jdk.compiler-gendata needs the BUILD_JDK. If the BUILD_JDK was supplied - # externally, no extra prerequisites are needed. + # jdk.compiler gendata generates ct.sym, which requires all generated + # java source and compiled classes present. + jdk.compiler-gendata: $(JAVA_TARGETS) + + # jdk.javadoc gendata generates element-list, which requires all java sources + # but not compiled classes. + jdk.javadoc-gendata: $(GENSRC_TARGETS) + + # ct.sym and element-list generation also needs the BUILD_JDK. If the + # BUILD_JDK was supplied externally, no extra prerequisites are needed. ifeq ($(CREATE_BUILDJDK), true) ifneq ($(CREATING_BUILDJDK), true) # When cross compiling and an external BUILD_JDK wasn't supplied, it's # produced by the create-buildjdk target. jdk.compiler-gendata: create-buildjdk + jdk.javadoc-gendata: create-buildjdk endif else ifeq ($(EXTERNAL_BUILDJDK), false) # When not cross compiling, the BUILD_JDK is the interim jdk image, and # the javac launcher is needed. jdk.compiler-gendata: jdk.compiler-launchers + jdk.javadoc-gendata: jdk.compiler-launchers endif # Declare dependencies between jmod targets. diff --git a/make/autoconf/flags-cflags.m4 b/make/autoconf/flags-cflags.m4 index df44f7a2d59..357f5bcee95 100644 --- a/make/autoconf/flags-cflags.m4 +++ b/make/autoconf/flags-cflags.m4 @@ -425,7 +425,7 @@ AC_DEFUN([FLAGS_SETUP_CFLAGS_HELPER], [ #### OS DEFINES, these should be independent on toolchain if test "x$OPENJDK_TARGET_OS" = xlinux; then - CFLAGS_OS_DEF_JVM="-DLINUX" + CFLAGS_OS_DEF_JVM="-DLINUX -D_FILE_OFFSET_BITS=64" CFLAGS_OS_DEF_JDK="-D_GNU_SOURCE -D_REENTRANT -D_LARGEFILE64_SOURCE" elif test "x$OPENJDK_TARGET_OS" = xmacosx; then CFLAGS_OS_DEF_JVM="-D_ALLBSD_SOURCE -D_DARWIN_C_SOURCE -D_XOPEN_SOURCE" diff --git a/make/autoconf/jdk-version.m4 b/make/autoconf/jdk-version.m4 index 6a7662556fd..7c9ecad7779 100644 --- a/make/autoconf/jdk-version.m4 +++ b/make/autoconf/jdk-version.m4 @@ -110,6 +110,15 @@ AC_DEFUN_ONCE([JDKVER_SETUP_JDK_VERSION_NUMBERS], CHECK_VALUE: [UTIL_CHECK_STRING_NON_EMPTY_PRINTABLE]) AC_SUBST(COMPANY_NAME) + # Set the JDK RC Company name + # Otherwise uses the value set for "vendor-name". + UTIL_ARG_WITH(NAME: jdk-rc-company-name, TYPE: string, + DEFAULT: $COMPANY_NAME, + DESC: [Set JDK RC company name. This is used for CompanyName properties of MS Windows binaries.], + DEFAULT_DESC: [from branding.conf], + CHECK_VALUE: [UTIL_CHECK_STRING_NON_EMPTY_PRINTABLE]) + AC_SUBST(JDK_RC_COMPANY_NAME) + # The vendor URL, if any # Only set VENDOR_URL if '--with-vendor-url' was used and is not empty. # Otherwise we will use the value from "branding.conf" included above. diff --git a/make/autoconf/spec.gmk.in b/make/autoconf/spec.gmk.in index 8a1eb8ed27f..90168e6df0f 100644 --- a/make/autoconf/spec.gmk.in +++ b/make/autoconf/spec.gmk.in @@ -191,6 +191,7 @@ PRODUCT_NAME := @PRODUCT_NAME@ PRODUCT_SUFFIX := @PRODUCT_SUFFIX@ JDK_RC_PLATFORM_NAME := @JDK_RC_PLATFORM_NAME@ JDK_RC_NAME := @JDK_RC_NAME@ +JDK_RC_COMPANY_NAME:=@JDK_RC_COMPANY_NAME@ COMPANY_NAME := @COMPANY_NAME@ HOTSPOT_VM_DISTRO := @HOTSPOT_VM_DISTRO@ MACOSX_BUNDLE_NAME_BASE := @MACOSX_BUNDLE_NAME_BASE@ diff --git a/make/autoconf/toolchain.m4 b/make/autoconf/toolchain.m4 index 289eec3356b..7a24815d163 100644 --- a/make/autoconf/toolchain.m4 +++ b/make/autoconf/toolchain.m4 @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2023, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2024, 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 @@ -389,6 +389,10 @@ AC_DEFUN_ONCE([TOOLCHAIN_POST_DETECTION], # This is necessary since AC_PROG_CC defaults CFLAGS to "-g -O2" CFLAGS="$ORG_CFLAGS" CXXFLAGS="$ORG_CXXFLAGS" + + # filter out some unwanted additions autoconf may add to CXX; we saw this on macOS with autoconf 2.72 + UTIL_GET_NON_MATCHING_VALUES(cxx_filtered, $CXX, -std=c++11 -std=gnu++11) + CXX="$cxx_filtered" ]) # Check if a compiler is of the toolchain type we expect, and save the version diff --git a/make/autoconf/util.m4 b/make/autoconf/util.m4 index 349a04a089e..3fae951224e 100644 --- a/make/autoconf/util.m4 +++ b/make/autoconf/util.m4 @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2023, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2024, 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 @@ -199,7 +199,7 @@ AC_DEFUN([UTIL_GET_NON_MATCHING_VALUES], if test -z "$legal_values"; then $1="$2" else - result=`$GREP -Fvx "$legal_values" <<< "$values_to_check" | $GREP -v '^$'` + result=`$GREP -Fvx -- "$legal_values" <<< "$values_to_check" | $GREP -v '^$'` $1=${result//$'\n'/ } fi ]) @@ -226,7 +226,7 @@ AC_DEFUN([UTIL_GET_MATCHING_VALUES], if test -z "$illegal_values"; then $1="" else - result=`$GREP -Fx "$illegal_values" <<< "$values_to_check" | $GREP -v '^$'` + result=`$GREP -Fx -- "$illegal_values" <<< "$values_to_check" | $GREP -v '^$'` $1=${result//$'\n'/ } fi ]) diff --git a/make/common/JdkNativeCompilation.gmk b/make/common/JdkNativeCompilation.gmk index 6a963ac2c49..1a1333cf517 100644 --- a/make/common/JdkNativeCompilation.gmk +++ b/make/common/JdkNativeCompilation.gmk @@ -98,7 +98,7 @@ GLOBAL_VERSION_INFO_RESOURCE := $(TOPDIR)/src/java.base/windows/native/common/ve JDK_RCFLAGS=$(RCFLAGS) \ -D"JDK_VERSION_STRING=$(VERSION_STRING)" \ - -D"JDK_COMPANY=$(COMPANY_NAME)" \ + -D"JDK_COMPANY=$(JDK_RC_COMPANY_NAME)" \ -D"JDK_VER=$(VERSION_NUMBER_FOUR_POSITIONS)" \ -D"JDK_COPYRIGHT=Copyright \xA9 $(COPYRIGHT_YEAR)" \ -D"JDK_NAME=$(JDK_RC_NAME) $(VERSION_SHORT)" \ diff --git a/make/conf/version-numbers.conf b/make/conf/version-numbers.conf index b902ba7624f..485e4ef464d 100644 --- a/make/conf/version-numbers.conf +++ b/make/conf/version-numbers.conf @@ -28,15 +28,15 @@ DEFAULT_VERSION_FEATURE=22 DEFAULT_VERSION_INTERIM=0 -DEFAULT_VERSION_UPDATE=0 +DEFAULT_VERSION_UPDATE=1 DEFAULT_VERSION_PATCH=0 DEFAULT_VERSION_EXTRA1=0 DEFAULT_VERSION_EXTRA2=0 DEFAULT_VERSION_EXTRA3=0 -DEFAULT_VERSION_DATE=2024-03-19 +DEFAULT_VERSION_DATE=2024-04-16 DEFAULT_VERSION_CLASSFILE_MAJOR=66 # "`$EXPR $DEFAULT_VERSION_FEATURE + 44`" DEFAULT_VERSION_CLASSFILE_MINOR=0 DEFAULT_VERSION_DOCS_API_SINCE=11 DEFAULT_ACCEPTABLE_BOOT_VERSIONS="21 22" DEFAULT_JDK_SOURCE_TARGET_VERSION=22 -DEFAULT_PROMOTED_VERSION_PRE=ea +DEFAULT_PROMOTED_VERSION_PRE= diff --git a/make/data/hotspot-symbols/symbols-unix b/make/data/hotspot-symbols/symbols-unix index 9ca040794f3..fbb82a11fac 100644 --- a/make/data/hotspot-symbols/symbols-unix +++ b/make/data/hotspot-symbols/symbols-unix @@ -223,6 +223,7 @@ JVM_VirtualThreadEnd JVM_VirtualThreadMount JVM_VirtualThreadUnmount JVM_VirtualThreadHideFrames +JVM_VirtualThreadDisableSuspend # Scoped values JVM_EnsureMaterializedForStackWalk_func diff --git a/make/hotspot/gensrc/GensrcAdlc.gmk b/make/hotspot/gensrc/GensrcAdlc.gmk index 0898d91e1c2..bb356476847 100644 --- a/make/hotspot/gensrc/GensrcAdlc.gmk +++ b/make/hotspot/gensrc/GensrcAdlc.gmk @@ -51,7 +51,7 @@ ifeq ($(call check-jvm-feature, compiler2), true) endif # Set the C++ standard - ADLC_CFLAGS += $(ADLC_LANGSTD_CXXFLAG) + ADLC_CFLAGS += $(ADLC_LANGSTD_CXXFLAGS) # NOTE: The old build didn't set -DASSERT for windows but it doesn't seem to # hurt. diff --git a/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java b/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java index b6298c00c9a..442a245f92f 100644 --- a/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java +++ b/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2024, 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 @@ -1289,25 +1289,58 @@ private static Map coverageLevelsMap() throws Exception { */ private static void generateTZDBShortNamesMap() throws IOException { Files.walk(Path.of(tzDataDir), 1, FileVisitOption.FOLLOW_LINKS) - .filter(p -> p.toFile().isFile()) + .filter(p -> p.toFile().isFile() && !p.endsWith("jdk11_backward")) .forEach(p -> { try { String zone = null; String rule = null; String format = null; + boolean inVanguard = false; + boolean inRearguard = false; for (var line : Files.readAllLines(p)) { - if (line.contains("#STDOFF")) continue; + // Interpret the line in rearguard mode so that STD/DST + // correctly handles negative DST cases, such as "GMT/IST" + // vs. "IST/GMT" case for Europe/Dublin + if (inVanguard) { + if (line.startsWith("# Rearguard")) { + inVanguard = false; + inRearguard = true; + } + continue; + } else if (line.startsWith("# Vanguard")) { + inVanguard = true; + continue; + } + if (inRearguard) { + if (line.startsWith("# End of rearguard")) { + inRearguard = false; + continue; + } else { + if (line.startsWith("#\t")) { + line = line.substring(1); // omit # + } + } + } + if (line.isBlank() || line.matches("^[ \t]*#.*")) { + // ignore blank/comment lines + continue; + } + // remove comments in-line line = line.replaceAll("[ \t]*#.*", ""); // Zone line if (line.startsWith("Zone")) { + if (zone != null) { + tzdbShortNamesMap.put(zone, format + NBSP + rule); + } var zl = line.split("[ \t]+", -1); zone = zl[1]; rule = zl[3]; format = zl[4]; } else { if (zone != null) { - if (line.isBlank()) { + if (line.startsWith("Rule") || + line.startsWith("Link")) { tzdbShortNamesMap.put(zone, format + NBSP + rule); zone = null; rule = null; diff --git a/make/jdk/src/classes/build/tools/generatecurrencydata/GenerateCurrencyData.java b/make/jdk/src/classes/build/tools/generatecurrencydata/GenerateCurrencyData.java index 561edbef034..9655e08016c 100644 --- a/make/jdk/src/classes/build/tools/generatecurrencydata/GenerateCurrencyData.java +++ b/make/jdk/src/classes/build/tools/generatecurrencydata/GenerateCurrencyData.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2023, 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,6 +32,7 @@ import java.io.FileOutputStream; import java.io.InputStream; import java.text.SimpleDateFormat; +import java.util.Arrays; import java.util.Date; import java.util.HashMap; import java.util.Locale; @@ -339,9 +340,15 @@ private static void buildOtherTables() { validCurrencyCodes.substring(i * 7 + 3, i * 7 + 6)); checkCurrencyCode(currencyCode); int tableEntry = mainTable[(currencyCode.charAt(0) - 'A') * A_TO_Z + (currencyCode.charAt(1) - 'A')]; - if (tableEntry == INVALID_COUNTRY_ENTRY || - (tableEntry & SPECIAL_CASE_COUNTRY_MASK) != 0 || - (tableEntry & SIMPLE_CASE_COUNTRY_FINAL_CHAR_MASK) != (currencyCode.charAt(2) - 'A')) { + + // Do not allow a future currency to be classified as an otherCurrency, + // otherwise it will leak out into Currency:getAvailableCurrencies + boolean futureCurrency = Arrays.asList(specialCaseNewCurrencies).contains(currencyCode); + boolean simpleCurrency = (tableEntry & SIMPLE_CASE_COUNTRY_FINAL_CHAR_MASK) == (currencyCode.charAt(2) - 'A'); + + // If neither a simple currency, or one defined in the future + // then the current currency is applicable to be added to the otherTable + if (!futureCurrency && !simpleCurrency) { if (otherCurrenciesCount == maxOtherCurrencies) { throw new RuntimeException("too many other currencies"); } diff --git a/make/modules/java.desktop/lib/Awt2dLibraries.gmk b/make/modules/java.desktop/lib/Awt2dLibraries.gmk index 4d5ff751981..e274005e607 100644 --- a/make/modules/java.desktop/lib/Awt2dLibraries.gmk +++ b/make/modules/java.desktop/lib/Awt2dLibraries.gmk @@ -449,7 +449,6 @@ else LIBFREETYPE_LIBS := -lfreetype endif - # gcc_ftobjs.c := maybe-uninitialized required for GCC 7 builds. $(eval $(call SetupJdkLibrary, BUILD_LIBFREETYPE, \ NAME := freetype, \ OPTIMIZATION := HIGHEST, \ @@ -458,7 +457,6 @@ else EXTRA_HEADER_DIRS := $(BUILD_LIBFREETYPE_HEADER_DIRS), \ DISABLED_WARNINGS_microsoft := 4267 4244 4996, \ DISABLED_WARNINGS_gcc := dangling-pointer stringop-overflow, \ - DISABLED_WARNINGS_gcc_ftobjs.c := maybe-uninitialized, \ LDFLAGS := $(LDFLAGS_JDKLIB) \ $(call SET_SHARED_LIBRARY_ORIGIN), \ )) diff --git a/src/demo/share/java2d/J2DBench/Makefile b/src/demo/share/java2d/J2DBench/Makefile index 04b0818a2c3..edc4494e131 100644 --- a/src/demo/share/java2d/J2DBench/Makefile +++ b/src/demo/share/java2d/J2DBench/Makefile @@ -29,6 +29,23 @@ # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # + +ifndef SOURCE +export SOURCE := 7 +endif +ifndef TARGET +export TARGET := 7 +endif +ifndef JAVAC +export JAVAC := javac +endif +ifndef JAVA +export JAVA := java +endif +ifndef JAR +export JAR := jar +endif + SOURCEPATH=src CLASSES=build DIST=dist @@ -80,18 +97,18 @@ SCM_DIRs = .hg .svn CVS RCS SCCS Codemgr_wsdata deleted_files all: mkdirs J2DBench.jar J2DAnalyzer.jar run: mkdirs J2DBench.jar - java -jar $(DIST)/J2DBench.jar + $(JAVA) -jar $(DIST)/J2DBench.jar analyze: mkdirs J2DAnalyzer.jar - java -jar $(DIST)/J2DAnalyzer.jar + $(JAVA) -jar $(DIST)/J2DAnalyzer.jar J2DBench.jar: \ $(J2DBENCH_CLASSES) $(J2DBENCH_RESOURCES) \ $(CLASSES)/j2dbench.manifest - jar cvmf $(CLASSES)/j2dbench.manifest $(DIST)/J2DBench.jar -C $(CLASSES) j2dbench + $(JAR) cvmf $(CLASSES)/j2dbench.manifest $(DIST)/J2DBench.jar -C $(CLASSES) j2dbench J2DAnalyzer.jar: $(J2DANALYZER_CLASSES) $(CLASSES)/j2danalyzer.manifest - jar cvmf $(CLASSES)/j2danalyzer.manifest \ + $(JAR) cvmf $(CLASSES)/j2danalyzer.manifest \ $(DIST)/J2DAnalyzer.jar -C $(CLASSES) j2dbench/report $(CLASSES)/j2dbench/tests/iio/images: $(RESOURCES)/images @@ -120,7 +137,7 @@ $(CLASSES): mkdirs: $(DIST) $(CLASSES) $(CLASSES)/j2dbench/%.class: $(SOURCEPATH)/j2dbench/%.java - javac -g:none -source 1.7 -target 1.7 -d $(CLASSES) -sourcepath $(SOURCEPATH) $< + $(JAVAC) -g:none -source $(SOURCE) -target $(TARGET) -d $(CLASSES) -sourcepath $(SOURCEPATH) $< clean: rm -rf $(CLASSES) diff --git a/src/demo/share/java2d/J2DBench/README b/src/demo/share/java2d/J2DBench/README index 3b9f25c13f1..513c984a655 100644 --- a/src/demo/share/java2d/J2DBench/README +++ b/src/demo/share/java2d/J2DBench/README @@ -23,6 +23,9 @@ The benchmark requires at least jdk1.4 to compile and run. Note that source/target is set to 1.7 in the makefile and build.xml, because of support in jdk 14 compiler. To check compatibility with jdk1.4 you can use "-source 1.4 -target 1.4" options and jdk1.7. +Yo can use TARGET/SOURCE of makefile and -Dtarget/surce to set them up for your convinience. +Similarly you can set JAVA/JAVAC/JAR and -Djava/javac to select diffferent java/javac then is on yoru PATH +Unluckily in ant, you can not set jar, but ant should honor JAVA_HOME ----------------------------------------------------------------------- How To Compile diff --git a/src/demo/share/java2d/J2DBench/build.xml b/src/demo/share/java2d/J2DBench/build.xml index 7b202946cf1..415c315899e 100644 --- a/src/demo/share/java2d/J2DBench/build.xml +++ b/src/demo/share/java2d/J2DBench/build.xml @@ -39,6 +39,27 @@ + + + + + + + + + + + + + + + + + + + + + @@ -49,13 +70,14 @@ - + @@ -64,6 +86,7 @@ description="run J2DAnalyzer" > diff --git a/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp index 360ef7a747a..b83d6185062 100644 --- a/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, 2020, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -282,7 +282,8 @@ void LIR_Assembler::osr_entry() { __ bind(L); } #endif - __ ldp(r19, r20, Address(OSR_buf, slot_offset)); + __ ldr(r19, Address(OSR_buf, slot_offset)); + __ ldr(r20, Address(OSR_buf, slot_offset + BytesPerWord)); __ str(r19, frame_map()->address_for_monitor_lock(i)); __ str(r20, frame_map()->address_for_monitor_object(i)); } diff --git a/src/hotspot/cpu/aarch64/c1_LIRGenerator_aarch64.cpp b/src/hotspot/cpu/aarch64/c1_LIRGenerator_aarch64.cpp index 952e060ed21..a9a24f7e712 100644 --- a/src/hotspot/cpu/aarch64/c1_LIRGenerator_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c1_LIRGenerator_aarch64.cpp @@ -168,8 +168,10 @@ LIR_Address* LIRGenerator::generate_address(LIR_Opr base, LIR_Opr index, if (index->is_register()) { // apply the shift and accumulate the displacement if (shift > 0) { - LIR_Opr tmp = new_pointer_register(); - __ shift_left(index, shift, tmp); + // Use long register to avoid overflow when shifting large index values left. + LIR_Opr tmp = new_register(T_LONG); + __ convert(Bytecodes::_i2l, index, tmp); + __ shift_left(tmp, shift, tmp); index = tmp; } if (large_disp != 0) { diff --git a/src/hotspot/cpu/aarch64/compressedKlass_aarch64.cpp b/src/hotspot/cpu/aarch64/compressedKlass_aarch64.cpp index d035ab21093..47b6f1f2f38 100644 --- a/src/hotspot/cpu/aarch64/compressedKlass_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/compressedKlass_aarch64.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2023, Red Hat, Inc. All rights reserved. - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, 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 @@ static char* reserve_at_eor_compatible_address(size_t size, bool aslr) { 0x7ffc, 0x7ffe, 0x7fff }; static constexpr int num_immediates = sizeof(immediates) / sizeof(immediates[0]); - const int start_index = aslr ? os::random() : 0; + const int start_index = aslr ? os::next_random((int)os::javaTimeNanos()) : 0; constexpr int max_tries = 64; for (int ntry = 0; result == nullptr && ntry < max_tries; ntry ++) { // As in os::attempt_reserve_memory_between, we alternate between higher and lower diff --git a/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp b/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp index c7b45ff0dde..8694734c751 100644 --- a/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp @@ -310,7 +310,7 @@ int SharedRuntime::java_calling_convention(const BasicType *sig_bt, uint int_args = 0; uint fp_args = 0; - uint stk_args = 0; // inc by 2 each time + uint stk_args = 0; for (int i = 0; i < total_args_passed; i++) { switch (sig_bt[i]) { @@ -322,8 +322,9 @@ int SharedRuntime::java_calling_convention(const BasicType *sig_bt, if (int_args < Argument::n_int_register_parameters_j) { regs[i].set1(INT_ArgReg[int_args++]->as_VMReg()); } else { + stk_args = align_up(stk_args, 2); regs[i].set1(VMRegImpl::stack2reg(stk_args)); - stk_args += 2; + stk_args += 1; } break; case T_VOID: @@ -340,6 +341,7 @@ int SharedRuntime::java_calling_convention(const BasicType *sig_bt, if (int_args < Argument::n_int_register_parameters_j) { regs[i].set2(INT_ArgReg[int_args++]->as_VMReg()); } else { + stk_args = align_up(stk_args, 2); regs[i].set2(VMRegImpl::stack2reg(stk_args)); stk_args += 2; } @@ -348,8 +350,9 @@ int SharedRuntime::java_calling_convention(const BasicType *sig_bt, if (fp_args < Argument::n_float_register_parameters_j) { regs[i].set1(FP_ArgReg[fp_args++]->as_VMReg()); } else { + stk_args = align_up(stk_args, 2); regs[i].set1(VMRegImpl::stack2reg(stk_args)); - stk_args += 2; + stk_args += 1; } break; case T_DOUBLE: @@ -357,6 +360,7 @@ int SharedRuntime::java_calling_convention(const BasicType *sig_bt, if (fp_args < Argument::n_float_register_parameters_j) { regs[i].set2(FP_ArgReg[fp_args++]->as_VMReg()); } else { + stk_args = align_up(stk_args, 2); regs[i].set2(VMRegImpl::stack2reg(stk_args)); stk_args += 2; } @@ -367,7 +371,7 @@ int SharedRuntime::java_calling_convention(const BasicType *sig_bt, } } - return align_up(stk_args, 2); + return stk_args; } // Patch the callers callsite with entry to compiled code if it exists. diff --git a/src/hotspot/cpu/arm/interp_masm_arm.cpp b/src/hotspot/cpu/arm/interp_masm_arm.cpp index 481c3d09e58..635acd781f9 100644 --- a/src/hotspot/cpu/arm/interp_masm_arm.cpp +++ b/src/hotspot/cpu/arm/interp_masm_arm.cpp @@ -303,15 +303,19 @@ void InterpreterMacroAssembler::load_field_entry(Register cache, Register index, } void InterpreterMacroAssembler::load_method_entry(Register cache, Register index, int bcp_offset) { + assert_different_registers(cache, index); + // Get index out of bytecode pointer get_index_at_bcp(index, bcp_offset, cache /* as tmp */, sizeof(u2)); + + // sizeof(ResolvedMethodEntry) is not a power of 2 on Arm, so can't use shift mov(cache, sizeof(ResolvedMethodEntry)); mul(index, index, cache); // Scale the index to be the entry index * sizeof(ResolvedMethodEntry) // load constant pool cache pointer ldr(cache, Address(FP, frame::interpreter_frame_cache_offset * wordSize)); // Get address of method entries array - ldr(cache, Address(cache, ConstantPoolCache::method_entries_offset())); + ldr(cache, Address(cache, in_bytes(ConstantPoolCache::method_entries_offset()))); add(cache, cache, Array::base_offset_in_bytes()); add(cache, cache, index); } diff --git a/src/hotspot/cpu/arm/sharedRuntime_arm.cpp b/src/hotspot/cpu/arm/sharedRuntime_arm.cpp index 9a65f9f09fe..716c7b7575e 100644 --- a/src/hotspot/cpu/arm/sharedRuntime_arm.cpp +++ b/src/hotspot/cpu/arm/sharedRuntime_arm.cpp @@ -441,7 +441,6 @@ int SharedRuntime::java_calling_convention(const BasicType *sig_bt, } } - if (slot & 1) slot++; return slot; } diff --git a/src/hotspot/cpu/arm/templateInterpreterGenerator_arm.cpp b/src/hotspot/cpu/arm/templateInterpreterGenerator_arm.cpp index ba9a3fd7a9b..efaf78ee568 100644 --- a/src/hotspot/cpu/arm/templateInterpreterGenerator_arm.cpp +++ b/src/hotspot/cpu/arm/templateInterpreterGenerator_arm.cpp @@ -370,17 +370,16 @@ address TemplateInterpreterGenerator::generate_return_entry_for(TosState state, if (index_size == sizeof(u4)) { __ load_resolved_indy_entry(Rcache, Rindex); __ ldrh(Rcache, Address(Rcache, in_bytes(ResolvedIndyEntry::num_parameters_offset()))); - __ check_stack_top(); - __ add(Rstack_top, Rstack_top, AsmOperand(Rcache, lsl, Interpreter::logStackElementSize)); } else { // Pop N words from the stack assert(index_size == sizeof(u2), "Can only be u2"); __ load_method_entry(Rcache, Rindex); - __ ldrh(Rcache, Address(Rcache, in_bytes(ResolvedIndyEntry::num_parameters_offset()))); - __ check_stack_top(); - __ add(Rstack_top, Rstack_top, AsmOperand(Rcache, lsl, Interpreter::logStackElementSize)); + __ ldrh(Rcache, Address(Rcache, in_bytes(ResolvedMethodEntry::num_parameters_offset()))); } + __ check_stack_top(); + __ add(Rstack_top, Rstack_top, AsmOperand(Rcache, lsl, Interpreter::logStackElementSize)); + __ convert_retval_to_tos(state); __ check_and_handle_popframe(); diff --git a/src/hotspot/cpu/arm/templateTable_arm.cpp b/src/hotspot/cpu/arm/templateTable_arm.cpp index e478f08c977..55a0120e7c7 100644 --- a/src/hotspot/cpu/arm/templateTable_arm.cpp +++ b/src/hotspot/cpu/arm/templateTable_arm.cpp @@ -3666,15 +3666,15 @@ void TemplateTable::prepare_invoke(Register Rcache, Register recv) { // load receiver if needed (after extra argument is pushed so parameter size is correct) if (load_receiver) { __ ldrh(recv, Address(Rcache, in_bytes(ResolvedMethodEntry::num_parameters_offset()))); - Address recv_addr = __ receiver_argument_address(Rstack_top, Rtemp, recv); - __ ldr(recv, recv_addr); + __ add(recv, Rstack_top, AsmOperand(recv, lsl, Interpreter::logStackElementSize)); + __ ldr(recv, Address(recv, -Interpreter::stackElementSize)); __ verify_oop(recv); } // load return address { const address table = (address) Interpreter::invoke_return_entry_table_for(code); - __ mov_slow(Rtemp, table); - __ ldr(LR, Address::indexed_ptr(Rtemp, ret_type)); + __ mov_slow(LR, table); + __ ldr(LR, Address::indexed_ptr(LR, ret_type)); } } @@ -3744,10 +3744,13 @@ void TemplateTable::invokevirtual(int byte_no) { void TemplateTable::invokespecial(int byte_no) { transition(vtos, vtos); assert(byte_no == f1_byte, "use this argument"); + const Register Rrecv = R2_tmp; - load_resolved_method_entry_special_or_static(R2_tmp, // ResolvedMethodEntry* + const Register Rflags = R3_tmp; + + load_resolved_method_entry_special_or_static(Rrecv, // ResolvedMethodEntry* Rmethod, // Method* - R3_tmp); // Flags + Rflags); // Flags prepare_invoke(Rrecv, Rrecv); __ verify_oop(Rrecv); __ null_check(Rrecv, Rtemp); @@ -3760,12 +3763,16 @@ void TemplateTable::invokespecial(int byte_no) { void TemplateTable::invokestatic(int byte_no) { transition(vtos, vtos); assert(byte_no == f1_byte, "use this argument"); - load_resolved_method_entry_special_or_static(R2_tmp, // ResolvedMethodEntry* + + const Register Rrecv = R2_tmp; + const Register Rflags = R3_tmp; + + load_resolved_method_entry_special_or_static(Rrecv, // ResolvedMethodEntry* Rmethod, // Method* - R3_tmp); // Flags - prepare_invoke(R2_tmp, R2_tmp); + Rflags); // Flags + prepare_invoke(Rrecv, Rrecv); // do the call - __ profile_call(R2_tmp); + __ profile_call(Rrecv); __ jump_from_interpreted(Rmethod); } @@ -3788,10 +3795,10 @@ void TemplateTable::invokeinterface(int byte_no) { const Register Rflags = R3_tmp; const Register Rklass = R2_tmp; // Note! Same register with Rrecv - load_resolved_method_entry_interface(R2_tmp, // ResolvedMethodEntry* - R1_tmp, // Klass* + load_resolved_method_entry_interface(Rrecv, // ResolvedMethodEntry* + Rinterf, // Klass* Rmethod, // Method* or itable/vtable index - R3_tmp); // Flags + Rflags); // Flags prepare_invoke(Rrecv, Rrecv); // First check for Object case, then private interface method, diff --git a/src/hotspot/cpu/ppc/c1_CodeStubs_ppc.cpp b/src/hotspot/cpu/ppc/c1_CodeStubs_ppc.cpp index 1a00c9ad268..dc70c73d4b3 100644 --- a/src/hotspot/cpu/ppc/c1_CodeStubs_ppc.cpp +++ b/src/hotspot/cpu/ppc/c1_CodeStubs_ppc.cpp @@ -456,6 +456,9 @@ void ArrayCopyStub::emit_code(LIR_Assembler* ce) { __ extsw(R7_ARG5, length()->as_register()); ce->emit_static_call_stub(); + if (ce->compilation()->bailed_out()) { + return; // CodeCache is full + } bool success = ce->emit_trampoline_stub_for_call(SharedRuntime::get_resolve_static_call_stub()); if (!success) { return; } diff --git a/src/hotspot/cpu/ppc/c1_LIRGenerator_ppc.cpp b/src/hotspot/cpu/ppc/c1_LIRGenerator_ppc.cpp index 32aab91c7d3..b58defc1847 100644 --- a/src/hotspot/cpu/ppc/c1_LIRGenerator_ppc.cpp +++ b/src/hotspot/cpu/ppc/c1_LIRGenerator_ppc.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012, 2023 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -165,8 +165,10 @@ LIR_Address* LIRGenerator::generate_address(LIR_Opr base, LIR_Opr index, if (index->is_register()) { // Apply the shift and accumulate the displacement. if (shift > 0) { - LIR_Opr tmp = new_pointer_register(); - __ shift_left(index, shift, tmp); + // Use long register to avoid overflow when shifting large index values left. + LIR_Opr tmp = new_register(T_LONG); + __ convert(Bytecodes::_i2l, index, tmp); + __ shift_left(tmp, shift, tmp); index = tmp; } if (large_disp != 0) { diff --git a/src/hotspot/cpu/ppc/ppc.ad b/src/hotspot/cpu/ppc/ppc.ad index be37ff1785b..48ad6e81b6e 100644 --- a/src/hotspot/cpu/ppc/ppc.ad +++ b/src/hotspot/cpu/ppc/ppc.ad @@ -2062,7 +2062,10 @@ int HandlerImpl::emit_exception_handler(CodeBuffer &cbuf) { C2_MacroAssembler _masm(&cbuf); address base = __ start_a_stub(size_exception_handler()); - if (base == NULL) return 0; // CodeBuffer::expand failed + if (base == nullptr) { + ciEnv::current()->record_failure("CodeCache is full"); + return 0; // CodeBuffer::expand failed + } int offset = __ offset(); __ b64_patchable((address)OptoRuntime::exception_blob()->content_begin(), @@ -2079,7 +2082,10 @@ int HandlerImpl::emit_deopt_handler(CodeBuffer& cbuf) { C2_MacroAssembler _masm(&cbuf); address base = __ start_a_stub(size_deopt_handler()); - if (base == NULL) return 0; // CodeBuffer::expand failed + if (base == nullptr) { + ciEnv::current()->record_failure("CodeCache is full"); + return 0; // CodeBuffer::expand failed + } int offset = __ offset(); __ bl64_patchable((address)SharedRuntime::deopt_blob()->unpack(), @@ -2801,15 +2807,16 @@ encode %{ intptr_t val = $src$$constant; relocInfo::relocType constant_reloc = $src->constant_reloc(); // src address const_toc_addr; + RelocationHolder r; // Initializes type to none. if (constant_reloc == relocInfo::oop_type) { // Create an oop constant and a corresponding relocation. - AddressLiteral a = __ allocate_oop_address((jobject)val); + AddressLiteral a = __ constant_oop_address((jobject)val); const_toc_addr = __ address_constant((address)a.value(), RelocationHolder::none); - __ relocate(a.rspec()); + r = a.rspec(); } else if (constant_reloc == relocInfo::metadata_type) { + // Notify OOP recorder (don't need the relocation) AddressLiteral a = __ constant_metadata_address((Metadata *)val); const_toc_addr = __ address_constant((address)a.value(), RelocationHolder::none); - __ relocate(a.rspec()); } else { // Create a non-oop constant, no relocation needed. const_toc_addr = __ long_constant((jlong)$src$$constant); @@ -2819,6 +2826,7 @@ encode %{ ciEnv::current()->record_out_of_memory_failure(); return; } + __ relocate(r); // If set above. // Get the constant's TOC offset. toc_offset = __ offset_to_method_toc(const_toc_addr); @@ -2832,15 +2840,16 @@ encode %{ intptr_t val = $src$$constant; relocInfo::relocType constant_reloc = $src->constant_reloc(); // src address const_toc_addr; + RelocationHolder r; // Initializes type to none. if (constant_reloc == relocInfo::oop_type) { // Create an oop constant and a corresponding relocation. - AddressLiteral a = __ allocate_oop_address((jobject)val); + AddressLiteral a = __ constant_oop_address((jobject)val); const_toc_addr = __ address_constant((address)a.value(), RelocationHolder::none); - __ relocate(a.rspec()); + r = a.rspec(); } else if (constant_reloc == relocInfo::metadata_type) { + // Notify OOP recorder (don't need the relocation) AddressLiteral a = __ constant_metadata_address((Metadata *)val); const_toc_addr = __ address_constant((address)a.value(), RelocationHolder::none); - __ relocate(a.rspec()); } else { // non-oop pointers, e.g. card mark base, heap top // Create a non-oop constant, no relocation needed. const_toc_addr = __ long_constant((jlong)$src$$constant); @@ -2850,6 +2859,7 @@ encode %{ ciEnv::current()->record_out_of_memory_failure(); return; } + __ relocate(r); // If set above. // Get the constant's TOC offset. const int toc_offset = __ offset_to_method_toc(const_toc_addr); // Store the toc offset of the constant. diff --git a/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp b/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp index 824996168a9..3382df355da 100644 --- a/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp +++ b/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp @@ -734,7 +734,7 @@ int SharedRuntime::java_calling_convention(const BasicType *sig_bt, ShouldNotReachHere(); } } - return align_up(stk, 2); + return stk; } #if defined(COMPILER1) || defined(COMPILER2) diff --git a/src/hotspot/cpu/riscv/assembler_riscv.hpp b/src/hotspot/cpu/riscv/assembler_riscv.hpp index 922e412356d..9385d63fd1a 100644 --- a/src/hotspot/cpu/riscv/assembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/assembler_riscv.hpp @@ -2940,6 +2940,17 @@ enum Nf { return uabs(target - branch) < branch_range; } + // Decode the given instruction, checking if it's a 16-bit compressed + // instruction and return the address of the next instruction. + static address locate_next_instruction(address inst) { + // Instruction wider than 16 bits has the two least-significant bits set. + if ((0x3 & *inst) == 0x3) { + return inst + instruction_size; + } else { + return inst + compressed_instruction_size; + } + } + Assembler(CodeBuffer* code) : AbstractAssembler(code), _in_compressible_region(true) {} }; diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp index 02e0a195138..0444c64c2b1 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp @@ -4342,6 +4342,57 @@ void MacroAssembler::zero_dcache_blocks(Register base, Register cnt, Register tm bge(cnt, tmp1, loop); } +// java.lang.Math.round(float a) +// Returns the closest int to the argument, with ties rounding to positive infinity. +void MacroAssembler::java_round_float(Register dst, FloatRegister src, FloatRegister ftmp) { + // this instructions calling sequence provides performance improvement on all tested devices; + // don't change it without re-verification + Label done; + mv(t0, jint_cast(0.5f)); + fmv_w_x(ftmp, t0); + + // dst = 0 if NaN + feq_s(t0, src, src); // replacing fclass with feq as performance optimization + mv(dst, zr); + beqz(t0, done); + + // dst = (src + 0.5f) rounded down towards negative infinity + // Adding 0.5f to some floats exceeds the precision limits for a float and rounding takes place. + // RDN is required for fadd_s, RNE gives incorrect results: + // -------------------------------------------------------------------- + // fadd.s rne (src + 0.5f): src = 8388609.000000 ftmp = 8388610.000000 + // fcvt.w.s rdn: ftmp = 8388610.000000 dst = 8388610 + // -------------------------------------------------------------------- + // fadd.s rdn (src + 0.5f): src = 8388609.000000 ftmp = 8388609.000000 + // fcvt.w.s rdn: ftmp = 8388609.000000 dst = 8388609 + // -------------------------------------------------------------------- + fadd_s(ftmp, src, ftmp, RoundingMode::rdn); + fcvt_w_s(dst, ftmp, RoundingMode::rdn); + + bind(done); +} + +// java.lang.Math.round(double a) +// Returns the closest long to the argument, with ties rounding to positive infinity. +void MacroAssembler::java_round_double(Register dst, FloatRegister src, FloatRegister ftmp) { + // this instructions calling sequence provides performance improvement on all tested devices; + // don't change it without re-verification + Label done; + mv(t0, julong_cast(0.5)); + fmv_d_x(ftmp, t0); + + // dst = 0 if NaN + feq_d(t0, src, src); // replacing fclass with feq as performance optimization + mv(dst, zr); + beqz(t0, done); + + // dst = (src + 0.5) rounded down towards negative infinity + fadd_d(ftmp, src, ftmp, RoundingMode::rdn); // RDN is required here otherwise some inputs produce incorrect results + fcvt_l_d(dst, ftmp, RoundingMode::rdn); + + bind(done); +} + #define FCVT_SAFE(FLOATCVT, FLOATSIG) \ void MacroAssembler::FLOATCVT##_safe(Register dst, FloatRegister src, Register tmp) { \ Label done; \ diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp index 3b110cd3e28..4b4c7a59aab 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp @@ -1252,6 +1252,9 @@ class MacroAssembler: public Assembler { void fcvt_w_d_safe(Register dst, FloatRegister src, Register tmp = t0); void fcvt_l_d_safe(Register dst, FloatRegister src, Register tmp = t0); + void java_round_float(Register dst, FloatRegister src, FloatRegister ftmp); + void java_round_double(Register dst, FloatRegister src, FloatRegister ftmp); + // vector load/store unit-stride instructions void vlex_v(VectorRegister vd, Register base, Assembler::SEW sew, VectorMask vm = unmasked) { switch (sew) { diff --git a/src/hotspot/cpu/riscv/riscv.ad b/src/hotspot/cpu/riscv/riscv.ad index 1096ca80043..fe20e795aad 100644 --- a/src/hotspot/cpu/riscv/riscv.ad +++ b/src/hotspot/cpu/riscv/riscv.ad @@ -1001,6 +1001,7 @@ definitions %{ int_def LOAD_COST ( 300, 3 * DEFAULT_COST); // load, fpload int_def STORE_COST ( 100, 1 * DEFAULT_COST); // store, fpstore int_def XFER_COST ( 300, 3 * DEFAULT_COST); // mfc, mtc, fcvt, fmove, fcmp + int_def FMVX_COST ( 100, 1 * DEFAULT_COST); // shuffles with no conversion int_def BRANCH_COST ( 200, 2 * DEFAULT_COST); // branch, jmp, call int_def IMUL_COST ( 1000, 10 * DEFAULT_COST); // imul int_def IDIVSI_COST ( 3400, 34 * DEFAULT_COST); // idivsi @@ -8417,6 +8418,34 @@ instruct convN2I(iRegINoSp dst, iRegN src) ins_pipe(ialu_reg); %} +instruct round_double_reg(iRegLNoSp dst, fRegD src, fRegD ftmp) %{ + match(Set dst (RoundD src)); + + ins_cost(XFER_COST + BRANCH_COST); + effect(TEMP ftmp); + format %{ "java_round_double $dst, $src\t#@round_double_reg" %} + + ins_encode %{ + __ java_round_double($dst$$Register, as_FloatRegister($src$$reg), as_FloatRegister($ftmp$$reg)); + %} + + ins_pipe(pipe_slow); +%} + +instruct round_float_reg(iRegINoSp dst, fRegF src, fRegF ftmp) %{ + match(Set dst (RoundF src)); + + ins_cost(XFER_COST + BRANCH_COST); + effect(TEMP ftmp); + format %{ "java_round_float $dst, $src\t#@round_float_reg" %} + + ins_encode %{ + __ java_round_float($dst$$Register, as_FloatRegister($src$$reg), as_FloatRegister($ftmp$$reg)); + %} + + ins_pipe(pipe_slow); +%} + // Convert oop pointer into compressed form instruct encodeHeapOop(iRegNNoSp dst, iRegP src) %{ match(Set dst (EncodeP src)); @@ -8646,7 +8675,7 @@ instruct MoveF2I_reg_reg(iRegINoSp dst, fRegF src) %{ effect(DEF dst, USE src); - ins_cost(XFER_COST); + ins_cost(FMVX_COST); format %{ "fmv.x.w $dst, $src\t#@MoveF2I_reg_reg" %} @@ -8664,7 +8693,7 @@ instruct MoveI2F_reg_reg(fRegF dst, iRegI src) %{ effect(DEF dst, USE src); - ins_cost(XFER_COST); + ins_cost(FMVX_COST); format %{ "fmv.w.x $dst, $src\t#@MoveI2F_reg_reg" %} @@ -8682,7 +8711,7 @@ instruct MoveD2L_reg_reg(iRegLNoSp dst, fRegD src) %{ effect(DEF dst, USE src); - ins_cost(XFER_COST); + ins_cost(FMVX_COST); format %{ "fmv.x.d $dst, $src\t#@MoveD2L_reg_reg" %} @@ -8700,7 +8729,7 @@ instruct MoveL2D_reg_reg(fRegD dst, iRegL src) %{ effect(DEF dst, USE src); - ins_cost(XFER_COST); + ins_cost(FMVX_COST); format %{ "fmv.d.x $dst, $src\t#@MoveL2D_reg_reg" %} diff --git a/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp b/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp index 36430e126f9..582aa400875 100644 --- a/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp +++ b/src/hotspot/cpu/riscv/sharedRuntime_riscv.cpp @@ -266,7 +266,7 @@ int SharedRuntime::java_calling_convention(const BasicType *sig_bt, uint int_args = 0; uint fp_args = 0; - uint stk_args = 0; // inc by 2 each time + uint stk_args = 0; for (int i = 0; i < total_args_passed; i++) { switch (sig_bt[i]) { @@ -278,8 +278,9 @@ int SharedRuntime::java_calling_convention(const BasicType *sig_bt, if (int_args < Argument::n_int_register_parameters_j) { regs[i].set1(INT_ArgReg[int_args++]->as_VMReg()); } else { + stk_args = align_up(stk_args, 2); regs[i].set1(VMRegImpl::stack2reg(stk_args)); - stk_args += 2; + stk_args += 1; } break; case T_VOID: @@ -295,6 +296,7 @@ int SharedRuntime::java_calling_convention(const BasicType *sig_bt, if (int_args < Argument::n_int_register_parameters_j) { regs[i].set2(INT_ArgReg[int_args++]->as_VMReg()); } else { + stk_args = align_up(stk_args, 2); regs[i].set2(VMRegImpl::stack2reg(stk_args)); stk_args += 2; } @@ -303,8 +305,9 @@ int SharedRuntime::java_calling_convention(const BasicType *sig_bt, if (fp_args < Argument::n_float_register_parameters_j) { regs[i].set1(FP_ArgReg[fp_args++]->as_VMReg()); } else { + stk_args = align_up(stk_args, 2); regs[i].set1(VMRegImpl::stack2reg(stk_args)); - stk_args += 2; + stk_args += 1; } break; case T_DOUBLE: @@ -312,6 +315,7 @@ int SharedRuntime::java_calling_convention(const BasicType *sig_bt, if (fp_args < Argument::n_float_register_parameters_j) { regs[i].set2(FP_ArgReg[fp_args++]->as_VMReg()); } else { + stk_args = align_up(stk_args, 2); regs[i].set2(VMRegImpl::stack2reg(stk_args)); stk_args += 2; } @@ -321,7 +325,7 @@ int SharedRuntime::java_calling_convention(const BasicType *sig_bt, } } - return align_up(stk_args, 2); + return stk_args; } // Patch the callers callsite with entry to compiled code if it exists. diff --git a/src/hotspot/cpu/s390/c1_LIRGenerator_s390.cpp b/src/hotspot/cpu/s390/c1_LIRGenerator_s390.cpp index c216897d68f..8df13597425 100644 --- a/src/hotspot/cpu/s390/c1_LIRGenerator_s390.cpp +++ b/src/hotspot/cpu/s390/c1_LIRGenerator_s390.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2016, 2017 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -157,8 +157,10 @@ LIR_Address* LIRGenerator::generate_address(LIR_Opr base, LIR_Opr index, return new LIR_Address(base, index, type); } else { if (shift > 0) { - LIR_Opr tmp = new_pointer_register(); - __ shift_left(index, shift, tmp); + // Use long register to avoid overflow when shifting large index values left. + LIR_Opr tmp = new_register(T_LONG); + __ convert(Bytecodes::_i2l, index, tmp); + __ shift_left(tmp, shift, tmp); index = tmp; } return new LIR_Address(base, index, disp, type); diff --git a/src/hotspot/cpu/s390/sharedRuntime_s390.cpp b/src/hotspot/cpu/s390/sharedRuntime_s390.cpp index 4798f35f19d..ed1795cfa33 100644 --- a/src/hotspot/cpu/s390/sharedRuntime_s390.cpp +++ b/src/hotspot/cpu/s390/sharedRuntime_s390.cpp @@ -755,7 +755,7 @@ int SharedRuntime::java_calling_convention(const BasicType *sig_bt, ShouldNotReachHere(); } } - return align_up(stk, 2); + return stk; } int SharedRuntime::c_calling_convention(const BasicType *sig_bt, diff --git a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp index 54e5f55fa2b..a197a8e3c7d 100644 --- a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp @@ -1089,7 +1089,8 @@ void C2_MacroAssembler::vminmax_fp(int opcode, BasicType elem_bt, assert(opcode == Op_MinV || opcode == Op_MinReductionV || opcode == Op_MaxV || opcode == Op_MaxReductionV, "sanity"); assert(elem_bt == T_FLOAT || elem_bt == T_DOUBLE, "sanity"); - assert_different_registers(a, b, tmp, atmp, btmp); + assert_different_registers(a, tmp, atmp, btmp); + assert_different_registers(b, tmp, atmp, btmp); bool is_min = (opcode == Op_MinV || opcode == Op_MinReductionV); bool is_double_word = is_double_word_type(elem_bt); @@ -1176,7 +1177,8 @@ void C2_MacroAssembler::evminmax_fp(int opcode, BasicType elem_bt, assert(opcode == Op_MinV || opcode == Op_MinReductionV || opcode == Op_MaxV || opcode == Op_MaxReductionV, "sanity"); assert(elem_bt == T_FLOAT || elem_bt == T_DOUBLE, "sanity"); - assert_different_registers(dst, a, b, atmp, btmp); + assert_different_registers(dst, a, atmp, btmp); + assert_different_registers(dst, b, atmp, btmp); bool is_min = (opcode == Op_MinV || opcode == Op_MinReductionV); bool is_double_word = is_double_word_type(elem_bt); diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.cpp b/src/hotspot/cpu/x86/macroAssembler_x86.cpp index aec1f3c9105..88296656485 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.cpp @@ -1871,92 +1871,6 @@ void MacroAssembler::cmpoop(Register src1, jobject src2, Register rscratch) { } #endif -void MacroAssembler::cvtss2sd(XMMRegister dst, XMMRegister src) { - if ((UseAVX > 0) && (dst != src)) { - xorpd(dst, dst); - } - Assembler::cvtss2sd(dst, src); -} - -void MacroAssembler::cvtss2sd(XMMRegister dst, Address src) { - if (UseAVX > 0) { - xorpd(dst, dst); - } - Assembler::cvtss2sd(dst, src); -} - -void MacroAssembler::cvtsd2ss(XMMRegister dst, XMMRegister src) { - if ((UseAVX > 0) && (dst != src)) { - xorps(dst, dst); - } - Assembler::cvtsd2ss(dst, src); -} - -void MacroAssembler::cvtsd2ss(XMMRegister dst, Address src) { - if (UseAVX > 0) { - xorps(dst, dst); - } - Assembler::cvtsd2ss(dst, src); -} - -void MacroAssembler::cvtsi2sdl(XMMRegister dst, Register src) { - if (UseAVX > 0) { - xorpd(dst, dst); - } - Assembler::cvtsi2sdl(dst, src); -} - -void MacroAssembler::cvtsi2sdl(XMMRegister dst, Address src) { - if (UseAVX > 0) { - xorpd(dst, dst); - } - Assembler::cvtsi2sdl(dst, src); -} - -void MacroAssembler::cvtsi2ssl(XMMRegister dst, Register src) { - if (UseAVX > 0) { - xorps(dst, dst); - } - Assembler::cvtsi2ssl(dst, src); -} - -void MacroAssembler::cvtsi2ssl(XMMRegister dst, Address src) { - if (UseAVX > 0) { - xorps(dst, dst); - } - Assembler::cvtsi2ssl(dst, src); -} - -#ifdef _LP64 -void MacroAssembler::cvtsi2sdq(XMMRegister dst, Register src) { - if (UseAVX > 0) { - xorpd(dst, dst); - } - Assembler::cvtsi2sdq(dst, src); -} - -void MacroAssembler::cvtsi2sdq(XMMRegister dst, Address src) { - if (UseAVX > 0) { - xorpd(dst, dst); - } - Assembler::cvtsi2sdq(dst, src); -} - -void MacroAssembler::cvtsi2ssq(XMMRegister dst, Register src) { - if (UseAVX > 0) { - xorps(dst, dst); - } - Assembler::cvtsi2ssq(dst, src); -} - -void MacroAssembler::cvtsi2ssq(XMMRegister dst, Address src) { - if (UseAVX > 0) { - xorps(dst, dst); - } - Assembler::cvtsi2ssq(dst, src); -} -#endif // _LP64 - void MacroAssembler::locked_cmpxchgptr(Register reg, AddressLiteral adr, Register rscratch) { assert(rscratch != noreg || always_reachable(adr), "missing"); diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.hpp b/src/hotspot/cpu/x86/macroAssembler_x86.hpp index ea6a37d16ed..1908703b9bf 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.hpp @@ -800,23 +800,6 @@ class MacroAssembler: public Assembler { void cmpxchgptr(Register reg, Address adr); - - // cvt instructions - void cvtss2sd(XMMRegister dst, XMMRegister src); - void cvtss2sd(XMMRegister dst, Address src); - void cvtsd2ss(XMMRegister dst, XMMRegister src); - void cvtsd2ss(XMMRegister dst, Address src); - void cvtsi2sdl(XMMRegister dst, Register src); - void cvtsi2sdl(XMMRegister dst, Address src); - void cvtsi2ssl(XMMRegister dst, Register src); - void cvtsi2ssl(XMMRegister dst, Address src); -#ifdef _LP64 - void cvtsi2sdq(XMMRegister dst, Register src); - void cvtsi2sdq(XMMRegister dst, Address src); - void cvtsi2ssq(XMMRegister dst, Register src); - void cvtsi2ssq(XMMRegister dst, Address src); -#endif - void locked_cmpxchgptr(Register reg, AddressLiteral adr, Register rscratch = noreg); void imulptr(Register dst, Register src) { LP64_ONLY(imulq(dst, src)) NOT_LP64(imull(dst, src)); } diff --git a/src/hotspot/cpu/x86/sharedRuntime_x86_32.cpp b/src/hotspot/cpu/x86/sharedRuntime_x86_32.cpp index 3ae539bac8d..571160523cb 100644 --- a/src/hotspot/cpu/x86/sharedRuntime_x86_32.cpp +++ b/src/hotspot/cpu/x86/sharedRuntime_x86_32.cpp @@ -528,8 +528,7 @@ int SharedRuntime::java_calling_convention(const BasicType *sig_bt, } } - // return value can be odd number of VMRegImpl stack slots make multiple of 2 - return align_up(stack, 2); + return stack; } // Patch the callers callsite with entry to compiled code if it exists. diff --git a/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp b/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp index bf15dab0703..faa423bcf8e 100644 --- a/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp +++ b/src/hotspot/cpu/x86/sharedRuntime_x86_64.cpp @@ -498,7 +498,7 @@ int SharedRuntime::java_calling_convention(const BasicType *sig_bt, uint int_args = 0; uint fp_args = 0; - uint stk_args = 0; // inc by 2 each time + uint stk_args = 0; for (int i = 0; i < total_args_passed; i++) { switch (sig_bt[i]) { @@ -510,8 +510,9 @@ int SharedRuntime::java_calling_convention(const BasicType *sig_bt, if (int_args < Argument::n_int_register_parameters_j) { regs[i].set1(INT_ArgReg[int_args++]->as_VMReg()); } else { + stk_args = align_up(stk_args, 2); regs[i].set1(VMRegImpl::stack2reg(stk_args)); - stk_args += 2; + stk_args += 1; } break; case T_VOID: @@ -528,6 +529,7 @@ int SharedRuntime::java_calling_convention(const BasicType *sig_bt, if (int_args < Argument::n_int_register_parameters_j) { regs[i].set2(INT_ArgReg[int_args++]->as_VMReg()); } else { + stk_args = align_up(stk_args, 2); regs[i].set2(VMRegImpl::stack2reg(stk_args)); stk_args += 2; } @@ -536,8 +538,9 @@ int SharedRuntime::java_calling_convention(const BasicType *sig_bt, if (fp_args < Argument::n_float_register_parameters_j) { regs[i].set1(FP_ArgReg[fp_args++]->as_VMReg()); } else { + stk_args = align_up(stk_args, 2); regs[i].set1(VMRegImpl::stack2reg(stk_args)); - stk_args += 2; + stk_args += 1; } break; case T_DOUBLE: @@ -545,6 +548,7 @@ int SharedRuntime::java_calling_convention(const BasicType *sig_bt, if (fp_args < Argument::n_float_register_parameters_j) { regs[i].set2(FP_ArgReg[fp_args++]->as_VMReg()); } else { + stk_args = align_up(stk_args, 2); regs[i].set2(VMRegImpl::stack2reg(stk_args)); stk_args += 2; } @@ -555,7 +559,7 @@ int SharedRuntime::java_calling_convention(const BasicType *sig_bt, } } - return align_up(stk_args, 2); + return stk_args; } // Patch the callers callsite with entry to compiled code if it exists. diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp index c73e0759b57..9abc559090a 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, 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 @@ -2318,7 +2318,7 @@ address StubGenerator::generate_base64_decodeBlock() { const Register isURL = c_rarg5;// Base64 or URL character set __ movl(isMIME, Address(rbp, 2 * wordSize)); #else - const Address dp_mem(rbp, 6 * wordSize); // length is on stack on Win64 + const Address dp_mem(rbp, 6 * wordSize); // length is on stack on Win64 const Address isURL_mem(rbp, 7 * wordSize); const Register isURL = r10; // pick the volatile windows register const Register dp = r12; @@ -2540,10 +2540,12 @@ address StubGenerator::generate_base64_decodeBlock() { // output_size in r13 // Strip pad characters, if any, and adjust length and mask + __ addq(length, start_offset); __ cmpb(Address(source, length, Address::times_1, -1), '='); __ jcc(Assembler::equal, L_padding); __ BIND(L_donePadding); + __ subq(length, start_offset); // Output size is (64 - output_size), output mask is (all 1s >> output_size). __ kmovql(input_mask, rax); diff --git a/src/hotspot/cpu/x86/x86_64.ad b/src/hotspot/cpu/x86/x86_64.ad index 759dd8a1d48..80f281a1bf9 100644 --- a/src/hotspot/cpu/x86/x86_64.ad +++ b/src/hotspot/cpu/x86/x86_64.ad @@ -10095,7 +10095,7 @@ instruct cmpD_imm(rRegI dst, regD src, immD con, rFlagsReg cr) %{ instruct convF2D_reg_reg(regD dst, regF src) %{ match(Set dst (ConvF2D src)); - effect(TEMP dst); + format %{ "cvtss2sd $dst, $src" %} ins_encode %{ __ cvtss2sd ($dst$$XMMRegister, $src$$XMMRegister); @@ -10117,7 +10117,7 @@ instruct convF2D_reg_mem(regD dst, memory src) instruct convD2F_reg_reg(regF dst, regD src) %{ match(Set dst (ConvD2F src)); - effect(TEMP dst); + format %{ "cvtsd2ss $dst, $src" %} ins_encode %{ __ cvtsd2ss ($dst$$XMMRegister, $src$$XMMRegister); diff --git a/src/hotspot/os/aix/globals_aix.hpp b/src/hotspot/os/aix/globals_aix.hpp index a047e79b695..fb353348a53 100644 --- a/src/hotspot/os/aix/globals_aix.hpp +++ b/src/hotspot/os/aix/globals_aix.hpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2012, 2018 SAP SE. All rights reserved. + * Copyright (c) 2005, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2024 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -49,11 +49,12 @@ "Allow VM to run with EXTSHM=ON.") \ \ /* Maximum expected size of the data segment. That correlates with the */ \ - /* to the maximum C Heap consumption we expect. */ \ - /* We need to know this because we need to leave "breathing space" for the */ \ - /* data segment when placing the java heap. If that space is too small, we */ \ - /* reduce our chance of getting a low heap address (needed for compressed */ \ - /* Oops). */ \ + /* maximum C Heap consumption we expect. */ \ + /* We need to leave "breathing space" for the data segment when */ \ + /* placing the java heap. If the MaxExpectedDataSegmentSize setting */ \ + /* is too small, we might run into resource issues creating many native */ \ + /* threads, if it is too large, we reduce our chance of getting a low heap */ \ + /* address (needed for compressed Oops). */ \ product(uintx, MaxExpectedDataSegmentSize, 8*G, \ "Maximum expected Data Segment Size.") \ \ diff --git a/src/hotspot/os/aix/os_aix.cpp b/src/hotspot/os/aix/os_aix.cpp index 54c538cf367..21137a2f0c7 100644 --- a/src/hotspot/os/aix/os_aix.cpp +++ b/src/hotspot/os/aix/os_aix.cpp @@ -1118,7 +1118,9 @@ void *os::dll_load(const char *filename, char *ebuf, int ebuflen) { } if (!filename || strlen(filename) == 0) { - ::strncpy(ebuf, "dll_load: empty filename specified", ebuflen - 1); + if (ebuf != nullptr && ebuflen > 0) { + ::strncpy(ebuf, "dll_load: empty filename specified", ebuflen - 1); + } return nullptr; } @@ -1133,8 +1135,9 @@ void *os::dll_load(const char *filename, char *ebuf, int ebuflen) { } void* result; + const char* error_report = nullptr; JFR_ONLY(NativeLibraryLoadEvent load_event(filename, &result);) - result = ::dlopen(filename, dflags); + result = Aix_dlopen(filename, dflags, &error_report); if (result != nullptr) { Events::log_dll_message(nullptr, "Loaded shared library %s", filename); // Reload dll cache. Don't do this in signal handling. @@ -1143,7 +1146,6 @@ void *os::dll_load(const char *filename, char *ebuf, int ebuflen) { return result; } else { // error analysis when dlopen fails - const char* error_report = ::dlerror(); if (error_report == nullptr) { error_report = "dlerror returned no error description"; } @@ -3031,31 +3033,3 @@ void os::jfr_report_memory_info() {} #endif // INCLUDE_JFR -// Simulate the library search algorithm of dlopen() (in os::dll_load) -int os::Aix::stat64x_via_LIBPATH(const char* path, struct stat64x* stat) { - if (path[0] == '/' || - (path[0] == '.' && (path[1] == '/' || - (path[1] == '.' && path[2] == '/')))) { - return stat64x(path, stat); - } - - const char* env = getenv("LIBPATH"); - if (env == nullptr || *env == 0) - return -1; - - int ret = -1; - size_t libpathlen = strlen(env); - char* libpath = NEW_C_HEAP_ARRAY(char, libpathlen + 1, mtServiceability); - char* combined = NEW_C_HEAP_ARRAY(char, libpathlen + strlen(path) + 1, mtServiceability); - char *saveptr, *token; - strcpy(libpath, env); - for (token = strtok_r(libpath, ":", &saveptr); token != nullptr; token = strtok_r(nullptr, ":", &saveptr)) { - sprintf(combined, "%s/%s", token, path); - if (0 == (ret = stat64x(combined, stat))) - break; - } - - FREE_C_HEAP_ARRAY(char*, combined); - FREE_C_HEAP_ARRAY(char*, libpath); - return ret; -} diff --git a/src/hotspot/os/aix/os_aix.hpp b/src/hotspot/os/aix/os_aix.hpp index f2596874b05..a1db2b2be3c 100644 --- a/src/hotspot/os/aix/os_aix.hpp +++ b/src/hotspot/os/aix/os_aix.hpp @@ -175,8 +175,6 @@ class os::Aix { static bool platform_print_native_stack(outputStream* st, const void* context, char *buf, int buf_size, address& lastpc); static void* resolve_function_descriptor(void* p); - // Simulate the library search algorithm of dlopen() (in os::dll_load) - static int stat64x_via_LIBPATH(const char* path, struct stat64x* stat); }; #endif // OS_AIX_OS_AIX_HPP diff --git a/src/hotspot/os/aix/os_perf_aix.cpp b/src/hotspot/os/aix/os_perf_aix.cpp index e1719df48c3..b5ae1a6a725 100644 --- a/src/hotspot/os/aix/os_perf_aix.cpp +++ b/src/hotspot/os/aix/os_perf_aix.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2022, IBM Corp. + * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, IBM Corp. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -87,6 +87,7 @@ static bool read_psinfo(const u_longlong_t& pid, psinfo_t& psinfo) { } len = fread(&psinfo, 1, sizeof(psinfo_t), fp); + fclose(fp); return len == sizeof(psinfo_t); } diff --git a/src/hotspot/os/aix/porting_aix.cpp b/src/hotspot/os/aix/porting_aix.cpp index ab84dc81027..68233097b49 100644 --- a/src/hotspot/os/aix/porting_aix.cpp +++ b/src/hotspot/os/aix/porting_aix.cpp @@ -21,6 +21,12 @@ * questions. * */ +// needs to be defined first, so that the implicit loaded xcoff.h header defines +// the right structures to analyze the loader header of 64 Bit executable files +// this is needed for rtv_linkedin_libpath() to get the linked (burned) in library +// search path of an XCOFF executable +#define __XCOFF64__ +#include #include "asm/assembler.hpp" #include "compiler/disassembler.hpp" @@ -891,3 +897,275 @@ bool AixMisc::query_stack_bounds_for_current_thread(stackbounds_t* out) { return true; } + +// variables needed to emulate linux behavior in os::dll_load() if library is loaded twice +static pthread_mutex_t g_handletable_mutex = PTHREAD_MUTEX_INITIALIZER; + +struct TableLocker { + TableLocker() { pthread_mutex_lock(&g_handletable_mutex); } + ~TableLocker() { pthread_mutex_unlock(&g_handletable_mutex); } +}; +struct handletableentry{ + void* handle; + ino64_t inode; + dev64_t devid; + uint refcount; +}; +constexpr unsigned init_num_handles = 128; +static unsigned max_handletable = 0; +static unsigned g_handletable_used = 0; +// We start with an empty array. At first use we will dynamically allocate memory for 128 entries. +// If this table is full we dynamically reallocate a memory reagion of double size, and so on. +static struct handletableentry* p_handletable = nullptr; + +// get the library search path burned in to the executable file during linking +// If the libpath cannot be retrieved return an empty path +static const char* rtv_linkedin_libpath() { + constexpr int bufsize = 4096; + static char buffer[bufsize]; + static const char* libpath = 0; + + // we only try to retrieve the libpath once. After that try we + // let libpath point to buffer, which then contains a valid libpath + // or an empty string + if (libpath != nullptr) { + return libpath; + } + + // retrieve the path to the currently running executable binary + // to open it + snprintf(buffer, 100, "/proc/%ld/object/a.out", (long)getpid()); + FILE* f = nullptr; + struct xcoffhdr the_xcoff; + struct scnhdr the_scn; + struct ldhdr the_ldr; + constexpr size_t xcoffsz = FILHSZ + _AOUTHSZ_EXEC; + STATIC_ASSERT(sizeof(the_xcoff) == xcoffsz); + STATIC_ASSERT(sizeof(the_scn) == SCNHSZ); + STATIC_ASSERT(sizeof(the_ldr) == LDHDRSZ); + // read the generic XCOFF header and analyze the substructures + // to find the burned in libpath. In any case of error perform the assert + if (nullptr == (f = fopen(buffer, "r")) || + xcoffsz != fread(&the_xcoff, 1, xcoffsz, f) || + the_xcoff.filehdr.f_magic != U64_TOCMAGIC || + 0 != fseek(f, (FILHSZ + the_xcoff.filehdr.f_opthdr + (the_xcoff.aouthdr.o_snloader -1)*SCNHSZ), SEEK_SET) || + SCNHSZ != fread(&the_scn, 1, SCNHSZ, f) || + 0 != strcmp(the_scn.s_name, ".loader") || + 0 != fseek(f, the_scn.s_scnptr, SEEK_SET) || + LDHDRSZ != fread(&the_ldr, 1, LDHDRSZ, f) || + 0 != fseek(f, the_scn.s_scnptr + the_ldr.l_impoff, SEEK_SET) || + 0 == fread(buffer, 1, bufsize, f)) { + buffer[0] = 0; + assert(false, "could not retrieve burned in library path from executables loader section"); + } + + if (f) { + fclose(f); + } + libpath = buffer; + + return libpath; +} + +// Simulate the library search algorithm of dlopen() (in os::dll_load) +static bool search_file_in_LIBPATH(const char* path, struct stat64x* stat) { + if (path == nullptr) + return false; + + char* path2 = os::strdup(path); + // if exist, strip off trailing (shr_64.o) or similar + char* substr; + if (path2[strlen(path2) - 1] == ')' && (substr = strrchr(path2, '('))) { + *substr = 0; + } + + bool ret = false; + // If FilePath contains a slash character, FilePath is used directly, + // and no directories are searched. + // But if FilePath does not start with / or . we have to prepend it with ./ + if (strchr(path2, '/')) { + stringStream combined; + if (*path2 == '/' || *path2 == '.') { + combined.print("%s", path2); + } else { + combined.print("./%s", path2); + } + ret = (0 == stat64x(combined.base(), stat)); + os::free(path2); + return ret; + } + + const char* env = getenv("LIBPATH"); + if (env == nullptr) { + // no LIBPATH, try with LD_LIBRARY_PATH + env = getenv("LD_LIBRARY_PATH"); + } + + stringStream Libpath; + if (env == nullptr) { + // no LIBPATH or LD_LIBRARY_PATH given -> try only with burned in libpath + Libpath.print("%s", rtv_linkedin_libpath()); + } else if (*env == 0) { + // LIBPATH or LD_LIBRARY_PATH given but empty -> try first with burned + // in libpath and with current working directory second + Libpath.print("%s:.", rtv_linkedin_libpath()); + } else { + // LIBPATH or LD_LIBRARY_PATH given with content -> try first with + // LIBPATH or LD_LIBRARY_PATH and second with burned in libpath. + // No check against current working directory + Libpath.print("%s:%s", env, rtv_linkedin_libpath()); + } + + char* libpath = os::strdup(Libpath.base()); + + char *saveptr, *token; + for (token = strtok_r(libpath, ":", &saveptr); token != nullptr; token = strtok_r(nullptr, ":", &saveptr)) { + stringStream combined; + combined.print("%s/%s", token, path2); + if ((ret = (0 == stat64x(combined.base(), stat)))) + break; + } + + os::free(libpath); + os::free(path2); + return ret; +} + +// specific AIX versions for ::dlopen() and ::dlclose(), which handles the struct g_handletable +// This way we mimic dl handle equality for a library +// opened a second time, as it is implemented on other platforms. +void* Aix_dlopen(const char* filename, int Flags, const char** error_report) { + assert(error_report != nullptr, "error_report is nullptr"); + void* result; + struct stat64x libstat; + + if (false == search_file_in_LIBPATH(filename, &libstat)) { + // file with filename does not exist + #ifdef ASSERT + result = ::dlopen(filename, Flags); + assert(result == nullptr, "dll_load: Could not stat() file %s, but dlopen() worked; Have to improve stat()", filename); + #endif + *error_report = "Could not load module .\nSystem error: No such file or directory"; + return nullptr; + } + else { + unsigned i = 0; + TableLocker lock; + // check if library belonging to filename is already loaded. + // If yes use stored handle from previous ::dlopen() and increase refcount + for (i = 0; i < g_handletable_used; i++) { + if ((p_handletable + i)->handle && + (p_handletable + i)->inode == libstat.st_ino && + (p_handletable + i)->devid == libstat.st_dev) { + (p_handletable + i)->refcount++; + result = (p_handletable + i)->handle; + break; + } + } + if (i == g_handletable_used) { + // library not yet loaded. Check if there is space left in array + // to store new ::dlopen() handle + if (g_handletable_used == max_handletable) { + // No place in array anymore; increase array. + unsigned new_max = MAX2(max_handletable * 2, init_num_handles); + struct handletableentry* new_tab = (struct handletableentry*)::realloc(p_handletable, new_max * sizeof(struct handletableentry)); + assert(new_tab != nullptr, "no more memory for handletable"); + if (new_tab == nullptr) { + *error_report = "dlopen: no more memory for handletable"; + return nullptr; + } + max_handletable = new_max; + p_handletable = new_tab; + } + // Library not yet loaded; load it, then store its handle in handle table + result = ::dlopen(filename, Flags); + if (result != nullptr) { + g_handletable_used++; + (p_handletable + i)->handle = result; + (p_handletable + i)->inode = libstat.st_ino; + (p_handletable + i)->devid = libstat.st_dev; + (p_handletable + i)->refcount = 1; + } + else { + // error analysis when dlopen fails + *error_report = ::dlerror(); + if (*error_report == nullptr) { + *error_report = "dlerror returned no error description"; + } + } + } + } + return result; +} + +bool os::pd_dll_unload(void* libhandle, char* ebuf, int ebuflen) { + unsigned i = 0; + bool res = false; + + if (ebuf && ebuflen > 0) { + ebuf[0] = '\0'; + ebuf[ebuflen - 1] = '\0'; + } + + { + TableLocker lock; + // try to find handle in array, which means library was loaded by os::dll_load() call + for (i = 0; i < g_handletable_used; i++) { + if ((p_handletable + i)->handle == libhandle) { + // handle found, decrease refcount + assert((p_handletable + i)->refcount > 0, "Sanity"); + (p_handletable + i)->refcount--; + if ((p_handletable + i)->refcount > 0) { + // if refcount is still >0 then we have to keep library and just return true + return true; + } + // refcount == 0, so we have to ::dlclose() the lib + // and delete the entry from the array. + break; + } + } + + // If we reach this point either the libhandle was found with refcount == 0, or the libhandle + // was not found in the array at all. In both cases we have to ::dlclose the lib and perform + // the error handling. In the first case we then also have to delete the entry from the array + // while in the second case we simply have to nag. + res = (0 == ::dlclose(libhandle)); + if (!res) { + // error analysis when dlopen fails + const char* error_report = ::dlerror(); + if (error_report == nullptr) { + error_report = "dlerror returned no error description"; + } + if (ebuf != nullptr && ebuflen > 0) { + snprintf(ebuf, ebuflen - 1, "%s", error_report); + } + assert(false, "os::pd_dll_unload() ::dlclose() failed"); + } + + if (i < g_handletable_used) { + if (res) { + // First case: libhandle was found (with refcount == 0) and ::dlclose successful, + // so delete entry from array + g_handletable_used--; + // If the entry was the last one of the array, the previous g_handletable_used-- + // is sufficient to remove the entry from the array, otherwise we move the last + // entry of the array to the place of the entry we want to remove and overwrite it + if (i < g_handletable_used) { + *(p_handletable + i) = *(p_handletable + g_handletable_used); + (p_handletable + g_handletable_used)->handle = nullptr; + } + } + } + else { + // Second case: libhandle was not found (library was not loaded by os::dll_load()) + // therefore nag + assert(false, "os::pd_dll_unload() library was not loaded by os::dll_load()"); + } + } + + // Update the dll cache + LoadedLibraries::reload(); + + return res; +} // end: os::pd_dll_unload() + diff --git a/src/hotspot/os/aix/porting_aix.hpp b/src/hotspot/os/aix/porting_aix.hpp index 2c4c0e002a8..109eceee3fc 100644 --- a/src/hotspot/os/aix/porting_aix.hpp +++ b/src/hotspot/os/aix/porting_aix.hpp @@ -115,4 +115,6 @@ class AixMisc { }; +void* Aix_dlopen(const char* filename, int Flags, const char** error_report); + #endif // OS_AIX_PORTING_AIX_HPP diff --git a/src/hotspot/os/bsd/os_bsd.cpp b/src/hotspot/os/bsd/os_bsd.cpp index 18f3cd2b38d..5e243794ca9 100644 --- a/src/hotspot/os/bsd/os_bsd.cpp +++ b/src/hotspot/os/bsd/os_bsd.cpp @@ -2557,3 +2557,25 @@ void os::jfr_report_memory_info() { } #endif // INCLUDE_JFR + +bool os::pd_dll_unload(void* libhandle, char* ebuf, int ebuflen) { + + if (ebuf && ebuflen > 0) { + ebuf[0] = '\0'; + ebuf[ebuflen - 1] = '\0'; + } + + bool res = (0 == ::dlclose(libhandle)); + if (!res) { + // error analysis when dlopen fails + const char* error_report = ::dlerror(); + if (error_report == nullptr) { + error_report = "dlerror returned no error description"; + } + if (ebuf != nullptr && ebuflen > 0) { + snprintf(ebuf, ebuflen - 1, "%s", error_report); + } + } + + return res; +} // end: os::pd_dll_unload() diff --git a/src/hotspot/os/linux/attachListener_linux.cpp b/src/hotspot/os/linux/attachListener_linux.cpp index 41a24c45007..0e98bca0607 100644 --- a/src/hotspot/os/linux/attachListener_linux.cpp +++ b/src/hotspot/os/linux/attachListener_linux.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2024, 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 @@ -184,6 +184,8 @@ int LinuxAttachListener::init() { char initial_path[UNIX_PATH_MAX]; // socket file during setup int listener; // listener socket (file descriptor) + static_assert(sizeof(off_t) == 8, "Expected Large File Support in this file"); + // register function to cleanup if (!_atexit_registered) { _atexit_registered = true; @@ -446,14 +448,14 @@ AttachOperation* AttachListener::dequeue() { void AttachListener::vm_start() { char fn[UNIX_PATH_MAX]; - struct stat64 st; + struct stat st; int ret; int n = snprintf(fn, UNIX_PATH_MAX, "%s/.java_pid%d", os::get_temp_directory(), os::current_process_id()); assert(n < (int)UNIX_PATH_MAX, "java_pid file name buffer overflow"); - RESTARTABLE(::stat64(fn, &st), ret); + RESTARTABLE(::stat(fn, &st), ret); if (ret == 0) { ret = ::unlink(fn); if (ret == -1) { @@ -473,8 +475,8 @@ int AttachListener::pd_init() { bool AttachListener::check_socket_file() { int ret; - struct stat64 st; - ret = stat64(LinuxAttachListener::path(), &st); + struct stat st; + ret = stat(LinuxAttachListener::path(), &st); if (ret == -1) { // need to restart attach listener. log_debug(attach)("Socket file %s does not exist - Restart Attach Listener", LinuxAttachListener::path()); @@ -513,14 +515,14 @@ bool AttachListener::is_init_trigger() { } char fn[PATH_MAX + 1]; int ret; - struct stat64 st; + struct stat st; os::snprintf_checked(fn, sizeof(fn), ".attach_pid%d", os::current_process_id()); - RESTARTABLE(::stat64(fn, &st), ret); + RESTARTABLE(::stat(fn, &st), ret); if (ret == -1) { log_trace(attach)("Failed to find attach file: %s, trying alternate", fn); snprintf(fn, sizeof(fn), "%s/.attach_pid%d", os::get_temp_directory(), os::current_process_id()); - RESTARTABLE(::stat64(fn, &st), ret); + RESTARTABLE(::stat(fn, &st), ret); if (ret == -1) { log_debug(attach)("Failed to find attach file: %s", fn); } diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp index 3fc025e5100..4d1284337a1 100644 --- a/src/hotspot/os/linux/os_linux.cpp +++ b/src/hotspot/os/linux/os_linux.cpp @@ -1,6 +1,6 @@ /* - * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2015, 2022 SAP SE. All rights reserved. + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -417,7 +417,7 @@ pid_t os::Linux::gettid() { julong os::Linux::host_swap() { struct sysinfo si; sysinfo(&si); - return (julong)si.totalswap; + return (julong)(si.totalswap * si.mem_unit); } // Most versions of linux have a bug where the number of processors are @@ -2096,7 +2096,6 @@ const char* distro_files[] = { "/etc/mandrake-release", "/etc/sun-release", "/etc/redhat-release", - "/etc/SuSE-release", "/etc/lsb-release", "/etc/turbolinux-release", "/etc/gentoo-release", @@ -2104,6 +2103,7 @@ const char* distro_files[] = { "/etc/angstrom-version", "/etc/system-release", "/etc/os-release", + "/etc/SuSE-release", // Deprecated in favor of os-release since SuSE 12 nullptr }; void os::Linux::print_distro_info(outputStream* st) { @@ -2215,6 +2215,8 @@ void os::Linux::print_system_memory_info(outputStream* st) { // https://www.kernel.org/doc/Documentation/vm/transhuge.txt _print_ascii_file_h("/sys/kernel/mm/transparent_hugepage/enabled", "/sys/kernel/mm/transparent_hugepage/enabled", st); + _print_ascii_file_h("/sys/kernel/mm/transparent_hugepage/hpage_pmd_size", + "/sys/kernel/mm/transparent_hugepage/hpage_pmd_size", st); _print_ascii_file_h("/sys/kernel/mm/transparent_hugepage/shmem_enabled", "/sys/kernel/mm/transparent_hugepage/shmem_enabled", st); _print_ascii_file_h("/sys/kernel/mm/transparent_hugepage/defrag (defrag/compaction efforts parameter)", @@ -2753,6 +2755,8 @@ void os::jvm_path(char *buf, jint buflen) { void linux_wrap_code(char* base, size_t size) { static volatile jint cnt = 0; + static_assert(sizeof(off_t) == 8, "Expected Large File Support in this file"); + if (!UseOprofile) { return; } @@ -4247,7 +4251,7 @@ jlong os::Linux::fast_thread_cpu_time(clockid_t clockid) { // the number of bytes written to out_fd is returned if transfer was successful // otherwise, returns -1 that implies an error jlong os::Linux::sendfile(int out_fd, int in_fd, jlong* offset, jlong count) { - return ::sendfile64(out_fd, in_fd, (off64_t*)offset, (size_t)count); + return ::sendfile(out_fd, in_fd, (off_t*)offset, (size_t)count); } // Determine if the vmid is the parent pid for a child in a PID namespace. @@ -4925,14 +4929,14 @@ int os::open(const char *path, int oflag, int mode) { oflag |= O_CLOEXEC; #endif - int fd = ::open64(path, oflag, mode); + int fd = ::open(path, oflag, mode); if (fd == -1) return -1; //If the open succeeded, the file might still be a directory { - struct stat64 buf64; - int ret = ::fstat64(fd, &buf64); - int st_mode = buf64.st_mode; + struct stat buf; + int ret = ::fstat(fd, &buf); + int st_mode = buf.st_mode; if (ret != -1) { if ((st_mode & S_IFMT) == S_IFDIR) { @@ -4969,17 +4973,17 @@ int os::open(const char *path, int oflag, int mode) { int os::create_binary_file(const char* path, bool rewrite_existing) { int oflags = O_WRONLY | O_CREAT; oflags |= rewrite_existing ? O_TRUNC : O_EXCL; - return ::open64(path, oflags, S_IREAD | S_IWRITE); + return ::open(path, oflags, S_IREAD | S_IWRITE); } // return current position of file pointer jlong os::current_file_offset(int fd) { - return (jlong)::lseek64(fd, (off64_t)0, SEEK_CUR); + return (jlong)::lseek(fd, (off_t)0, SEEK_CUR); } // move file pointer to the specified offset jlong os::seek_to_file_offset(int fd, jlong offset) { - return (jlong)::lseek64(fd, (off64_t)offset, SEEK_SET); + return (jlong)::lseek(fd, (off_t)offset, SEEK_SET); } // Map a block of memory. @@ -5468,3 +5472,25 @@ bool os::trim_native_heap(os::size_change_t* rss_change) { return false; // musl #endif } + +bool os::pd_dll_unload(void* libhandle, char* ebuf, int ebuflen) { + + if (ebuf && ebuflen > 0) { + ebuf[0] = '\0'; + ebuf[ebuflen - 1] = '\0'; + } + + bool res = (0 == ::dlclose(libhandle)); + if (!res) { + // error analysis when dlopen fails + const char* error_report = ::dlerror(); + if (error_report == nullptr) { + error_report = "dlerror returned no error description"; + } + if (ebuf != nullptr && ebuflen > 0) { + snprintf(ebuf, ebuflen - 1, "%s", error_report); + } + } + + return res; +} // end: os::pd_dll_unload() diff --git a/src/hotspot/os/posix/os_posix.cpp b/src/hotspot/os/posix/os_posix.cpp index 960fb465590..926045df259 100644 --- a/src/hotspot/os/posix/os_posix.cpp +++ b/src/hotspot/os/posix/os_posix.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -56,6 +56,7 @@ #ifdef AIX #include "loadlib_aix.hpp" +#include "os_aix.hpp" #endif #ifdef LINUX #include "os_linux.hpp" @@ -286,6 +287,7 @@ static char* reserve_mmapped_memory(size_t bytes, char* requested_addr) { } static int util_posix_fallocate(int fd, off_t offset, off_t len) { + static_assert(sizeof(off_t) == 8, "Expected Large File Support in this file"); #ifdef __APPLE__ fstore_t store = { F_ALLOCATECONTIG, F_PEOFPOSMODE, 0, len }; // First we try to get a continuous chunk of disk space @@ -731,36 +733,31 @@ void os::dll_unload(void *lib) { if (l_path == nullptr) { l_path = ""; } - int res = ::dlclose(lib); - if (res == 0) { + char ebuf[1024]; + bool res = os::pd_dll_unload(lib, ebuf, sizeof(ebuf)); + + if (res) { Events::log_dll_message(nullptr, "Unloaded shared library \"%s\" [" INTPTR_FORMAT "]", l_path, p2i(lib)); log_info(os)("Unloaded shared library \"%s\" [" INTPTR_FORMAT "]", l_path, p2i(lib)); JFR_ONLY(unload_event.set_result(true);) } else { - const char* error_report = ::dlerror(); - if (error_report == nullptr) { - error_report = "dlerror returned no error description"; - } - Events::log_dll_message(nullptr, "Attempt to unload shared library \"%s\" [" INTPTR_FORMAT "] failed, %s", - l_path, p2i(lib), error_report); + l_path, p2i(lib), ebuf); log_info(os)("Attempt to unload shared library \"%s\" [" INTPTR_FORMAT "] failed, %s", - l_path, p2i(lib), error_report); - JFR_ONLY(unload_event.set_error_msg(error_report);) + l_path, p2i(lib), ebuf); + JFR_ONLY(unload_event.set_error_msg(ebuf);) } - // Update the dll cache - AIX_ONLY(LoadedLibraries::reload()); LINUX_ONLY(os::free(l_pathdup)); } jlong os::lseek(int fd, jlong offset, int whence) { - return (jlong) BSD_ONLY(::lseek) NOT_BSD(::lseek64)(fd, offset, whence); + return (jlong) AIX_ONLY(::lseek64) NOT_AIX(::lseek)(fd, offset, whence); } int os::ftruncate(int fd, jlong length) { - return BSD_ONLY(::ftruncate) NOT_BSD(::ftruncate64)(fd, length); + return AIX_ONLY(::ftruncate64) NOT_AIX(::ftruncate)(fd, length); } const char* os::get_current_directory(char *buf, size_t buflen) { diff --git a/src/hotspot/os/posix/os_posix.hpp b/src/hotspot/os/posix/os_posix.hpp index 8c71516f70b..d872a6dae89 100644 --- a/src/hotspot/os/posix/os_posix.hpp +++ b/src/hotspot/os/posix/os_posix.hpp @@ -31,7 +31,7 @@ // Note: the Posix API aims to capture functionality available on all Posix // compliant platforms, but in practice the implementations may depend on -// non-Posix functionality. For example, the use of lseek64 and ftruncate64. +// non-Posix functionality. // This use of non-Posix API's is made possible by compiling/linking in a mode // that is not restricted to being fully Posix complaint, such as by declaring // -D_GNU_SOURCE. But be aware that in doing so we may enable non-Posix diff --git a/src/hotspot/os_cpu/linux_riscv/os_linux_riscv.cpp b/src/hotspot/os_cpu/linux_riscv/os_linux_riscv.cpp index 8b9d1178ca5..282467bc9e0 100644 --- a/src/hotspot/os_cpu/linux_riscv/os_linux_riscv.cpp +++ b/src/hotspot/os_cpu/linux_riscv/os_linux_riscv.cpp @@ -232,7 +232,7 @@ bool PosixSignals::pd_hotspot_signal_handler(int sig, siginfo_t* info, CompiledMethod* nm = (cb != nullptr) ? cb->as_compiled_method_or_null() : nullptr; bool is_unsafe_arraycopy = (thread->doing_unsafe_access() && UnsafeCopyMemory::contains_pc(pc)); if ((nm != nullptr && nm->has_unsafe_access()) || is_unsafe_arraycopy) { - address next_pc = pc + NativeCall::instruction_size; + address next_pc = Assembler::locate_next_instruction(pc); if (is_unsafe_arraycopy) { next_pc = UnsafeCopyMemory::page_error_continue_pc(pc); } @@ -271,7 +271,7 @@ bool PosixSignals::pd_hotspot_signal_handler(int sig, siginfo_t* info, thread->thread_state() == _thread_in_native) && sig == SIGBUS && /* info->si_code == BUS_OBJERR && */ thread->doing_unsafe_access()) { - address next_pc = pc + NativeCall::instruction_size; + address next_pc = Assembler::locate_next_instruction(pc); if (UnsafeCopyMemory::contains_pc(pc)) { next_pc = UnsafeCopyMemory::page_error_continue_pc(pc); } diff --git a/src/hotspot/os_cpu/linux_riscv/vm_version_linux_riscv.cpp b/src/hotspot/os_cpu/linux_riscv/vm_version_linux_riscv.cpp index 6e93406b1a3..2e735f623a6 100644 --- a/src/hotspot/os_cpu/linux_riscv/vm_version_linux_riscv.cpp +++ b/src/hotspot/os_cpu/linux_riscv/vm_version_linux_riscv.cpp @@ -169,13 +169,13 @@ void VM_Version::os_aux_features() { } VM_Version::VM_MODE VM_Version::parse_satp_mode(const char* vm_mode) { - if (!strcmp(vm_mode, "sv39")) { + if (!strncmp(vm_mode, "sv39", sizeof "sv39" - 1)) { return VM_SV39; - } else if (!strcmp(vm_mode, "sv48")) { + } else if (!strncmp(vm_mode, "sv48", sizeof "sv48" - 1)) { return VM_SV48; - } else if (!strcmp(vm_mode, "sv57")) { + } else if (!strncmp(vm_mode, "sv57", sizeof "sv57" - 1)) { return VM_SV57; - } else if (!strcmp(vm_mode, "sv64")) { + } else if (!strncmp(vm_mode, "sv64", sizeof "sv64" - 1)) { return VM_SV64; } else { return VM_MBARE; @@ -197,7 +197,7 @@ char* VM_Version::os_uarch_additional_features() { if ((p = strchr(buf, ':')) != nullptr) { if (mode == VM_NOTSET) { if (strncmp(buf, "mmu", sizeof "mmu" - 1) == 0) { - mode = VM_Version::parse_satp_mode(p); + mode = VM_Version::parse_satp_mode(p + 2); } } if (ret == nullptr) { diff --git a/src/hotspot/share/c1/c1_FrameMap.cpp b/src/hotspot/share/c1/c1_FrameMap.cpp index c55e41f4583..ace4fe8209d 100644 --- a/src/hotspot/share/c1/c1_FrameMap.cpp +++ b/src/hotspot/share/c1/c1_FrameMap.cpp @@ -72,7 +72,7 @@ CallingConvention* FrameMap::java_calling_convention(const BasicTypeArray* signa } } - intptr_t out_preserve = SharedRuntime::java_calling_convention(sig_bt, regs, sizeargs); + intptr_t out_preserve = align_up(SharedRuntime::java_calling_convention(sig_bt, regs, sizeargs), 2); LIR_OprList* args = new LIR_OprList(signature->length()); for (i = 0; i < sizeargs;) { BasicType t = sig_bt[i]; diff --git a/src/hotspot/share/c1/c1_RangeCheckElimination.cpp b/src/hotspot/share/c1/c1_RangeCheckElimination.cpp index 4af9f29f263..256f8190b50 100644 --- a/src/hotspot/share/c1/c1_RangeCheckElimination.cpp +++ b/src/hotspot/share/c1/c1_RangeCheckElimination.cpp @@ -421,8 +421,11 @@ void RangeCheckEliminator::add_access_indexed_info(InstructionList &indices, int aii->_max = idx; aii->_list = new AccessIndexedList(); } else if (idx >= aii->_min && idx <= aii->_max) { - remove_range_check(ai); - return; + // Guard against underflow/overflow (see 'range_cond' check in RangeCheckEliminator::in_block_motion) + if (aii->_max < 0 || (aii->_max + min_jint) <= aii->_min) { + remove_range_check(ai); + return; + } } aii->_min = MIN2(aii->_min, idx); aii->_max = MAX2(aii->_max, idx); @@ -465,9 +468,9 @@ void RangeCheckEliminator::in_block_motion(BlockBegin *block, AccessIndexedList } } } else { - int last_integer = 0; + jint last_integer = 0; Instruction *last_instruction = index; - int base = 0; + jint base = 0; ArithmeticOp *ao = index->as_ArithmeticOp(); while (ao != nullptr && (ao->x()->as_Constant() || ao->y()->as_Constant()) && (ao->op() == Bytecodes::_iadd || ao->op() == Bytecodes::_isub)) { @@ -479,12 +482,12 @@ void RangeCheckEliminator::in_block_motion(BlockBegin *block, AccessIndexedList } if (c) { - int value = c->type()->as_IntConstant()->value(); + jint value = c->type()->as_IntConstant()->value(); if (value != min_jint) { if (ao->op() == Bytecodes::_isub) { value = -value; } - base += value; + base = java_add(base, value); last_integer = base; last_instruction = other; } @@ -506,12 +509,12 @@ void RangeCheckEliminator::in_block_motion(BlockBegin *block, AccessIndexedList assert(info != nullptr, "Info must not be null"); // if idx < 0, max > 0, max + idx may fall between 0 and - // length-1 and if min < 0, min + idx may overflow and be >= + // length-1 and if min < 0, min + idx may underflow/overflow and be >= // 0. The predicate wouldn't trigger but some accesses could // be with a negative index. This test guarantees that for the // min and max value that are kept the predicate can't let // some incorrect accesses happen. - bool range_cond = (info->_max < 0 || info->_max + min_jint <= info->_min); + bool range_cond = (info->_max < 0 || (info->_max + min_jint) <= info->_min); // Generate code only if more than 2 range checks can be eliminated because of that. // 2 because at least 2 comparisons are done @@ -859,7 +862,7 @@ void RangeCheckEliminator::process_access_indexed(BlockBegin *loop_header, Block ); remove_range_check(ai); - } else if (_optimistic && loop_header) { + } else if (false && _optimistic && loop_header) { assert(ai->array(), "Array must not be null!"); assert(ai->index(), "Index must not be null!"); diff --git a/src/hotspot/share/cds/filemap.cpp b/src/hotspot/share/cds/filemap.cpp index 99acbb4ace8..e7225cb977b 100644 --- a/src/hotspot/share/cds/filemap.cpp +++ b/src/hotspot/share/cds/filemap.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, 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 @@ -576,12 +576,14 @@ int FileMapInfo::get_module_shared_path_index(Symbol* location) { const char* file = ClassLoader::skip_uri_protocol(location->as_C_string()); for (int i = ClassLoaderExt::app_module_paths_start_index(); i < get_number_of_shared_paths(); i++) { SharedClassPathEntry* ent = shared_path(i); - assert(ent->in_named_module(), "must be"); - bool cond = strcmp(file, ent->name()) == 0; - log_debug(class, path)("get_module_shared_path_index (%d) %s : %s = %s", i, - location->as_C_string(), ent->name(), cond ? "same" : "different"); - if (cond) { - return i; + if (!ent->is_non_existent()) { + assert(ent->in_named_module(), "must be"); + bool cond = strcmp(file, ent->name()) == 0; + log_debug(class, path)("get_module_shared_path_index (%d) %s : %s = %s", i, + location->as_C_string(), ent->name(), cond ? "same" : "different"); + if (cond) { + return i; + } } } diff --git a/src/hotspot/share/cds/filemap.hpp b/src/hotspot/share/cds/filemap.hpp index 7ad7b62b760..51de517e50c 100644 --- a/src/hotspot/share/cds/filemap.hpp +++ b/src/hotspot/share/cds/filemap.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, 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 @@ -89,6 +89,7 @@ class SharedClassPathEntry : public MetaspaceObj { bool is_dir() const { return _type == dir_entry; } bool is_modules_image() const { return _type == modules_image_entry; } bool is_jar() const { return _type == jar_entry; } + bool is_non_existent() const { return _type == non_existent_entry; } bool from_class_path_attr() { return _from_class_path_attr; } time_t timestamp() const { return _timestamp; } const char* name() const; diff --git a/src/hotspot/share/classfile/javaClasses.cpp b/src/hotspot/share/classfile/javaClasses.cpp index d65c8b2b79e..9432cc1bc4c 100644 --- a/src/hotspot/share/classfile/javaClasses.cpp +++ b/src/hotspot/share/classfile/javaClasses.cpp @@ -2076,18 +2076,17 @@ oop java_lang_Throwable::message(oop throwable) { return throwable->obj_field(_detailMessage_offset); } -oop java_lang_Throwable::cause(oop throwable) { - return throwable->obj_field(_cause_offset); +const char* java_lang_Throwable::message_as_utf8(oop throwable) { + oop msg = java_lang_Throwable::message(throwable); + const char* msg_utf8 = nullptr; + if (msg != nullptr) { + msg_utf8 = java_lang_String::as_utf8_string(msg); + } + return msg_utf8; } -// Return Symbol for detailed_message or null -Symbol* java_lang_Throwable::detail_message(oop throwable) { - PreserveExceptionMark pm(Thread::current()); - oop detailed_message = java_lang_Throwable::message(throwable); - if (detailed_message != nullptr) { - return java_lang_String::as_symbol(detailed_message); - } - return nullptr; +oop java_lang_Throwable::cause(oop throwable) { + return throwable->obj_field(_cause_offset); } void java_lang_Throwable::set_message(oop throwable, oop value) { diff --git a/src/hotspot/share/classfile/javaClasses.hpp b/src/hotspot/share/classfile/javaClasses.hpp index 23409f82470..b8933d72b7e 100644 --- a/src/hotspot/share/classfile/javaClasses.hpp +++ b/src/hotspot/share/classfile/javaClasses.hpp @@ -595,12 +595,14 @@ class java_lang_Throwable: AllStatic { static void set_backtrace(oop throwable, oop value); static int depth(oop throwable); static void set_depth(oop throwable, int value); - static int get_detailMessage_offset() { CHECK_INIT(_detailMessage_offset); } // Message + static int get_detailMessage_offset() { CHECK_INIT(_detailMessage_offset); } static oop message(oop throwable); - static oop cause(oop throwable); + static const char* message_as_utf8(oop throwable); static void set_message(oop throwable, oop value); - static Symbol* detail_message(oop throwable); + + static oop cause(oop throwable); + static void print_stack_element(outputStream *st, Method* method, int bci); static void compute_offsets(); diff --git a/src/hotspot/share/classfile/loaderConstraints.cpp b/src/hotspot/share/classfile/loaderConstraints.cpp index 4206fc10d4f..e6021e00d33 100644 --- a/src/hotspot/share/classfile/loaderConstraints.cpp +++ b/src/hotspot/share/classfile/loaderConstraints.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, 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 @@ -387,7 +387,7 @@ bool LoaderConstraintTable::add_entry(Symbol* class_name, } else if (pp1 == nullptr) { pp2->extend_loader_constraint(class_name, loader1, klass); } else if (pp2 == nullptr) { - pp1->extend_loader_constraint(class_name, loader1, klass); + pp1->extend_loader_constraint(class_name, loader2, klass); } else { merge_loader_constraints(class_name, pp1, pp2, klass); } diff --git a/src/hotspot/share/classfile/resolutionErrors.cpp b/src/hotspot/share/classfile/resolutionErrors.cpp index dc916eefaf2..cf598df59d7 100644 --- a/src/hotspot/share/classfile/resolutionErrors.cpp +++ b/src/hotspot/share/classfile/resolutionErrors.cpp @@ -66,8 +66,8 @@ void ResolutionErrorTable::initialize() { // create new error entry void ResolutionErrorTable::add_entry(const constantPoolHandle& pool, int cp_index, - Symbol* error, Symbol* message, - Symbol* cause, Symbol* cause_msg) + Symbol* error, const char* message, + Symbol* cause, const char* cause_msg) { assert_locked_or_safepoint(SystemDictionary_lock); assert(!pool.is_null() && error != nullptr, "adding null obj"); @@ -97,26 +97,30 @@ ResolutionErrorEntry* ResolutionErrorTable::find_entry(const constantPoolHandle& return entry == nullptr ? nullptr : *entry; } -ResolutionErrorEntry::ResolutionErrorEntry(Symbol* error, Symbol* message, - Symbol* cause, Symbol* cause_msg): +ResolutionErrorEntry::ResolutionErrorEntry(Symbol* error, const char* message, + Symbol* cause, const char* cause_msg): _error(error), - _message(message), + _message(message != nullptr ? os::strdup(message) : nullptr), _cause(cause), - _cause_msg(cause_msg), + _cause_msg(cause_msg != nullptr ? os::strdup(cause_msg) : nullptr), _nest_host_error(nullptr) { Symbol::maybe_increment_refcount(_error); - Symbol::maybe_increment_refcount(_message); Symbol::maybe_increment_refcount(_cause); - Symbol::maybe_increment_refcount(_cause_msg); } ResolutionErrorEntry::~ResolutionErrorEntry() { // decrement error refcount Symbol::maybe_decrement_refcount(_error); - Symbol::maybe_decrement_refcount(_message); Symbol::maybe_decrement_refcount(_cause); - Symbol::maybe_decrement_refcount(_cause_msg); + + if (_message != nullptr) { + FREE_C_HEAP_ARRAY(char, _message); + } + + if (_cause_msg != nullptr) { + FREE_C_HEAP_ARRAY(char, _cause_msg); + } if (nest_host_error() != nullptr) { FREE_C_HEAP_ARRAY(char, nest_host_error()); diff --git a/src/hotspot/share/classfile/resolutionErrors.hpp b/src/hotspot/share/classfile/resolutionErrors.hpp index 388ab6c4ec6..ad6d793c6c0 100644 --- a/src/hotspot/share/classfile/resolutionErrors.hpp +++ b/src/hotspot/share/classfile/resolutionErrors.hpp @@ -36,10 +36,11 @@ class ResolutionErrorTable : AllStatic { public: static void initialize(); - static void add_entry(const constantPoolHandle& pool, int which, Symbol* error, Symbol* message, - Symbol* cause, Symbol* cause_msg); + static void add_entry(const constantPoolHandle& pool, int cp_index, + Symbol* error, const char* error_msg, + Symbol* cause, const char* cause_msg); - static void add_entry(const constantPoolHandle& pool, int which, const char* message); + static void add_entry(const constantPoolHandle& pool, int cp_index, const char* message); // find error given the constant pool and constant pool index static ResolutionErrorEntry* find_entry(const constantPoolHandle& pool, int cp_index); @@ -68,34 +69,38 @@ class ResolutionErrorTable : AllStatic { class ResolutionErrorEntry : public CHeapObj { private: Symbol* _error; - Symbol* _message; + const char* _message; Symbol* _cause; - Symbol* _cause_msg; + const char* _cause_msg; const char* _nest_host_error; NONCOPYABLE(ResolutionErrorEntry); public: - ResolutionErrorEntry(Symbol* error, Symbol* message, Symbol* cause, Symbol* cause_msg); + // The incoming message and cause_msg are copied to the C-Heap. + ResolutionErrorEntry(Symbol* error, const char* message, + Symbol* cause, const char* cause_msg); - ResolutionErrorEntry(const char* message): + // The incoming nest host error message is already in the C-Heap. + ResolutionErrorEntry(const char* message): _error(nullptr), _message(nullptr), _cause(nullptr), _cause_msg(nullptr), _nest_host_error(message) {} - ~ResolutionErrorEntry(); + ~ResolutionErrorEntry(); - void set_nest_host_error(const char* message) { - _nest_host_error = message; - } + // The incoming nest host error message is already in the C-Heap. + void set_nest_host_error(const char* message) { + _nest_host_error = message; + } Symbol* error() const { return _error; } - Symbol* message() const { return _message; } + const char* message() const { return _message; } Symbol* cause() const { return _cause; } - Symbol* cause_msg() const { return _cause_msg; } + const char* cause_msg() const { return _cause_msg; } const char* nest_host_error() const { return _nest_host_error; } }; diff --git a/src/hotspot/share/classfile/systemDictionary.cpp b/src/hotspot/share/classfile/systemDictionary.cpp index e635c825633..951fefae8e3 100644 --- a/src/hotspot/share/classfile/systemDictionary.cpp +++ b/src/hotspot/share/classfile/systemDictionary.cpp @@ -1111,14 +1111,13 @@ InstanceKlass* SystemDictionary::load_shared_lambda_proxy_class(InstanceKlass* i if (loaded_ik != nullptr) { assert(shared_nest_host->is_same_class_package(ik), "lambda proxy class and its nest host must be in the same package"); + // The lambda proxy class and its nest host have the same class loader and class loader data, + // as verified in SystemDictionaryShared::add_lambda_proxy_class() + assert(shared_nest_host->class_loader() == class_loader(), "mismatched class loader"); + assert(shared_nest_host->class_loader_data() == class_loader_data(class_loader), "mismatched class loader data"); + ik->set_nest_host(shared_nest_host); } - // The lambda proxy class and its nest host have the same class loader and class loader data, - // as verified in SystemDictionaryShared::add_lambda_proxy_class() - assert(shared_nest_host->class_loader() == class_loader(), "mismatched class loader"); - assert(shared_nest_host->class_loader_data() == class_loader_data(class_loader), "mismatched class loader data"); - ik->set_nest_host(shared_nest_host); - return loaded_ik; } @@ -1800,8 +1799,8 @@ bool SystemDictionary::add_loader_constraint(Symbol* class_name, // Add entry to resolution error table to record the error when the first // attempt to resolve a reference to a class has failed. void SystemDictionary::add_resolution_error(const constantPoolHandle& pool, int which, - Symbol* error, Symbol* message, - Symbol* cause, Symbol* cause_msg) { + Symbol* error, const char* message, + Symbol* cause, const char* cause_msg) { { MutexLocker ml(Thread::current(), SystemDictionary_lock); ResolutionErrorEntry* entry = ResolutionErrorTable::find_entry(pool, which); @@ -1818,7 +1817,8 @@ void SystemDictionary::delete_resolution_error(ConstantPool* pool) { // Lookup resolution error table. Returns error if found, otherwise null. Symbol* SystemDictionary::find_resolution_error(const constantPoolHandle& pool, int which, - Symbol** message, Symbol** cause, Symbol** cause_msg) { + const char** message, + Symbol** cause, const char** cause_msg) { { MutexLocker ml(Thread::current(), SystemDictionary_lock); diff --git a/src/hotspot/share/classfile/systemDictionary.hpp b/src/hotspot/share/classfile/systemDictionary.hpp index a65606e8cf6..9f65cb593d3 100644 --- a/src/hotspot/share/classfile/systemDictionary.hpp +++ b/src/hotspot/share/classfile/systemDictionary.hpp @@ -272,12 +272,13 @@ class SystemDictionary : AllStatic { // Record the error when the first attempt to resolve a reference from a constant // pool entry to a class fails. - static void add_resolution_error(const constantPoolHandle& pool, int which, Symbol* error, - Symbol* message, Symbol* cause = nullptr, Symbol* cause_msg = nullptr); + static void add_resolution_error(const constantPoolHandle& pool, int which, + Symbol* error, const char* message, + Symbol* cause = nullptr, const char* cause_msg = nullptr); static void delete_resolution_error(ConstantPool* pool); static Symbol* find_resolution_error(const constantPoolHandle& pool, int which, - Symbol** message, Symbol** cause, Symbol** cause_msg); - + const char** message, + Symbol** cause, const char** cause_msg); // Record a nest host resolution/validation error static void add_nest_host_error(const constantPoolHandle& pool, int which, diff --git a/src/hotspot/share/classfile/verifier.cpp b/src/hotspot/share/classfile/verifier.cpp index 4aa95aff0e1..743bd9d06ba 100644 --- a/src/hotspot/share/classfile/verifier.cpp +++ b/src/hotspot/share/classfile/verifier.cpp @@ -2257,11 +2257,12 @@ void ClassVerifier::verify_switch( "low must be less than or equal to high in tableswitch"); return; } - keys = high - low + 1; - if (keys < 0) { + int64_t keys64 = ((int64_t)high - low) + 1; + if (keys64 > 65535) { // Max code length verify_error(ErrorContext::bad_code(bci), "too many keys in tableswitch"); return; } + keys = (int)keys64; delta = 1; } else { keys = (int)Bytes::get_Java_u4(aligned_bcp + jintSize); diff --git a/src/hotspot/share/classfile/vmIntrinsics.hpp b/src/hotspot/share/classfile/vmIntrinsics.hpp index 8ed99d74c0b..c9bc4acbeff 100644 --- a/src/hotspot/share/classfile/vmIntrinsics.hpp +++ b/src/hotspot/share/classfile/vmIntrinsics.hpp @@ -597,6 +597,7 @@ class methodHandle; do_intrinsic(_notifyJvmtiVThreadMount, java_lang_VirtualThread, notifyJvmtiMount_name, bool_void_signature, F_RN) \ do_intrinsic(_notifyJvmtiVThreadUnmount, java_lang_VirtualThread, notifyJvmtiUnmount_name, bool_void_signature, F_RN) \ do_intrinsic(_notifyJvmtiVThreadHideFrames, java_lang_VirtualThread, notifyJvmtiHideFrames_name, bool_void_signature, F_RN) \ + do_intrinsic(_notifyJvmtiVThreadDisableSuspend, java_lang_VirtualThread, notifyJvmtiDisableSuspend_name, bool_void_signature, F_RN) \ \ /* support for UnsafeConstants */ \ do_class(jdk_internal_misc_UnsafeConstants, "jdk/internal/misc/UnsafeConstants") \ diff --git a/src/hotspot/share/classfile/vmSymbols.hpp b/src/hotspot/share/classfile/vmSymbols.hpp index 16ddc2602b1..fb4b059b5bd 100644 --- a/src/hotspot/share/classfile/vmSymbols.hpp +++ b/src/hotspot/share/classfile/vmSymbols.hpp @@ -421,6 +421,7 @@ class SerializeClosure; template(notifyJvmtiMount_name, "notifyJvmtiMount") \ template(notifyJvmtiUnmount_name, "notifyJvmtiUnmount") \ template(notifyJvmtiHideFrames_name, "notifyJvmtiHideFrames") \ + template(notifyJvmtiDisableSuspend_name, "notifyJvmtiDisableSuspend") \ template(doYield_name, "doYield") \ template(enter_name, "enter") \ template(enterSpecial_name, "enterSpecial") \ diff --git a/src/hotspot/share/code/compiledIC.cpp b/src/hotspot/share/code/compiledIC.cpp index 2127d5e2d26..b966b580984 100644 --- a/src/hotspot/share/code/compiledIC.cpp +++ b/src/hotspot/share/code/compiledIC.cpp @@ -128,11 +128,13 @@ void CompiledIC::internal_set_ic_destination(address entry_point, bool is_icstub tty->cr(); } +#ifdef ASSERT { CodeBlob* cb = CodeCache::find_blob(_call->instruction_address()); assert(cb != nullptr && cb->is_compiled(), "must be compiled"); - _call->set_destination_mt_safe(entry_point); } +#endif + _call->set_destination_mt_safe(entry_point); if (is_optimized() || is_icstub) { // Optimized call sites don't have a cache value and ICStub call diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index 64adc566a24..75582201087 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -3017,7 +3017,7 @@ void nmethod::print_nmethod_labels(outputStream* stream, address block_begin, bo assert(sig_index == sizeargs, ""); } const char* spname = "sp"; // make arch-specific? - intptr_t out_preserve = SharedRuntime::java_calling_convention(sig_bt, regs, sizeargs); + SharedRuntime::java_calling_convention(sig_bt, regs, sizeargs); int stack_slot_offset = this->frame_size() * wordSize; int tab1 = 14, tab2 = 24; int sig_index = 0; diff --git a/src/hotspot/share/compiler/compileBroker.cpp b/src/hotspot/share/compiler/compileBroker.cpp index 9ccbcf9481f..35c18609eb3 100644 --- a/src/hotspot/share/compiler/compileBroker.cpp +++ b/src/hotspot/share/compiler/compileBroker.cpp @@ -841,8 +841,15 @@ void DeoptimizeObjectsALotThread::deoptimize_objects_alot_loop_all() { JavaThread* CompileBroker::make_thread(ThreadType type, jobject thread_handle, CompileQueue* queue, AbstractCompiler* comp, JavaThread* THREAD) { - JavaThread* new_thread = nullptr; + Handle thread_oop(THREAD, JNIHandles::resolve_non_null(thread_handle)); + if (java_lang_Thread::thread(thread_oop()) != nullptr) { + assert(type == compiler_t, "should only happen with reused compiler threads"); + // The compiler thread hasn't actually exited yet so don't try to reuse it + return nullptr; + } + + JavaThread* new_thread = nullptr; switch (type) { case compiler_t: assert(comp != nullptr, "Compiler instance missing."); @@ -871,7 +878,6 @@ JavaThread* CompileBroker::make_thread(ThreadType type, jobject thread_handle, C // JavaThread due to lack of resources. We will handle that failure below. // Also check new_thread so that static analysis is happy. if (new_thread != nullptr && new_thread->osthread() != nullptr) { - Handle thread_oop(THREAD, JNIHandles::resolve_non_null(thread_handle)); if (type == compiler_t) { CompilerThread::cast(new_thread)->set_compiler(comp); diff --git a/src/hotspot/share/gc/g1/g1YoungCollector.cpp b/src/hotspot/share/gc/g1/g1YoungCollector.cpp index ec32f8b589b..b52bfdfbb08 100644 --- a/src/hotspot/share/gc/g1/g1YoungCollector.cpp +++ b/src/hotspot/share/gc/g1/g1YoungCollector.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024, 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 @@ -403,7 +403,7 @@ class G1PrepareEvacuationTask : public WorkerTask { _g1h->register_region_with_region_attr(hr); } log_debug(gc, humongous)("Humongous region %u (object size %zu @ " PTR_FORMAT ") remset %zu code roots %zu " - "marked %d pinned count %u reclaim candidate %d type array %d", + "marked %d pinned count %zu reclaim candidate %d type array %d", index, cast_to_oop(hr->bottom())->size() * HeapWordSize, p2i(hr->bottom()), diff --git a/src/hotspot/share/gc/g1/heapRegion.cpp b/src/hotspot/share/gc/g1/heapRegion.cpp index 29fe5031a35..69040028d98 100644 --- a/src/hotspot/share/gc/g1/heapRegion.cpp +++ b/src/hotspot/share/gc/g1/heapRegion.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2024, 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 @@ -424,7 +424,7 @@ void HeapRegion::print_on(outputStream* st) const { st->print("|-"); } } - st->print("|%3u", Atomic::load(&_pinned_object_count)); + st->print("|%3zu", Atomic::load(&_pinned_object_count)); st->print_cr(""); } diff --git a/src/hotspot/share/gc/g1/heapRegion.hpp b/src/hotspot/share/gc/g1/heapRegion.hpp index 2706b814000..725433215c4 100644 --- a/src/hotspot/share/gc/g1/heapRegion.hpp +++ b/src/hotspot/share/gc/g1/heapRegion.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2024, 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 @@ -257,7 +257,7 @@ class HeapRegion : public CHeapObj { uint _node_index; // Number of objects in this region that are currently pinned. - volatile uint _pinned_object_count; + volatile size_t _pinned_object_count; void report_region_type_change(G1HeapRegionTraceType::Type to); @@ -408,7 +408,7 @@ class HeapRegion : public CHeapObj { bool is_old_or_humongous() const { return _type.is_old_or_humongous(); } - uint pinned_count() const { return Atomic::load(&_pinned_object_count); } + size_t pinned_count() const { return Atomic::load(&_pinned_object_count); } bool has_pinned_objects() const { return pinned_count() > 0; } void set_free(); diff --git a/src/hotspot/share/gc/g1/heapRegion.inline.hpp b/src/hotspot/share/gc/g1/heapRegion.inline.hpp index ec68407b546..4a42b922182 100644 --- a/src/hotspot/share/gc/g1/heapRegion.inline.hpp +++ b/src/hotspot/share/gc/g1/heapRegion.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2024, 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 @@ -554,11 +554,11 @@ inline void HeapRegion::record_surv_words_in_group(size_t words_survived) { } inline void HeapRegion::increment_pinned_object_count() { - Atomic::add(&_pinned_object_count, 1u, memory_order_relaxed); + Atomic::add(&_pinned_object_count, (size_t)1, memory_order_relaxed); } inline void HeapRegion::decrement_pinned_object_count() { - Atomic::sub(&_pinned_object_count, 1u, memory_order_relaxed); + Atomic::sub(&_pinned_object_count, (size_t)1, memory_order_relaxed); } #endif // SHARE_GC_G1_HEAPREGION_INLINE_HPP diff --git a/src/hotspot/share/gc/g1/vmStructs_g1.hpp b/src/hotspot/share/gc/g1/vmStructs_g1.hpp index 94ade0f387c..9ce61531989 100644 --- a/src/hotspot/share/gc/g1/vmStructs_g1.hpp +++ b/src/hotspot/share/gc/g1/vmStructs_g1.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2024, 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,7 +41,7 @@ nonstatic_field(HeapRegion, _bottom, HeapWord* const) \ nonstatic_field(HeapRegion, _top, HeapWord* volatile) \ nonstatic_field(HeapRegion, _end, HeapWord* const) \ - nonstatic_field(HeapRegion, _pinned_object_count, volatile uint) \ + volatile_nonstatic_field(HeapRegion, _pinned_object_count, size_t) \ \ nonstatic_field(HeapRegionType, _tag, HeapRegionType::Tag volatile) \ \ diff --git a/src/hotspot/share/gc/shared/workerThread.cpp b/src/hotspot/share/gc/shared/workerThread.cpp index b64c5050a22..49e43c284fa 100644 --- a/src/hotspot/share/gc/shared/workerThread.cpp +++ b/src/hotspot/share/gc/shared/workerThread.cpp @@ -31,6 +31,7 @@ #include "runtime/init.hpp" #include "runtime/java.hpp" #include "runtime/os.hpp" +#include "runtime/safepoint.hpp" WorkerTaskDispatcher::WorkerTaskDispatcher() : _task(nullptr), @@ -141,40 +142,44 @@ void WorkerThreads::threads_do(ThreadClosure* tc) const { } } -void WorkerThreads::set_indirectly_suspendible_threads() { +template +void WorkerThreads::threads_do_f(Function function) const { + for (uint i = 0; i < _created_workers; i++) { + function(_workers[i]); + } +} + +void WorkerThreads::set_indirect_states() { #ifdef ASSERT - class SetIndirectlySuspendibleThreadClosure : public ThreadClosure { - virtual void do_thread(Thread* thread) { + const bool is_suspendible = Thread::current()->is_suspendible_thread(); + const bool is_safepointed = Thread::current()->is_VM_thread() && SafepointSynchronize::is_at_safepoint(); + + threads_do_f([&](Thread* thread) { + assert(!thread->is_indirectly_suspendible_thread(), "Unexpected"); + assert(!thread->is_indirectly_safepoint_thread(), "Unexpected"); + if (is_suspendible) { thread->set_indirectly_suspendible_thread(); } - }; - - if (Thread::current()->is_suspendible_thread()) { - SetIndirectlySuspendibleThreadClosure cl; - threads_do(&cl); - } + if (is_safepointed) { + thread->set_indirectly_safepoint_thread(); + } + }); #endif } -void WorkerThreads::clear_indirectly_suspendible_threads() { +void WorkerThreads::clear_indirect_states() { #ifdef ASSERT - class ClearIndirectlySuspendibleThreadClosure : public ThreadClosure { - virtual void do_thread(Thread* thread) { - thread->clear_indirectly_suspendible_thread(); - } - }; - - if (Thread::current()->is_suspendible_thread()) { - ClearIndirectlySuspendibleThreadClosure cl; - threads_do(&cl); - } + threads_do_f([&](Thread* thread) { + thread->clear_indirectly_suspendible_thread(); + thread->clear_indirectly_safepoint_thread(); + }); #endif } void WorkerThreads::run_task(WorkerTask* task) { - set_indirectly_suspendible_threads(); + set_indirect_states(); _dispatcher.coordinator_distribute_task(task, _active_workers); - clear_indirectly_suspendible_threads(); + clear_indirect_states(); } void WorkerThreads::run_task(WorkerTask* task, uint num_workers) { diff --git a/src/hotspot/share/gc/shared/workerThread.hpp b/src/hotspot/share/gc/shared/workerThread.hpp index 39687e2581c..642c8d93f59 100644 --- a/src/hotspot/share/gc/shared/workerThread.hpp +++ b/src/hotspot/share/gc/shared/workerThread.hpp @@ -93,8 +93,8 @@ class WorkerThreads : public CHeapObj { WorkerThread* create_worker(uint name_suffix); - void set_indirectly_suspendible_threads(); - void clear_indirectly_suspendible_threads(); + void set_indirect_states(); + void clear_indirect_states(); protected: virtual void on_create_worker(WorkerThread* worker) {} @@ -111,6 +111,8 @@ class WorkerThreads : public CHeapObj { uint set_active_workers(uint num_workers); void threads_do(ThreadClosure* tc) const; + template + void threads_do_f(Function function) const; const char* name() const { return _name; } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahDegeneratedGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahDegeneratedGC.cpp index d8398bb1ed8..e7cf402a527 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahDegeneratedGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahDegeneratedGC.cpp @@ -131,6 +131,27 @@ void ShenandoahDegenGC::op_degenerated() { // and we can do evacuation. Otherwise, it would be the shortcut cycle. if (heap->is_evacuation_in_progress()) { + if (_degen_point == _degenerated_evac) { + // Degeneration under oom-evac protocol allows the mutator LRB to expose + // references to from-space objects. This is okay, in theory, because we + // will come to the safepoint here to complete the evacuations and update + // the references. However, if the from-space reference is written to a + // region that was EC during final mark or was recycled after final mark + // it will not have TAMS or UWM updated. Such a region is effectively + // skipped during update references which can lead to crashes and corruption + // if the from-space reference is accessed. + if (UseTLAB) { + heap->labs_make_parsable(); + } + + for (size_t i = 0; i < heap->num_regions(); i++) { + ShenandoahHeapRegion* r = heap->get_region(i); + if (r->is_active() && r->top() > r->get_update_watermark()) { + r->set_update_watermark_at_safepoint(r->top()); + } + } + } + // Degeneration under oom-evac protocol might have left some objects in // collection set un-evacuated. Restart evacuation from the beginning to // capture all objects. For all the objects that are already evacuated, diff --git a/src/hotspot/share/gc/shenandoah/shenandoahFullGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahFullGC.cpp index 18fd09ead0a..4cef5378d30 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahFullGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahFullGC.cpp @@ -910,6 +910,9 @@ class ShenandoahPostCompactClosure : public ShenandoahHeapRegionClosure { // Make empty regions that have been allocated into regular if (r->is_empty() && live > 0) { r->make_regular_bypass(); + if (ZapUnusedHeapArea) { + SpaceMangler::mangle_region(MemRegion(r->top(), r->end())); + } } // Reclaim regular regions that became empty diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp index 67d7f0eb4fa..d6b724a836d 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp @@ -504,6 +504,7 @@ ShenandoahHeap::ShenandoahHeap(ShenandoahCollectorPolicy* policy) : _num_regions(0), _regions(nullptr), _update_refs_iterator(this), + _gc_state_changed(false), _gc_no_progress_count(0), _control_thread(nullptr), _shenandoah_policy(policy), @@ -1741,16 +1742,21 @@ void ShenandoahHeap::prepare_update_heap_references(bool concurrent) { _update_refs_iterator.reset(); } -void ShenandoahHeap::set_gc_state_all_threads(char state) { - for (JavaThreadIteratorWithHandle jtiwh; JavaThread *t = jtiwh.next(); ) { - ShenandoahThreadLocalData::set_gc_state(t, state); +void ShenandoahHeap::set_gc_state_all_threads() { + assert(ShenandoahSafepoint::is_at_shenandoah_safepoint(), "Must be at Shenandoah safepoint"); + if (_gc_state_changed) { + _gc_state_changed = false; + char state = gc_state(); + for (JavaThreadIteratorWithHandle jtiwh; JavaThread *t = jtiwh.next(); ) { + ShenandoahThreadLocalData::set_gc_state(t, state); + } } } void ShenandoahHeap::set_gc_state_mask(uint mask, bool value) { - assert(ShenandoahSafepoint::is_at_shenandoah_safepoint(), "Should really be Shenandoah safepoint"); + assert(ShenandoahSafepoint::is_at_shenandoah_safepoint(), "Must be at Shenandoah safepoint"); _gc_state.set_cond(mask, value); - set_gc_state_all_threads(_gc_state.raw_value()); + _gc_state_changed = true; } void ShenandoahHeap::set_concurrent_mark_in_progress(bool in_progress) { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp index f5030efa748..1873ee040e3 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp @@ -124,6 +124,7 @@ class ShenandoahHeap : public CollectedHeap, public ShenandoahSpaceInfo { friend class ShenandoahGCStateResetter; friend class ShenandoahParallelObjectIterator; friend class ShenandoahSafepoint; + // Supported GC friend class ShenandoahConcurrentGC; friend class ShenandoahDegenGC; @@ -283,6 +284,7 @@ class ShenandoahHeap : public CollectedHeap, public ShenandoahSpaceInfo { }; private: + bool _gc_state_changed; ShenandoahSharedBitmap _gc_state; ShenandoahSharedFlag _degenerated_gc_in_progress; ShenandoahSharedFlag _full_gc_in_progress; @@ -291,11 +293,12 @@ class ShenandoahHeap : public CollectedHeap, public ShenandoahSpaceInfo { size_t _gc_no_progress_count; - void set_gc_state_all_threads(char state); void set_gc_state_mask(uint mask, bool value); public: char gc_state() const; + void set_gc_state_all_threads(); + bool has_gc_state_changed() { return _gc_state_changed; } void set_concurrent_mark_in_progress(bool in_progress); void set_evacuation_in_progress(bool in_progress); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahReferenceProcessor.cpp b/src/hotspot/share/gc/shenandoah/shenandoahReferenceProcessor.cpp index f99de804bd5..f395119d46a 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahReferenceProcessor.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahReferenceProcessor.cpp @@ -362,7 +362,7 @@ bool ShenandoahReferenceProcessor::discover_reference(oop reference, ReferenceTy log_trace(gc, ref)("Encountered Reference: " PTR_FORMAT " (%s)", p2i(reference), reference_type_name(type)); uint worker_id = WorkerThread::worker_id(); - _ref_proc_thread_locals->inc_encountered(type); + _ref_proc_thread_locals[worker_id].inc_encountered(type); if (UseCompressedOops) { return discover(reference, type, worker_id); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahVMOperations.cpp b/src/hotspot/share/gc/shenandoah/shenandoahVMOperations.cpp index 4a97e599f3e..970f99ad0f5 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahVMOperations.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahVMOperations.cpp @@ -35,12 +35,23 @@ #include "interpreter/oopMapCache.hpp" #include "memory/universe.hpp" +bool VM_ShenandoahOperation::doit_prologue() { + assert(!ShenandoahHeap::heap()->has_gc_state_changed(), "GC State can only be changed on a safepoint."); + return true; +} + +void VM_ShenandoahOperation::doit_epilogue() { + assert(!ShenandoahHeap::heap()->has_gc_state_changed(), "GC State was not synchronized to java threads."); +} + bool VM_ShenandoahReferenceOperation::doit_prologue() { + VM_ShenandoahOperation::doit_prologue(); Heap_lock->lock(); return true; } void VM_ShenandoahReferenceOperation::doit_epilogue() { + VM_ShenandoahOperation::doit_epilogue(); OopMapCache::cleanup_old_entries(); if (Universe::has_reference_pending_list()) { Heap_lock->notify_all(); @@ -51,34 +62,41 @@ void VM_ShenandoahReferenceOperation::doit_epilogue() { void VM_ShenandoahInitMark::doit() { ShenandoahGCPauseMark mark(_gc_id, "Init Mark", SvcGCMarker::CONCURRENT); _gc->entry_init_mark(); + ShenandoahHeap::heap()->set_gc_state_all_threads(); } void VM_ShenandoahFinalMarkStartEvac::doit() { ShenandoahGCPauseMark mark(_gc_id, "Final Mark", SvcGCMarker::CONCURRENT); _gc->entry_final_mark(); + ShenandoahHeap::heap()->set_gc_state_all_threads(); } void VM_ShenandoahFullGC::doit() { ShenandoahGCPauseMark mark(_gc_id, "Full GC", SvcGCMarker::FULL); _full_gc->entry_full(_gc_cause); + ShenandoahHeap::heap()->set_gc_state_all_threads(); } void VM_ShenandoahDegeneratedGC::doit() { ShenandoahGCPauseMark mark(_gc_id, "Degenerated GC", SvcGCMarker::CONCURRENT); _gc->entry_degenerated(); + ShenandoahHeap::heap()->set_gc_state_all_threads(); } void VM_ShenandoahInitUpdateRefs::doit() { ShenandoahGCPauseMark mark(_gc_id, "Init Update Refs", SvcGCMarker::CONCURRENT); _gc->entry_init_updaterefs(); + ShenandoahHeap::heap()->set_gc_state_all_threads(); } void VM_ShenandoahFinalUpdateRefs::doit() { ShenandoahGCPauseMark mark(_gc_id, "Final Update Refs", SvcGCMarker::CONCURRENT); _gc->entry_final_updaterefs(); + ShenandoahHeap::heap()->set_gc_state_all_threads(); } void VM_ShenandoahFinalRoots::doit() { ShenandoahGCPauseMark mark(_gc_id, "Final Roots", SvcGCMarker::CONCURRENT); _gc->entry_final_roots(); + ShenandoahHeap::heap()->set_gc_state_all_threads(); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahVMOperations.hpp b/src/hotspot/share/gc/shenandoah/shenandoahVMOperations.hpp index 65ddd8b1f11..1b78766935f 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahVMOperations.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahVMOperations.hpp @@ -47,14 +47,16 @@ class VM_ShenandoahOperation : public VM_Operation { uint _gc_id; public: VM_ShenandoahOperation() : _gc_id(GCId::current()) {}; - virtual bool skip_thread_oop_barriers() const { return true; } + bool skip_thread_oop_barriers() const override { return true; } + bool doit_prologue() override; + void doit_epilogue() override; }; class VM_ShenandoahReferenceOperation : public VM_ShenandoahOperation { public: VM_ShenandoahReferenceOperation() : VM_ShenandoahOperation() {}; - bool doit_prologue(); - void doit_epilogue(); + bool doit_prologue() override; + void doit_epilogue() override; }; class VM_ShenandoahInitMark: public VM_ShenandoahOperation { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp b/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp index 1d5d962a4ec..6a977c2e4a4 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp @@ -620,6 +620,8 @@ void ShenandoahVerifier::verify_at_safepoint(const char *label, guarantee(ShenandoahSafepoint::is_at_shenandoah_safepoint(), "only when nothing else happens"); guarantee(ShenandoahVerify, "only when enabled, and bitmap is initialized in ShenandoahHeap::initialize"); + ShenandoahHeap::heap()->set_gc_state_all_threads(); + // Avoid side-effect of changing workers' active thread count, but bypass concurrent/parallel protocol check ShenandoahPushWorkerScope verify_worker_scope(_heap->workers(), _heap->max_workers(), false /*bypass check*/); diff --git a/src/hotspot/share/gc/z/zBarrier.inline.hpp b/src/hotspot/share/gc/z/zBarrier.inline.hpp index e0d83619934..2c81c14865b 100644 --- a/src/hotspot/share/gc/z/zBarrier.inline.hpp +++ b/src/hotspot/share/gc/z/zBarrier.inline.hpp @@ -26,14 +26,13 @@ #include "gc/z/zBarrier.hpp" -#include "code/codeCache.hpp" #include "gc/z/zAddress.inline.hpp" #include "gc/z/zGeneration.inline.hpp" #include "gc/z/zHeap.inline.hpp" #include "gc/z/zResurrection.inline.hpp" +#include "gc/z/zVerify.hpp" #include "oops/oop.hpp" #include "runtime/atomic.hpp" -#include "runtime/continuation.hpp" // A self heal must always "upgrade" the address metadata bits in // accordance with the metadata bits state machine. The following @@ -320,17 +319,9 @@ inline zaddress ZBarrier::make_load_good_no_relocate(zpointer o) { return remap(ZPointer::uncolor_unsafe(o), remap_generation(o)); } -inline void z_assert_is_barrier_safe() { - assert(!Thread::current()->is_ConcurrentGC_thread() || /* Need extra checks for ConcurrentGCThreads */ - Thread::current()->is_suspendible_thread() || /* Thread prevents safepoints */ - Thread::current()->is_indirectly_suspendible_thread() || /* Coordinator thread prevents safepoints */ - SafepointSynchronize::is_at_safepoint(), /* Is at safepoint */ - "Shouldn't perform load barrier"); -} - template inline zaddress ZBarrier::barrier(ZBarrierFastPath fast_path, ZBarrierSlowPath slow_path, ZBarrierColor color, volatile zpointer* p, zpointer o, bool allow_null) { - z_assert_is_barrier_safe(); + z_verify_safepoints_are_blocked(); // Fast path if (fast_path(o)) { diff --git a/src/hotspot/share/gc/z/zBarrierSet.cpp b/src/hotspot/share/gc/z/zBarrierSet.cpp index a82cc67754b..48228a3e1ab 100644 --- a/src/hotspot/share/gc/z/zBarrierSet.cpp +++ b/src/hotspot/share/gc/z/zBarrierSet.cpp @@ -152,11 +152,12 @@ void ZBarrierSet::on_slowpath_allocation_exit(JavaThread* thread, oop new_obj) { deoptimize_allocation(thread); } -void ZBarrierSet::clone_obj_array(objArrayOop src_obj, objArrayOop dst_obj, size_t size) { +void ZBarrierSet::clone_obj_array(objArrayOop src_obj, objArrayOop dst_obj) { volatile zpointer* src = (volatile zpointer*)src_obj->base(); volatile zpointer* dst = (volatile zpointer*)dst_obj->base(); + const int length = src_obj->length(); - for (const zpointer* const end = cast_from_oop(src_obj) + size; src < end; src++, dst++) { + for (const volatile zpointer* const end = src + length; src < end; src++, dst++) { zaddress elem = ZBarrier::load_barrier_on_oop_field(src); // We avoid healing here because the store below colors the pointer store good, // hence avoiding the cost of a CAS. diff --git a/src/hotspot/share/gc/z/zBarrierSet.hpp b/src/hotspot/share/gc/z/zBarrierSet.hpp index adba5ee15c1..bf233df683a 100644 --- a/src/hotspot/share/gc/z/zBarrierSet.hpp +++ b/src/hotspot/share/gc/z/zBarrierSet.hpp @@ -39,7 +39,7 @@ class ZBarrierSet : public BarrierSet { static ZBarrierSetAssembler* assembler(); static bool barrier_needed(DecoratorSet decorators, BasicType type); - static void clone_obj_array(objArrayOop src, objArrayOop dst, size_t size); + static void clone_obj_array(objArrayOop src, objArrayOop dst); virtual void on_thread_create(Thread* thread); virtual void on_thread_destroy(Thread* thread); diff --git a/src/hotspot/share/gc/z/zBarrierSet.inline.hpp b/src/hotspot/share/gc/z/zBarrierSet.inline.hpp index 997e5bae58d..d53b69345dd 100644 --- a/src/hotspot/share/gc/z/zBarrierSet.inline.hpp +++ b/src/hotspot/share/gc/z/zBarrierSet.inline.hpp @@ -439,7 +439,7 @@ inline void ZBarrierSet::AccessBarrier::clone_in_heap(o // for cloning arrays transform the clone to an optimized allocation // and arraycopy sequence, so the performance of this runtime call // does not matter for object arrays. - clone_obj_array(objArrayOop(src), objArrayOop(dst), size); + clone_obj_array(objArrayOop(src), objArrayOop(dst)); return; } diff --git a/src/hotspot/share/gc/z/zGeneration.cpp b/src/hotspot/share/gc/z/zGeneration.cpp index 4621101eb88..bb0653f72ea 100644 --- a/src/hotspot/share/gc/z/zGeneration.cpp +++ b/src/hotspot/share/gc/z/zGeneration.cpp @@ -286,6 +286,10 @@ void ZGeneration::desynchronize_relocation() { _relocate.desynchronize(); } +bool ZGeneration::is_relocate_queue_active() const { + return _relocate.is_queue_active(); +} + void ZGeneration::reset_statistics() { assert(SafepointSynchronize::is_at_safepoint(), "Should be at safepoint"); _freed = 0; @@ -1496,7 +1500,7 @@ void ZGenerationOld::remap_young_roots() { uint remap_nworkers = clamp(ZGeneration::young()->workers()->active_workers() + prev_nworkers, 1u, ZOldGCThreads); _workers.set_active_workers(remap_nworkers); - // TODO: The STS joiner is only needed to satisfy z_assert_is_barrier_safe that doesn't + // TODO: The STS joiner is only needed to satisfy ZBarrier::assert_is_state_barrier_safe that doesn't // understand the driver locker. Consider making the assert aware of the driver locker. SuspendibleThreadSetJoiner sts_joiner; diff --git a/src/hotspot/share/gc/z/zGeneration.hpp b/src/hotspot/share/gc/z/zGeneration.hpp index 23736f45b7b..32762a50b62 100644 --- a/src/hotspot/share/gc/z/zGeneration.hpp +++ b/src/hotspot/share/gc/z/zGeneration.hpp @@ -166,6 +166,7 @@ class ZGeneration { // Relocation void synchronize_relocation(); void desynchronize_relocation(); + bool is_relocate_queue_active() const; zaddress relocate_or_remap_object(zaddress_unsafe addr); zaddress remap_object(zaddress_unsafe addr); diff --git a/src/hotspot/share/gc/z/zIterator.inline.hpp b/src/hotspot/share/gc/z/zIterator.inline.hpp index 9ccacdc9a3c..af97a549b0d 100644 --- a/src/hotspot/share/gc/z/zIterator.inline.hpp +++ b/src/hotspot/share/gc/z/zIterator.inline.hpp @@ -26,11 +26,21 @@ #include "gc/z/zIterator.hpp" +#include "gc/z/zVerify.hpp" #include "memory/iterator.inline.hpp" #include "oops/objArrayOop.hpp" #include "oops/oop.inline.hpp" inline bool ZIterator::is_invisible_object(oop obj) { + // This is a good place to make sure that we can't concurrently iterate over + // objects while VMThread operations think they have exclusive access to the + // object graph. + // + // One example that have caused problems is the JFR Leak Profiler, which + // sets the mark word to a value that makes the object arrays look like + // invisible objects. + z_verify_safepoints_are_blocked(); + return obj->mark_acquire().is_marked(); } diff --git a/src/hotspot/share/gc/z/zRelocate.cpp b/src/hotspot/share/gc/z/zRelocate.cpp index 60a6616d0a7..78efa7cdb12 100644 --- a/src/hotspot/share/gc/z/zRelocate.cpp +++ b/src/hotspot/share/gc/z/zRelocate.cpp @@ -87,6 +87,7 @@ ZRelocateQueue::ZRelocateQueue() _nworkers(0), _nsynchronized(0), _synchronize(false), + _is_active(false), _needs_attention(0) {} bool ZRelocateQueue::needs_attention() const { @@ -103,6 +104,20 @@ void ZRelocateQueue::dec_needs_attention() { assert(needs_attention == 0 || needs_attention == 1, "Invalid state"); } +void ZRelocateQueue::activate(uint nworkers) { + _is_active = true; + join(nworkers); +} + +void ZRelocateQueue::deactivate() { + Atomic::store(&_is_active, false); + clear(); +} + +bool ZRelocateQueue::is_active() const { + return Atomic::load(&_is_active); +} + void ZRelocateQueue::join(uint nworkers) { assert(nworkers != 0, "Must request at least one worker"); assert(_nworkers == 0, "Invalid state"); @@ -327,7 +342,7 @@ ZWorkers* ZRelocate::workers() const { } void ZRelocate::start() { - _queue.join(workers()->active_workers()); + _queue.activate(workers()->active_workers()); } void ZRelocate::add_remset(volatile zpointer* p) { @@ -1088,6 +1103,9 @@ class ZRelocateTask : public ZRestartableTask { ~ZRelocateTask() { _generation->stat_relocation()->at_relocate_end(_small_allocator.in_place_count(), _medium_allocator.in_place_count()); + + // Signal that we're not using the queue anymore. Used mostly for asserts. + _queue->deactivate(); } virtual void work() { @@ -1232,8 +1250,6 @@ void ZRelocate::relocate(ZRelocationSet* relocation_set) { ZRelocateAddRemsetForFlipPromoted task(relocation_set->flip_promoted_pages()); workers()->run(&task); } - - _queue.clear(); } ZPageAge ZRelocate::compute_to_age(ZPageAge from_age) { @@ -1316,3 +1332,7 @@ void ZRelocate::desynchronize() { ZRelocateQueue* ZRelocate::queue() { return &_queue; } + +bool ZRelocate::is_queue_active() const { + return _queue.is_active(); +} diff --git a/src/hotspot/share/gc/z/zRelocate.hpp b/src/hotspot/share/gc/z/zRelocate.hpp index ed54103d53c..1b35abdf521 100644 --- a/src/hotspot/share/gc/z/zRelocate.hpp +++ b/src/hotspot/share/gc/z/zRelocate.hpp @@ -41,6 +41,7 @@ class ZRelocateQueue { uint _nworkers; uint _nsynchronized; bool _synchronize; + volatile bool _is_active; volatile int _needs_attention; bool needs_attention() const; @@ -53,6 +54,10 @@ class ZRelocateQueue { public: ZRelocateQueue(); + void activate(uint nworkers); + void deactivate(); + bool is_active() const; + void join(uint nworkers); void resize_workers(uint nworkers); void leave(); @@ -99,6 +104,8 @@ class ZRelocate { void desynchronize(); ZRelocateQueue* queue(); + + bool is_queue_active() const; }; #endif // SHARE_GC_Z_ZRELOCATE_HPP diff --git a/src/hotspot/share/gc/z/zRelocationSet.cpp b/src/hotspot/share/gc/z/zRelocationSet.cpp index 83bdf13b2bb..92f245777b4 100644 --- a/src/hotspot/share/gc/z/zRelocationSet.cpp +++ b/src/hotspot/share/gc/z/zRelocationSet.cpp @@ -106,11 +106,16 @@ class ZRelocationSetInstallTask : public ZTask { } virtual void work() { + // Join the STS to block out VMThreads while running promote_barrier_on_young_oop_field + SuspendibleThreadSetJoiner sts_joiner; + // Allocate and install forwardings for small pages for (size_t page_index; _small_iter.next_index(&page_index);) { ZPage* page = _small->at(int(page_index)); ZForwarding* const forwarding = ZForwarding::alloc(_allocator, page, to_age(page)); install_small(forwarding, _medium->length() + page_index); + + SuspendibleThreadSet::yield(); } // Allocate and install forwardings for medium pages @@ -118,6 +123,8 @@ class ZRelocationSetInstallTask : public ZTask { ZPage* page = _medium->at(int(page_index)); ZForwarding* const forwarding = ZForwarding::alloc(_allocator, page, to_age(page)); install_medium(forwarding, page_index); + + SuspendibleThreadSet::yield(); } } diff --git a/src/hotspot/share/gc/z/zUncoloredRoot.inline.hpp b/src/hotspot/share/gc/z/zUncoloredRoot.inline.hpp index 3eb28d3cafe..a7d39e5ed9c 100644 --- a/src/hotspot/share/gc/z/zUncoloredRoot.inline.hpp +++ b/src/hotspot/share/gc/z/zUncoloredRoot.inline.hpp @@ -29,11 +29,12 @@ #include "gc/z/zAddress.inline.hpp" #include "gc/z/zBarrier.inline.hpp" #include "gc/z/zHeap.inline.hpp" +#include "gc/z/zBarrier.hpp" #include "oops/oop.hpp" template inline void ZUncoloredRoot::barrier(ObjectFunctionT function, zaddress_unsafe* p, uintptr_t color) { - z_assert_is_barrier_safe(); + z_verify_safepoints_are_blocked(); const zaddress_unsafe addr = Atomic::load(p); assert_is_valid(addr); diff --git a/src/hotspot/share/gc/z/zVerify.cpp b/src/hotspot/share/gc/z/zVerify.cpp index 6950f669158..b168610db3a 100644 --- a/src/hotspot/share/gc/z/zVerify.cpp +++ b/src/hotspot/share/gc/z/zVerify.cpp @@ -43,16 +43,67 @@ #include "runtime/frame.inline.hpp" #include "runtime/globals.hpp" #include "runtime/handles.hpp" -#include "runtime/javaThread.hpp" +#include "runtime/javaThread.inline.hpp" +#include "runtime/mutexLocker.hpp" #include "runtime/safepoint.hpp" #include "runtime/stackFrameStream.inline.hpp" #include "runtime/stackWatermark.inline.hpp" #include "runtime/stackWatermarkSet.inline.hpp" +#include "runtime/thread.hpp" #include "utilities/debug.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/preserveException.hpp" #include "utilities/resourceHash.hpp" +#ifdef ASSERT + +// Used to verify that safepoints operations can't be scheduled concurrently +// with callers to this function. Typically used to verify that object oops +// and headers are safe to access. +void z_verify_safepoints_are_blocked() { + Thread* current = Thread::current(); + + if (current->is_ConcurrentGC_thread()) { + assert(current->is_suspendible_thread(), // Thread prevents safepoints + "Safepoints are not blocked by current thread"); + + } else if (current->is_Worker_thread()) { + assert(// Check if ... + // the thread prevents safepoints + current->is_suspendible_thread() || + // the coordinator thread is the safepointing VMThread + current->is_indirectly_safepoint_thread() || + // the coordinator thread prevents safepoints + current->is_indirectly_suspendible_thread() || + // the RelocateQueue prevents safepoints + // + // RelocateQueue acts as a pseudo STS leaver/joiner and blocks + // safepoints. There's currently no infrastructure to check if the + // current thread is active or not, so check the global states instead. + ZGeneration::young()->is_relocate_queue_active() || + ZGeneration::old()->is_relocate_queue_active(), + "Safepoints are not blocked by current thread"); + + } else if (current->is_Java_thread()) { + JavaThreadState state = JavaThread::cast(current)->thread_state(); + assert(state == _thread_in_Java || state == _thread_in_vm || state == _thread_new, + "Safepoints are not blocked by current thread from state: %d", state); + + } else if (current->is_JfrSampler_thread()) { + // The JFR sampler thread blocks out safepoints with this lock. + assert_lock_strong(Threads_lock); + + } else if (current->is_VM_thread()) { + // The VM Thread doesn't schedule new safepoints while executing + // other safepoint or handshake operations. + + } else { + fatal("Unexpected thread type"); + } +} + +#endif + #define BAD_OOP_ARG(o, p) "Bad oop " PTR_FORMAT " found at " PTR_FORMAT, untype(o), p2i(p) static bool z_is_null_relaxed(zpointer o) { diff --git a/src/hotspot/share/gc/z/zVerify.hpp b/src/hotspot/share/gc/z/zVerify.hpp index e9ada2cefa9..447d38504a2 100644 --- a/src/hotspot/share/gc/z/zVerify.hpp +++ b/src/hotspot/share/gc/z/zVerify.hpp @@ -30,6 +30,8 @@ class frame; class ZForwarding; class ZPageAllocator; +NOT_DEBUG(inline) void z_verify_safepoints_are_blocked() NOT_DEBUG_RETURN; + class ZVerify : public AllStatic { private: static void roots_strong(bool verify_after_old_mark); diff --git a/src/hotspot/share/include/jvm.h b/src/hotspot/share/include/jvm.h index cc1b3d94cbd..5d6ab27a3a1 100644 --- a/src/hotspot/share/include/jvm.h +++ b/src/hotspot/share/include/jvm.h @@ -1154,6 +1154,9 @@ JVM_VirtualThreadUnmount(JNIEnv* env, jobject vthread, jboolean hide); JNIEXPORT void JNICALL JVM_VirtualThreadHideFrames(JNIEnv* env, jobject vthread, jboolean hide); +JNIEXPORT void JNICALL +JVM_VirtualThreadDisableSuspend(JNIEnv* env, jobject vthread, jboolean enter); + /* * Core reflection support. */ diff --git a/src/hotspot/share/interpreter/bytecodes.cpp b/src/hotspot/share/interpreter/bytecodes.cpp index 89dab8382d3..44d1fd668d6 100644 --- a/src/hotspot/share/interpreter/bytecodes.cpp +++ b/src/hotspot/share/interpreter/bytecodes.cpp @@ -385,13 +385,18 @@ int Bytecodes::special_length_at(Bytecodes::Code code, address bcp, address end) if (end != nullptr && aligned_bcp + 3*jintSize >= end) { return -1; // don't read past end of code buffer } - // Promote calculation to 64 bits to do range checks, used by the verifier. + // Promote calculation to signed 64 bits to do range checks, used by the verifier. int64_t lo = (int)Bytes::get_Java_u4(aligned_bcp + 1*jintSize); int64_t hi = (int)Bytes::get_Java_u4(aligned_bcp + 2*jintSize); int64_t len = (aligned_bcp - bcp) + (3 + hi - lo + 1)*jintSize; - // only return len if it can be represented as a positive int; - // return -1 otherwise - return (len > 0 && len == (int)len) ? (int)len : -1; + // Only return len if it can be represented as a positive int and lo <= hi. + // The caller checks for bytecode stream overflow. + if (lo <= hi && len == (int)len) { + assert(len > 0, "must be"); + return (int)len; + } else { + return -1; + } } case _lookupswitch: // fall through @@ -404,9 +409,13 @@ int Bytecodes::special_length_at(Bytecodes::Code code, address bcp, address end) // Promote calculation to 64 bits to do range checks, used by the verifier. int64_t npairs = (int)Bytes::get_Java_u4(aligned_bcp + jintSize); int64_t len = (aligned_bcp - bcp) + (2 + 2*npairs)*jintSize; - // only return len if it can be represented as a positive int; - // return -1 otherwise - return (len > 0 && len == (int)len) ? (int)len : -1; + // Only return len if it can be represented as a positive int and npairs >= 0. + if (npairs >= 0 && len == (int)len) { + assert(len > 0, "must be"); + return (int)len; + } else { + return -1; + } } default: // Note: Length functions must return <=0 for invalid bytecodes. diff --git a/src/hotspot/share/jfr/jfr.cpp b/src/hotspot/share/jfr/jfr.cpp index 45848fb0243..03b47bcd21d 100644 --- a/src/hotspot/share/jfr/jfr.cpp +++ b/src/hotspot/share/jfr/jfr.cpp @@ -67,7 +67,9 @@ void Jfr::on_create_vm_3() { } void Jfr::on_unloading_classes() { - JfrCheckpointManager::on_unloading_classes(); + if (JfrRecorder::is_created() || JfrRecorder::is_started_on_commandline()) { + JfrCheckpointManager::on_unloading_classes(); + } } bool Jfr::is_excluded(Thread* t) { diff --git a/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointManager.cpp b/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointManager.cpp index 799d6ef899d..0aed916702e 100644 --- a/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointManager.cpp +++ b/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointManager.cpp @@ -117,16 +117,16 @@ bool JfrCheckpointManager::initialize_early() { assert(_thread_local_mspace == nullptr, "invariant"); _thread_local_mspace = new JfrThreadLocalCheckpointMspace(); if (_thread_local_mspace == nullptr || !_thread_local_mspace->initialize(thread_local_buffer_size, - thread_local_buffer_prealloc_count, - thread_local_buffer_prealloc_count)) { + thread_local_buffer_prealloc_count, + thread_local_buffer_prealloc_count)) { return false; } assert(_virtual_thread_local_mspace == nullptr, "invariant"); _virtual_thread_local_mspace = new JfrThreadLocalCheckpointMspace(); if (_virtual_thread_local_mspace == nullptr || !_virtual_thread_local_mspace->initialize(virtual_thread_local_buffer_size, - JFR_MSPACE_UNLIMITED_CACHE_SIZE, - virtual_thread_local_buffer_prealloc_count)) { + JFR_MSPACE_UNLIMITED_CACHE_SIZE, + virtual_thread_local_buffer_prealloc_count)) { return false; } return true; diff --git a/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointWriter.hpp b/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointWriter.hpp index f99159b3a51..a8ec2fd70f5 100644 --- a/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointWriter.hpp +++ b/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointWriter.hpp @@ -55,6 +55,7 @@ struct JfrCheckpointContext { class JfrCheckpointWriter : public JfrCheckpointWriterBase { friend class JfrCheckpointManager; + friend class JfrDeprecationManager; friend class JfrSerializerRegistration; friend class JfrTypeManager; private: diff --git a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp index 94ac0772969..3a86f204e61 100644 --- a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp +++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp @@ -66,20 +66,38 @@ static bool _class_unload = false; static bool _flushpoint = false; static bool _initial_type_set = true; -static bool current_epoch() { - return _class_unload || _flushpoint; +static inline bool flushpoint() { + return _flushpoint; } -static bool previous_epoch() { +static inline bool unloading() { + return _class_unload; +} + +static inline bool current_epoch() { + return flushpoint() || unloading(); +} + +static inline bool previous_epoch() { return !current_epoch(); } -static bool is_initial_typeset_for_chunk() { - return _initial_type_set && !_class_unload; +template +static inline bool used(const T* ptr) { + assert(ptr != nullptr, "invariant"); + return current_epoch() ? USED_THIS_EPOCH(ptr) : USED_PREVIOUS_EPOCH(ptr); +} + +template +static inline bool not_used(const T* ptr) { + return !used(ptr); } -static bool is_complete() { - return !_artifacts->has_klass_entries() && current_epoch(); +template +static void do_artifact(const T* ptr) { + if (used(ptr)) { + _subsystem_callback->do_artifact(ptr); + } } static traceid mark_symbol(KlassPtr klass, bool leakp) { @@ -94,66 +112,113 @@ static traceid get_bootstrap_name(bool leakp) { return _artifacts->bootstrap_name(leakp); } -static const char* primitive_name(KlassPtr type_array_klass) { - switch (type_array_klass->name()->base()[1]) { - case JVM_SIGNATURE_BOOLEAN: return "boolean"; - case JVM_SIGNATURE_BYTE: return "byte"; - case JVM_SIGNATURE_CHAR: return "char"; - case JVM_SIGNATURE_SHORT: return "short"; - case JVM_SIGNATURE_INT: return "int"; - case JVM_SIGNATURE_LONG: return "long"; - case JVM_SIGNATURE_FLOAT: return "float"; - case JVM_SIGNATURE_DOUBLE: return "double"; - } - assert(false, "invalid type array klass"); - return nullptr; +template +static traceid artifact_id(const T* ptr) { + assert(ptr != nullptr, "invariant"); + return JfrTraceId::load_raw(ptr); } -static Symbol* primitive_symbol(KlassPtr type_array_klass) { - if (type_array_klass == nullptr) { - // void.class - static Symbol* const void_class_name = SymbolTable::probe("void", 4); - assert(void_class_name != nullptr, "invariant"); - return void_class_name; +template +static traceid artifact_tag(const T* ptr, bool leakp) { + assert(ptr != nullptr, "invariant"); + if (leakp) { + if (IS_NOT_LEAKP(ptr)) { + SET_LEAKP(ptr); + } + assert(IS_LEAKP(ptr), "invariant"); + return artifact_id(ptr); } - const char* const primitive_type_str = primitive_name(type_array_klass); - assert(primitive_type_str != nullptr, "invariant"); - Symbol* const primitive_type_sym = SymbolTable::probe(primitive_type_str, (int)strlen(primitive_type_str)); - assert(primitive_type_sym != nullptr, "invariant"); - return primitive_type_sym; + if (not_used(ptr)) { + SET_TRANSIENT(ptr); + } + assert(used(ptr), "invariant"); + return artifact_id(ptr); } -template -static traceid artifact_id(const T* ptr) { - assert(ptr != nullptr, "invariant"); - return JfrTraceId::load_raw(ptr); +static inline CldPtr get_cld(ModPtr mod) { + return mod != nullptr ? mod->loader_data() : nullptr; } -static traceid package_id(KlassPtr klass, bool leakp) { +static ClassLoaderData* get_cld(const Klass* klass) { assert(klass != nullptr, "invariant"); - PkgPtr pkg_entry = klass->package(); - if (pkg_entry == nullptr) { - return 0; + if (klass->is_objArray_klass()) { + klass = ObjArrayKlass::cast(klass)->bottom_klass(); } - if (leakp) { - SET_LEAKP(pkg_entry); + return klass->is_non_strong_hidden() ? nullptr : klass->class_loader_data(); +} + +static inline bool should_do_cld_klass(const Klass* cld_klass, bool leakp) { + return cld_klass != nullptr && _artifacts->should_do_cld_klass(cld_klass, leakp); +} + +static inline bool should_enqueue(const Klass* cld_klass) { + assert(cld_klass != nullptr, "invariant"); + if (previous_epoch()) { + return false; + } + CldPtr cld = get_cld(cld_klass); + return cld != nullptr && !cld->is_unloading(); +} + +static inline KlassPtr get_cld_klass(CldPtr cld, bool leakp) { + if (cld == nullptr) { + return nullptr; } - // package implicitly tagged already - return artifact_id(pkg_entry); + assert(leakp ? IS_LEAKP(cld) : used(cld), "invariant"); + KlassPtr cld_klass = cld->class_loader_klass(); + if (!should_do_cld_klass(cld_klass, leakp)) { + return nullptr; + } + if (should_enqueue(cld_klass)) { + // This will enqueue the klass, which is important for + // reachability when doing clear and reset at rotation. + JfrTraceId::load(cld_klass); + } else { + artifact_tag(cld_klass, leakp); + } + return cld_klass; +} + +static inline ModPtr get_module(PkgPtr pkg) { + return pkg != nullptr ? pkg->module() : nullptr; +} + +static inline PkgPtr get_package(KlassPtr klass) { + return klass != nullptr ? klass->package() : nullptr; +} + +static inline KlassPtr get_module_cld_klass(KlassPtr klass, bool leakp) { + assert(klass != nullptr, "invariant"); + return get_cld_klass(get_cld(get_module(get_package(klass))), leakp); +} + +static traceid cld_id(CldPtr cld, bool leakp) { + assert(cld != nullptr, "invariant"); + return artifact_tag(cld, leakp); } static traceid module_id(PkgPtr pkg, bool leakp) { assert(pkg != nullptr, "invariant"); - ModPtr module_entry = pkg->module(); - if (module_entry == nullptr) { + ModPtr mod = get_module(pkg); + if (mod == nullptr) { return 0; } - if (leakp) { - SET_LEAKP(module_entry); - } else { - SET_TRANSIENT(module_entry); + CldPtr cld = get_cld(mod); + if (cld != nullptr) { + cld_id(cld, leakp); + } + return artifact_tag(mod, leakp); +} + +static traceid package_id(KlassPtr klass, bool leakp) { + assert(klass != nullptr, "invariant"); + PkgPtr pkg = get_package(klass); + if (pkg == nullptr) { + return 0; } - return artifact_id(module_entry); + // Ensure module and its CLD gets tagged. + module_id(pkg, leakp); + return artifact_tag(pkg, leakp); } static traceid method_id(KlassPtr klass, MethodPtr method) { @@ -162,16 +227,6 @@ static traceid method_id(KlassPtr klass, MethodPtr method) { return METHOD_ID(klass, method); } -static traceid cld_id(CldPtr cld, bool leakp) { - assert(cld != nullptr, "invariant"); - if (leakp) { - SET_LEAKP(cld); - } else { - SET_TRANSIENT(cld); - } - return artifact_id(cld); -} - template static s4 get_flags(const T* ptr) { assert(ptr != nullptr, "invariant"); @@ -183,73 +238,203 @@ static u4 get_primitive_flags() { return JVM_ACC_ABSTRACT | JVM_ACC_FINAL | JVM_ACC_PUBLIC; } -static ClassLoaderData* get_cld(const Klass* klass) { - assert(klass != nullptr, "invariant"); - if (klass->is_objArray_klass()) { - klass = ObjArrayKlass::cast(klass)->bottom_klass(); +class PackageFieldSelector { + public: + typedef PkgPtr TypePtr; + static TypePtr select(KlassPtr klass) { + assert(klass != nullptr, "invariant"); + return klass->package(); } - if (klass->is_non_strong_hidden()) return nullptr; - return klass->class_loader_data(); -} +}; + +class ModuleFieldSelector { + public: + typedef ModPtr TypePtr; + static TypePtr select(KlassPtr klass) { + assert(klass != nullptr, "invariant"); + PkgPtr pkg = klass->package(); + return pkg != nullptr ? pkg->module() : nullptr; + } +}; + +class KlassCldFieldSelector { + public: + typedef CldPtr TypePtr; + static TypePtr select(KlassPtr klass) { + assert(klass != nullptr, "invariant"); + return get_cld(klass); + } +}; + +class ModuleCldFieldSelector { + public: + typedef CldPtr TypePtr; + static TypePtr select(KlassPtr klass) { + assert(klass != nullptr, "invariant"); + ModPtr mod = ModuleFieldSelector::select(klass); + return mod != nullptr ? mod->loader_data() : nullptr; + } +}; + +template +class SerializePredicate { + bool _class_unload; + public: + SerializePredicate(bool class_unload) : _class_unload(class_unload) {} + bool operator()(T const& value) { + assert(value != nullptr, "invariant"); + return _class_unload ? _artifacts->should_do_unloading_artifact(value) : IS_NOT_SERIALIZED(value); + } +}; + +template <> +class SerializePredicate { + bool _class_unload; +public: + SerializePredicate(bool class_unload) : _class_unload(class_unload) {} + bool operator()(const Klass* klass) { + assert(klass != nullptr, "invariant"); + return _class_unload ? true : IS_NOT_SERIALIZED(klass); + } +}; + +template <> +class SerializePredicate { + bool _class_unload; +public: + SerializePredicate(bool class_unload) : _class_unload(class_unload) {} + bool operator()(const Method* method) { + assert(method != nullptr, "invariant"); + return _class_unload ? true : METHOD_IS_NOT_SERIALIZED(method); + } +}; template static void set_serialized(const T* ptr) { assert(ptr != nullptr, "invariant"); - SET_SERIALIZED(ptr); - assert(IS_SERIALIZED(ptr), "invariant"); if (current_epoch()) { CLEAR_THIS_EPOCH_CLEARED_BIT(ptr); } + SET_SERIALIZED(ptr); + assert(IS_SERIALIZED(ptr), "invariant"); } /* - * In C++03, functions used as template parameters must have external linkage; - * this restriction was removed in C++11. Change back to "static" and - * rename functions when C++11 becomes available. + *********************** Klasses ************************* + * + * When we process a Klass, we need to process its transitive closure. + * + * This includes two branches: + * + * [1] Klass -> CLD -> class_loader_Klass + * [2] Klass -> PackageEntry -> ModuleEntry -> CLD -> class_loader_Klass + * + * A Klass viewed as this closure becomes a node in a binary tree: + * + * Klass + * O + * / \ + * / \ + * [1] O O [2] + * + * We write the Klass and tag the artifacts in its closure (subtree) + * using preorder traversal by recursing the class_loader_Klass(es). * - * The weird naming is an effort to decrease the risk of name clashes. */ -static int write_klass(JfrCheckpointWriter* writer, KlassPtr klass, bool leakp) { +static void do_write_klass(JfrCheckpointWriter* writer, CldPtr cld, KlassPtr klass, bool leakp) { assert(writer != nullptr, "invariant"); assert(_artifacts != nullptr, "invariant"); assert(klass != nullptr, "invariant"); writer->write(artifact_id(klass)); - ClassLoaderData* cld = get_cld(klass); writer->write(cld != nullptr ? cld_id(cld, leakp) : 0); writer->write(mark_symbol(klass, leakp)); writer->write(package_id(klass, leakp)); writer->write(klass->modifier_flags()); writer->write(klass->is_hidden()); - return 1; + if (!leakp) { + set_serialized(klass); + } +} + +static inline bool should_write_cld_klass(KlassPtr klass, bool leakp) { + return klass != nullptr && (leakp || IS_NOT_SERIALIZED(klass)); +} + +static void write_klass(JfrCheckpointWriter* writer, KlassPtr klass, bool leakp, int& elements) { + assert(elements >= 0, "invariant"); + ClassLoaderData* cld = get_cld(klass); + do_write_klass(writer, cld, klass, leakp); + ++elements; + if (cld != nullptr) { + // Write the klass for the direct cld. + KlassPtr cld_klass = get_cld_klass(cld, leakp); + if (should_write_cld_klass(cld_klass, leakp)) { + write_klass(writer, cld_klass, leakp, elements); + } + } + KlassPtr mod_klass = get_module_cld_klass(klass, leakp); + if (should_write_cld_klass(mod_klass, leakp)) { + // Write the klass for the module cld. + write_klass(writer, mod_klass, leakp, elements); + } } +/* + * In C++03, functions used as template parameters must have external linkage; + * this restriction was removed in C++11. Change back to "static" and + * rename functions when C++11 becomes available. + * + * The weird naming is an effort to decrease the risk of name clashes. + */ int write__klass(JfrCheckpointWriter* writer, const void* k) { assert(k != nullptr, "invariant"); - KlassPtr klass = (KlassPtr)k; - set_serialized(klass); - return write_klass(writer, klass, false); + KlassPtr klass = static_cast(k); + int elements = 0; + write_klass(writer, klass, false, elements); + return elements; } int write__klass__leakp(JfrCheckpointWriter* writer, const void* k) { assert(k != nullptr, "invariant"); - KlassPtr klass = (KlassPtr)k; + KlassPtr klass = static_cast(k); CLEAR_LEAKP(klass); - return write_klass(writer, klass, true); + int elements = 0; + write_klass(writer, klass, true, elements); + return elements; } -static bool is_implied(const Klass* klass) { - assert(klass != nullptr, "invariant"); - return klass->is_subclass_of(vmClasses::ClassLoader_klass()) || klass == vmClasses::Object_klass(); -} +static int primitives_count = 9; -static void do_klass(Klass* klass) { - assert(klass != nullptr, "invariant"); - assert(_flushpoint ? USED_THIS_EPOCH(klass) : USED_PREVIOUS_EPOCH(klass), "invariant"); - assert(_subsystem_callback != nullptr, "invariant"); - _subsystem_callback->do_artifact(klass); +static const char* primitive_name(KlassPtr type_array_klass) { + switch (type_array_klass->name()->base()[1]) { + case JVM_SIGNATURE_BOOLEAN: return "boolean"; + case JVM_SIGNATURE_BYTE: return "byte"; + case JVM_SIGNATURE_CHAR: return "char"; + case JVM_SIGNATURE_SHORT: return "short"; + case JVM_SIGNATURE_INT: return "int"; + case JVM_SIGNATURE_LONG: return "long"; + case JVM_SIGNATURE_FLOAT: return "float"; + case JVM_SIGNATURE_DOUBLE: return "double"; + } + assert(false, "invalid type array klass"); + return nullptr; } +static Symbol* primitive_symbol(KlassPtr type_array_klass) { + if (type_array_klass == nullptr) { + // void.class + static Symbol* const void_class_name = SymbolTable::probe("void", 4); + assert(void_class_name != nullptr, "invariant"); + return void_class_name; + } + const char* const primitive_type_str = primitive_name(type_array_klass); + assert(primitive_type_str != nullptr, "invariant"); + Symbol* const primitive_type_sym = SymbolTable::probe(primitive_type_str, + (int)strlen(primitive_type_str)); + assert(primitive_type_sym != nullptr, "invariant"); + return primitive_type_sym; +} static traceid primitive_id(KlassPtr array_klass) { if (array_klass == nullptr) { @@ -271,148 +456,69 @@ static void write_primitive(JfrCheckpointWriter* writer, KlassPtr type_array_kla writer->write(false); } -static void do_loader_klass(const Klass* klass) { - if (klass != nullptr && _artifacts->should_do_loader_klass(klass)) { - if (_leakp_writer != nullptr) { - SET_LEAKP(klass); - } - SET_TRANSIENT(klass); - _subsystem_callback->do_artifact(klass); - } -} - -static bool register_klass_unload(Klass* klass) { - assert(klass != nullptr, "invariant"); - return JfrKlassUnloading::on_unload(klass); -} - -static void do_unloading_klass(Klass* klass) { - assert(klass != nullptr, "invariant"); - assert(_subsystem_callback != nullptr, "invariant"); - if (register_klass_unload(klass)) { - _subsystem_callback->do_artifact(klass); - do_loader_klass(klass->class_loader_data()->class_loader_klass()); - } -} - -/* - * Abstract klasses are filtered out unconditionally. - * If a klass is not yet initialized, i.e yet to run its - * it is also filtered out so we don't accidentally - * trigger initialization. - */ -static bool is_classloader_klass_allowed(const Klass* k) { - assert(k != nullptr, "invariant"); - return !(k->is_abstract() || k->should_be_initialized()); -} - -static void do_classloaders() { - for (ClassHierarchyIterator iter(vmClasses::ClassLoader_klass()); !iter.done(); iter.next()) { - Klass* subk = iter.klass(); - if (is_classloader_klass_allowed(subk)) { - do_loader_klass(subk); - } - } +static bool is_initial_typeset_for_chunk() { + return _initial_type_set && !unloading(); } -static int primitives_count = 9; - // A mirror representing a primitive class (e.g. int.class) has no reified Klass*, // instead it has an associated TypeArrayKlass* (e.g. int[].class). // We can use the TypeArrayKlass* as a proxy for deriving the id of the primitive class. // The exception is the void.class, which has neither a Klass* nor a TypeArrayKlass*. // It will use a reserved constant. static void do_primitives() { - // Only write the primitive classes once per chunk. - if (is_initial_typeset_for_chunk()) { - write_primitive(_writer, Universe::boolArrayKlassObj()); - write_primitive(_writer, Universe::byteArrayKlassObj()); - write_primitive(_writer, Universe::charArrayKlassObj()); - write_primitive(_writer, Universe::shortArrayKlassObj()); - write_primitive(_writer, Universe::intArrayKlassObj()); - write_primitive(_writer, Universe::longArrayKlassObj()); - write_primitive(_writer, Universe::floatArrayKlassObj()); - write_primitive(_writer, Universe::doubleArrayKlassObj()); - write_primitive(_writer, nullptr); // void.class - } + assert(is_initial_typeset_for_chunk(), "invariant"); + write_primitive(_writer, Universe::boolArrayKlassObj()); + write_primitive(_writer, Universe::byteArrayKlassObj()); + write_primitive(_writer, Universe::charArrayKlassObj()); + write_primitive(_writer, Universe::shortArrayKlassObj()); + write_primitive(_writer, Universe::intArrayKlassObj()); + write_primitive(_writer, Universe::longArrayKlassObj()); + write_primitive(_writer, Universe::floatArrayKlassObj()); + write_primitive(_writer, Universe::doubleArrayKlassObj()); + write_primitive(_writer, nullptr); // void.class } -static void do_object() { - SET_TRANSIENT(vmClasses::Object_klass()); - do_klass(vmClasses::Object_klass()); -} - -static void do_klasses() { - if (_class_unload) { - ClassLoaderDataGraph::classes_unloading_do(&do_unloading_klass); - return; - } - JfrTraceIdLoadBarrier::do_klasses(&do_klass, previous_epoch()); - do_classloaders(); - do_primitives(); - do_object(); -} - -template -static void do_previous_epoch_artifact(JfrArtifactClosure* callback, T* value) { - assert(callback != nullptr, "invariant"); - assert(value != nullptr, "invariant"); - if (USED_PREVIOUS_EPOCH(value)) { - callback->do_artifact(value); - } - if (IS_SERIALIZED(value)) { - CLEAR_SERIALIZED(value); - } - assert(IS_NOT_SERIALIZED(value), "invariant"); -} - -static void do_previous_epoch_klass(JfrArtifactClosure* callback, const Klass* value) { - assert(callback != nullptr, "invariant"); - assert(value != nullptr, "invariant"); - if (USED_PREVIOUS_EPOCH(value)) { - callback->do_artifact(value); +static void do_unloading_klass(Klass* klass) { + assert(klass != nullptr, "invariant"); + assert(_subsystem_callback != nullptr, "invariant"); + if (JfrKlassUnloading::on_unload(klass)) { + _subsystem_callback->do_artifact(klass); } } -static void do_klass_on_clear(Klass* klass) { +static void do_klass(Klass* klass) { assert(klass != nullptr, "invariant"); + assert(used(klass), "invariant"); assert(_subsystem_callback != nullptr, "invariant"); - do_previous_epoch_klass(_subsystem_callback, klass); + _subsystem_callback->do_artifact(klass); } -static void do_loader_klass_on_clear(const Klass* klass) { - if (klass != nullptr && _artifacts->should_do_loader_klass(klass)) { - if (_leakp_writer != nullptr) { - SET_LEAKP(klass); - } - SET_TRANSIENT(klass); - do_previous_epoch_klass(_subsystem_callback, klass); +static void do_klasses() { + if (unloading()) { + ClassLoaderDataGraph::classes_unloading_do(&do_unloading_klass); + return; } -} - -static void do_classloaders_on_clear() { - for (ClassHierarchyIterator iter(vmClasses::ClassLoader_klass()); !iter.done(); iter.next()) { - Klass* subk = iter.klass(); - if (is_classloader_klass_allowed(subk)) { - do_loader_klass_on_clear(subk); - } + if (is_initial_typeset_for_chunk()) { + // Only write the primitive classes once per chunk. + do_primitives(); } + JfrTraceIdLoadBarrier::do_klasses(&do_klass, previous_epoch()); } -static void do_object_on_clear() { - SET_TRANSIENT(vmClasses::Object_klass()); - do_klass_on_clear(vmClasses::Object_klass()); +static void do_klass_on_clear(Klass* klass) { + do_artifact(klass); } static void do_all_klasses() { ClassLoaderDataGraph::classes_do(&do_klass_on_clear); - do_classloaders_on_clear(); - do_object_on_clear(); } +// KlassWriter. typedef SerializePredicate KlassPredicate; typedef JfrPredicatedTypeWriterImplHost KlassWriterImpl; typedef JfrTypeWriterHost KlassWriter; + +// Klass registration. typedef CompositeFunctor KlassWriterRegistration; typedef JfrArtifactCallbackHost KlassCallback; @@ -422,29 +528,31 @@ class LeakPredicate { LeakPredicate(bool class_unload) {} bool operator()(const Klass* klass) { assert(klass != nullptr, "invariant"); - return IS_LEAKP(klass) || is_implied(klass); + return IS_LEAKP(klass); } }; +// KlassWriter for leakp. Only used during start or rotation, i.e. the previous epoch. typedef LeakPredicate LeakKlassPredicate; typedef JfrPredicatedTypeWriterImplHost LeakKlassWriterImpl; typedef JfrTypeWriterHost LeakKlassWriter; +// Composite KlassWriter with registration. typedef CompositeFunctor CompositeKlassWriter; typedef CompositeFunctor CompositeKlassWriterRegistration; typedef JfrArtifactCallbackHost CompositeKlassCallback; -static bool write_klasses() { +static void write_klasses() { assert(!_artifacts->has_klass_entries(), "invariant"); assert(_writer != nullptr, "invariant"); KlassArtifactRegistrator reg(_artifacts); - KlassWriter kw(_writer, _class_unload); + KlassWriter kw(_writer, unloading()); KlassWriterRegistration kwr(&kw, ®); if (_leakp_writer == nullptr) { KlassCallback callback(&_subsystem_callback, &kwr); do_klasses(); } else { - LeakKlassWriter lkw(_leakp_writer, _class_unload); + LeakKlassWriter lkw(_leakp_writer, unloading()); CompositeKlassWriter ckw(&lkw, &kw); CompositeKlassWriterRegistration ckwr(&ckw, ®); CompositeKlassCallback callback(&_subsystem_callback, &ckwr); @@ -455,32 +563,26 @@ static bool write_klasses() { // their count is not automatically incremented. kw.add(primitives_count); } - if (is_complete()) { - return false; - } _artifacts->tally(kw); - return true; } -static bool write_klasses_on_clear() { +static void write_klasses_on_clear() { assert(!_artifacts->has_klass_entries(), "invariant"); assert(_writer != nullptr, "invariant"); assert(_leakp_writer != nullptr, "invariant"); KlassArtifactRegistrator reg(_artifacts); - KlassWriter kw(_writer, _class_unload); + KlassWriter kw(_writer, unloading()); KlassWriterRegistration kwr(&kw, ®); - LeakKlassWriter lkw(_leakp_writer, _class_unload); + LeakKlassWriter lkw(_leakp_writer, unloading()); CompositeKlassWriter ckw(&lkw, &kw); CompositeKlassWriterRegistration ckwr(&ckw, ®); CompositeKlassCallback callback(&_subsystem_callback, &ckwr); do_all_klasses(); - if (is_complete()) { - return false; - } _artifacts->tally(kw); - return true; } +/***** Packages *****/ + static int write_package(JfrCheckpointWriter* writer, PkgPtr pkg, bool leakp) { assert(writer != nullptr, "invariant"); assert(_artifacts != nullptr, "invariant"); @@ -494,98 +596,101 @@ static int write_package(JfrCheckpointWriter* writer, PkgPtr pkg, bool leakp) { int write__package(JfrCheckpointWriter* writer, const void* p) { assert(p != nullptr, "invariant"); - PkgPtr pkg = (PkgPtr)p; + PkgPtr pkg = static_cast(p); set_serialized(pkg); return write_package(writer, pkg, false); } int write__package__leakp(JfrCheckpointWriter* writer, const void* p) { assert(p != nullptr, "invariant"); - PkgPtr pkg = (PkgPtr)p; + PkgPtr pkg = static_cast(p); CLEAR_LEAKP(pkg); return write_package(writer, pkg, true); } -static void do_package(PackageEntry* entry) { - do_previous_epoch_artifact(_subsystem_callback, entry); -} - -static void do_packages() { - ClassLoaderDataGraph::packages_do(&do_package); -} - -class PackageFieldSelector { - public: - typedef PkgPtr TypePtr; - static TypePtr select(KlassPtr klass) { - assert(klass != nullptr, "invariant"); - return klass->package(); - } -}; +// PackageWriter. typedef SerializePredicate PackagePredicate; typedef JfrPredicatedTypeWriterImplHost PackageWriterImpl; typedef JfrTypeWriterHost PackageWriter; -typedef CompositeFunctor > PackageWriterWithClear; +typedef JfrArtifactCallbackHost PackageCallback; + +// PackageWriter used during flush or unloading i.e. the current epoch. typedef KlassToFieldEnvelope KlassPackageWriter; -typedef JfrArtifactCallbackHost PackageCallback; +// PackageWriter with clear. Only used during start or rotation, i.e. the previous epoch. +typedef CompositeFunctor > PackageWriterWithClear; +typedef JfrArtifactCallbackHost PackageClearCallback; + +// PackageWriter for leakp. Only used during start or rotation, i.e. the previous epoch. typedef LeakPredicate LeakPackagePredicate; typedef JfrPredicatedTypeWriterImplHost LeakPackageWriterImpl; typedef JfrTypeWriterHost LeakPackageWriter; +// Composite PackageWriter with clear. Only used during start or rotation, i.e. the previous epoch. typedef CompositeFunctor CompositePackageWriter; -typedef KlassToFieldEnvelope KlassCompositePackageWriter; -typedef KlassToFieldEnvelope KlassPackageWriterWithClear; typedef CompositeFunctor > CompositePackageWriterWithClear; -typedef JfrArtifactCallbackHost CompositePackageCallback; +typedef JfrArtifactCallbackHost CompositePackageClearCallback; + +static void do_package(PackageEntry* pkg) { + do_artifact(pkg); +} + +static void do_all_packages() { + ClassLoaderDataGraph::packages_do(&do_package); +} + +static void do_all_packages(PackageWriter& pw) { + do_all_packages(); + _artifacts->tally(pw); +} + +static void do_packages(PackageWriter& pw) { + KlassPackageWriter kpw(&pw); + _artifacts->iterate_klasses(kpw); + _artifacts->tally(pw); +} + +static void write_packages_with_leakp(PackageWriter& pw) { + assert(_writer != nullptr, "invariant"); + assert(_leakp_writer != nullptr, "invariant"); + assert(previous_epoch(), "invariant"); + LeakPackageWriter lpw(_leakp_writer, unloading()); + CompositePackageWriter cpw(&lpw, &pw); + ClearArtifact clear; + CompositePackageWriterWithClear cpwwc(&cpw, &clear); + CompositePackageClearCallback callback(&_subsystem_callback, &cpwwc); + do_all_packages(pw); +} static void write_packages() { assert(_writer != nullptr, "invariant"); - PackageWriter pw(_writer, _class_unload); - KlassPackageWriter kpw(&pw); + PackageWriter pw(_writer, unloading()); if (current_epoch()) { - _artifacts->iterate_klasses(kpw); - _artifacts->tally(pw); + do_packages(pw); return; } assert(previous_epoch(), "invariant"); if (_leakp_writer == nullptr) { - _artifacts->iterate_klasses(kpw); ClearArtifact clear; PackageWriterWithClear pwwc(&pw, &clear); - PackageCallback callback(&_subsystem_callback, &pwwc); - do_packages(); - } else { - LeakPackageWriter lpw(_leakp_writer, _class_unload); - CompositePackageWriter cpw(&lpw, &pw); - KlassCompositePackageWriter kcpw(&cpw); - _artifacts->iterate_klasses(kcpw); - ClearArtifact clear; - CompositePackageWriterWithClear cpwwc(&cpw, &clear); - CompositePackageCallback callback(&_subsystem_callback, &cpwwc); - do_packages(); + PackageClearCallback callback(&_subsystem_callback, &pwwc); + do_all_packages(pw); + return; } - _artifacts->tally(pw); + write_packages_with_leakp(pw); } static void write_packages_on_clear() { assert(_writer != nullptr, "invariant"); assert(_leakp_writer != nullptr, "invariant"); assert(previous_epoch(), "invariant"); - PackageWriter pw(_writer, _class_unload); - KlassPackageWriter kpw(&pw); - LeakPackageWriter lpw(_leakp_writer, _class_unload); - CompositePackageWriter cpw(&lpw, &pw); - KlassCompositePackageWriter kcpw(&cpw); - _artifacts->iterate_klasses(kcpw); - ClearArtifact clear; - CompositePackageWriterWithClear cpwwc(&cpw, &clear); - CompositePackageCallback callback(&_subsystem_callback, &cpwwc); - do_packages(); - _artifacts->tally(pw); + PackageWriter pw(_writer, unloading()); + write_packages_with_leakp(pw); } +/***** Modules *****/ + static int write_module(JfrCheckpointWriter* writer, ModPtr mod, bool leakp) { assert(mod != nullptr, "invariant"); assert(_artifacts != nullptr, "invariant"); @@ -599,99 +704,101 @@ static int write_module(JfrCheckpointWriter* writer, ModPtr mod, bool leakp) { int write__module(JfrCheckpointWriter* writer, const void* m) { assert(m != nullptr, "invariant"); - ModPtr mod = (ModPtr)m; + ModPtr mod = static_cast(m); set_serialized(mod); return write_module(writer, mod, false); } int write__module__leakp(JfrCheckpointWriter* writer, const void* m) { assert(m != nullptr, "invariant"); - ModPtr mod = (ModPtr)m; + ModPtr mod = static_cast(m); CLEAR_LEAKP(mod); return write_module(writer, mod, true); } -static void do_module(ModuleEntry* entry) { - do_previous_epoch_artifact(_subsystem_callback, entry); -} - -static void do_modules() { - ClassLoaderDataGraph::modules_do(&do_module); -} - -class ModuleFieldSelector { - public: - typedef ModPtr TypePtr; - static TypePtr select(KlassPtr klass) { - assert(klass != nullptr, "invariant"); - PkgPtr pkg = klass->package(); - return pkg != nullptr ? pkg->module() : nullptr; - } -}; - +// ModuleWriter. typedef SerializePredicate ModulePredicate; typedef JfrPredicatedTypeWriterImplHost ModuleWriterImpl; typedef JfrTypeWriterHost ModuleWriter; -typedef CompositeFunctor > ModuleWriterWithClear; -typedef JfrArtifactCallbackHost ModuleCallback; +typedef JfrArtifactCallbackHost ModuleCallback; + +// ModuleWriter used during flush or unloading i.e. the current epoch. typedef KlassToFieldEnvelope KlassModuleWriter; +// ModuleWriter with clear. Only used during start or rotation, i.e. the previous epoch. +typedef CompositeFunctor > ModuleWriterWithClear; +typedef JfrArtifactCallbackHost ModuleClearCallback; + +// ModuleWriter for leakp. Only used during start or rotation, i.e. the previous epoch. typedef LeakPredicate LeakModulePredicate; typedef JfrPredicatedTypeWriterImplHost LeakModuleWriterImpl; typedef JfrTypeWriterHost LeakModuleWriter; +// Composite ModuleWriter with clear. Only used during start or rotation, i.e. the previous epoch. typedef CompositeFunctor CompositeModuleWriter; -typedef KlassToFieldEnvelope KlassCompositeModuleWriter; typedef CompositeFunctor > CompositeModuleWriterWithClear; -typedef JfrArtifactCallbackHost CompositeModuleCallback; +typedef JfrArtifactCallbackHost CompositeModuleClearCallback; + +static void do_module(ModuleEntry* mod) { + do_artifact(mod); +} + +static void do_all_modules() { + ClassLoaderDataGraph::modules_do(&do_module); +} + +static void do_all_modules(ModuleWriter& mw) { + do_all_modules(); + _artifacts->tally(mw); +} + +static void do_modules(ModuleWriter& mw) { + KlassModuleWriter kmw(&mw); + _artifacts->iterate_klasses(kmw); + _artifacts->tally(mw); +} + +static void write_modules_with_leakp(ModuleWriter& mw) { + assert(_writer != nullptr, "invariant"); + assert(_leakp_writer != nullptr, "invariant"); + assert(previous_epoch(), "invariant"); + LeakModuleWriter lmw(_leakp_writer, unloading()); + CompositeModuleWriter cmw(&lmw, &mw); + ClearArtifact clear; + CompositeModuleWriterWithClear cmwwc(&cmw, &clear); + CompositeModuleClearCallback callback(&_subsystem_callback, &cmwwc); + do_all_modules(mw); +} static void write_modules() { assert(_writer != nullptr, "invariant"); - ModuleWriter mw(_writer, _class_unload); - KlassModuleWriter kmw(&mw); + ModuleWriter mw(_writer, unloading()); if (current_epoch()) { - _artifacts->iterate_klasses(kmw); - _artifacts->tally(mw); + do_modules(mw); return; } assert(previous_epoch(), "invariant"); if (_leakp_writer == nullptr) { - _artifacts->iterate_klasses(kmw); ClearArtifact clear; ModuleWriterWithClear mwwc(&mw, &clear); - ModuleCallback callback(&_subsystem_callback, &mwwc); - do_modules(); - } else { - LeakModuleWriter lmw(_leakp_writer, _class_unload); - CompositeModuleWriter cmw(&lmw, &mw); - KlassCompositeModuleWriter kcpw(&cmw); - _artifacts->iterate_klasses(kcpw); - ClearArtifact clear; - CompositeModuleWriterWithClear cmwwc(&cmw, &clear); - CompositeModuleCallback callback(&_subsystem_callback, &cmwwc); - do_modules(); + ModuleClearCallback callback(&_subsystem_callback, &mwwc); + do_all_modules(mw); + return; } - _artifacts->tally(mw); + write_modules_with_leakp(mw); } static void write_modules_on_clear() { assert(_writer != nullptr, "invariant"); assert(_leakp_writer != nullptr, "invariant"); assert(previous_epoch(), "invariant"); - ModuleWriter mw(_writer, _class_unload); - KlassModuleWriter kmw(&mw); - LeakModuleWriter lmw(_leakp_writer, _class_unload); - CompositeModuleWriter cmw(&lmw, &mw); - KlassCompositeModuleWriter kcpw(&cmw); - _artifacts->iterate_klasses(kcpw); - ClearArtifact clear; - CompositeModuleWriterWithClear cmwwc(&cmw, &clear); - CompositeModuleCallback callback(&_subsystem_callback, &cmwwc); - do_modules(); - _artifacts->tally(mw); + ModuleWriter mw(_writer, unloading()); + write_modules_with_leakp(mw); } -static int write_classloader(JfrCheckpointWriter* writer, CldPtr cld, bool leakp) { +/***** ClassLoaderData - CLD *****/ + +static int write_cld(JfrCheckpointWriter* writer, CldPtr cld, bool leakp) { assert(cld != nullptr, "invariant"); // class loader type const Klass* class_loader_klass = cld->class_loader_klass(); @@ -701,7 +808,7 @@ static int write_classloader(JfrCheckpointWriter* writer, CldPtr cld, bool leakp writer->write((traceid)0); // class loader type id (absence of) writer->write(get_bootstrap_name(leakp)); // maps to synthetic name -> "bootstrap" } else { - assert(_class_unload ? true : IS_SERIALIZED(class_loader_klass), "invariant"); + assert(IS_SERIALIZED(class_loader_klass), "invariant"); writer->write(artifact_id(cld)); // class loader instance id writer->write(artifact_id(class_loader_klass)); // class loader type id writer->write(mark_symbol(cld->name(), leakp)); // class loader instance name @@ -709,146 +816,127 @@ static int write_classloader(JfrCheckpointWriter* writer, CldPtr cld, bool leakp return 1; } -int write__classloader(JfrCheckpointWriter* writer, const void* c) { +int write__cld(JfrCheckpointWriter* writer, const void* c) { assert(c != nullptr, "invariant"); - CldPtr cld = (CldPtr)c; + CldPtr cld = static_cast(c); set_serialized(cld); - return write_classloader(writer, cld, false); + return write_cld(writer, cld, false); } -int write__classloader__leakp(JfrCheckpointWriter* writer, const void* c) { +int write__cld__leakp(JfrCheckpointWriter* writer, const void* c) { assert(c != nullptr, "invariant"); - CldPtr cld = (CldPtr)c; + CldPtr cld = static_cast(c); CLEAR_LEAKP(cld); - return write_classloader(writer, cld, true); + return write_cld(writer, cld, true); } -static void do_class_loader_data(ClassLoaderData* cld) { - do_previous_epoch_artifact(_subsystem_callback, cld); -} +// CldWriter. +typedef SerializePredicate CldPredicate; +typedef JfrPredicatedTypeWriterImplHost CldWriterImpl; +typedef JfrTypeWriterHost CldWriter; +typedef JfrArtifactCallbackHost CldCallback; -class KlassCldFieldSelector { - public: - typedef CldPtr TypePtr; - static TypePtr select(KlassPtr klass) { - assert(klass != nullptr, "invariant"); - return get_cld(klass); - } -}; +// CldWriter used during flush or unloading i.e. the current epoch. +typedef KlassToFieldEnvelope KlassCldWriter; +typedef KlassToFieldEnvelope ModuleCldWriter; +typedef CompositeFunctor KlassAndModuleCldWriter; -class ModuleCldFieldSelector { -public: - typedef CldPtr TypePtr; - static TypePtr select(KlassPtr klass) { - assert(klass != nullptr, "invariant"); - ModPtr mod = ModuleFieldSelector::select(klass); - return mod != nullptr ? mod->loader_data() : nullptr; - } -}; +// CldWriter with clear. Only used during start or rotation, i.e. the previous epoch. +typedef CompositeFunctor > CldWriterWithClear; +typedef JfrArtifactCallbackHost CldClearCallback; + +// CldWriter for leakp. Only used during start or rotation, i.e. the previous epoch. +typedef LeakPredicate LeakCldPredicate; +typedef JfrPredicatedTypeWriterImplHost LeakCldWriterImpl; +typedef JfrTypeWriterHost LeakCldWriter; + +// Composite CldWriter with clear. Only used during start or rotation, i.e. the previous epoch. +typedef CompositeFunctor CompositeCldWriter; +typedef CompositeFunctor > CompositeCldWriterWithClear; +typedef JfrArtifactCallbackHost CompositeCldClearCallback; class CLDCallback : public CLDClosure { public: - CLDCallback() {} void do_cld(ClassLoaderData* cld) { assert(cld != nullptr, "invariant"); - if (cld->has_class_mirror_holder()) { - return; + if (!cld->has_class_mirror_holder()) { + do_artifact(cld); } - do_class_loader_data(cld); } }; -static void do_class_loaders() { +static void do_all_clds() { CLDCallback cld_cb; ClassLoaderDataGraph::loaded_cld_do(&cld_cb); } -typedef SerializePredicate CldPredicate; -typedef JfrPredicatedTypeWriterImplHost CldWriterImpl; -typedef JfrTypeWriterHost CldWriter; -typedef CompositeFunctor > CldWriterWithClear; -typedef JfrArtifactCallbackHost CldCallback; -typedef KlassToFieldEnvelope KlassCldWriter; -typedef KlassToFieldEnvelope ModuleCldWriter; -typedef CompositeFunctor KlassAndModuleCldWriter; - -typedef LeakPredicate LeakCldPredicate; -typedef JfrPredicatedTypeWriterImplHost LeakCldWriterImpl; -typedef JfrTypeWriterHost LeakCldWriter; - -typedef CompositeFunctor CompositeCldWriter; -typedef KlassToFieldEnvelope KlassCompositeCldWriter; -typedef KlassToFieldEnvelope ModuleCompositeCldWriter; -typedef CompositeFunctor KlassAndModuleCompositeCldWriter; -typedef CompositeFunctor > CompositeCldWriterWithClear; -typedef JfrArtifactCallbackHost CompositeCldCallback; +static void do_all_clds(CldWriter& cldw) { + do_all_clds(); + _artifacts->tally(cldw); +} -static void write_classloaders() { - assert(_writer != nullptr, "invariant"); - CldWriter cldw(_writer, _class_unload); +static void do_clds(CldWriter& cldw) { KlassCldWriter kcw(&cldw); ModuleCldWriter mcw(&cldw); KlassAndModuleCldWriter kmcw(&kcw, &mcw); + _artifacts->iterate_klasses(kmcw); + _artifacts->tally(cldw); +} + +static void write_clds_with_leakp(CldWriter& cldw) { + assert(_writer != nullptr, "invariant"); + assert(_leakp_writer != nullptr, "invariant"); + assert(previous_epoch(), "invariant"); + LeakCldWriter lcldw(_leakp_writer, unloading()); + CompositeCldWriter ccldw(&lcldw, &cldw); + ClearArtifact clear; + CompositeCldWriterWithClear ccldwwc(&ccldw, &clear); + CompositeCldClearCallback callback(&_subsystem_callback, &ccldwwc); + do_all_clds(cldw); +} + +static void write_clds() { + assert(_writer != nullptr, "invariant"); + CldWriter cldw(_writer, unloading()); if (current_epoch()) { - _artifacts->iterate_klasses(kmcw); - _artifacts->tally(cldw); + do_clds(cldw); return; } assert(previous_epoch(), "invariant"); if (_leakp_writer == nullptr) { - _artifacts->iterate_klasses(kmcw); ClearArtifact clear; CldWriterWithClear cldwwc(&cldw, &clear); - CldCallback callback(&_subsystem_callback, &cldwwc); - do_class_loaders(); - } else { - LeakCldWriter lcldw(_leakp_writer, _class_unload); - CompositeCldWriter ccldw(&lcldw, &cldw); - KlassCompositeCldWriter kccldw(&ccldw); - ModuleCompositeCldWriter mccldw(&ccldw); - KlassAndModuleCompositeCldWriter kmccldw(&kccldw, &mccldw); - _artifacts->iterate_klasses(kmccldw); - ClearArtifact clear; - CompositeCldWriterWithClear ccldwwc(&ccldw, &clear); - CompositeCldCallback callback(&_subsystem_callback, &ccldwwc); - do_class_loaders(); + CldClearCallback callback(&_subsystem_callback, &cldwwc); + do_all_clds(cldw); + return; } - _artifacts->tally(cldw); + write_clds_with_leakp(cldw); } -static void write_classloaders_on_clear() { +static void write_clds_on_clear() { assert(_writer != nullptr, "invariant"); assert(_leakp_writer != nullptr, "invariant"); - CldWriter cldw(_writer, _class_unload); - KlassCldWriter kcw(&cldw); - ModuleCldWriter mcw(&cldw); - KlassAndModuleCldWriter kmcw(&kcw, &mcw); - LeakCldWriter lcldw(_leakp_writer, _class_unload); - CompositeCldWriter ccldw(&lcldw, &cldw); - KlassCompositeCldWriter kccldw(&ccldw); - ModuleCompositeCldWriter mccldw(&ccldw); - KlassAndModuleCompositeCldWriter kmccldw(&kccldw, &mccldw); - _artifacts->iterate_klasses(kmccldw); - ClearArtifact clear; - CompositeCldWriterWithClear ccldwwc(&ccldw, &clear); - CompositeCldCallback callback(&_subsystem_callback, &ccldwwc); - do_class_loaders(); - _artifacts->tally(cldw); + assert(previous_epoch(), "invariant"); + CldWriter cldw(_writer, unloading()); + write_clds_with_leakp(cldw); } -static u1 get_visibility(MethodPtr method) { - assert(method != nullptr, "invariant"); - return const_cast(method)->is_hidden() ? (u1)1 : (u1)0; -} +/***** Methods *****/ template <> void set_serialized(MethodPtr method) { assert(method != nullptr, "invariant"); - SET_METHOD_SERIALIZED(method); - assert(METHOD_IS_SERIALIZED(method), "invariant"); if (current_epoch()) { CLEAR_THIS_EPOCH_METHOD_CLEARED_BIT(method); } + assert(unloading() ? true : METHOD_IS_NOT_SERIALIZED(method), "invariant"); + SET_METHOD_SERIALIZED(method); + assert(METHOD_IS_SERIALIZED(method), "invariant"); +} + +static inline u1 get_visibility(MethodPtr method) { + assert(method != nullptr, "invariant"); + return const_cast(method)->is_hidden() ? (u1)1 : (u1)0; } static int write_method(JfrCheckpointWriter* writer, MethodPtr method, bool leakp) { @@ -857,58 +945,36 @@ static int write_method(JfrCheckpointWriter* writer, MethodPtr method, bool leak assert(_artifacts != nullptr, "invariant"); KlassPtr klass = method->method_holder(); assert(klass != nullptr, "invariant"); + assert(used(klass), "invariant"); + assert(IS_SERIALIZED(klass), "invariant"); writer->write(method_id(klass, method)); writer->write(artifact_id(klass)); writer->write(mark_symbol(method->name(), leakp)); writer->write(mark_symbol(method->signature(), leakp)); - writer->write((u2)get_flags(method)); + writer->write(static_cast(get_flags(method))); writer->write(get_visibility(method)); return 1; } int write__method(JfrCheckpointWriter* writer, const void* m) { assert(m != nullptr, "invariant"); - MethodPtr method = (MethodPtr)m; + MethodPtr method = static_cast(m); set_serialized(method); return write_method(writer, method, false); } int write__method__leakp(JfrCheckpointWriter* writer, const void* m) { assert(m != nullptr, "invariant"); - MethodPtr method = (MethodPtr)m; + MethodPtr method = static_cast(m); CLEAR_LEAKP_METHOD(method); return write_method(writer, method, true); } - -class BitMapFilter { - ResourceBitMap _bitmap; - public: - explicit BitMapFilter(int length = 0) : _bitmap((size_t)length) {} - bool operator()(size_t idx) { - if (_bitmap.size() == 0) { - return true; - } - if (_bitmap.at(idx)) { - return false; - } - _bitmap.set_bit(idx); - return true; - } -}; - -class AlwaysTrue { - public: - explicit AlwaysTrue(int length = 0) {} - bool operator()(size_t idx) { - return true; - } -}; - -template +template class MethodIteratorHost { private: MethodCallback _method_cb; KlassCallback _klass_cb; + KlassUsedPredicate _klass_used_predicate; MethodUsedPredicate _method_used_predicate; MethodFlagPredicate _method_flag_predicate; public: @@ -918,6 +984,7 @@ class MethodIteratorHost { bool skip_header = false) : _method_cb(writer, class_unload, skip_header), _klass_cb(writer, class_unload, skip_header), + _klass_used_predicate(current_epoch), _method_used_predicate(current_epoch), _method_flag_predicate(current_epoch) {} @@ -937,7 +1004,7 @@ class MethodIteratorHost { ik = ik->previous_versions(); } } - return _klass_cb(klass); + return _klass_used_predicate(klass) ? _klass_cb(klass) : true; } int count() const { return _method_cb.count(); } @@ -964,37 +1031,42 @@ typedef SerializePredicate MethodPredicate; typedef JfrPredicatedTypeWriterImplHost MethodWriterImplTarget; typedef Wrapper KlassCallbackStub; typedef JfrTypeWriterHost MethodWriterImpl; -typedef MethodIteratorHost MethodWriter; +typedef MethodIteratorHost MethodWriter; typedef LeakPredicate LeakMethodPredicate; typedef JfrPredicatedTypeWriterImplHost LeakMethodWriterImplTarget; typedef JfrTypeWriterHost LeakMethodWriterImpl; -typedef MethodIteratorHost LeakMethodWriter; -typedef MethodIteratorHost LeakMethodWriter; +typedef MethodIteratorHost LeakMethodWriter; +typedef MethodIteratorHost LeakMethodWriter; typedef CompositeFunctor CompositeMethodWriter; +static void write_methods_with_leakp(MethodWriter& mw) { + assert(_writer != nullptr, "invariant"); + assert(_leakp_writer != nullptr, "invariant"); + assert(previous_epoch(), "invariant"); + LeakMethodWriter lpmw(_leakp_writer, current_epoch(), unloading()); + CompositeMethodWriter cmw(&lpmw, &mw); + _artifacts->iterate_klasses(cmw); + _artifacts->tally(mw); +} + static void write_methods() { assert(_writer != nullptr, "invariant"); - MethodWriter mw(_writer, current_epoch(), _class_unload); + MethodWriter mw(_writer, current_epoch(), unloading()); if (_leakp_writer == nullptr) { _artifacts->iterate_klasses(mw); - } else { - LeakMethodWriter lpmw(_leakp_writer, current_epoch(), _class_unload); - CompositeMethodWriter cmw(&lpmw, &mw); - _artifacts->iterate_klasses(cmw); + _artifacts->tally(mw); + return; } - _artifacts->tally(mw); + write_methods_with_leakp(mw); } static void write_methods_on_clear() { assert(_writer != nullptr, "invariant"); assert(_leakp_writer != nullptr, "invariant"); assert(previous_epoch(), "invariant"); - MethodWriter mw(_writer, current_epoch(), _class_unload); - LeakMethodWriter lpmw(_leakp_writer, current_epoch(), _class_unload); - CompositeMethodWriter cmw(&lpmw, &mw); - _artifacts->iterate_klasses(cmw); - _artifacts->tally(mw); + MethodWriter mw(_writer, current_epoch(), unloading()); + write_methods_with_leakp(mw); } template <> @@ -1022,14 +1094,14 @@ static int write_symbol(JfrCheckpointWriter* writer, SymbolEntryPtr entry, bool int write__symbol(JfrCheckpointWriter* writer, const void* e) { assert(e != nullptr, "invariant"); - SymbolEntryPtr entry = (SymbolEntryPtr)e; + SymbolEntryPtr entry = static_cast(e); set_serialized(entry); return write_symbol(writer, entry, false); } int write__symbol__leakp(JfrCheckpointWriter* writer, const void* e) { assert(e != nullptr, "invariant"); - SymbolEntryPtr entry = (SymbolEntryPtr)e; + SymbolEntryPtr entry = static_cast(e); return write_symbol(writer, entry, true); } @@ -1043,14 +1115,14 @@ static int write_string(JfrCheckpointWriter* writer, StringEntryPtr entry, bool int write__string(JfrCheckpointWriter* writer, const void* e) { assert(e != nullptr, "invariant"); - StringEntryPtr entry = (StringEntryPtr)e; + StringEntryPtr entry = static_cast(e); set_serialized(entry); return write_string(writer, entry, false); } int write__string__leakp(JfrCheckpointWriter* writer, const void* e) { assert(e != nullptr, "invariant"); - StringEntryPtr entry = (StringEntryPtr)e; + StringEntryPtr entry = static_cast(e); return write_string(writer, entry, true); } @@ -1071,30 +1143,15 @@ typedef JfrTypeWriterHost LeakStringEntr typedef CompositeFunctor CompositeStringWriter; static void write_symbols_with_leakp() { - assert(_leakp_writer != nullptr, "invariant"); - SymbolEntryWriter sw(_writer, _class_unload); - LeakSymbolEntryWriter lsw(_leakp_writer, _class_unload); - CompositeSymbolWriter csw(&lsw, &sw); - _artifacts->iterate_symbols(csw); - StringEntryWriter sew(_writer, _class_unload, true); // skip header - LeakStringEntryWriter lsew(_leakp_writer, _class_unload, true); // skip header - CompositeStringWriter csew(&lsew, &sew); - _artifacts->iterate_strings(csew); - sw.add(sew.count()); - lsw.add(lsew.count()); - _artifacts->tally(sw); -} - -static void write_symbols_on_clear() { assert(_writer != nullptr, "invariant"); assert(_leakp_writer != nullptr, "invariant"); assert(previous_epoch(), "invariant"); - SymbolEntryWriter sw(_writer, _class_unload); - LeakSymbolEntryWriter lsw(_leakp_writer, _class_unload); + SymbolEntryWriter sw(_writer, unloading()); + LeakSymbolEntryWriter lsw(_leakp_writer, unloading()); CompositeSymbolWriter csw(&lsw, &sw); _artifacts->iterate_symbols(csw); - StringEntryWriter sew(_writer, _class_unload, true); // skip header - LeakStringEntryWriter lsew(_leakp_writer, _class_unload, true); // skip header + StringEntryWriter sew(_writer, unloading(), true); // skip header + LeakStringEntryWriter lsew(_leakp_writer, unloading(), true); // skip header CompositeStringWriter csew(&lsew, &sew); _artifacts->iterate_strings(csew); sw.add(sew.count()); @@ -1108,17 +1165,24 @@ static void write_symbols() { write_symbols_with_leakp(); return; } - SymbolEntryWriter sw(_writer, _class_unload); + SymbolEntryWriter sw(_writer, unloading()); _artifacts->iterate_symbols(sw); - StringEntryWriter sew(_writer, _class_unload, true); // skip header + StringEntryWriter sew(_writer, unloading(), true); // skip header _artifacts->iterate_strings(sew); sw.add(sew.count()); _artifacts->tally(sw); } +static void write_symbols_on_clear() { + assert(_writer != nullptr, "invariant"); + assert(_leakp_writer != nullptr, "invariant"); + assert(previous_epoch(), "invariant"); + write_symbols_with_leakp(); +} + typedef Wrapper ClearKlassBits; typedef Wrapper ClearMethodFlag; -typedef MethodIteratorHost ClearKlassAndMethods; +typedef MethodIteratorHost ClearKlassAndMethods; static void clear_klasses_and_methods() { ClearKlassAndMethods clear(_writer); @@ -1165,19 +1229,17 @@ size_t JfrTypeSet::serialize(JfrCheckpointWriter* writer, JfrCheckpointWriter* l setup(writer, leakp_writer, class_unload, flushpoint); // write order is important because an individual write step // might tag an artifact to be written in a subsequent step - if (!write_klasses()) { - return 0; - } + write_klasses(); write_packages(); write_modules(); - write_classloaders(); + write_clds(); write_methods(); write_symbols(); return teardown(); } /** - * Clear all tags from the previous epoch. + * Clear all tags from the previous epoch. Reset support structures. */ void JfrTypeSet::clear(JfrCheckpointWriter* writer, JfrCheckpointWriter* leakp_writer) { ResourceMark rm; @@ -1185,7 +1247,7 @@ void JfrTypeSet::clear(JfrCheckpointWriter* writer, JfrCheckpointWriter* leakp_w write_klasses_on_clear(); write_packages_on_clear(); write_modules_on_clear(); - write_classloaders_on_clear(); + write_clds_on_clear(); write_methods_on_clear(); write_symbols_on_clear(); teardown(); diff --git a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.cpp b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.cpp index 0876281d53f..883821f853c 100644 --- a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.cpp +++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.cpp @@ -32,7 +32,8 @@ JfrArtifactSet::JfrArtifactSet(bool class_unload) : _symbol_table(nullptr), _klass_list(nullptr), - _total_count(0) { + _total_count(0), + _class_unload(class_unload) { initialize(class_unload); assert(_klass_list != nullptr, "invariant"); } @@ -41,6 +42,7 @@ static const size_t initial_klass_list_size = 256; const int initial_klass_loader_set_size = 64; void JfrArtifactSet::initialize(bool class_unload) { + _class_unload = class_unload; if (_symbol_table == nullptr) { _symbol_table = JfrSymbolTable::create(); assert(_symbol_table != nullptr, "invariant"); @@ -51,6 +53,11 @@ void JfrArtifactSet::initialize(bool class_unload) { // resource allocation _klass_list = new GrowableArray(initial_klass_list_size); _klass_loader_set = new GrowableArray(initial_klass_loader_set_size); + _klass_loader_leakp_set = new GrowableArray(initial_klass_loader_set_size); + + if (class_unload) { + _unloading_set = new GrowableArray(initial_klass_list_size); + } } void JfrArtifactSet::clear() { @@ -97,10 +104,27 @@ int JfrArtifactSet::entries() const { return _klass_list->length(); } -bool JfrArtifactSet::should_do_loader_klass(const Klass* k) { +static inline bool not_in_set(GrowableArray* set, const Klass* k) { + assert(set != nullptr, "invariant"); + assert(k != nullptr, "invariant"); + return !JfrMutablePredicate::test(set, k); +} + +bool JfrArtifactSet::should_do_cld_klass(const Klass* k, bool leakp) { assert(k != nullptr, "invariant"); assert(_klass_loader_set != nullptr, "invariant"); - return !JfrMutablePredicate::test(_klass_loader_set, k); + assert(_klass_loader_leakp_set != nullptr, "invariant"); + return not_in_set(leakp ? _klass_loader_leakp_set : _klass_loader_set, k); +} + +bool JfrArtifactSet::should_do_unloading_artifact(const void* ptr) { + assert(ptr != nullptr, "invariant"); + assert(_class_unload, "invariant"); + assert(_unloading_set != nullptr, "invariant"); + // The incoming pointers are of all kinds of different types. + // However, we are only interested in set membership. + // Treat them uniformly as const Klass* for simplicity and code reuse. + return not_in_set(_unloading_set, static_cast(ptr)); } void JfrArtifactSet::register_klass(const Klass* k) { diff --git a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.hpp b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.hpp index b0c2d989de5..24424fdef3a 100644 --- a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.hpp +++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSetUtils.hpp @@ -114,28 +114,6 @@ class ClearArtifact { } }; -template -class SerializePredicate { - bool _class_unload; - public: - SerializePredicate(bool class_unload) : _class_unload(class_unload) {} - bool operator()(T const& value) { - assert(value != nullptr, "invariant"); - return _class_unload ? true : IS_NOT_SERIALIZED(value); - } -}; - -template <> -class SerializePredicate { - bool _class_unload; - public: - SerializePredicate(bool class_unload) : _class_unload(class_unload) {} - bool operator()(const Method* method) { - assert(method != nullptr, "invariant"); - return _class_unload ? true : METHOD_IS_NOT_SERIALIZED(method); - } -}; - template class SymbolPredicate { bool _class_unload; @@ -150,11 +128,23 @@ class SymbolPredicate { } }; +class KlassUsedPredicate { + bool _current_epoch; +public: + KlassUsedPredicate(bool current_epoch) : _current_epoch(current_epoch) {} + bool operator()(const Klass* klass) { + return _current_epoch ? USED_THIS_EPOCH(klass) : USED_PREVIOUS_EPOCH(klass); + } +}; + class MethodUsedPredicate { bool _current_epoch; public: MethodUsedPredicate(bool current_epoch) : _current_epoch(current_epoch) {} bool operator()(const Klass* klass) { + if (!klass->is_instance_klass()) { + return false; + } return _current_epoch ? METHOD_USED_THIS_EPOCH(klass) : METHOD_USED_PREVIOUS_EPOCH(klass); } }; @@ -210,7 +200,10 @@ class JfrArtifactSet : public JfrCHeapObj { JfrSymbolTable* _symbol_table; GrowableArray* _klass_list; GrowableArray* _klass_loader_set; + GrowableArray* _klass_loader_leakp_set; + GrowableArray* _unloading_set; size_t _total_count; + bool _class_unload; public: JfrArtifactSet(bool class_unload); @@ -235,14 +228,20 @@ class JfrArtifactSet : public JfrCHeapObj { int entries() const; size_t total_count() const; void register_klass(const Klass* k); - bool should_do_loader_klass(const Klass* k); + bool should_do_cld_klass(const Klass* k, bool leakp); + bool should_do_unloading_artifact(const void* ptr); void increment_checkpoint_id(); template void iterate_klasses(Functor& functor) const { for (int i = 0; i < _klass_list->length(); ++i) { if (!functor(_klass_list->at(i))) { - break; + return; + } + } + for (int i = 0; i < _klass_loader_set->length(); ++i) { + if (!functor(_klass_loader_set->at(i))) { + return; } } } diff --git a/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceIdLoadBarrier.inline.hpp b/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceIdLoadBarrier.inline.hpp index e5b9a33ef56..13853e14a13 100644 --- a/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceIdLoadBarrier.inline.hpp +++ b/src/hotspot/share/jfr/recorder/checkpoint/types/traceid/jfrTraceIdLoadBarrier.inline.hpp @@ -33,6 +33,7 @@ #include "jfr/recorder/checkpoint/types/traceid/jfrTraceIdBits.inline.hpp" #include "jfr/recorder/checkpoint/types/traceid/jfrTraceIdEpoch.hpp" #include "jfr/recorder/checkpoint/types/traceid/jfrTraceIdMacros.hpp" +#include "jfr/support/jfrKlassExtension.hpp" #include "oops/klass.hpp" #include "oops/method.hpp" #include "runtime/javaThread.hpp" @@ -66,10 +67,14 @@ inline traceid set_used_and_get(const T* type) { return TRACE_ID(type); } +// We set the 'method_and_class' bits to have a consistent +// bit pattern set always. This is because the tag is non-atomic, +// hence, we always need the same bit pattern in an epoch to avoid losing information. inline void JfrTraceIdLoadBarrier::load_barrier(const Klass* klass) { - SET_USED_THIS_EPOCH(klass); - enqueue(klass); - JfrTraceIdEpoch::set_changed_tag_state(); + SET_METHOD_AND_CLASS_USED_THIS_EPOCH(klass); + assert(METHOD_AND_CLASS_USED_THIS_EPOCH(klass), "invariant"); + enqueue(klass); + JfrTraceIdEpoch::set_changed_tag_state(); } inline traceid JfrTraceIdLoadBarrier::load(const Klass* klass) { @@ -113,26 +118,36 @@ inline traceid JfrTraceIdLoadBarrier::load_no_enqueue(const Klass* klass, const return (METHOD_ID(klass, method)); } -inline traceid JfrTraceIdLoadBarrier::load(const ModuleEntry* module) { - return set_used_and_get(module); -} - -inline traceid JfrTraceIdLoadBarrier::load(const PackageEntry* package) { - return set_used_and_get(package); -} - inline traceid JfrTraceIdLoadBarrier::load(const ClassLoaderData* cld) { assert(cld != nullptr, "invariant"); if (cld->has_class_mirror_holder()) { return 0; } const Klass* const class_loader_klass = cld->class_loader_klass(); - if (class_loader_klass != nullptr && should_tag(class_loader_klass)) { - load_barrier(class_loader_klass); + if (class_loader_klass != nullptr) { + load(class_loader_klass); } return set_used_and_get(cld); } +inline traceid JfrTraceIdLoadBarrier::load(const ModuleEntry* module) { + assert(module != nullptr, "invariant"); + const ClassLoaderData* cld = module->loader_data(); + if (cld != nullptr) { + load(cld); + } + return set_used_and_get(module); +} + +inline traceid JfrTraceIdLoadBarrier::load(const PackageEntry* package) { + assert(package != nullptr, "invariant"); + const ModuleEntry* const module_entry = package->module(); + if (module_entry != nullptr) { + load(module_entry); + } + return set_used_and_get(package); +} + inline traceid JfrTraceIdLoadBarrier::load_leakp(const Klass* klass, const Method* method) { assert(klass != nullptr, "invariant"); assert(METHOD_AND_CLASS_USED_THIS_EPOCH(klass), "invariant"); diff --git a/src/hotspot/share/jfr/recorder/jfrRecorder.cpp b/src/hotspot/share/jfr/recorder/jfrRecorder.cpp index 40c3d7a8c4f..cc460f8c2aa 100644 --- a/src/hotspot/share/jfr/recorder/jfrRecorder.cpp +++ b/src/hotspot/share/jfr/recorder/jfrRecorder.cpp @@ -86,9 +86,6 @@ bool JfrRecorder::create_oop_storages() { return ObjectSampler::create_oop_storage(); } -// Subsystem -static JfrCheckpointManager* _checkpoint_manager = nullptr; - bool JfrRecorder::on_create_vm_1() { if (!is_disabled()) { if (FlightRecorder || is_started_on_commandline()) { @@ -99,9 +96,10 @@ bool JfrRecorder::on_create_vm_1() { return false; } - _checkpoint_manager = JfrCheckpointManager::create(); - if (_checkpoint_manager == nullptr || !_checkpoint_manager->initialize_early()) { - return false; + if (is_started_on_commandline()) { + if (!create_checkpoint_manager()) { + return false; + } } // fast time initialization @@ -292,7 +290,7 @@ bool JfrRecorder::create_components() { if (!create_storage()) { return false; } - if (!create_checkpoint_manager()) { + if (!initialize_checkpoint_manager()) { return false; } if (!create_stacktrace_repository()) { @@ -321,6 +319,7 @@ static JfrStackTraceRepository* _stack_trace_repository; static JfrStringPool* _stringpool = nullptr; static JfrOSInterface* _os_interface = nullptr; static JfrThreadSampling* _thread_sampling = nullptr; +static JfrCheckpointManager* _checkpoint_manager = nullptr; bool JfrRecorder::create_java_event_writer() { return JfrJavaEventWriter::initialize(); @@ -357,6 +356,17 @@ bool JfrRecorder::create_storage() { } bool JfrRecorder::create_checkpoint_manager() { + assert(_checkpoint_manager == nullptr, "invariant"); + _checkpoint_manager = JfrCheckpointManager::create(); + return _checkpoint_manager != nullptr && _checkpoint_manager->initialize_early(); +} + +bool JfrRecorder::initialize_checkpoint_manager() { + if (_checkpoint_manager == nullptr) { + if (!create_checkpoint_manager()) { + return false; + } + } assert(_checkpoint_manager != nullptr, "invariant"); assert(_repository != nullptr, "invariant"); return _checkpoint_manager->initialize(&_repository->chunkwriter()); diff --git a/src/hotspot/share/jfr/recorder/jfrRecorder.hpp b/src/hotspot/share/jfr/recorder/jfrRecorder.hpp index 3e2541fad98..9f4969b0187 100644 --- a/src/hotspot/share/jfr/recorder/jfrRecorder.hpp +++ b/src/hotspot/share/jfr/recorder/jfrRecorder.hpp @@ -42,6 +42,7 @@ class JfrRecorder : public JfrCHeapObj { static bool on_create_vm_2(); static bool on_create_vm_3(); static bool create_checkpoint_manager(); + static bool initialize_checkpoint_manager(); static bool create_chunk_repository(); static bool create_java_event_writer(); static bool create_jvmti_agent(); diff --git a/src/hotspot/share/jfr/recorder/storage/jfrMemorySpace.inline.hpp b/src/hotspot/share/jfr/recorder/storage/jfrMemorySpace.inline.hpp index 09a452caaa5..49ced300e55 100644 --- a/src/hotspot/share/jfr/recorder/storage/jfrMemorySpace.inline.hpp +++ b/src/hotspot/share/jfr/recorder/storage/jfrMemorySpace.inline.hpp @@ -626,8 +626,8 @@ inline bool ReinitializeAllReleaseRetiredOp::process(typename const bool retired = node->retired(); node->reinitialize(); assert(node->empty(), "invariant"); - assert(!node->retired(), "invariant"); if (retired) { + assert(!node->retired(), "invariant"); _prev = _list.excise(_prev, node); node->release(); mspace_release(node, _mspace); diff --git a/src/hotspot/share/jfr/support/jfrDeprecationManager.cpp b/src/hotspot/share/jfr/support/jfrDeprecationManager.cpp index a36b85dbb7e..5f5c87d239c 100644 --- a/src/hotspot/share/jfr/support/jfrDeprecationManager.cpp +++ b/src/hotspot/share/jfr/support/jfrDeprecationManager.cpp @@ -371,8 +371,10 @@ void JfrDeprecationManager::write_edges(JfrChunkWriter& cw, Thread* thread, bool void JfrDeprecationManager::on_type_set(JfrCheckpointWriter& writer, JfrChunkWriter* cw, Thread* thread) { assert(_pending_list.is_empty(), "invariant"); - if (writer.has_data() && _pending_head != nullptr) { + if (_pending_head != nullptr) { save_type_set_blob(writer); + } else { + writer.cancel(); } if (cw != nullptr) { write_edges(*cw, thread); diff --git a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp index 5fdc70d7bc7..bac9a786fd9 100644 --- a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp +++ b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp @@ -220,6 +220,7 @@ nonstatic_field(JavaThread, _lock_stack, LockStack) \ JVMTI_ONLY(nonstatic_field(JavaThread, _is_in_VTMS_transition, bool)) \ JVMTI_ONLY(nonstatic_field(JavaThread, _is_in_tmp_VTMS_transition, bool)) \ + JVMTI_ONLY(nonstatic_field(JavaThread, _is_disable_suspend, bool)) \ \ nonstatic_field(LockStack, _top, uint32_t) \ \ diff --git a/src/hotspot/share/legal/siphash.md b/src/hotspot/share/legal/siphash.md new file mode 100644 index 00000000000..1583f229e1e --- /dev/null +++ b/src/hotspot/share/legal/siphash.md @@ -0,0 +1,150 @@ +## SipHash v1.0-68c8a7c + +### Notice +SipHash reference C implementation + +``` + Copyright (c) 2012-2021 Jean-Philippe Aumasson + + Copyright (c) 2012-2014 Daniel J. Bernstein + To the extent possible under law, the author(s) have dedicated all copyright + and related and neighboring rights to this software to the public domain + worldwide. This software is distributed without any warranty. + You should have received a copy of the CC0 Public Domain Dedication along + with + this software. If not, see + . +``` + +### Licenses +The code is dual-licensed CCO and MIT + +#### MIT License +``` +Copyright 2012-2024 JP Aumasson + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +``` + +#### CC0 1.0 Universal +``` +Statement of Purpose + +The laws of most jurisdictions throughout the world automatically confer +exclusive Copyright and Related Rights (defined below) upon the creator and +subsequent owner(s) (each and all, an "owner") of an original work of +authorship and/or a database (each, a "Work"). + +Certain owners wish to permanently relinquish those rights to a Work for the +purpose of contributing to a commons of creative, cultural and scientific +works ("Commons") that the public can reliably and without fear of later +claims of infringement build upon, modify, incorporate in other works, reuse +and redistribute as freely as possible in any form whatsoever and for any +purposes, including without limitation commercial purposes. These owners may +contribute to the Commons to promote the ideal of a free culture and the +further production of creative, cultural and scientific works, or to gain +reputation or greater distribution for their Work in part through the use and +efforts of others. + +For these and/or other purposes and motivations, and without any expectation +of additional consideration or compensation, the person associating CC0 with a +Work (the "Affirmer"), to the extent that he or she is an owner of Copyright +and Related Rights in the Work, voluntarily elects to apply CC0 to the Work +and publicly distribute the Work under its terms, with knowledge of his or her +Copyright and Related Rights in the Work and the meaning and intended legal +effect of CC0 on those rights. + +1. Copyright and Related Rights. A Work made available under CC0 may be +protected by copyright and related or neighboring rights ("Copyright and +Related Rights"). Copyright and Related Rights include, but are not limited +to, the following: + + i. the right to reproduce, adapt, distribute, perform, display, communicate, + and translate a Work; + + ii. moral rights retained by the original author(s) and/or performer(s); + + iii. publicity and privacy rights pertaining to a person's image or likeness + depicted in a Work; + + iv. rights protecting against unfair competition in regards to a Work, + subject to the limitations in paragraph 4(a), below; + + v. rights protecting the extraction, dissemination, use and reuse of data in + a Work; + + vi. database rights (such as those arising under Directive 96/9/EC of the + European Parliament and of the Council of 11 March 1996 on the legal + protection of databases, and under any national implementation thereof, + including any amended or successor version of such directive); and + + vii. other similar, equivalent or corresponding rights throughout the world + based on applicable law or treaty, and any national implementations thereof. + +2. Waiver. To the greatest extent permitted by, but not in contravention of, +applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and +unconditionally waives, abandons, and surrenders all of Affirmer's Copyright +and Related Rights and associated claims and causes of action, whether now +known or unknown (including existing as well as future claims and causes of +action), in the Work (i) in all territories worldwide, (ii) for the maximum +duration provided by applicable law or treaty (including future time +extensions), (iii) in any current or future medium and for any number of +copies, and (iv) for any purpose whatsoever, including without limitation +commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes +the Waiver for the benefit of each member of the public at large and to the +detriment of Affirmer's heirs and successors, fully intending that such Waiver +shall not be subject to revocation, rescission, cancellation, termination, or +any other legal or equitable action to disrupt the quiet enjoyment of the Work +by the public as contemplated by Affirmer's express Statement of Purpose. + +3. Public License Fallback. Should any part of the Waiver for any reason be +judged legally invalid or ineffective under applicable law, then the Waiver +shall be preserved to the maximum extent permitted taking into account +Affirmer's express Statement of Purpose. In addition, to the extent the Waiver +is so judged Affirmer hereby grants to each affected person a royalty-free, +non transferable, non sublicensable, non exclusive, irrevocable and +unconditional license to exercise Affirmer's Copyright and Related Rights in +the Work (i) in all territories worldwide, (ii) for the maximum duration +provided by applicable law or treaty (including future time extensions), (iii) +in any current or future medium and for any number of copies, and (iv) for any +purpose whatsoever, including without limitation commercial, advertising or +promotional purposes (the "License"). The License shall be deemed effective as +of the date CC0 was applied by Affirmer to the Work. Should any part of the +License for any reason be judged legally invalid or ineffective under +applicable law, such partial invalidity or ineffectiveness shall not +invalidate the remainder of the License, and in such case Affirmer hereby +affirms that he or she will not (i) exercise any of his or her remaining +Copyright and Related Rights in the Work or (ii) assert any associated claims +and causes of action with respect to the Work, in either case contrary to +Affirmer's express Statement of Purpose. + +4. Limitations and Disclaimers. + + a. No trademark or patent rights held by Affirmer are waived, abandoned, + surrendered, licensed or otherwise affected by this document. + + b. Affirmer offers the Work as-is and makes no representations or warranties + of any kind concerning the Work, express, implied, statutory or otherwise, + including without limitation warranties of title, merchantability, fitness + for a particular purpose, non infringement, or the absence of latent or + other defects, accuracy, or the present or absence of errors, whether or not + discoverable, all to the greatest extent permissible under applicable law. + + c. Affirmer disclaims responsibility for clearing rights of other persons + that may apply to the Work or any use thereof, including without limitation + any person's Copyright and Related Rights in the Work. Further, Affirmer + disclaims responsibility for obtaining any necessary consents, permissions + or other rights required for any use of the Work. + + d. Affirmer understands and acknowledges that Creative Commons is not a + party to this document and has no duty or obligation with respect to this + CC0 or use of the Work. + +For more information, please see + + +``` diff --git a/src/hotspot/share/oops/constantPool.cpp b/src/hotspot/share/oops/constantPool.cpp index 623d8e326b0..8913b789117 100644 --- a/src/hotspot/share/oops/constantPool.cpp +++ b/src/hotspot/share/oops/constantPool.cpp @@ -802,13 +802,16 @@ void ConstantPool::resolve_string_constants_impl(const constantPoolHandle& this_ } } -static Symbol* exception_message(const constantPoolHandle& this_cp, int which, constantTag tag, oop pending_exception) { +static const char* exception_message(const constantPoolHandle& this_cp, int which, constantTag tag, oop pending_exception) { + // Note: caller needs ResourceMark + // Dig out the detailed message to reuse if possible - Symbol* message = java_lang_Throwable::detail_message(pending_exception); - if (message != nullptr) { - return message; + const char* msg = java_lang_Throwable::message_as_utf8(pending_exception); + if (msg != nullptr) { + return msg; } + Symbol* message = nullptr; // Return specific message for the tag switch (tag.value()) { case JVM_CONSTANT_UnresolvedClass: @@ -831,49 +834,48 @@ static Symbol* exception_message(const constantPoolHandle& this_cp, int which, c ShouldNotReachHere(); } - return message; + return message != nullptr ? message->as_C_string() : nullptr; } -static void add_resolution_error(const constantPoolHandle& this_cp, int which, +static void add_resolution_error(JavaThread* current, const constantPoolHandle& this_cp, int which, constantTag tag, oop pending_exception) { + ResourceMark rm(current); Symbol* error = pending_exception->klass()->name(); oop cause = java_lang_Throwable::cause(pending_exception); // Also dig out the exception cause, if present. Symbol* cause_sym = nullptr; - Symbol* cause_msg = nullptr; + const char* cause_msg = nullptr; if (cause != nullptr && cause != pending_exception) { cause_sym = cause->klass()->name(); - cause_msg = java_lang_Throwable::detail_message(cause); + cause_msg = java_lang_Throwable::message_as_utf8(cause); } - Symbol* message = exception_message(this_cp, which, tag, pending_exception); + const char* message = exception_message(this_cp, which, tag, pending_exception); SystemDictionary::add_resolution_error(this_cp, which, error, message, cause_sym, cause_msg); } void ConstantPool::throw_resolution_error(const constantPoolHandle& this_cp, int which, TRAPS) { ResourceMark rm(THREAD); - Symbol* message = nullptr; + const char* message = nullptr; Symbol* cause = nullptr; - Symbol* cause_msg = nullptr; + const char* cause_msg = nullptr; Symbol* error = SystemDictionary::find_resolution_error(this_cp, which, &message, &cause, &cause_msg); assert(error != nullptr, "checking"); - const char* cause_str = cause_msg != nullptr ? cause_msg->as_C_string() : nullptr; CLEAR_PENDING_EXCEPTION; if (message != nullptr) { - char* msg = message->as_C_string(); if (cause != nullptr) { - Handle h_cause = Exceptions::new_exception(THREAD, cause, cause_str); - THROW_MSG_CAUSE(error, msg, h_cause); + Handle h_cause = Exceptions::new_exception(THREAD, cause, cause_msg); + THROW_MSG_CAUSE(error, message, h_cause); } else { - THROW_MSG(error, msg); + THROW_MSG(error, message); } } else { if (cause != nullptr) { - Handle h_cause = Exceptions::new_exception(THREAD, cause, cause_str); + Handle h_cause = Exceptions::new_exception(THREAD, cause, cause_msg); THROW_CAUSE(error, h_cause); } else { THROW(error); @@ -895,7 +897,7 @@ void ConstantPool::save_and_throw_exception(const constantPoolHandle& this_cp, i // and OutOfMemoryError, etc, or if the thread was hit by stop() // Needs clarification to section 5.4.3 of the VM spec (see 6308271) } else if (this_cp->tag_at(cp_index).value() != error_tag) { - add_resolution_error(this_cp, cp_index, tag, PENDING_EXCEPTION); + add_resolution_error(THREAD, this_cp, cp_index, tag, PENDING_EXCEPTION); // CAS in the tag. If a thread beat us to registering this error that's fine. // If another thread resolved the reference, this is a race condition. This // thread may have had a security manager or something temporary. diff --git a/src/hotspot/share/oops/cpCache.cpp b/src/hotspot/share/oops/cpCache.cpp index daa094baa7e..02d4d8ed3a5 100644 --- a/src/hotspot/share/oops/cpCache.cpp +++ b/src/hotspot/share/oops/cpCache.cpp @@ -566,9 +566,9 @@ bool ConstantPoolCache::save_and_throw_indy_exc( CLEAR_PENDING_EXCEPTION; return false; } - + ResourceMark rm(THREAD); Symbol* error = PENDING_EXCEPTION->klass()->name(); - Symbol* message = java_lang_Throwable::detail_message(PENDING_EXCEPTION); + const char* message = java_lang_Throwable::message_as_utf8(PENDING_EXCEPTION); int encoded_index = ResolutionErrorTable::encode_indy_index( ConstantPool::encode_invokedynamic_index(index)); diff --git a/src/hotspot/share/oops/method.hpp b/src/hotspot/share/oops/method.hpp index 34f982d9f40..89d5ccbb168 100644 --- a/src/hotspot/share/oops/method.hpp +++ b/src/hotspot/share/oops/method.hpp @@ -395,7 +395,8 @@ class Method : public Metadata { void remove_unshareable_flags() NOT_CDS_RETURN; // the number of argument reg slots that the compiled method uses on the stack. - int num_stack_arg_slots() const { return constMethod()->num_stack_arg_slots(); } + int num_stack_arg_slots(bool rounded = true) const { + return rounded ? align_up(constMethod()->num_stack_arg_slots(), 2) : constMethod()->num_stack_arg_slots(); } virtual void metaspace_pointers_do(MetaspaceClosure* iter); virtual MetaspaceObj::Type type() const { return MethodType; } diff --git a/src/hotspot/share/oops/stackChunkOop.hpp b/src/hotspot/share/oops/stackChunkOop.hpp index 36b06ecd324..abfe47ad3f1 100644 --- a/src/hotspot/share/oops/stackChunkOop.hpp +++ b/src/hotspot/share/oops/stackChunkOop.hpp @@ -155,7 +155,7 @@ class stackChunkOopDesc : public instanceOopDesc { inline void* gc_data() const; inline BitMapView bitmap() const; - inline BitMap::idx_t bit_index_for(intptr_t* p) const; + inline BitMap::idx_t bit_index_for(address p) const; inline intptr_t* address_for_bit(BitMap::idx_t index) const; template inline BitMap::idx_t bit_index_for(OopT* p) const; template inline OopT* address_for_bit(BitMap::idx_t index) const; diff --git a/src/hotspot/share/oops/stackChunkOop.inline.hpp b/src/hotspot/share/oops/stackChunkOop.inline.hpp index e1993207266..c7590861032 100644 --- a/src/hotspot/share/oops/stackChunkOop.inline.hpp +++ b/src/hotspot/share/oops/stackChunkOop.inline.hpp @@ -256,12 +256,13 @@ inline BitMapView stackChunkOopDesc::bitmap() const { return bitmap; } -inline BitMap::idx_t stackChunkOopDesc::bit_index_for(intptr_t* p) const { +inline BitMap::idx_t stackChunkOopDesc::bit_index_for(address p) const { return UseCompressedOops ? bit_index_for((narrowOop*)p) : bit_index_for((oop*)p); } template inline BitMap::idx_t stackChunkOopDesc::bit_index_for(OopT* p) const { + assert(is_aligned(p, alignof(OopT)), "should be aligned: " PTR_FORMAT, p2i(p)); assert(p >= (OopT*)start_address(), "Address not in chunk"); return p - (OopT*)start_address(); } diff --git a/src/hotspot/share/opto/c2_globals.hpp b/src/hotspot/share/opto/c2_globals.hpp index 9a398e0dbb5..c522e9e81df 100644 --- a/src/hotspot/share/opto/c2_globals.hpp +++ b/src/hotspot/share/opto/c2_globals.hpp @@ -467,7 +467,7 @@ develop(bool, TracePostallocExpand, false, "Trace expanding nodes after" \ " register allocation.") \ \ - product(bool, ReduceAllocationMerges, true, DIAGNOSTIC, \ + product(bool, ReduceAllocationMerges, false, DIAGNOSTIC, \ "Try to simplify allocation merges before Scalar Replacement") \ \ notproduct(bool, TraceReduceAllocationMerges, false, \ diff --git a/src/hotspot/share/opto/c2compiler.cpp b/src/hotspot/share/opto/c2compiler.cpp index 5e9dfcacafd..ba383a679e1 100644 --- a/src/hotspot/share/opto/c2compiler.cpp +++ b/src/hotspot/share/opto/c2compiler.cpp @@ -822,6 +822,7 @@ bool C2Compiler::is_intrinsic_supported(vmIntrinsics::ID id) { case vmIntrinsics::_notifyJvmtiVThreadMount: case vmIntrinsics::_notifyJvmtiVThreadUnmount: case vmIntrinsics::_notifyJvmtiVThreadHideFrames: + case vmIntrinsics::_notifyJvmtiVThreadDisableSuspend: #endif break; diff --git a/src/hotspot/share/opto/callnode.cpp b/src/hotspot/share/opto/callnode.cpp index 71f78057707..e04dd9c361b 100644 --- a/src/hotspot/share/opto/callnode.cpp +++ b/src/hotspot/share/opto/callnode.cpp @@ -1463,9 +1463,10 @@ void SafePointNode::disconnect_from_root(PhaseIterGVN *igvn) { //============== SafePointScalarObjectNode ============== -SafePointScalarObjectNode::SafePointScalarObjectNode(const TypeOopPtr* tp, Node* alloc, uint first_index, uint n_fields) : +SafePointScalarObjectNode::SafePointScalarObjectNode(const TypeOopPtr* tp, Node* alloc, uint first_index, uint depth, uint n_fields) : TypeNode(tp, 1), // 1 control input -- seems required. Get from root. _first_index(first_index), + _depth(depth), _n_fields(n_fields), _alloc(alloc) { diff --git a/src/hotspot/share/opto/callnode.hpp b/src/hotspot/share/opto/callnode.hpp index b659cb67082..efa84850bb2 100644 --- a/src/hotspot/share/opto/callnode.hpp +++ b/src/hotspot/share/opto/callnode.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, 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 @@ -508,7 +508,7 @@ class SafePointNode : public MultiNode { class SafePointScalarObjectNode: public TypeNode { uint _first_index; // First input edge relative index of a SafePoint node where // states of the scalarized object fields are collected. - // It is relative to the last (youngest) jvms->_scloff. + uint _depth; // Depth of the JVM state the _first_index field refers to uint _n_fields; // Number of non-static fields of the scalarized object. Node* _alloc; // Just for debugging purposes. @@ -519,7 +519,7 @@ class SafePointScalarObjectNode: public TypeNode { uint first_index() const { return _first_index; } public: - SafePointScalarObjectNode(const TypeOopPtr* tp, Node* alloc, uint first_index, uint n_fields); + SafePointScalarObjectNode(const TypeOopPtr* tp, Node* alloc, uint first_index, uint depth, uint n_fields); virtual int Opcode() const; virtual uint ideal_reg() const; @@ -529,7 +529,7 @@ class SafePointScalarObjectNode: public TypeNode { uint first_index(JVMState* jvms) const { assert(jvms != nullptr, "missed JVMS"); - return jvms->scloff() + _first_index; + return jvms->of_depth(_depth)->scloff() + _first_index; } uint n_fields() const { return _n_fields; } diff --git a/src/hotspot/share/opto/escape.cpp b/src/hotspot/share/opto/escape.cpp index 514155c6af8..f133e688cc5 100644 --- a/src/hotspot/share/opto/escape.cpp +++ b/src/hotspot/share/opto/escape.cpp @@ -4006,6 +4006,13 @@ void ConnectionGraph::split_unique_types(GrowableArray &alloc_worklist, if (n == nullptr) { continue; } + } else if (n->is_CallLeaf()) { + // Runtime calls with narrow memory input (no MergeMem node) + // get the memory projection + n = n->as_Call()->proj_out_or_null(TypeFunc::Memory); + if (n == nullptr) { + continue; + } } else if (n->Opcode() == Op_StrCompressedCopy || n->Opcode() == Op_EncodeISOArray) { // get the memory projection @@ -4048,7 +4055,7 @@ void ConnectionGraph::split_unique_types(GrowableArray &alloc_worklist, continue; } memnode_worklist.append_if_missing(use); - } else if (use->is_MemBar()) { + } else if (use->is_MemBar() || use->is_CallLeaf()) { if (use->in(TypeFunc::Memory) == n) { // Ignore precedent edge memnode_worklist.append_if_missing(use); } diff --git a/src/hotspot/share/opto/ifnode.cpp b/src/hotspot/share/opto/ifnode.cpp index 2751e891262..230a928b0c1 100644 --- a/src/hotspot/share/opto/ifnode.cpp +++ b/src/hotspot/share/opto/ifnode.cpp @@ -1872,6 +1872,46 @@ Node* RangeCheckNode::Ideal(PhaseGVN *phase, bool can_reshape) { // then we are guaranteed to fail, so just start interpreting there. // We 'expand' the top 3 range checks to include all post-dominating // checks. + // + // Example: + // a[i+x] // (1) 1 < x < 6 + // a[i+3] // (2) + // a[i+4] // (3) + // a[i+6] // max = max of all constants + // a[i+2] + // a[i+1] // min = min of all constants + // + // If x < 3: + // (1) a[i+x]: Leave unchanged + // (2) a[i+3]: Replace with a[i+max] = a[i+6]: i+x < i+3 <= i+6 -> (2) is covered + // (3) a[i+4]: Replace with a[i+min] = a[i+1]: i+1 < i+4 <= i+6 -> (3) and all following checks are covered + // Remove all other a[i+c] checks + // + // If x >= 3: + // (1) a[i+x]: Leave unchanged + // (2) a[i+3]: Replace with a[i+min] = a[i+1]: i+1 < i+3 <= i+x -> (2) is covered + // (3) a[i+4]: Replace with a[i+max] = a[i+6]: i+1 < i+4 <= i+6 -> (3) and all following checks are covered + // Remove all other a[i+c] checks + // + // We only need the top 2 range checks if x is the min or max of all constants. + // + // This, however, only works if the interval [i+min,i+max] is not larger than max_int (i.e. abs(max - min) < max_int): + // The theoretical max size of an array is max_int with: + // - Valid index space: [0,max_int-1] + // - Invalid index space: [max_int,-1] // max_int, min_int, min_int - 1 ..., -1 + // + // The size of the consecutive valid index space is smaller than the size of the consecutive invalid index space. + // If we choose min and max in such a way that: + // - abs(max - min) < max_int + // - i+max and i+min are inside the valid index space + // then all indices [i+min,i+max] must be in the valid index space. Otherwise, the invalid index space must be + // smaller than the valid index space which is never the case for any array size. + // + // Choosing a smaller array size only makes the valid index space smaller and the invalid index space larger and + // the argument above still holds. + // + // Note that the same optimization with the same maximal accepted interval size can also be found in C1. + const jlong maximum_number_of_min_max_interval_indices = (jlong)max_jint; // The top 3 range checks seen const int NRC = 3; @@ -1906,13 +1946,18 @@ Node* RangeCheckNode::Ideal(PhaseGVN *phase, bool can_reshape) { found_immediate_dominator = true; break; } - // Gather expanded bounds - off_lo = MIN2(off_lo,offset2); - off_hi = MAX2(off_hi,offset2); - // Record top NRC range checks - prev_checks[nb_checks%NRC].ctl = prev_dom; - prev_checks[nb_checks%NRC].off = offset2; - nb_checks++; + + // "x - y" -> must add one to the difference for number of elements in [x,y] + const jlong diff = (jlong)MIN2(offset2, off_lo) - (jlong)MAX2(offset2, off_hi); + if (ABS(diff) < maximum_number_of_min_max_interval_indices) { + // Gather expanded bounds + off_lo = MIN2(off_lo, offset2); + off_hi = MAX2(off_hi, offset2); + // Record top NRC range checks + prev_checks[nb_checks % NRC].ctl = prev_dom; + prev_checks[nb_checks % NRC].off = offset2; + nb_checks++; + } } } prev_dom = dom; diff --git a/src/hotspot/share/opto/library_call.cpp b/src/hotspot/share/opto/library_call.cpp index 6e104f09b9d..c2b4eaab1bc 100644 --- a/src/hotspot/share/opto/library_call.cpp +++ b/src/hotspot/share/opto/library_call.cpp @@ -492,7 +492,8 @@ bool LibraryCallKit::try_to_inline(int predicate) { "notifyJvmtiMount", false, false); case vmIntrinsics::_notifyJvmtiVThreadUnmount: return inline_native_notify_jvmti_funcs(CAST_FROM_FN_PTR(address, OptoRuntime::notify_jvmti_vthread_unmount()), "notifyJvmtiUnmount", false, false); - case vmIntrinsics::_notifyJvmtiVThreadHideFrames: return inline_native_notify_jvmti_hide(); + case vmIntrinsics::_notifyJvmtiVThreadHideFrames: return inline_native_notify_jvmti_hide(); + case vmIntrinsics::_notifyJvmtiVThreadDisableSuspend: return inline_native_notify_jvmti_sync(); #endif #ifdef JFR_HAVE_INTRINSICS @@ -2950,6 +2951,29 @@ bool LibraryCallKit::inline_native_notify_jvmti_hide() { return true; } +// Always update the is_disable_suspend bit. +bool LibraryCallKit::inline_native_notify_jvmti_sync() { + if (!DoJVMTIVirtualThreadTransitions) { + return true; + } + IdealKit ideal(this); + + { + // unconditionally update the is_disable_suspend bit in current JavaThread + Node* thread = ideal.thread(); + Node* arg = _gvn.transform(argument(1)); // argument for notification + Node* addr = basic_plus_adr(thread, in_bytes(JavaThread::is_disable_suspend_offset())); + const TypePtr *addr_type = _gvn.type(addr)->isa_ptr(); + + sync_kit(ideal); + access_store_at(nullptr, addr, addr_type, arg, _gvn.type(arg), T_BOOLEAN, IN_NATIVE | MO_UNORDERED); + ideal.sync_kit(this); + } + final_sync(ideal); + + return true; +} + #endif // INCLUDE_JVMTI #ifdef JFR_HAVE_INTRINSICS diff --git a/src/hotspot/share/opto/library_call.hpp b/src/hotspot/share/opto/library_call.hpp index 55d1dc78f1f..47f9d7d4713 100644 --- a/src/hotspot/share/opto/library_call.hpp +++ b/src/hotspot/share/opto/library_call.hpp @@ -245,6 +245,7 @@ class LibraryCallKit : public GraphKit { #if INCLUDE_JVMTI bool inline_native_notify_jvmti_funcs(address funcAddr, const char* funcName, bool is_start, bool is_end); bool inline_native_notify_jvmti_hide(); + bool inline_native_notify_jvmti_sync(); #endif #ifdef JFR_HAVE_INTRINSICS diff --git a/src/hotspot/share/opto/loopPredicate.cpp b/src/hotspot/share/opto/loopPredicate.cpp index d569bfcfab5..ca98f0ffc8c 100644 --- a/src/hotspot/share/opto/loopPredicate.cpp +++ b/src/hotspot/share/opto/loopPredicate.cpp @@ -849,9 +849,10 @@ BoolNode* PhaseIdealLoop::rc_predicate(IdealLoopTree* loop, Node* ctrl, int scal // Check if (scale * max_idx_expr) may overflow const TypeInt* scale_type = TypeInt::make(scale); MulINode* mul = new MulINode(max_idx_expr, con_scale); - idx_type = (TypeInt*)mul->mul_ring(idx_type, scale_type); - if (overflow || TypeInt::INT->higher_equal(idx_type)) { + + if (overflow || MulINode::does_overflow(idx_type, scale_type)) { // May overflow + idx_type = TypeInt::INT; mul->destruct(&_igvn); if (!overflow) { max_idx_expr = new ConvI2LNode(max_idx_expr); @@ -864,6 +865,7 @@ BoolNode* PhaseIdealLoop::rc_predicate(IdealLoopTree* loop, Node* ctrl, int scal } else { // No overflow possible max_idx_expr = mul; + idx_type = (TypeInt*)mul->mul_ring(idx_type, scale_type); } register_new_node(max_idx_expr, ctrl); } diff --git a/src/hotspot/share/opto/loopnode.cpp b/src/hotspot/share/opto/loopnode.cpp index e9655b329e1..ac822453356 100644 --- a/src/hotspot/share/opto/loopnode.cpp +++ b/src/hotspot/share/opto/loopnode.cpp @@ -491,19 +491,19 @@ PhiNode* PhaseIdealLoop::loop_iv_phi(Node* xphi, Node* phi_incr, Node* x, IdealL return phi; } -static int check_stride_overflow(jlong stride_con, const TypeInteger* limit_t, BasicType bt) { - if (stride_con > 0) { - if (limit_t->lo_as_long() > (max_signed_integer(bt) - stride_con)) { +static int check_stride_overflow(jlong final_correction, const TypeInteger* limit_t, BasicType bt) { + if (final_correction > 0) { + if (limit_t->lo_as_long() > (max_signed_integer(bt) - final_correction)) { return -1; } - if (limit_t->hi_as_long() > (max_signed_integer(bt) - stride_con)) { + if (limit_t->hi_as_long() > (max_signed_integer(bt) - final_correction)) { return 1; } } else { - if (limit_t->hi_as_long() < (min_signed_integer(bt) - stride_con)) { + if (limit_t->hi_as_long() < (min_signed_integer(bt) - final_correction)) { return -1; } - if (limit_t->lo_as_long() < (min_signed_integer(bt) - stride_con)) { + if (limit_t->lo_as_long() < (min_signed_integer(bt) - final_correction)) { return 1; } } @@ -1773,49 +1773,204 @@ bool PhaseIdealLoop::is_counted_loop(Node* x, IdealLoopTree*&loop, BasicType iv_ C->print_method(PHASE_BEFORE_CLOOPS, 3); // =================================================== - // Generate loop limit check to avoid integer overflow - // in cases like next (cyclic loops): + // We can only convert this loop to a counted loop if we can guarantee that the iv phi will never overflow at runtime. + // This is an implicit assumption taken by some loop optimizations. We therefore must ensure this property at all cost. + // At this point, we've already excluded some trivial cases where an overflow could have been proven statically. + // But even though we cannot prove that an overflow will *not* happen, we still want to speculatively convert this loop + // to a counted loop. This can be achieved by adding additional iv phi overflow checks before the loop. If they fail, + // we trap and resume execution before the loop without having executed any iteration of the loop, yet. + // + // These additional iv phi overflow checks can be inserted as Loop Limit Check Predicates above the Loop Limit Check + // Parse Predicate which captures a JVM state just before the entry of the loop. If there is no such Parse Predicate, + // we cannot generate a Loop Limit Check Predicate and thus cannot speculatively convert the loop to a counted loop. + // + // In the following, we only focus on int loops with stride > 0 to keep things simple. The argumentation and proof + // for stride < 0 is analogously. For long loops, we would replace max_int with max_long. + // + // + // The loop to be converted does not always need to have the often used shape: + // + // i = init + // i = init loop: + // do { ... + // // ... equivalent i+=stride + // i+=stride <==> if (i < limit) + // } while (i < limit); goto loop + // exit: + // ... + // + // where the loop exit check uses the post-incremented iv phi and a '<'-operator. + // + // We could also have '<='-operator (or '>='-operator for negative strides) or use the pre-incremented iv phi value + // in the loop exit check: + // + // i = init + // loop: + // ... + // if (i <= limit) + // i+=stride + // goto loop + // exit: + // ... + // + // Let's define the following terms: + // - iv_pre_i: The pre-incremented iv phi before the i-th iteration. + // - iv_post_i: The post-incremented iv phi after the i-th iteration. + // + // The iv_pre_i and iv_post_i have the following relation: + // iv_pre_i + stride = iv_post_i + // + // When converting a loop to a counted loop, we want to have a canonicalized loop exit check of the form: + // iv_post_i < adjusted_limit + // + // If that is not the case, we need to canonicalize the loop exit check by using different values for adjusted_limit: + // (LE1) iv_post_i < limit: Already canonicalized. We can directly use limit as adjusted_limit. + // -> adjusted_limit = limit. + // (LE2) iv_post_i <= limit: + // iv_post_i < limit + 1 + // -> adjusted limit = limit + 1 + // (LE3) iv_pre_i < limit: + // iv_pre_i + stride < limit + stride + // iv_post_i < limit + stride + // -> adjusted_limit = limit + stride + // (LE4) iv_pre_i <= limit: + // iv_pre_i < limit + 1 + // iv_pre_i + stride < limit + stride + 1 + // iv_post_i < limit + stride + 1 + // -> adjusted_limit = limit + stride + 1 + // + // Note that: + // (AL) limit <= adjusted_limit. + // + // The following loop invariant has to hold for counted loops with n iterations (i.e. loop exit check true after n-th + // loop iteration) and a canonicalized loop exit check to guarantee that no iv_post_i over- or underflows: + // (INV) For i = 1..n, min_int <= iv_post_i <= max_int + // + // To prove (INV), we require the following two conditions/assumptions: + // (i): adjusted_limit - 1 + stride <= max_int + // (ii): init < limit + // + // If we can prove (INV), we know that there can be no over- or underflow of any iv phi value. We prove (INV) by + // induction by assuming (i) and (ii). + // + // Proof by Induction + // ------------------ + // > Base case (i = 1): We show that (INV) holds after the first iteration: + // min_int <= iv_post_1 = init + stride <= max_int + // Proof: + // First, we note that (ii) implies + // (iii) init <= limit - 1 + // max_int >= adjusted_limit - 1 + stride [using (i)] + // >= limit - 1 + stride [using (AL)] + // >= init + stride [using (iii)] + // >= min_int [using stride > 0, no underflow] + // Thus, no overflow happens after the first iteration and (INV) holds for i = 1. + // + // Note that to prove the base case we need (i) and (ii). + // + // > Induction Hypothesis (i = j, j > 1): Assume that (INV) holds after the j-th iteration: + // min_int <= iv_post_j <= max_int + // > Step case (i = j + 1): We show that (INV) also holds after the j+1-th iteration: + // min_int <= iv_post_{j+1} = iv_post_j + stride <= max_int + // Proof: + // If iv_post_j >= adjusted_limit: + // We exit the loop after the j-th iteration, and we don't execute the j+1-th iteration anymore. Thus, there is + // also no iv_{j+1}. Since (INV) holds for iv_j, there is nothing left to prove. + // If iv_post_j < adjusted_limit: + // First, we note that: + // (iv) iv_post_j <= adjusted_limit - 1 + // max_int >= adjusted_limit - 1 + stride [using (i)] + // >= iv_post_j + stride [using (iv)] + // >= min_int [using stride > 0, no underflow] // - // for (i=0; i <= max_jint; i++) {} - // for (i=0; i < max_jint; i+=2) {} + // Note that to prove the step case we only need (i). // + // Thus, by assuming (i) and (ii), we proved (INV). // - // Limit check predicate depends on the loop test: // - // for(;i != limit; i++) --> limit <= (max_jint) - // for(;i < limit; i+=stride) --> limit <= (max_jint - stride + 1) - // for(;i <= limit; i+=stride) --> limit <= (max_jint - stride ) + // It is therefore enough to add the following two Loop Limit Check Predicates to check assumptions (i) and (ii): // + // (1) Loop Limit Check Predicate for (i): + // Using (i): adjusted_limit - 1 + stride <= max_int + // + // This condition is now restated to use limit instead of adjusted_limit: + // + // To prevent an overflow of adjusted_limit -1 + stride itself, we rewrite this check to + // max_int - stride + 1 >= adjusted_limit + // We can merge the two constants into + // canonicalized_correction = stride - 1 + // which gives us + // max_int - canonicalized_correction >= adjusted_limit + // + // To directly use limit instead of adjusted_limit in the predicate condition, we split adjusted_limit into: + // adjusted_limit = limit + limit_correction + // Since stride > 0 and limit_correction <= stride + 1, we can restate this with no over- or underflow into: + // max_int - canonicalized_correction - limit_correction >= limit + // Since canonicalized_correction and limit_correction are both constants, we can replace them with a new constant: + // final_correction = canonicalized_correction + limit_correction + // which gives us: + // + // Final predicate condition: + // max_int - final_correction >= limit + // + // (2) Loop Limit Check Predicate for (ii): + // Using (ii): init < limit + // + // This Loop Limit Check Predicate is not required if we can prove at compile time that either: + // (2.1) type(init) < type(limit) + // In this case, we know: + // all possible values of init < all possible values of limit + // and we can skip the predicate. + // + // (2.2) init < limit is already checked before (i.e. found as a dominating check) + // In this case, we do not need to re-check the condition and can skip the predicate. + // This is often found for while- and for-loops which have the following shape: + // + // if (init < limit) { // Dominating test. Do not need the Loop Limit Check Predicate below. + // i = init; + // if (init >= limit) { trap(); } // Here we would insert the Loop Limit Check Predicate + // do { + // i += stride; + // } while (i < limit); + // } + // + // (2.3) init + stride <= max_int + // In this case, there is no overflow of the iv phi after the first loop iteration. + // In the proof of the base case above we showed that init + stride <= max_int by using assumption (ii): + // init < limit + // In the proof of the step case above, we did not need (ii) anymore. Therefore, if we already know at + // compile time that init + stride <= max_int then we have trivially proven the base case and that + // there is no overflow of the iv phi after the first iteration. In this case, we don't need to check (ii) + // again and can skip the predicate. - // Check if limit is excluded to do more precise int overflow check. - bool incl_limit = (bt == BoolTest::le || bt == BoolTest::ge); - jlong stride_m = stride_con - (incl_limit ? 0 : (stride_con > 0 ? 1 : -1)); - // If compare points directly to the phi we need to adjust - // the compare so that it points to the incr. Limit have - // to be adjusted to keep trip count the same and the - // adjusted limit should be checked for int overflow. - Node* adjusted_limit = limit; - if (phi_incr != nullptr) { - stride_m += stride_con; - } + // Accounting for (LE3) and (LE4) where we use pre-incremented phis in the loop exit check. + const jlong limit_correction_for_pre_iv_exit_check = (phi_incr != nullptr) ? stride_con : 0; - Node *init_control = x->in(LoopNode::EntryControl); + // Accounting for (LE2) and (LE4) where we use <= or >= in the loop exit check. + const bool includes_limit = (bt == BoolTest::le || bt == BoolTest::ge); + const jlong limit_correction_for_le_ge_exit_check = (includes_limit ? (stride_con > 0 ? 1 : -1) : 0); + + const jlong limit_correction = limit_correction_for_pre_iv_exit_check + limit_correction_for_le_ge_exit_check; + const jlong canonicalized_correction = stride_con + (stride_con > 0 ? -1 : 1); + const jlong final_correction = canonicalized_correction + limit_correction; + + int sov = check_stride_overflow(final_correction, limit_t, iv_bt); + Node* init_control = x->in(LoopNode::EntryControl); - int sov = check_stride_overflow(stride_m, limit_t, iv_bt); // If sov==0, limit's type always satisfies the condition, for // example, when it is an array length. if (sov != 0) { if (sov < 0) { return false; // Bailout: integer overflow is certain. } + // (1) Loop Limit Check Predicate is required because we could not statically prove that + // limit + final_correction = adjusted_limit - 1 + stride <= max_int assert(!x->as_Loop()->is_loop_nest_inner_loop(), "loop was transformed"); - // Generate loop's limit check. - // Loop limit check predicate should be near the loop. const Predicates predicates(init_control); const PredicateBlock* loop_limit_check_predicate_block = predicates.loop_limit_check_predicate_block(); if (!loop_limit_check_predicate_block->has_parse_predicate()) { - // The limit check predicate is not generated if this method trapped here before. + // The Loop Limit Check Parse Predicate is not generated if this method trapped here before. #ifdef ASSERT if (TraceLoopLimitCheck) { tty->print("Missing Loop Limit Check Parse Predicate:"); @@ -1835,67 +1990,81 @@ bool PhaseIdealLoop::is_counted_loop(Node* x, IdealLoopTree*&loop, BasicType iv_ Node* bol; if (stride_con > 0) { - cmp_limit = CmpNode::make(limit, _igvn.integercon(max_signed_integer(iv_bt) - stride_m, iv_bt), iv_bt); + cmp_limit = CmpNode::make(limit, _igvn.integercon(max_signed_integer(iv_bt) - final_correction, iv_bt), iv_bt); bol = new BoolNode(cmp_limit, BoolTest::le); } else { - cmp_limit = CmpNode::make(limit, _igvn.integercon(min_signed_integer(iv_bt) - stride_m, iv_bt), iv_bt); + cmp_limit = CmpNode::make(limit, _igvn.integercon(min_signed_integer(iv_bt) - final_correction, iv_bt), iv_bt); bol = new BoolNode(cmp_limit, BoolTest::ge); } insert_loop_limit_check_predicate(init_control->as_IfTrue(), cmp_limit, bol); } - // Now we need to canonicalize loop condition. - if (bt == BoolTest::ne) { - assert(stride_con == 1 || stride_con == -1, "simple increment only"); - if (stride_con > 0 && init_t->hi_as_long() < limit_t->lo_as_long()) { - // 'ne' can be replaced with 'lt' only when init < limit. - bt = BoolTest::lt; - } else if (stride_con < 0 && init_t->lo_as_long() > limit_t->hi_as_long()) { - // 'ne' can be replaced with 'gt' only when init > limit. - bt = BoolTest::gt; - } else { - const Predicates predicates(init_control); - const PredicateBlock* loop_limit_check_predicate_block = predicates.loop_limit_check_predicate_block(); - if (!loop_limit_check_predicate_block->has_parse_predicate()) { - // The limit check predicate is not generated if this method trapped here before. + // (2.3) + const bool init_plus_stride_could_overflow = + (stride_con > 0 && init_t->hi_as_long() > max_signed_integer(iv_bt) - stride_con) || + (stride_con < 0 && init_t->lo_as_long() < min_signed_integer(iv_bt) - stride_con); + // (2.1) + const bool init_gte_limit = (stride_con > 0 && init_t->hi_as_long() >= limit_t->lo_as_long()) || + (stride_con < 0 && init_t->lo_as_long() <= limit_t->hi_as_long()); + + if (init_gte_limit && // (2.1) + ((bt == BoolTest::ne || init_plus_stride_could_overflow) && // (2.3) + !has_dominating_loop_limit_check(init_trip, limit, stride_con, iv_bt, init_control))) { // (2.2) + // (2) Iteration Loop Limit Check Predicate is required because neither (2.1), (2.2), nor (2.3) holds. + // We use the following condition: + // - stride > 0: init < limit + // - stride < 0: init > limit + // + // This predicate is always required if we have a non-equal-operator in the loop exit check (where stride = 1 is + // a requirement). We transform the loop exit check by using a less-than-operator. By doing so, we must always + // check that init < limit. Otherwise, we could have a different number of iterations at runtime. + + const Predicates predicates(init_control); + const PredicateBlock* loop_limit_check_predicate_block = predicates.loop_limit_check_predicate_block(); + if (!loop_limit_check_predicate_block->has_parse_predicate()) { + // The Loop Limit Check Parse Predicate is not generated if this method trapped here before. #ifdef ASSERT - if (TraceLoopLimitCheck) { - tty->print("Missing Loop Limit Check Parse Predicate:"); - loop->dump_head(); - x->dump(1); - } -#endif - return false; + if (TraceLoopLimitCheck) { + tty->print("Missing Loop Limit Check Parse Predicate:"); + loop->dump_head(); + x->dump(1); } +#endif + return false; + } - ParsePredicateNode* loop_limit_check_parse_predicate = loop_limit_check_predicate_block->parse_predicate(); - Node* parse_predicate_entry = loop_limit_check_parse_predicate->in(0); - if (!is_dominator(get_ctrl(limit), parse_predicate_entry) || - !is_dominator(get_ctrl(init_trip), parse_predicate_entry)) { - return false; - } + ParsePredicateNode* loop_limit_check_parse_predicate = loop_limit_check_predicate_block->parse_predicate(); + Node* parse_predicate_entry = loop_limit_check_parse_predicate->in(0); + if (!is_dominator(get_ctrl(limit), parse_predicate_entry) || + !is_dominator(get_ctrl(init_trip), parse_predicate_entry)) { + return false; + } - Node* cmp_limit; - Node* bol; + Node* cmp_limit; + Node* bol; - if (stride_con > 0) { - cmp_limit = CmpNode::make(init_trip, limit, iv_bt); - bol = new BoolNode(cmp_limit, BoolTest::lt); - } else { - cmp_limit = CmpNode::make(init_trip, limit, iv_bt); - bol = new BoolNode(cmp_limit, BoolTest::gt); - } + if (stride_con > 0) { + cmp_limit = CmpNode::make(init_trip, limit, iv_bt); + bol = new BoolNode(cmp_limit, BoolTest::lt); + } else { + cmp_limit = CmpNode::make(init_trip, limit, iv_bt); + bol = new BoolNode(cmp_limit, BoolTest::gt); + } - insert_loop_limit_check_predicate(init_control->as_IfTrue(), cmp_limit, bol); + insert_loop_limit_check_predicate(init_control->as_IfTrue(), cmp_limit, bol); + } - if (stride_con > 0) { - // 'ne' can be replaced with 'lt' only when init < limit. - bt = BoolTest::lt; - } else if (stride_con < 0) { - // 'ne' can be replaced with 'gt' only when init > limit. - bt = BoolTest::gt; - } + if (bt == BoolTest::ne) { + // Now we need to canonicalize the loop condition if it is 'ne'. + assert(stride_con == 1 || stride_con == -1, "simple increment only - checked before"); + if (stride_con > 0) { + // 'ne' can be replaced with 'lt' only when init < limit. This is ensured by the inserted predicate above. + bt = BoolTest::lt; + } else { + assert(stride_con < 0, "must be"); + // 'ne' can be replaced with 'gt' only when init > limit. This is ensured by the inserted predicate above. + bt = BoolTest::gt; } } @@ -1940,6 +2109,7 @@ bool PhaseIdealLoop::is_counted_loop(Node* x, IdealLoopTree*&loop, BasicType iv_ } #endif + Node* adjusted_limit = limit; if (phi_incr != nullptr) { // If compare points directly to the phi we need to adjust // the compare so that it points to the incr. Limit have @@ -1953,7 +2123,7 @@ bool PhaseIdealLoop::is_counted_loop(Node* x, IdealLoopTree*&loop, BasicType iv_ adjusted_limit = gvn->transform(AddNode::make(limit, stride, iv_bt)); } - if (incl_limit) { + if (includes_limit) { // The limit check guaranties that 'limit <= (max_jint - stride)' so // we can convert 'i <= limit' to 'i < limit+1' since stride != 0. // @@ -2134,6 +2304,37 @@ bool PhaseIdealLoop::is_counted_loop(Node* x, IdealLoopTree*&loop, BasicType iv_ return true; } +// Check if there is a dominating loop limit check of the form 'init < limit' starting at the loop entry. +// If there is one, then we do not need to create an additional Loop Limit Check Predicate. +bool PhaseIdealLoop::has_dominating_loop_limit_check(Node* init_trip, Node* limit, const jlong stride_con, + const BasicType iv_bt, Node* loop_entry) { + // Eagerly call transform() on the Cmp and Bool node to common them up if possible. This is required in order to + // successfully find a dominated test with the If node below. + Node* cmp_limit; + Node* bol; + if (stride_con > 0) { + cmp_limit = _igvn.transform(CmpNode::make(init_trip, limit, iv_bt)); + bol = _igvn.transform(new BoolNode(cmp_limit, BoolTest::lt)); + } else { + cmp_limit = _igvn.transform(CmpNode::make(init_trip, limit, iv_bt)); + bol = _igvn.transform(new BoolNode(cmp_limit, BoolTest::gt)); + } + + // Check if there is already a dominating init < limit check. If so, we do not need a Loop Limit Check Predicate. + IfNode* iff = new IfNode(loop_entry, bol, PROB_MIN, COUNT_UNKNOWN); + // Also add fake IfProj nodes in order to call transform() on the newly created IfNode. + IfFalseNode* if_false = new IfFalseNode(iff); + IfTrueNode* if_true = new IfTrueNode(iff); + Node* dominated_iff = _igvn.transform(iff); + // ConI node? Found dominating test (IfNode::dominated_by() returns a ConI node). + const bool found_dominating_test = dominated_iff != nullptr && dominated_iff->is_ConI(); + + // Kill the If with its projections again in the next IGVN round by cutting it off from the graph. + _igvn.replace_input_of(iff, 0, C->top()); + _igvn.replace_input_of(iff, 1, C->top()); + return found_dominating_test; +} + //----------------------exact_limit------------------------------------------- Node* PhaseIdealLoop::exact_limit( IdealLoopTree *loop ) { assert(loop->_head->is_CountedLoop(), ""); diff --git a/src/hotspot/share/opto/loopnode.hpp b/src/hotspot/share/opto/loopnode.hpp index 4a34d7e49ba..86d9b20d16f 100644 --- a/src/hotspot/share/opto/loopnode.hpp +++ b/src/hotspot/share/opto/loopnode.hpp @@ -1103,6 +1103,7 @@ class PhaseIdealLoop : public PhaseTransform { // Compute the Ideal Node to Loop mapping PhaseIdealLoop(PhaseIterGVN& igvn, LoopOptsMode mode) : PhaseTransform(Ideal_Loop), + _loop_or_ctrl(igvn.C->comp_arena()), _igvn(igvn), _verify_me(nullptr), _verify_only(false), @@ -1117,6 +1118,7 @@ class PhaseIdealLoop : public PhaseTransform { // or only verify that the graph is valid if verify_me is null. PhaseIdealLoop(PhaseIterGVN& igvn, const PhaseIdealLoop* verify_me = nullptr) : PhaseTransform(Ideal_Loop), + _loop_or_ctrl(igvn.C->comp_arena()), _igvn(igvn), _verify_me(verify_me), _verify_only(verify_me == nullptr), @@ -1346,6 +1348,8 @@ class PhaseIdealLoop : public PhaseTransform { void rewire_cloned_nodes_to_ctrl(const ProjNode* old_ctrl, Node* new_ctrl, const Node_List& nodes_with_same_ctrl, const Dict& old_new_mapping); void rewire_inputs_of_clones_to_clones(Node* new_ctrl, Node* clone, const Dict& old_new_mapping, const Node* next); + bool has_dominating_loop_limit_check(Node* init_trip, Node* limit, jlong stride_con, BasicType iv_bt, + Node* loop_entry); public: void register_control(Node* n, IdealLoopTree *loop, Node* pred, bool update_body = true); diff --git a/src/hotspot/share/opto/loopopts.cpp b/src/hotspot/share/opto/loopopts.cpp index ea1bdc933d0..65b31addc1b 100644 --- a/src/hotspot/share/opto/loopopts.cpp +++ b/src/hotspot/share/opto/loopopts.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2024, 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 @@ -287,7 +287,11 @@ bool PhaseIdealLoop::cannot_split_division(const Node* n, const Node* region) co return false; } - assert(n->in(0) == nullptr, "divisions with zero check should already have bailed out earlier in split-if"); + if (n->in(0) != nullptr) { + // Cannot split through phi if Div or Mod node has a control dependency to a zero check. + return true; + } + Node* divisor = n->in(2); return is_divisor_counted_loop_phi(divisor, region) && loop_phi_backedge_type_contains_zero(divisor, zero); @@ -567,8 +571,8 @@ Node* PhaseIdealLoop::remix_address_expressions(Node* n) { } // Replace ((I1 +p V) +p I2) with ((I1 +p I2) +p V), - // but not if I2 is a constant. - if (n_op == Op_AddP) { + // but not if I2 is a constant. Skip for irreducible loops. + if (n_op == Op_AddP && n_loop->_head->is_Loop()) { if (n2_loop == n_loop && n3_loop != n_loop) { if (n->in(2)->Opcode() == Op_AddP && !n->in(3)->is_Con()) { Node* n22_ctrl = get_ctrl(n->in(2)->in(2)); diff --git a/src/hotspot/share/opto/macro.cpp b/src/hotspot/share/opto/macro.cpp index 960206137f6..99b1ca7d31c 100644 --- a/src/hotspot/share/opto/macro.cpp +++ b/src/hotspot/share/opto/macro.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2024, 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 @@ -766,7 +766,7 @@ SafePointScalarObjectNode* PhaseMacroExpand::create_scalarized_object_descriptio } } - SafePointScalarObjectNode* sobj = new SafePointScalarObjectNode(res_type, alloc, first_ind, nfields); + SafePointScalarObjectNode* sobj = new SafePointScalarObjectNode(res_type, alloc, first_ind, sfpt->jvms()->depth(), nfields); sobj->init_req(0, C->root()); transform_later(sobj); diff --git a/src/hotspot/share/opto/mulnode.cpp b/src/hotspot/share/opto/mulnode.cpp index 3b493b5efa2..a59ec86a2b6 100644 --- a/src/hotspot/share/opto/mulnode.cpp +++ b/src/hotspot/share/opto/mulnode.cpp @@ -281,45 +281,86 @@ Node *MulINode::Ideal(PhaseGVN *phase, bool can_reshape) { return res; // Return final result } -// Classes to perform mul_ring() for MulI/MulLNode. +// This template class performs type multiplication for MulI/MulLNode. NativeType is either jint or jlong. +// In this class, the inputs of the MulNodes are named left and right with types [left_lo,left_hi] and [right_lo,right_hi]. // -// This class checks if all cross products of the left and right input of a multiplication have the same "overflow value". -// Without overflow/underflow: -// Product is positive? High signed multiplication result: 0 -// Product is negative? High signed multiplication result: -1 +// In general, the multiplication of two x-bit values could produce a result that consumes up to 2x bits if there is +// enough space to hold them all. We can therefore distinguish the following two cases for the product: +// - no overflow (i.e. product fits into x bits) +// - overflow (i.e. product does not fit into x bits) // -// We normalize these values (see normalize_overflow_value()) such that we get the same "overflow value" by adding 1 if -// the product is negative. This allows us to compare all the cross product "overflow values". If one is different, -// compared to the others, then we know that this multiplication has a different number of over- or underflows compared -// to the others. In this case, we need to use bottom type and cannot guarantee a better type. Otherwise, we can take -// the min und max of all computed cross products as type of this Mul node. -template -class IntegerMulRing { - using NativeType = std::conditional_t::value, jint, jlong>; +// When multiplying the two x-bit inputs 'left' and 'right' with their x-bit types [left_lo,left_hi] and [right_lo,right_hi] +// we need to find the minimum and maximum of all possible products to define a new type. To do that, we compute the +// cross product of [left_lo,left_hi] and [right_lo,right_hi] in 2x-bit space where no over- or underflow can happen. +// The cross product consists of the following four multiplications with 2x-bit results: +// (1) left_lo * right_lo +// (2) left_lo * right_hi +// (3) left_hi * right_lo +// (4) left_hi * right_hi +// +// Let's define the following two functions: +// - Lx(i): Returns the lower x bits of the 2x-bit number i. +// - Ux(i): Returns the upper x bits of the 2x-bit number i. +// +// Let's first assume all products are positive where only overflows are possible but no underflows. If there is no +// overflow for a product p, then the upper x bits of the 2x-bit result p are all zero: +// Ux(p) = 0 +// Lx(p) = p +// +// If none of the multiplications (1)-(4) overflow, we can truncate the upper x bits and use the following result type +// with x bits: +// [result_lo,result_hi] = [MIN(Lx(1),Lx(2),Lx(3),Lx(4)),MAX(Lx(1),Lx(2),Lx(3),Lx(4))] +// +// If any of these multiplications overflows, we could pessimistically take the bottom type for the x bit result +// (i.e. all values in the x-bit space could be possible): +// [result_lo,result_hi] = [NativeType_min,NativeType_max] +// +// However, in case of any overflow, we can do better by analyzing the upper x bits of all multiplications (1)-(4) with +// 2x-bit results. The upper x bits tell us something about how many times a multiplication has overflown the lower +// x bits. If the upper x bits of (1)-(4) are all equal, then we know that all of these multiplications overflowed +// the lower x bits the same number of times: +// Ux((1)) = Ux((2)) = Ux((3)) = Ux((4)) +// +// If all upper x bits are equal, we can conclude: +// Lx(MIN((1),(2),(3),(4))) = MIN(Lx(1),Lx(2),Lx(3),Lx(4))) +// Lx(MAX((1),(2),(3),(4))) = MAX(Lx(1),Lx(2),Lx(3),Lx(4))) +// +// Therefore, we can use the same precise x-bit result type as for the no-overflow case: +// [result_lo,result_hi] = [(MIN(Lx(1),Lx(2),Lx(3),Lx(4))),MAX(Lx(1),Lx(2),Lx(3),Lx(4)))] +// +// +// Now let's assume that (1)-(4) are signed multiplications where over- and underflow could occur: +// Negative numbers are all sign extend with ones. Therefore, if a negative product does not underflow, then the +// upper x bits of the 2x-bit result are all set to ones which is minus one in two's complement. If there is an underflow, +// the upper x bits are decremented by the number of times an underflow occurred. The smallest possible negative product +// is NativeType_min*NativeType_max, where the upper x bits are set to NativeType_min / 2 (b11...0). It is therefore +// impossible to underflow the upper x bits. Thus, when having all ones (i.e. minus one) in the upper x bits, we know +// that there is no underflow. +// +// To be able to compare the number of over-/underflows of positive and negative products, respectively, we normalize +// the upper x bits of negative 2x-bit products by adding one. This way a product has no over- or underflow if the +// normalized upper x bits are zero. Now we can use the same improved type as for strictly positive products because we +// can compare the upper x bits in a unified way with N() being the normalization function: +// N(Ux((1))) = N(Ux((2))) = N(Ux((3)) = N(Ux((4))) +template +class IntegerTypeMultiplication { NativeType _lo_left; NativeType _lo_right; NativeType _hi_left; NativeType _hi_right; - NativeType _lo_lo_product; - NativeType _lo_hi_product; - NativeType _hi_lo_product; - NativeType _hi_hi_product; short _widen_left; short _widen_right; static const Type* overflow_type(); - static NativeType multiply_high_signed_overflow_value(NativeType x, NativeType y); + static NativeType multiply_high(NativeType x, NativeType y); + const Type* create_type(NativeType lo, NativeType hi) const; - // Pre-compute cross products which are used at several places - void compute_cross_products() { - _lo_lo_product = java_multiply(_lo_left, _lo_right); - _lo_hi_product = java_multiply(_lo_left, _hi_right); - _hi_lo_product = java_multiply(_hi_left, _lo_right); - _hi_hi_product = java_multiply(_hi_left, _hi_right); + static NativeType multiply_high_signed_overflow_value(NativeType x, NativeType y) { + return normalize_overflow_value(x, y, multiply_high(x, y)); } - bool cross_products_not_same_overflow() const { + bool cross_product_not_same_overflow_value() const { const NativeType lo_lo_high_product = multiply_high_signed_overflow_value(_lo_left, _lo_right); const NativeType lo_hi_high_product = multiply_high_signed_overflow_value(_lo_left, _hi_right); const NativeType hi_lo_high_product = multiply_high_signed_overflow_value(_hi_left, _lo_right); @@ -329,66 +370,95 @@ class IntegerMulRing { hi_lo_high_product != hi_hi_high_product; } + bool does_product_overflow(NativeType x, NativeType y) const { + return multiply_high_signed_overflow_value(x, y) != 0; + } + static NativeType normalize_overflow_value(const NativeType x, const NativeType y, NativeType result) { return java_multiply(x, y) < 0 ? result + 1 : result; } public: - IntegerMulRing(const IntegerType* left, const IntegerType* right) : _lo_left(left->_lo), _lo_right(right->_lo), - _hi_left(left->_hi), _hi_right(right->_hi), _widen_left(left->_widen), _widen_right(right->_widen) { - compute_cross_products(); - } + template + IntegerTypeMultiplication(const IntegerType* left, const IntegerType* right) + : _lo_left(left->_lo), _lo_right(right->_lo), + _hi_left(left->_hi), _hi_right(right->_hi), + _widen_left(left->_widen), _widen_right(right->_widen) {} // Compute the product type by multiplying the two input type ranges. We take the minimum and maximum of all possible // values (requires 4 multiplications of all possible combinations of the two range boundary values). If any of these // multiplications overflows/underflows, we need to make sure that they all have the same number of overflows/underflows // If that is not the case, we return the bottom type to cover all values due to the inconsistent overflows/underflows). const Type* compute() const { - if (cross_products_not_same_overflow()) { + if (cross_product_not_same_overflow_value()) { return overflow_type(); } - const NativeType min = MIN4(_lo_lo_product, _lo_hi_product, _hi_lo_product, _hi_hi_product); - const NativeType max = MAX4(_lo_lo_product, _lo_hi_product, _hi_lo_product, _hi_hi_product); - return IntegerType::make(min, max, MAX2(_widen_left, _widen_right)); + + NativeType lo_lo_product = java_multiply(_lo_left, _lo_right); + NativeType lo_hi_product = java_multiply(_lo_left, _hi_right); + NativeType hi_lo_product = java_multiply(_hi_left, _lo_right); + NativeType hi_hi_product = java_multiply(_hi_left, _hi_right); + const NativeType min = MIN4(lo_lo_product, lo_hi_product, hi_lo_product, hi_hi_product); + const NativeType max = MAX4(lo_lo_product, lo_hi_product, hi_lo_product, hi_hi_product); + return create_type(min, max); } -}; + bool does_overflow() const { + return does_product_overflow(_lo_left, _lo_right) || + does_product_overflow(_lo_left, _hi_right) || + does_product_overflow(_hi_left, _lo_right) || + does_product_overflow(_hi_left, _hi_right); + } +}; template <> -const Type* IntegerMulRing::overflow_type() { +const Type* IntegerTypeMultiplication::overflow_type() { return TypeInt::INT; } template <> -jint IntegerMulRing::multiply_high_signed_overflow_value(const jint x, const jint y) { +jint IntegerTypeMultiplication::multiply_high(const jint x, const jint y) { const jlong x_64 = x; const jlong y_64 = y; const jlong product = x_64 * y_64; - const jint result = (jint)((uint64_t)product >> 32u); - return normalize_overflow_value(x, y, result); + return (jint)((uint64_t)product >> 32u); +} + +template <> +const Type* IntegerTypeMultiplication::create_type(jint lo, jint hi) const { + return TypeInt::make(lo, hi, MAX2(_widen_left, _widen_right)); } template <> -const Type* IntegerMulRing::overflow_type() { +const Type* IntegerTypeMultiplication::overflow_type() { return TypeLong::LONG; } template <> -jlong IntegerMulRing::multiply_high_signed_overflow_value(const jlong x, const jlong y) { - const jlong result = multiply_high_signed(x, y); - return normalize_overflow_value(x, y, result); +jlong IntegerTypeMultiplication::multiply_high(const jlong x, const jlong y) { + return multiply_high_signed(x, y); +} + +template <> +const Type* IntegerTypeMultiplication::create_type(jlong lo, jlong hi) const { + return TypeLong::make(lo, hi, MAX2(_widen_left, _widen_right)); } // Compute the product type of two integer ranges into this node. const Type* MulINode::mul_ring(const Type* type_left, const Type* type_right) const { - const IntegerMulRing integer_mul_ring(type_left->is_int(), type_right->is_int()); - return integer_mul_ring.compute(); + const IntegerTypeMultiplication integer_multiplication(type_left->is_int(), type_right->is_int()); + return integer_multiplication.compute(); +} + +bool MulINode::does_overflow(const TypeInt* type_left, const TypeInt* type_right) { + const IntegerTypeMultiplication integer_multiplication(type_left, type_right); + return integer_multiplication.does_overflow(); } // Compute the product type of two long ranges into this node. const Type* MulLNode::mul_ring(const Type* type_left, const Type* type_right) const { - const IntegerMulRing integer_mul_ring(type_left->is_long(), type_right->is_long()); - return integer_mul_ring.compute(); + const IntegerTypeMultiplication integer_multiplication(type_left->is_long(), type_right->is_long()); + return integer_multiplication.compute(); } //============================================================================= diff --git a/src/hotspot/share/opto/mulnode.hpp b/src/hotspot/share/opto/mulnode.hpp index d04648ee61a..10ef442299d 100644 --- a/src/hotspot/share/opto/mulnode.hpp +++ b/src/hotspot/share/opto/mulnode.hpp @@ -95,6 +95,7 @@ class MulINode : public MulNode { virtual int Opcode() const; virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); virtual const Type *mul_ring( const Type *, const Type * ) const; + static bool does_overflow(const TypeInt* type_left, const TypeInt* type_right); const Type *mul_id() const { return TypeInt::ONE; } const Type *add_id() const { return TypeInt::ZERO; } int add_opcode() const { return Op_AddI; } diff --git a/src/hotspot/share/opto/output.cpp b/src/hotspot/share/opto/output.cpp index 64d98f27ff6..9481b91ce39 100644 --- a/src/hotspot/share/opto/output.cpp +++ b/src/hotspot/share/opto/output.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2024, 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 @@ -775,7 +775,7 @@ void PhaseOutput::FillLocArray( int idx, MachSafePointNode* sfpt, Node *local, SafePointScalarMergeNode* smerge = local->as_SafePointScalarMerge(); ObjectMergeValue* mv = (ObjectMergeValue*) sv_for_node_id(objs, smerge->_idx); - if (mv == NULL) { + if (mv == nullptr) { GrowableArray deps; int merge_pointer_idx = smerge->merge_pointer_idx(sfpt->jvms()); @@ -783,7 +783,7 @@ void PhaseOutput::FillLocArray( int idx, MachSafePointNode* sfpt, Node *local, assert(deps.length() == 1, "missing value"); int selector_idx = smerge->selector_idx(sfpt->jvms()); - (void)FillLocArray(1, NULL, sfpt->in(selector_idx), &deps, NULL); + (void)FillLocArray(1, nullptr, sfpt->in(selector_idx), &deps, nullptr); assert(deps.length() == 2, "missing value"); mv = new ObjectMergeValue(smerge->_idx, deps.at(0), deps.at(1)); @@ -1085,6 +1085,30 @@ void PhaseOutput::Process_OopMap_Node(MachNode *mach, int current_offset) { } scval = sv; } + } else if (obj_node->is_SafePointScalarMerge()) { + SafePointScalarMergeNode* smerge = obj_node->as_SafePointScalarMerge(); + ObjectMergeValue* mv = (ObjectMergeValue*) sv_for_node_id(objs, smerge->_idx); + + if (mv == nullptr) { + GrowableArray deps; + + int merge_pointer_idx = smerge->merge_pointer_idx(youngest_jvms); + FillLocArray(0, sfn, sfn->in(merge_pointer_idx), &deps, objs); + assert(deps.length() == 1, "missing value"); + + int selector_idx = smerge->selector_idx(youngest_jvms); + FillLocArray(1, nullptr, sfn->in(selector_idx), &deps, nullptr); + assert(deps.length() == 2, "missing value"); + + mv = new ObjectMergeValue(smerge->_idx, deps.at(0), deps.at(1)); + set_sv_for_object_node(objs, mv); + + for (uint i = 1; i < smerge->req(); i++) { + Node* obj_node = smerge->in(i); + FillLocArray(mv->possible_objects()->length(), sfn, obj_node, mv->possible_objects(), objs); + } + } + scval = mv; } else if (!obj_node->is_Con()) { OptoReg::Name obj_reg = C->regalloc()->get_reg_first(obj_node); if( obj_node->bottom_type()->base() == Type::NarrowOop ) { diff --git a/src/hotspot/share/opto/subnode.cpp b/src/hotspot/share/opto/subnode.cpp index f6790172351..5ecd7b4251f 100644 --- a/src/hotspot/share/opto/subnode.cpp +++ b/src/hotspot/share/opto/subnode.cpp @@ -155,7 +155,7 @@ static bool ok_to_convert(Node* inc, Node* var) { static bool is_cloop_condition(BoolNode* bol) { for (DUIterator_Fast imax, i = bol->fast_outs(imax); i < imax; i++) { Node* out = bol->fast_out(i); - if (out->is_CountedLoopEnd()) { + if (out->is_BaseCountedLoopEnd()) { return true; } } diff --git a/src/hotspot/share/opto/subtypenode.cpp b/src/hotspot/share/opto/subtypenode.cpp index 1011cb54245..393585d453c 100644 --- a/src/hotspot/share/opto/subtypenode.cpp +++ b/src/hotspot/share/opto/subtypenode.cpp @@ -43,18 +43,6 @@ const Type* SubTypeCheckNode::sub(const Type* sub_t, const Type* super_t) const if (!superklass->is_interface() && superklass->is_abstract() && !superklass->as_instance_klass()->has_subklass()) { Compile::current()->dependencies()->assert_leaf_type(superklass); - if (subk->is_same_java_type_as(superk) && !sub_t->maybe_null()) { - // The super_t has no subclasses, and sub_t has the same type and is not null, - // hence the check should always evaluate to EQ. However, this is an impossible - // situation since super_t is also abstract, and hence sub_t cannot have the - // same type and be non-null. - // Still, if the non-static method of an abstract class without subclasses is - // force-compiled, the Param0 has the self/this pointer with NotNull. This - // method would now never be called, because of the leaf-type dependency. Hence, - // just for consistency with verification, we return EQ. - return TypeInt::CC_EQ; - } - // subk is either a supertype of superk, or null. In either case, superk is a subtype. return TypeInt::CC_GT; } } diff --git a/src/hotspot/share/opto/vector.cpp b/src/hotspot/share/opto/vector.cpp index 1c2c9d982b5..d5993171e2a 100644 --- a/src/hotspot/share/opto/vector.cpp +++ b/src/hotspot/share/opto/vector.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, 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 @@ -276,7 +276,7 @@ void PhaseVector::scalarize_vbox_node(VectorBoxNode* vec_box) { SafePointNode* sfpt = safepoints.pop()->as_SafePoint(); uint first_ind = (sfpt->req() - sfpt->jvms()->scloff()); - Node* sobj = new SafePointScalarObjectNode(vec_box->box_type(), vec_box, first_ind, n_fields); + Node* sobj = new SafePointScalarObjectNode(vec_box->box_type(), vec_box, first_ind, sfpt->jvms()->depth(), n_fields); sobj->init_req(0, C->root()); sfpt->add_req(vec_value); diff --git a/src/hotspot/share/prims/foreignGlobals.cpp b/src/hotspot/share/prims/foreignGlobals.cpp index f3653d29886..11b0b8ace7c 100644 --- a/src/hotspot/share/prims/foreignGlobals.cpp +++ b/src/hotspot/share/prims/foreignGlobals.cpp @@ -140,7 +140,7 @@ int ForeignGlobals::compute_out_arg_bytes(const GrowableArray& out_re int ForeignGlobals::java_calling_convention(const BasicType* signature, int num_args, GrowableArray& out_regs) { VMRegPair* vm_regs = NEW_RESOURCE_ARRAY(VMRegPair, num_args); - int slots = SharedRuntime::java_calling_convention(signature, vm_regs, num_args); + int slots = align_up(SharedRuntime::java_calling_convention(signature, vm_regs, num_args), 2); for (int i = 0; i < num_args; i++) { VMRegPair pair = vm_regs[i]; // note, we ignore second here. Signature should consist of register-size values. So there should be diff --git a/src/hotspot/share/prims/jni.cpp b/src/hotspot/share/prims/jni.cpp index 33dcfb6c3fe..b6a4443a8c7 100644 --- a/src/hotspot/share/prims/jni.cpp +++ b/src/hotspot/share/prims/jni.cpp @@ -930,6 +930,11 @@ static void jni_invoke_nonstatic(JNIEnv *env, JavaValue* result, jobject receive } } + if (selected_method->is_abstract()) { + ResourceMark rm(THREAD); + THROW_MSG(vmSymbols::java_lang_AbstractMethodError(), selected_method->name()->as_C_string()); + } + methodHandle method(THREAD, selected_method); // Create object to hold arguments for the JavaCall, and associate it with diff --git a/src/hotspot/share/prims/jvm.cpp b/src/hotspot/share/prims/jvm.cpp index f0a30ee0311..9a8a9a5bec0 100644 --- a/src/hotspot/share/prims/jvm.cpp +++ b/src/hotspot/share/prims/jvm.cpp @@ -3933,8 +3933,6 @@ JVM_ENTRY(void, JVM_VirtualThreadStart(JNIEnv* env, jobject vthread)) // set VTMS transition bit value in JavaThread and java.lang.VirtualThread object JvmtiVTMSTransitionDisabler::set_is_in_VTMS_transition(thread, vthread, false); } -#else - fatal("Should only be called with JVMTI enabled"); #endif JVM_END @@ -3950,8 +3948,6 @@ JVM_ENTRY(void, JVM_VirtualThreadEnd(JNIEnv* env, jobject vthread)) // set VTMS transition bit value in JavaThread and java.lang.VirtualThread object JvmtiVTMSTransitionDisabler::set_is_in_VTMS_transition(thread, vthread, true); } -#else - fatal("Should only be called with JVMTI enabled"); #endif JVM_END @@ -3969,8 +3965,6 @@ JVM_ENTRY(void, JVM_VirtualThreadMount(JNIEnv* env, jobject vthread, jboolean hi // set VTMS transition bit value in JavaThread and java.lang.VirtualThread object JvmtiVTMSTransitionDisabler::set_is_in_VTMS_transition(thread, vthread, hide); } -#else - fatal("Should only be called with JVMTI enabled"); #endif JVM_END @@ -3988,8 +3982,6 @@ JVM_ENTRY(void, JVM_VirtualThreadUnmount(JNIEnv* env, jobject vthread, jboolean // set VTMS transition bit value in JavaThread and java.lang.VirtualThread object JvmtiVTMSTransitionDisabler::set_is_in_VTMS_transition(thread, vthread, hide); } -#else - fatal("Should only be called with JVMTI enabled"); #endif JVM_END @@ -4003,8 +3995,20 @@ JVM_ENTRY(void, JVM_VirtualThreadHideFrames(JNIEnv* env, jobject vthread, jboole assert(!thread->is_in_VTMS_transition(), "sanity check"); assert(thread->is_in_tmp_VTMS_transition() != (bool)hide, "sanity check"); thread->toggle_is_in_tmp_VTMS_transition(); -#else - fatal("Should only be called with JVMTI enabled"); +#endif +JVM_END + +// Notification from VirtualThread about disabling JVMTI Suspend in a sync critical section. +// Needed to avoid deadlocks with JVMTI suspend mechanism. +JVM_ENTRY(void, JVM_VirtualThreadDisableSuspend(JNIEnv* env, jobject vthread, jboolean enter)) +#if INCLUDE_JVMTI + if (!DoJVMTIVirtualThreadTransitions) { + assert(!JvmtiExport::can_support_virtual_threads(), "sanity check"); + return; + } + assert(thread->is_disable_suspend() != (bool)enter, + "nested or unbalanced monitor enter/exit is not allowed"); + thread->toggle_is_disable_suspend(); #endif JVM_END diff --git a/src/hotspot/share/prims/jvmtiAgent.cpp b/src/hotspot/share/prims/jvmtiAgent.cpp index 7e2f14ead3c..1231fd5019f 100644 --- a/src/hotspot/share/prims/jvmtiAgent.cpp +++ b/src/hotspot/share/prims/jvmtiAgent.cpp @@ -75,10 +75,6 @@ JvmtiAgent::JvmtiAgent(const char* name, const char* options, bool is_absolute_p _options(copy_string(options)), _os_lib(nullptr), _os_lib_path(nullptr), -#ifdef AIX - _inode(0), - _device(0), -#endif _jplis(nullptr), _loaded(false), _absolute_path(is_absolute_path), @@ -123,24 +119,6 @@ const char* JvmtiAgent::os_lib_path() const { return _os_lib_path; } -#ifdef AIX -void JvmtiAgent::set_inode(ino64_t inode) { - _inode = inode; -} - -void JvmtiAgent::set_device(dev64_t device) { - _device = device; -} - -ino64_t JvmtiAgent::inode() const { - return _inode; -} - -dev64_t JvmtiAgent::device() const { - return _device; -} -#endif - bool JvmtiAgent::is_loaded() const { return _loaded; } @@ -295,20 +273,6 @@ static bool load_agent_from_executable(JvmtiAgent* agent, const char* on_load_sy return os::find_builtin_agent(agent, &on_load_symbols[0], num_symbol_entries); } -#ifdef AIX -// save the inode and device of the library's file as a signature. This signature can be used -// in the same way as the library handle as a signature on other platforms. -static void save_library_signature(JvmtiAgent* agent, const char* name) { - struct stat64x libstat; - if (0 == os::Aix::stat64x_via_LIBPATH(name, &libstat)) { - agent->set_inode(libstat.st_ino); - agent->set_device(libstat.st_dev); - } else { - assert(false, "stat64x failed"); - } -} -#endif - // Load the library from the absolute path of the agent, if available. static void* load_agent_from_absolute_path(JvmtiAgent* agent, bool vm_exit_on_error) { DEBUG_ONLY(assert_preload(agent);) @@ -318,7 +282,6 @@ static void* load_agent_from_absolute_path(JvmtiAgent* agent, bool vm_exit_on_er if (library == nullptr && vm_exit_on_error) { vm_exit(agent, " in absolute path, with error: ", nullptr); } - AIX_ONLY(if (library != nullptr) save_library_signature(agent, agent->name());) return library; } @@ -331,13 +294,11 @@ static void* load_agent_from_relative_path(JvmtiAgent* agent, bool vm_exit_on_er // Try to load the agent from the standard dll directory if (os::dll_locate_lib(&buffer[0], sizeof buffer, Arguments::get_dll_dir(), name)) { library = os::dll_load(&buffer[0], &ebuf[0], sizeof ebuf); - AIX_ONLY(if (library != nullptr) save_library_signature(agent, &buffer[0]);) } if (library == nullptr && os::dll_build_name(&buffer[0], sizeof buffer, name)) { // Try the library path directory. library = os::dll_load(&buffer[0], &ebuf[0], sizeof ebuf); if (library != nullptr) { - AIX_ONLY(save_library_signature(agent, &buffer[0]);) return library; } if (vm_exit_on_error) { @@ -555,11 +516,7 @@ static bool invoke_Agent_OnAttach(JvmtiAgent* agent, outputStream* st) { agent->set_os_lib_path(&buffer[0]); agent->set_os_lib(library); agent->set_loaded(); - #ifdef AIX - previously_loaded = JvmtiAgentList::is_dynamic_lib_loaded(agent->device(), agent->inode()); - #else previously_loaded = JvmtiAgentList::is_dynamic_lib_loaded(library); - #endif } // Print warning if agent was not previously loaded and EnableDynamicAgentLoading not enabled on the command line. diff --git a/src/hotspot/share/prims/jvmtiAgent.hpp b/src/hotspot/share/prims/jvmtiAgent.hpp index 95e910354e6..9baf6698868 100644 --- a/src/hotspot/share/prims/jvmtiAgent.hpp +++ b/src/hotspot/share/prims/jvmtiAgent.hpp @@ -43,10 +43,6 @@ class JvmtiAgent : public CHeapObj { const char* _options; void* _os_lib; const char* _os_lib_path; -#ifdef AIX - ino64_t _inode; - dev64_t _device; -#endif const void* _jplis; bool _loaded; bool _absolute_path; @@ -84,12 +80,6 @@ class JvmtiAgent : public CHeapObj { void initialization_end(); const Ticks& initialization_time() const; const Tickspan& initialization_duration() const; -#ifdef AIX - void set_inode(ino64_t inode); - void set_device(dev64_t device); - unsigned long inode() const; - unsigned long device() const; -#endif bool load(outputStream* st = nullptr); void unload(); diff --git a/src/hotspot/share/prims/jvmtiAgentList.cpp b/src/hotspot/share/prims/jvmtiAgentList.cpp index b7312b9b75e..a32eeb7076c 100644 --- a/src/hotspot/share/prims/jvmtiAgentList.cpp +++ b/src/hotspot/share/prims/jvmtiAgentList.cpp @@ -243,19 +243,6 @@ bool JvmtiAgentList::is_dynamic_lib_loaded(void* os_lib) { } return false; } -#ifdef AIX -bool JvmtiAgentList::is_dynamic_lib_loaded(dev64_t device, ino64_t inode) { - JvmtiAgentList::Iterator it = JvmtiAgentList::agents(); - while (it.has_next()) { - JvmtiAgent* const agent = it.next(); - if (!agent->is_static_lib() && device != 0 && inode != 0 && - agent->device() == device && agent->inode() == inode) { - return true; - } - } - return false; -} -#endif static bool match(JvmtiEnv* env, const JvmtiAgent* agent, const void* os_module_address) { assert(env != nullptr, "invariant"); diff --git a/src/hotspot/share/prims/jvmtiAgentList.hpp b/src/hotspot/share/prims/jvmtiAgentList.hpp index 95dad006ec3..cf698c69c01 100644 --- a/src/hotspot/share/prims/jvmtiAgentList.hpp +++ b/src/hotspot/share/prims/jvmtiAgentList.hpp @@ -78,9 +78,6 @@ class JvmtiAgentList : AllStatic { static bool is_static_lib_loaded(const char* name); static bool is_dynamic_lib_loaded(void* os_lib); -#ifdef AIX - static bool is_dynamic_lib_loaded(dev64_t device, ino64_t inode); -#endif static JvmtiAgent* lookup(JvmtiEnv* env, void* f_ptr); diff --git a/src/hotspot/share/prims/jvmtiEnvBase.cpp b/src/hotspot/share/prims/jvmtiEnvBase.cpp index 9d6296ee316..6a3ee718709 100644 --- a/src/hotspot/share/prims/jvmtiEnvBase.cpp +++ b/src/hotspot/share/prims/jvmtiEnvBase.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, 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 @@ -2407,6 +2407,7 @@ UpdateForPopTopFrameClosure::doit(Thread *target, bool self) { void SetFramePopClosure::do_thread(Thread *target) { Thread* current = Thread::current(); + ResourceMark rm(current); // vframes are resource allocated JavaThread* java_thread = JavaThread::cast(target); if (java_thread->is_exiting()) { @@ -2433,6 +2434,9 @@ SetFramePopClosure::do_thread(Thread *target) { void SetFramePopClosure::do_vthread(Handle target_h) { + Thread* current = Thread::current(); + ResourceMark rm(current); // vframes are resource allocated + if (!_self && !JvmtiVTSuspender::is_vthread_suspended(target_h())) { _result = JVMTI_ERROR_THREAD_NOT_SUSPENDED; return; diff --git a/src/hotspot/share/runtime/arguments.cpp b/src/hotspot/share/runtime/arguments.cpp index fd8f155af42..250bef15869 100644 --- a/src/hotspot/share/runtime/arguments.cpp +++ b/src/hotspot/share/runtime/arguments.cpp @@ -315,7 +315,6 @@ static bool matches_property_suffix(const char* option, const char* property, si // any of the reserved module properties. // property should be passed without the leading "-D". bool Arguments::is_internal_module_property(const char* property) { - assert((strncmp(property, "-D", 2) != 0), "Unexpected leading -D"); if (strncmp(property, MODULE_PROPERTY_PREFIX, MODULE_PROPERTY_PREFIX_LEN) == 0) { const char* property_suffix = property + MODULE_PROPERTY_PREFIX_LEN; if (matches_property_suffix(property_suffix, ADDEXPORTS, ADDEXPORTS_LEN) || diff --git a/src/hotspot/share/runtime/continuationFreezeThaw.cpp b/src/hotspot/share/runtime/continuationFreezeThaw.cpp index fe1dfc62ee4..47906e81f11 100644 --- a/src/hotspot/share/runtime/continuationFreezeThaw.cpp +++ b/src/hotspot/share/runtime/continuationFreezeThaw.cpp @@ -1775,7 +1775,7 @@ class ThawBase : public StackObj { inline void before_thaw_java_frame(const frame& hf, const frame& caller, bool bottom, int num_frame); inline void after_thaw_java_frame(const frame& f, bool bottom); inline void patch(frame& f, const frame& caller, bool bottom); - void clear_bitmap_bits(intptr_t* start, int range); + void clear_bitmap_bits(address start, address end); NOINLINE void recurse_thaw_interpreted_frame(const frame& hf, frame& caller, int num_frames); void recurse_thaw_compiled_frame(const frame& hf, frame& caller, int num_frames, bool stub_caller); @@ -2166,13 +2166,22 @@ inline void ThawBase::patch(frame& f, const frame& caller, bool bottom) { assert(!bottom || (_cont.is_empty() != Continuation::is_cont_barrier_frame(f)), ""); } -void ThawBase::clear_bitmap_bits(intptr_t* start, int range) { +void ThawBase::clear_bitmap_bits(address start, address end) { + assert(is_aligned(start, wordSize), "should be aligned: " PTR_FORMAT, p2i(start)); + assert(is_aligned(end, VMRegImpl::stack_slot_size), "should be aligned: " PTR_FORMAT, p2i(end)); + // we need to clear the bits that correspond to arguments as they reside in the caller frame - // or they will keep objects that are otherwise unreachable alive - log_develop_trace(continuations)("clearing bitmap for " INTPTR_FORMAT " - " INTPTR_FORMAT, p2i(start), p2i(start+range)); + // or they will keep objects that are otherwise unreachable alive. + + // Align `end` if UseCompressedOops is not set to avoid UB when calculating the bit index, since + // `end` could be at an odd number of stack slots from `start`, i.e might not be oop aligned. + // If that's the case the bit range corresponding to the last stack slot should not have bits set + // anyways and we assert that before returning. + address effective_end = UseCompressedOops ? end : align_down(end, wordSize); + log_develop_trace(continuations)("clearing bitmap for " INTPTR_FORMAT " - " INTPTR_FORMAT, p2i(start), p2i(effective_end)); stackChunkOop chunk = _cont.tail(); - chunk->bitmap().clear_range(chunk->bit_index_for(start), - chunk->bit_index_for(start+range)); + chunk->bitmap().clear_range(chunk->bit_index_for(start), chunk->bit_index_for(effective_end)); + assert(effective_end == end || !chunk->bitmap().at(chunk->bit_index_for(effective_end)), "bit should not be set"); } NOINLINE void ThawBase::recurse_thaw_interpreted_frame(const frame& hf, frame& caller, int num_frames) { @@ -2225,7 +2234,9 @@ NOINLINE void ThawBase::recurse_thaw_interpreted_frame(const frame& hf, frame& c _cont.tail()->fix_thawed_frame(caller, SmallRegisterMap::instance); } else if (_cont.tail()->has_bitmap() && locals > 0) { assert(hf.is_heap_frame(), "should be"); - clear_bitmap_bits(heap_frame_bottom - locals, locals); + address start = (address)(heap_frame_bottom - locals); + address end = (address)heap_frame_bottom; + clear_bitmap_bits(start, end); } DEBUG_ONLY(after_thaw_java_frame(f, is_bottom_frame);) @@ -2298,7 +2309,10 @@ void ThawBase::recurse_thaw_compiled_frame(const frame& hf, frame& caller, int n // can only fix caller once this frame is thawed (due to callee saved regs); this happens on the stack _cont.tail()->fix_thawed_frame(caller, SmallRegisterMap::instance); } else if (_cont.tail()->has_bitmap() && added_argsize > 0) { - clear_bitmap_bits(heap_frame_top + ContinuationHelper::CompiledFrame::size(hf) + frame::metadata_words_at_top, added_argsize); + address start = (address)(heap_frame_top + ContinuationHelper::CompiledFrame::size(hf) + frame::metadata_words_at_top); + int stack_args_slots = f.cb()->as_compiled_method()->method()->num_stack_arg_slots(false /* rounded */); + int argsize_in_bytes = stack_args_slots * VMRegImpl::stack_slot_size; + clear_bitmap_bits(start, start + argsize_in_bytes); } DEBUG_ONLY(after_thaw_java_frame(f, is_bottom_frame);) diff --git a/src/hotspot/share/runtime/deoptimization.cpp b/src/hotspot/share/runtime/deoptimization.cpp index a5f2e09afaa..87587944469 100644 --- a/src/hotspot/share/runtime/deoptimization.cpp +++ b/src/hotspot/share/runtime/deoptimization.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, 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 @@ -1603,6 +1603,10 @@ void Deoptimization::reassign_fields(frame* fr, RegisterMap* reg_map, GrowableAr reassign_object_array_elements(fr, reg_map, sv, (objArrayOop) obj()); } } + // These objects may escape when we return to Interpreter after deoptimization. + // We need barrier so that stores that initialize these objects can't be reordered + // with subsequent stores that make these objects accessible by other threads. + OrderAccess::storestore(); } diff --git a/src/hotspot/share/runtime/frame.cpp b/src/hotspot/share/runtime/frame.cpp index f4893bae5db..c68180e105b 100644 --- a/src/hotspot/share/runtime/frame.cpp +++ b/src/hotspot/share/runtime/frame.cpp @@ -1439,7 +1439,7 @@ void frame::describe(FrameValues& values, int frame_no, const RegisterMap* reg_m assert(sig_index == sizeargs, ""); } int stack_arg_slots = SharedRuntime::java_calling_convention(sig_bt, regs, sizeargs); - assert(stack_arg_slots == m->num_stack_arg_slots(), ""); + assert(stack_arg_slots == m->num_stack_arg_slots(false /* rounded */), ""); int out_preserve = SharedRuntime::out_preserve_stack_slots(); int sig_index = 0; int arg_index = (m->is_static() ? 0 : -1); diff --git a/src/hotspot/share/runtime/globals.hpp b/src/hotspot/share/runtime/globals.hpp index dce90c78eb4..f697099179a 100644 --- a/src/hotspot/share/runtime/globals.hpp +++ b/src/hotspot/share/runtime/globals.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, 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 @@ -1992,7 +1992,7 @@ const int ObjectAlignmentInBytes = 8; "2: monitors & new lightweight locking (LM_LIGHTWEIGHT)") \ range(0, 2) \ \ - product(uint, TrimNativeHeapInterval, 0, EXPERIMENTAL, \ + product(uint, TrimNativeHeapInterval, 0, \ "Interval, in ms, at which the JVM will trim the native heap if " \ "the platform supports that. Lower values will reclaim memory " \ "more eagerly at the cost of higher overhead. A value of 0 " \ diff --git a/src/hotspot/share/runtime/handshake.cpp b/src/hotspot/share/runtime/handshake.cpp index 50c93d666e2..3919a89789c 100644 --- a/src/hotspot/share/runtime/handshake.cpp +++ b/src/hotspot/share/runtime/handshake.cpp @@ -487,6 +487,12 @@ HandshakeOperation* HandshakeState::get_op_for_self(bool allow_suspend, bool che assert(_handshakee == Thread::current(), "Must be called by self"); assert(_lock.owned_by_self(), "Lock must be held"); assert(allow_suspend || !check_async_exception, "invalid case"); +#if INCLUDE_JVMTI + if (allow_suspend && _handshakee->is_disable_suspend()) { + // filter out suspend operations while JavaThread is in disable_suspend mode + allow_suspend = false; + } +#endif if (!allow_suspend) { return _queue.peek(no_suspend_no_async_exception_filter); } else if (check_async_exception && !_async_exceptions_blocked) { diff --git a/src/hotspot/share/runtime/javaThread.cpp b/src/hotspot/share/runtime/javaThread.cpp index 98b2a569b72..5e04e3644a9 100644 --- a/src/hotspot/share/runtime/javaThread.cpp +++ b/src/hotspot/share/runtime/javaThread.cpp @@ -440,6 +440,7 @@ JavaThread::JavaThread() : _carrier_thread_suspended(false), _is_in_VTMS_transition(false), _is_in_tmp_VTMS_transition(false), + _is_disable_suspend(false), #ifdef ASSERT _is_VTMS_transition_disabler(false), #endif @@ -744,6 +745,7 @@ static void ensure_join(JavaThread* thread) { // Clear the native thread instance - this makes isAlive return false and allows the join() // to complete once we've done the notify_all below. Needs a release() to obey Java Memory Model // requirements. + assert(java_lang_Thread::thread(threadObj()) == thread, "must be alive"); java_lang_Thread::release_set_thread(threadObj(), nullptr); lock.notify_all(thread); // Ignore pending exception, since we are exiting anyway @@ -2154,6 +2156,8 @@ void JavaThread::start_internal_daemon(JavaThread* current, JavaThread* target, // on a ThreadsList. We don't want to wait for the release when the // Theads_lock is dropped when the 'mu' destructor is run since the // JavaThread* is already visible to JVM/TI via the ThreadsList. + + assert(java_lang_Thread::thread(thread_oop()) == nullptr, "must not be alive"); java_lang_Thread::release_set_thread(thread_oop(), target); // isAlive == true now Thread::start(target); } diff --git a/src/hotspot/share/runtime/javaThread.hpp b/src/hotspot/share/runtime/javaThread.hpp index 71bf0cc1d49..fb1355b852a 100644 --- a/src/hotspot/share/runtime/javaThread.hpp +++ b/src/hotspot/share/runtime/javaThread.hpp @@ -317,6 +317,7 @@ class JavaThread: public Thread { volatile bool _carrier_thread_suspended; // Carrier thread is externally suspended bool _is_in_VTMS_transition; // thread is in virtual thread mount state transition bool _is_in_tmp_VTMS_transition; // thread is in temporary virtual thread mount state transition + bool _is_disable_suspend; // JVMTI suspend is temporarily disabled; used on current thread only #ifdef ASSERT bool _is_VTMS_transition_disabler; // thread currently disabled VTMS transitions #endif @@ -647,6 +648,9 @@ class JavaThread: public Thread { void set_is_in_VTMS_transition(bool val); void toggle_is_in_tmp_VTMS_transition() { _is_in_tmp_VTMS_transition = !_is_in_tmp_VTMS_transition; }; + bool is_disable_suspend() const { return _is_disable_suspend; } + void toggle_is_disable_suspend() { _is_disable_suspend = !_is_disable_suspend; }; + #ifdef ASSERT bool is_VTMS_transition_disabler() const { return _is_VTMS_transition_disabler; } void set_is_VTMS_transition_disabler(bool val); @@ -811,6 +815,7 @@ class JavaThread: public Thread { #if INCLUDE_JVMTI static ByteSize is_in_VTMS_transition_offset() { return byte_offset_of(JavaThread, _is_in_VTMS_transition); } static ByteSize is_in_tmp_VTMS_transition_offset() { return byte_offset_of(JavaThread, _is_in_tmp_VTMS_transition); } + static ByteSize is_disable_suspend_offset() { return byte_offset_of(JavaThread, _is_disable_suspend); } #endif // Returns the jni environment for this thread diff --git a/src/hotspot/share/runtime/os.hpp b/src/hotspot/share/runtime/os.hpp index 094fd2509a0..4163d0cb818 100644 --- a/src/hotspot/share/runtime/os.hpp +++ b/src/hotspot/share/runtime/os.hpp @@ -1063,6 +1063,7 @@ class os: AllStatic { char pathSep); static bool set_boot_path(char fileSep, char pathSep); + static bool pd_dll_unload(void* libhandle, char* ebuf, int ebuflen); }; // Note that "PAUSE" is almost always used with synchronization diff --git a/src/hotspot/share/runtime/sharedRuntime.cpp b/src/hotspot/share/runtime/sharedRuntime.cpp index 9d582b790a1..94d42622c81 100644 --- a/src/hotspot/share/runtime/sharedRuntime.cpp +++ b/src/hotspot/share/runtime/sharedRuntime.cpp @@ -2004,7 +2004,7 @@ void SharedRuntime::check_member_name_argument_is_last_argument(const methodHand assert(member_arg_pos >= 0 && member_arg_pos < total_args_passed, "oob"); assert(sig_bt[member_arg_pos] == T_OBJECT, "dispatch argument must be an object"); - int comp_args_on_stack = java_calling_convention(sig_bt, regs_without_member_name, total_args_passed - 1); + java_calling_convention(sig_bt, regs_without_member_name, total_args_passed - 1); for (int i = 0; i < member_arg_pos; i++) { VMReg a = regs_with_member_name[i].first(); @@ -3102,7 +3102,7 @@ void AdapterHandlerLibrary::create_native_wrapper(const methodHandle& method) { BasicType ret_type = si.return_type(); // Now get the compiled-Java arguments layout. - int comp_args_on_stack = SharedRuntime::java_calling_convention(sig_bt, regs, total_args_passed); + SharedRuntime::java_calling_convention(sig_bt, regs, total_args_passed); // Generate the compiled-to-native wrapper code nm = SharedRuntime::generate_native_wrapper(&_masm, method, compile_id, sig_bt, regs, ret_type); diff --git a/src/hotspot/share/runtime/signature.cpp b/src/hotspot/share/runtime/signature.cpp index b085bf5fd05..081bdd2e0d3 100644 --- a/src/hotspot/share/runtime/signature.cpp +++ b/src/hotspot/share/runtime/signature.cpp @@ -178,7 +178,6 @@ void Fingerprinter::compute_fingerprint_and_return_type(bool static_flag) { } #if defined(_LP64) && !defined(ZERO) - _stack_arg_slots = align_up(_stack_arg_slots, 2); #ifdef ASSERT int dbg_stack_arg_slots = compute_num_stack_arg_slots(_signature, _param_size, static_flag); assert(_stack_arg_slots == dbg_stack_arg_slots, "fingerprinter: %d full: %d", _stack_arg_slots, dbg_stack_arg_slots); @@ -235,14 +234,17 @@ void Fingerprinter::do_type_calling_convention(BasicType type) { case T_BYTE: case T_SHORT: case T_INT: -#if defined(PPC64) || defined(S390) if (_int_args < Argument::n_int_register_parameters_j) { _int_args++; } else { +#if defined(PPC64) || defined(S390) + _stack_arg_slots += 1; +#else + _stack_arg_slots = align_up(_stack_arg_slots, 2); _stack_arg_slots += 1; +#endif // defined(PPC64) || defined(S390) } break; -#endif // defined(PPC64) || defined(S390) case T_LONG: case T_OBJECT: case T_ARRAY: @@ -250,26 +252,27 @@ void Fingerprinter::do_type_calling_convention(BasicType type) { if (_int_args < Argument::n_int_register_parameters_j) { _int_args++; } else { - PPC64_ONLY(_stack_arg_slots = align_up(_stack_arg_slots, 2)); - S390_ONLY(_stack_arg_slots = align_up(_stack_arg_slots, 2)); + _stack_arg_slots = align_up(_stack_arg_slots, 2); _stack_arg_slots += 2; } break; case T_FLOAT: -#if defined(PPC64) || defined(S390) if (_fp_args < Argument::n_float_register_parameters_j) { _fp_args++; } else { +#if defined(PPC64) || defined(S390) + _stack_arg_slots += 1; +#else + _stack_arg_slots = align_up(_stack_arg_slots, 2); _stack_arg_slots += 1; +#endif // defined(PPC64) || defined(S390) } break; -#endif // defined(PPC64) || defined(S390) case T_DOUBLE: if (_fp_args < Argument::n_float_register_parameters_j) { _fp_args++; } else { - PPC64_ONLY(_stack_arg_slots = align_up(_stack_arg_slots, 2)); - S390_ONLY(_stack_arg_slots = align_up(_stack_arg_slots, 2)); + _stack_arg_slots = align_up(_stack_arg_slots, 2); _stack_arg_slots += 2; } break; diff --git a/src/hotspot/share/runtime/thread.cpp b/src/hotspot/share/runtime/thread.cpp index 851e5139f8a..7401629bf94 100644 --- a/src/hotspot/share/runtime/thread.cpp +++ b/src/hotspot/share/runtime/thread.cpp @@ -73,6 +73,7 @@ Thread::Thread() { set_lgrp_id(-1); DEBUG_ONLY(clear_suspendible_thread();) DEBUG_ONLY(clear_indirectly_suspendible_thread();) + DEBUG_ONLY(clear_indirectly_safepoint_thread();) // allocated data structures set_osthread(nullptr); diff --git a/src/hotspot/share/runtime/thread.hpp b/src/hotspot/share/runtime/thread.hpp index cc431e8c900..7461876f378 100644 --- a/src/hotspot/share/runtime/thread.hpp +++ b/src/hotspot/share/runtime/thread.hpp @@ -207,6 +207,7 @@ class Thread: public ThreadShadow { private: DEBUG_ONLY(bool _suspendible_thread;) DEBUG_ONLY(bool _indirectly_suspendible_thread;) + DEBUG_ONLY(bool _indirectly_safepoint_thread;) public: // Determines if a heap allocation failure will be retried @@ -225,6 +226,10 @@ class Thread: public ThreadShadow { void set_indirectly_suspendible_thread() { _indirectly_suspendible_thread = true; } void clear_indirectly_suspendible_thread() { _indirectly_suspendible_thread = false; } bool is_indirectly_suspendible_thread() { return _indirectly_suspendible_thread; } + + void set_indirectly_safepoint_thread() { _indirectly_safepoint_thread = true; } + void clear_indirectly_safepoint_thread() { _indirectly_safepoint_thread = false; } + bool is_indirectly_safepoint_thread() { return _indirectly_safepoint_thread; } #endif private: diff --git a/src/hotspot/share/services/heapDumper.cpp b/src/hotspot/share/services/heapDumper.cpp index a46101f6d8d..add86b338de 100644 --- a/src/hotspot/share/services/heapDumper.cpp +++ b/src/hotspot/share/services/heapDumper.cpp @@ -1641,6 +1641,19 @@ class ThreadDumper : public CHeapObj { && java_lang_VirtualThread::state(vt) != java_lang_VirtualThread::TERMINATED; } + static bool is_vthread_mounted(oop vt) { + // The code should be consistent with the "mounted virtual thread" case + // (VM_HeapDumper::dump_stack_traces(), ThreadDumper::get_top_frame()). + // I.e. virtual thread is mounted if its carrierThread is not null + // and is_vthread_mounted() for the carrier thread returns true. + oop carrier_thread = java_lang_VirtualThread::carrier_thread(vt); + if (carrier_thread == nullptr) { + return false; + } + JavaThread* java_thread = java_lang_Thread::thread(carrier_thread); + return java_thread->is_vthread_mounted(); + } + ThreadDumper(ThreadType thread_type, JavaThread* java_thread, oop thread_oop); // affects frame_count @@ -1918,7 +1931,10 @@ void HeapObjectDumper::do_object(oop o) { if (o->is_instance()) { // create a HPROF_GC_INSTANCE record for each object DumperSupport::dump_instance(writer(), o, &_class_cache); - if (java_lang_VirtualThread::is_instance(o) && ThreadDumper::should_dump_vthread(o)) { + // If we encounter an unmounted virtual thread it needs to be dumped explicitly + // (mounted virtual threads are dumped with their carriers). + if (java_lang_VirtualThread::is_instance(o) + && ThreadDumper::should_dump_vthread(o) && !ThreadDumper::is_vthread_mounted(o)) { _vthread_dumper->dump_vthread(o, writer()); } } else if (o->is_objArray()) { diff --git a/src/hotspot/share/utilities/copy.cpp b/src/hotspot/share/utilities/copy.cpp index 9ead75f2ceb..ed779796943 100644 --- a/src/hotspot/share/utilities/copy.cpp +++ b/src/hotspot/share/utilities/copy.cpp @@ -243,6 +243,16 @@ void Copy::fill_to_memory_atomic(void* to, size_t size, jubyte value) { } } else { // Not aligned, so no need to be atomic. +#ifdef MUSL_LIBC + // This code is used by Unsafe and may hit the next page after truncation of mapped memory. + // Therefore, we use volatile to prevent compilers from replacing the loop by memset which + // may not trigger SIGBUS as needed (observed on Alpine Linux x86_64) + jbyte fill = value; + for (uintptr_t off = 0; off < size; off += sizeof(jbyte)) { + *(volatile jbyte*)(dst + off) = fill; + } +#else Copy::fill_to_bytes(dst, size, value); +#endif } } diff --git a/src/hotspot/share/utilities/exceptions.cpp b/src/hotspot/share/utilities/exceptions.cpp index bca6837ee13..83cb3435fff 100644 --- a/src/hotspot/share/utilities/exceptions.cpp +++ b/src/hotspot/share/utilities/exceptions.cpp @@ -564,11 +564,11 @@ void Exceptions::debug_check_abort_helper(Handle exception, const char* message) // for logging exceptions void Exceptions::log_exception(Handle exception, const char* message) { ResourceMark rm; - Symbol* detail_message = java_lang_Throwable::detail_message(exception()); + const char* detail_message = java_lang_Throwable::message_as_utf8(exception()); if (detail_message != nullptr) { log_info(exceptions)("Exception <%s: %s>\n thrown in %s", exception->print_value_string(), - detail_message->as_C_string(), + detail_message, message); } else { log_info(exceptions)("Exception <%s>\n thrown in %s", diff --git a/src/java.base/linux/native/libjava/CgroupMetrics.c b/src/java.base/linux/native/libjava/CgroupMetrics.c index 4f7847edbde..a5e41167bc3 100644 --- a/src/java.base/linux/native/libjava/CgroupMetrics.c +++ b/src/java.base/linux/native/libjava/CgroupMetrics.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Red Hat, Inc. + * Copyright (c) 2020, 2024, Red Hat, Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -54,5 +54,5 @@ Java_jdk_internal_platform_CgroupMetrics_getTotalSwapSize0 if (retval < 0) { return 0; // syinfo failed, treat as no swap } - return (jlong)si.totalswap; + return (jlong)(si.totalswap * si.mem_unit); } diff --git a/src/java.base/macosx/native/libjava/HostLocaleProviderAdapter_md.c b/src/java.base/macosx/native/libjava/HostLocaleProviderAdapter_md.c index 14094e11c45..99dbbcb41d7 100644 --- a/src/java.base/macosx/native/libjava/HostLocaleProviderAdapter_md.c +++ b/src/java.base/macosx/native/libjava/HostLocaleProviderAdapter_md.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2024, 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 @@ -427,6 +427,9 @@ JNIEXPORT jstring JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapte JNIEXPORT jint JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getCalendarInt (JNIEnv *env, jclass cls, jstring jlangtag, jint type) { jint ret = 0; + // Majority of MacOSX fixed locales return Gregorian cal identifier + // Using CFCalendarCopyCurrent() provides a cal that is based off OS settings + // which is more accurate than one created with a Gregorian identifier CFCalendarRef cfcal = CFCalendarCopyCurrent(); if (cfcal != NULL) { diff --git a/src/java.base/share/classes/com/sun/crypto/provider/RSACipher.java b/src/java.base/share/classes/com/sun/crypto/provider/RSACipher.java index 4278003c465..df76f78bfb5 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/RSACipher.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/RSACipher.java @@ -98,6 +98,7 @@ public final class RSACipher extends CipherSpi { // cipher parameter for OAEP padding and TLS RSA premaster secret private AlgorithmParameterSpec spec = null; + private boolean forTlsPremasterSecret = false; // buffer for the data private byte[] buffer; @@ -286,6 +287,7 @@ private void init(int opmode, Key key, SecureRandom random, } spec = params; + forTlsPremasterSecret = true; this.random = random; // for TLS RSA premaster secret } int blockType = (mode <= MODE_DECRYPT) ? RSAPadding.PAD_BLOCKTYPE_2 @@ -377,7 +379,7 @@ private byte[] doFinal() throws BadPaddingException, byte[] decryptBuffer = RSACore.convert(buffer, 0, bufOfs); paddingCopy = RSACore.rsa(decryptBuffer, privateKey, false); result = padding.unpad(paddingCopy); - if (result == null) { + if (result == null && !forTlsPremasterSecret) { throw new BadPaddingException ("Padding error in decryption"); } @@ -466,26 +468,22 @@ protected Key engineUnwrap(byte[] wrappedKey, String algorithm, boolean isTlsRsaPremasterSecret = algorithm.equals("TlsRsaPremasterSecret"); - Exception failover = null; byte[] encoded = null; update(wrappedKey, 0, wrappedKey.length); try { encoded = doFinal(); - } catch (BadPaddingException e) { - if (isTlsRsaPremasterSecret) { - failover = e; - } else { - throw new InvalidKeyException("Unwrapping failed", e); - } - } catch (IllegalBlockSizeException e) { - // should not occur, handled with length check above + } catch (BadPaddingException | IllegalBlockSizeException e) { + // BadPaddingException cannot happen for TLS RSA unwrap. + // In that case, padding error is indicated by returning null. + // IllegalBlockSizeException cannot happen in any case, + // because of the length check above. throw new InvalidKeyException("Unwrapping failed", e); } try { if (isTlsRsaPremasterSecret) { - if (!(spec instanceof TlsRsaPremasterSecretParameterSpec)) { + if (!forTlsPremasterSecret) { throw new IllegalStateException( "No TlsRsaPremasterSecretParameterSpec specified"); } @@ -494,7 +492,7 @@ protected Key engineUnwrap(byte[] wrappedKey, String algorithm, encoded = KeyUtil.checkTlsPreMasterSecretKey( ((TlsRsaPremasterSecretParameterSpec) spec).getClientVersion(), ((TlsRsaPremasterSecretParameterSpec) spec).getServerVersion(), - random, encoded, (failover != null)); + random, encoded, encoded == null); } return ConstructKeys.constructKey(encoded, algorithm, type); diff --git a/src/java.base/share/classes/java/lang/PinnedThreadPrinter.java b/src/java.base/share/classes/java/lang/PinnedThreadPrinter.java index 02e0683a1b9..a9b40d028f5 100644 --- a/src/java.base/share/classes/java/lang/PinnedThreadPrinter.java +++ b/src/java.base/share/classes/java/lang/PinnedThreadPrinter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2023, 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,10 @@ import java.util.Set; import java.util.stream.Collectors; import static java.lang.StackWalker.Option.*; +import jdk.internal.access.JavaIOPrintStreamAccess; +import jdk.internal.access.SharedSecrets; +import jdk.internal.misc.InternalLock; +import jdk.internal.vm.Continuation; /** * Helper class to print the virtual thread stack trace when pinned. @@ -42,7 +46,8 @@ * code in that Class. This is used to avoid printing the same stack trace many times. */ class PinnedThreadPrinter { - static final StackWalker STACK_WALKER; + private static final JavaIOPrintStreamAccess JIOPSA = SharedSecrets.getJavaIOPrintStreamAccess(); + private static final StackWalker STACK_WALKER; static { var options = Set.of(SHOW_REFLECT_FRAMES, RETAIN_CLASS_REFERENCE); PrivilegedAction pa = () -> @@ -86,45 +91,59 @@ private static int hash(List stack) { } /** - * Prints the continuation stack trace. + * Returns true if the frame is native, a class initializer, or holds monitors. + */ + private static boolean isInterestingFrame(LiveStackFrame f) { + return f.isNativeMethod() + || "".equals(f.getMethodName()) + || (f.getMonitors().length > 0); + } + + /** + * Prints the current thread's stack trace. * * @param printAll true to print all stack frames, false to only print the * frames that are native or holding a monitor */ - static void printStackTrace(PrintStream out, boolean printAll) { + static void printStackTrace(PrintStream out, Continuation.Pinned reason, boolean printAll) { List stack = STACK_WALKER.walk(s -> s.map(f -> (LiveStackFrame) f) .filter(f -> f.getDeclaringClass() != PinnedThreadPrinter.class) .collect(Collectors.toList()) ); + Object lockObj = JIOPSA.lock(out); + if (lockObj instanceof InternalLock lock && lock.tryLock()) { + try { + // find the closest frame that is causing the thread to be pinned + stack.stream() + .filter(f -> isInterestingFrame(f)) + .map(LiveStackFrame::getDeclaringClass) + .findFirst() + .ifPresentOrElse(klass -> { + // print the stack trace if not already seen + int hash = hash(stack); + if (HASHES.get(klass).add(hash)) { + printStackTrace(out, reason, stack, printAll); + } + }, () -> printStackTrace(out, reason, stack, true)); // not found - // find the closest frame that is causing the thread to be pinned - stack.stream() - .filter(f -> (f.isNativeMethod() || f.getMonitors().length > 0)) - .map(LiveStackFrame::getDeclaringClass) - .findFirst() - .ifPresentOrElse(klass -> { - int hash = hash(stack); - Hashes hashes = HASHES.get(klass); - synchronized (hashes) { - // print the stack trace if not already seen - if (hashes.add(hash)) { - printStackTrace(stack, out, printAll); - } - } - }, () -> printStackTrace(stack, out, true)); // not found + } finally { + lock.unlock(); + } + } } - private static void printStackTrace(List stack, - PrintStream out, + private static void printStackTrace(PrintStream out, + Continuation.Pinned reason, + List stack, boolean printAll) { - out.println(Thread.currentThread()); + out.format("%s reason:%s%n", Thread.currentThread(), reason); for (LiveStackFrame frame : stack) { var ste = frame.toStackTraceElement(); int monitorCount = frame.getMonitors().length; if (monitorCount > 0) { out.format(" %s <== monitors:%d%n", ste, monitorCount); - } else if (frame.isNativeMethod() || printAll) { + } else if (printAll || isInterestingFrame(frame)) { out.format(" %s%n", ste); } } diff --git a/src/java.base/share/classes/java/lang/String.java b/src/java.base/share/classes/java/lang/String.java index 2245792999a..f5bd29083d3 100644 --- a/src/java.base/share/classes/java/lang/String.java +++ b/src/java.base/share/classes/java/lang/String.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2024, 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 @@ -841,7 +841,7 @@ private static String newStringNoRepl1(byte[] src, Charset cs) { } if (COMPACT_STRINGS) { byte[] val = StringUTF16.compress(ca, 0, caLen); - int coder = StringUTF16.coderFromArrayLen(val, len); + byte coder = StringUTF16.coderFromArrayLen(val, caLen); return new String(val, coder); } return new String(StringUTF16.toBytes(ca, 0, caLen), UTF16); diff --git a/src/java.base/share/classes/java/lang/StringBuffer.java b/src/java.base/share/classes/java/lang/StringBuffer.java index ec7ecb5d245..d77462f0c70 100644 --- a/src/java.base/share/classes/java/lang/StringBuffer.java +++ b/src/java.base/share/classes/java/lang/StringBuffer.java @@ -715,6 +715,7 @@ public synchronized StringBuffer reverse() { */ @Override public synchronized StringBuffer repeat(int codePoint, int count) { + toStringCache = null; super.repeat(codePoint, count); return this; } @@ -726,6 +727,7 @@ public synchronized StringBuffer repeat(int codePoint, int count) { */ @Override public synchronized StringBuffer repeat(CharSequence cs, int count) { + toStringCache = null; super.repeat(cs, count); return this; } diff --git a/src/java.base/share/classes/java/lang/System.java b/src/java.base/share/classes/java/lang/System.java index 0c100793167..fb2aca379da 100644 --- a/src/java.base/share/classes/java/lang/System.java +++ b/src/java.base/share/classes/java/lang/System.java @@ -57,6 +57,7 @@ import java.security.ProtectionDomain; import java.util.Collections; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Objects; import java.util.Properties; @@ -813,6 +814,10 @@ public static native void arraycopy(Object src, int srcPos, * Note that even if the security manager does not permit the * {@code getProperties} operation, it may choose to permit the * {@link #getProperty(String)} operation. + *

+ * Additional locale-related system properties defined by the + * {@link Locale##default_locale Default Locale} section in the {@code Locale} + * class description may also be obtained with this method. * * @apiNote * Changing a standard system property may have unpredictable results diff --git a/src/java.base/share/classes/java/lang/VirtualThread.java b/src/java.base/share/classes/java/lang/VirtualThread.java index 2707b3ba9bd..6f82516d864 100644 --- a/src/java.base/share/classes/java/lang/VirtualThread.java +++ b/src/java.base/share/classes/java/lang/VirtualThread.java @@ -191,7 +191,15 @@ private static class VThreadContinuation extends Continuation { protected void onPinned(Continuation.Pinned reason) { if (TRACE_PINNING_MODE > 0) { boolean printAll = (TRACE_PINNING_MODE == 1); - PinnedThreadPrinter.printStackTrace(System.out, printAll); + VirtualThread vthread = (VirtualThread) Thread.currentThread(); + int oldState = vthread.state(); + try { + // avoid printing when in transition states + vthread.setState(RUNNING); + PinnedThreadPrinter.printStackTrace(System.out, reason, printAll); + } finally { + vthread.setState(oldState); + } } } private static Runnable wrap(VirtualThread vthread, Runnable task) { @@ -743,11 +751,16 @@ void unpark() { } } else if ((s == PINNED) || (s == TIMED_PINNED)) { // unpark carrier thread when pinned - synchronized (carrierThreadAccessLock()) { - Thread carrier = carrierThread; - if (carrier != null && ((s = state()) == PINNED || s == TIMED_PINNED)) { - U.unpark(carrier); + notifyJvmtiDisableSuspend(true); + try { + synchronized (carrierThreadAccessLock()) { + Thread carrier = carrierThread; + if (carrier != null && ((s = state()) == PINNED || s == TIMED_PINNED)) { + U.unpark(carrier); + } } + } finally { + notifyJvmtiDisableSuspend(false); } } } @@ -844,16 +857,21 @@ boolean joinNanos(long nanos) throws InterruptedException { public void interrupt() { if (Thread.currentThread() != this) { checkAccess(); - synchronized (interruptLock) { - interrupted = true; - Interruptible b = nioBlocker; - if (b != null) { - b.interrupt(this); - } + notifyJvmtiDisableSuspend(true); + try { + synchronized (interruptLock) { + interrupted = true; + Interruptible b = nioBlocker; + if (b != null) { + b.interrupt(this); + } - // interrupt carrier thread if mounted - Thread carrier = carrierThread; - if (carrier != null) carrier.setInterrupt(); + // interrupt carrier thread if mounted + Thread carrier = carrierThread; + if (carrier != null) carrier.setInterrupt(); + } + } finally { + notifyJvmtiDisableSuspend(false); } } else { interrupted = true; @@ -872,9 +890,14 @@ boolean getAndClearInterrupt() { assert Thread.currentThread() == this; boolean oldValue = interrupted; if (oldValue) { - synchronized (interruptLock) { - interrupted = false; - carrierThread.clearInterrupt(); + notifyJvmtiDisableSuspend(true); + try { + synchronized (interruptLock) { + interrupted = false; + carrierThread.clearInterrupt(); + } + } finally { + notifyJvmtiDisableSuspend(false); } } return oldValue; @@ -899,11 +922,16 @@ Thread.State threadState() { return Thread.State.RUNNABLE; case RUNNING: // if mounted then return state of carrier thread - synchronized (carrierThreadAccessLock()) { - Thread carrierThread = this.carrierThread; - if (carrierThread != null) { - return carrierThread.threadState(); + notifyJvmtiDisableSuspend(true); + try { + synchronized (carrierThreadAccessLock()) { + Thread carrierThread = this.carrierThread; + if (carrierThread != null) { + return carrierThread.threadState(); + } } + } finally { + notifyJvmtiDisableSuspend(false); } // runnable, mounted return Thread.State.RUNNABLE; @@ -955,12 +983,12 @@ StackTraceElement[] asyncGetStackTrace() { * Returns null if the thread is mounted or in transition. */ private StackTraceElement[] tryGetStackTrace() { - int initialState = state(); + int initialState = state() & ~SUSPENDED; switch (initialState) { case NEW, STARTED, TERMINATED -> { return new StackTraceElement[0]; // unmounted, empty stack } - case RUNNING, PINNED -> { + case RUNNING, PINNED, TIMED_PINNED -> { return null; // mounted } case PARKED, TIMED_PARKED -> { @@ -972,7 +1000,7 @@ private StackTraceElement[] tryGetStackTrace() { case PARKING, TIMED_PARKING, YIELDING -> { return null; // in transition } - default -> throw new InternalError(); + default -> throw new InternalError("" + initialState); } // thread is unmounted, prevent it from continuing @@ -1019,14 +1047,19 @@ public String toString() { Thread carrier = carrierThread; if (carrier != null) { // include the carrier thread state and name when mounted - synchronized (carrierThreadAccessLock()) { - carrier = carrierThread; - if (carrier != null) { - String stateAsString = carrier.threadState().toString(); - sb.append(stateAsString.toLowerCase(Locale.ROOT)); - sb.append('@'); - sb.append(carrier.getName()); + notifyJvmtiDisableSuspend(true); + try { + synchronized (carrierThreadAccessLock()) { + carrier = carrierThread; + if (carrier != null) { + String stateAsString = carrier.threadState().toString(); + sb.append(stateAsString.toLowerCase(Locale.ROOT)); + sb.append('@'); + sb.append(carrier.getName()); + } } + } finally { + notifyJvmtiDisableSuspend(false); } } // include virtual thread state when not mounted @@ -1125,6 +1158,9 @@ private void setCarrierThread(Thread carrier) { @JvmtiMountTransition private native void notifyJvmtiHideFrames(boolean hide); + @IntrinsicCandidate + private native void notifyJvmtiDisableSuspend(boolean enter); + private static native void registerNatives(); static { registerNatives(); diff --git a/src/java.base/share/classes/java/lang/foreign/Arena.java b/src/java.base/share/classes/java/lang/foreign/Arena.java index 195f8a44db6..c9a79c9700d 100644 --- a/src/java.base/share/classes/java/lang/foreign/Arena.java +++ b/src/java.base/share/classes/java/lang/foreign/Arena.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, 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 @@ -219,6 +219,9 @@ public interface Arena extends SegmentAllocator, AutoCloseable { * Segments allocated with the returned arena can be * {@linkplain MemorySegment#isAccessibleBy(Thread) accessed} by any thread. * Calling {@link #close()} on the returned arena will result in an {@link UnsupportedOperationException}. + *

+ * Memory segments {@linkplain #allocate(long, long) allocated} by the returned arena + * are zero-initialized. * * @return a new arena that is managed, automatically, by the garbage collector */ @@ -231,6 +234,9 @@ static Arena ofAuto() { * {@linkplain MemorySegment#isAccessibleBy(Thread) accessed} by any thread. * Calling {@link #close()} on the returned arena will result in * an {@link UnsupportedOperationException}. + *

+ * Memory segments {@linkplain #allocate(long, long) allocated} by the returned arena + * are zero-initialized. */ static Arena global() { class Holder { @@ -243,14 +249,20 @@ class Holder { * {@return a new confined arena} Segments allocated with the confined arena can be * {@linkplain MemorySegment#isAccessibleBy(Thread) accessed} by the thread * that created the arena, the arena's owner thread. + *

+ * Memory segments {@linkplain #allocate(long, long) allocated} by the returned arena + * are zero-initialized. */ static Arena ofConfined() { return MemorySessionImpl.createConfined(Thread.currentThread()).asArena(); } /** - * {@return a new shared arena} Segments allocated with the global arena can be + * {@return a new shared arena} Segments allocated with the shared arena can be * {@linkplain MemorySegment#isAccessibleBy(Thread) accessed} by any thread. + *

+ * Memory segments {@linkplain #allocate(long, long) allocated} by the returned arena + * are zero-initialized. */ static Arena ofShared() { return MemorySessionImpl.createShared().asArena(); diff --git a/src/java.base/share/classes/java/lang/foreign/MemoryLayout.java b/src/java.base/share/classes/java/lang/foreign/MemoryLayout.java index 321d9b09bad..8a2b3b4df30 100644 --- a/src/java.base/share/classes/java/lang/foreign/MemoryLayout.java +++ b/src/java.base/share/classes/java/lang/foreign/MemoryLayout.java @@ -1016,7 +1016,7 @@ static PaddingLayout paddingLayout(long byteSize) { * @throws IllegalArgumentException if {@code elementLayout.byteSize() % elementLayout.byteAlignment() != 0} */ static SequenceLayout sequenceLayout(long elementCount, MemoryLayout elementLayout) { - MemoryLayoutUtil.requireNonNegative(elementCount); + Utils.checkNonNegativeArgument(elementCount, "elementCount"); Objects.requireNonNull(elementLayout); Utils.checkElementAlignment(elementLayout, "Element layout size is not multiple of alignment"); diff --git a/src/java.base/share/classes/java/lang/foreign/MemorySegment.java b/src/java.base/share/classes/java/lang/foreign/MemorySegment.java index da255b9912b..faf28b01bf0 100644 --- a/src/java.base/share/classes/java/lang/foreign/MemorySegment.java +++ b/src/java.base/share/classes/java/lang/foreign/MemorySegment.java @@ -44,6 +44,7 @@ import jdk.internal.foreign.AbstractMemorySegmentImpl; import jdk.internal.foreign.MemorySessionImpl; import jdk.internal.foreign.SegmentFactories; +import jdk.internal.foreign.Utils; import jdk.internal.javac.Restricted; import jdk.internal.reflect.CallerSensitive; import jdk.internal.vm.annotation.ForceInline; @@ -1591,6 +1592,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * incompatible with the alignment constraint * in the provided layout * @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()} + * or {@code offset < 0} */ byte get(ValueLayout.OfByte layout, long offset); @@ -1609,6 +1611,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * incompatible with the alignment constraint * in the provided layout * @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()} + * or {@code offset < 0} * @throws IllegalArgumentException if this segment is * {@linkplain #isReadOnly() read-only} */ @@ -1629,6 +1632,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * incompatible with the alignment constraint * in the provided layout * @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()} + * or {@code offset < 0} */ boolean get(ValueLayout.OfBoolean layout, long offset); @@ -1647,6 +1651,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * incompatible with the alignment constraint * in the provided layout * @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()} + * or {@code offset < 0} * @throws IllegalArgumentException if this segment is * {@linkplain #isReadOnly() read-only} */ @@ -1667,6 +1672,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * incompatible with the alignment constraint * in the provided layout * @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()} + * or {@code offset < 0} */ char get(ValueLayout.OfChar layout, long offset); @@ -1685,6 +1691,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * incompatible with the alignment constraint * in the provided layout * @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()} + * or {@code offset < 0} * @throws IllegalArgumentException if this segment is * {@linkplain #isReadOnly() read-only} */ @@ -1705,6 +1712,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * incompatible with the alignment constraint * in the provided layout * @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()} + * or {@code offset < 0} */ short get(ValueLayout.OfShort layout, long offset); @@ -1723,6 +1731,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * incompatible with the alignment constraint * in the provided layout * @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()} + * or {@code offset < 0} * @throws IllegalArgumentException if this segment is * {@linkplain #isReadOnly() read-only} */ @@ -1743,6 +1752,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * incompatible with the alignment constraint * in the provided layout * @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()} + * or {@code offset < 0} */ int get(ValueLayout.OfInt layout, long offset); @@ -1761,6 +1771,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * incompatible with the alignment constraint * in the provided layout * @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()} + * or {@code offset < 0} * @throws IllegalArgumentException if this segment is * {@linkplain #isReadOnly() read-only} */ @@ -1781,6 +1792,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * incompatible with the alignment constraint * in the provided layout * @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()} + * or {@code offset < 0} */ float get(ValueLayout.OfFloat layout, long offset); @@ -1799,6 +1811,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * incompatible with the alignment constraint * in the provided layout * @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()} + * or {@code offset < 0} * @throws IllegalArgumentException if this segment is * {@linkplain #isReadOnly() read-only} */ @@ -1819,6 +1832,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * incompatible with the alignment constraint * in the provided layout * @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()} + * or {@code offset < 0} */ long get(ValueLayout.OfLong layout, long offset); @@ -1837,6 +1851,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * incompatible with the alignment constraint * in the provided layout * @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()} + * or {@code offset < 0} * @throws IllegalArgumentException if this segment is * {@linkplain #isReadOnly() read-only} */ @@ -1857,6 +1872,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * incompatible with the alignment constraint * in the provided layout * @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()} + * or {@code offset < 0} */ double get(ValueLayout.OfDouble layout, long offset); @@ -1875,6 +1891,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * incompatible with the alignment constraint * in the provided layout * @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()} + * or {@code offset < 0} * @throws IllegalArgumentException if this segment is * {@linkplain #isReadOnly() read-only} */ @@ -1905,6 +1922,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * incompatible with the alignment constraint * in {@code T} * @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()} + * or {@code offset < 0} */ MemorySegment get(AddressLayout layout, long offset); @@ -1923,8 +1941,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * incompatible with the alignment constraint * in the provided layout * @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()} - * @throws UnsupportedOperationException if this segment is - * {@linkplain #isReadOnly() read-only} + * or {@code offset < 0} * @throws IllegalArgumentException if {@code value} is not a * {@linkplain #isNative() native} segment * @throws IllegalArgumentException if this segment is @@ -1951,6 +1968,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()} * @throws IndexOutOfBoundsException if {@code index * layout.byteSize()} overflows * @throws IndexOutOfBoundsException if {@code index * layout.byteSize() > byteSize() - layout.byteSize()} + * or {@code index < 0} */ byte getAtIndex(ValueLayout.OfByte layout, long index); @@ -1973,6 +1991,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()} * @throws IndexOutOfBoundsException if {@code index * layout.byteSize()} overflows * @throws IndexOutOfBoundsException if {@code index * layout.byteSize() > byteSize() - layout.byteSize()} + * or {@code index < 0} */ boolean getAtIndex(ValueLayout.OfBoolean layout, long index); @@ -1995,6 +2014,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()} * @throws IndexOutOfBoundsException if {@code index * layout.byteSize()} overflows * @throws IndexOutOfBoundsException if {@code index * layout.byteSize() > byteSize() - layout.byteSize()} + * or {@code index < 0} */ char getAtIndex(ValueLayout.OfChar layout, long index); @@ -2017,7 +2037,8 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()} * @throws IndexOutOfBoundsException if {@code index * layout.byteSize()} overflows * @throws IndexOutOfBoundsException if {@code index * layout.byteSize() > byteSize() - layout.byteSize()} - * @throws UnsupportedOperationException if this segment is {@linkplain #isReadOnly() read-only} + * or {@code index < 0} + * @throws IllegalArgumentException if this segment is {@linkplain #isReadOnly() read-only} */ void setAtIndex(ValueLayout.OfChar layout, long index, char value); @@ -2040,6 +2061,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()} * @throws IndexOutOfBoundsException if {@code index * layout.byteSize()} overflows * @throws IndexOutOfBoundsException if {@code index * layout.byteSize() > byteSize() - layout.byteSize()} + * or {@code index < 0} */ short getAtIndex(ValueLayout.OfShort layout, long index); @@ -2061,6 +2083,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()} * @throws IndexOutOfBoundsException if {@code index * layout.byteSize()} overflows * @throws IndexOutOfBoundsException if {@code index * layout.byteSize() > byteSize() - layout.byteSize()} + * or {@code index < 0} * @throws IllegalArgumentException if this segment is {@linkplain #isReadOnly() read-only} */ void setAtIndex(ValueLayout.OfByte layout, long index, byte value); @@ -2084,6 +2107,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()} * @throws IndexOutOfBoundsException if {@code index * layout.byteSize()} overflows * @throws IndexOutOfBoundsException if {@code index * layout.byteSize() > byteSize() - layout.byteSize()} + * or {@code index < 0} * @throws IllegalArgumentException if this segment is {@linkplain #isReadOnly() read-only} */ void setAtIndex(ValueLayout.OfBoolean layout, long index, boolean value); @@ -2107,6 +2131,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()} * @throws IndexOutOfBoundsException if {@code index * layout.byteSize()} overflows * @throws IndexOutOfBoundsException if {@code index * layout.byteSize() > byteSize() - layout.byteSize()} + * or {@code index < 0} * @throws IllegalArgumentException if this segment is {@linkplain #isReadOnly() read-only} */ void setAtIndex(ValueLayout.OfShort layout, long index, short value); @@ -2130,6 +2155,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()} * @throws IndexOutOfBoundsException if {@code index * layout.byteSize()} overflows * @throws IndexOutOfBoundsException if {@code index * layout.byteSize() > byteSize() - layout.byteSize()} + * or {@code index < 0} */ int getAtIndex(ValueLayout.OfInt layout, long index); @@ -2152,6 +2178,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()} * @throws IndexOutOfBoundsException if {@code index * layout.byteSize()} overflows * @throws IndexOutOfBoundsException if {@code index * layout.byteSize() > byteSize() - layout.byteSize()} + * or {@code index < 0} * @throws IllegalArgumentException if this segment is {@linkplain #isReadOnly() read-only} */ void setAtIndex(ValueLayout.OfInt layout, long index, int value); @@ -2175,6 +2202,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()} * @throws IndexOutOfBoundsException if {@code index * layout.byteSize()} overflows * @throws IndexOutOfBoundsException if {@code index * layout.byteSize() > byteSize() - layout.byteSize()} + * or {@code index < 0} */ float getAtIndex(ValueLayout.OfFloat layout, long index); @@ -2197,6 +2225,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()} * @throws IndexOutOfBoundsException if {@code index * layout.byteSize()} overflows * @throws IndexOutOfBoundsException if {@code index * layout.byteSize() > byteSize() - layout.byteSize()} + * or {@code index < 0} * @throws IllegalArgumentException if this segment is {@linkplain #isReadOnly() read-only} */ void setAtIndex(ValueLayout.OfFloat layout, long index, float value); @@ -2220,6 +2249,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()} * @throws IndexOutOfBoundsException if {@code index * layout.byteSize()} overflows * @throws IndexOutOfBoundsException if {@code index * layout.byteSize() > byteSize() - layout.byteSize()} + * or {@code index < 0} */ long getAtIndex(ValueLayout.OfLong layout, long index); @@ -2242,6 +2272,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()} * @throws IndexOutOfBoundsException if {@code index * layout.byteSize()} overflows * @throws IndexOutOfBoundsException if {@code index * layout.byteSize() > byteSize() - layout.byteSize()} + * or {@code index < 0} * @throws IllegalArgumentException if this segment is {@linkplain #isReadOnly() read-only} */ void setAtIndex(ValueLayout.OfLong layout, long index, long value); @@ -2265,6 +2296,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()} * @throws IndexOutOfBoundsException if {@code index * layout.byteSize()} overflows * @throws IndexOutOfBoundsException if {@code index * layout.byteSize() > byteSize() - layout.byteSize()} + * or {@code index < 0} */ double getAtIndex(ValueLayout.OfDouble layout, long index); @@ -2287,6 +2319,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()} * @throws IndexOutOfBoundsException if {@code index * layout.byteSize()} overflows * @throws IndexOutOfBoundsException if {@code index * layout.byteSize() > byteSize() - layout.byteSize()} + * or {@code index < 0} * @throws IllegalArgumentException if this segment is {@linkplain #isReadOnly() read-only} */ void setAtIndex(ValueLayout.OfDouble layout, long index, double value); @@ -2319,6 +2352,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * in {@code T} * @throws IndexOutOfBoundsException if {@code index * layout.byteSize()} overflows * @throws IndexOutOfBoundsException if {@code index * layout.byteSize() > byteSize() - layout.byteSize()} + * or {@code index < 0} */ MemorySegment getAtIndex(AddressLayout layout, long index); @@ -2341,7 +2375,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr * @throws IllegalArgumentException if {@code layout.byteAlignment() > layout.byteSize()} * @throws IndexOutOfBoundsException if {@code index * layout.byteSize()} overflows * @throws IndexOutOfBoundsException if {@code index * layout.byteSize() > byteSize() - layout.byteSize()} - * @throws UnsupportedOperationException if this segment is {@linkplain #isReadOnly() read-only} + * or {@code index < 0} * @throws IllegalArgumentException if {@code value} is not a {@linkplain #isNative() native} segment * @throws IllegalArgumentException if this segment is * {@linkplain #isReadOnly() read-only} diff --git a/src/java.base/share/classes/java/lang/foreign/SegmentAllocator.java b/src/java.base/share/classes/java/lang/foreign/SegmentAllocator.java index 6be9d949ea6..6c9cf51bee8 100644 --- a/src/java.base/share/classes/java/lang/foreign/SegmentAllocator.java +++ b/src/java.base/share/classes/java/lang/foreign/SegmentAllocator.java @@ -33,6 +33,7 @@ import jdk.internal.foreign.ArenaImpl; import jdk.internal.foreign.SlicingAllocator; import jdk.internal.foreign.StringSupport; +import jdk.internal.foreign.Utils; import jdk.internal.vm.annotation.ForceInline; /** @@ -390,9 +391,10 @@ default MemorySegment allocateFrom(AddressLayout layout, MemorySegment value) { * with {@code source} is not {@linkplain MemorySegment.Scope#isAlive() alive} * @throws WrongThreadException if this method is called from a thread {@code T}, * such that {@code source.isAccessibleBy(T) == false} - * @throws IndexOutOfBoundsException if {@code elementCount * sourceElementLayout.byteSize()} overflows + * @throws IllegalArgumentException if {@code elementCount * sourceElementLayout.byteSize()} overflows + * @throws IllegalArgumentException if {@code elementCount < 0} * @throws IndexOutOfBoundsException if {@code sourceOffset > source.byteSize() - (elementCount * sourceElementLayout.byteSize())} - * @throws IndexOutOfBoundsException if either {@code sourceOffset} or {@code elementCount} are {@code < 0} + * @throws IndexOutOfBoundsException if {@code sourceOffset < 0} */ @ForceInline default MemorySegment allocateFrom(ValueLayout elementLayout, diff --git a/src/java.base/share/classes/java/util/Locale.java b/src/java.base/share/classes/java/util/Locale.java index 8fac36fb84f..726fa7c22fc 100644 --- a/src/java.base/share/classes/java/util/Locale.java +++ b/src/java.base/share/classes/java/util/Locale.java @@ -45,6 +45,7 @@ import java.io.ObjectOutputStream; import java.io.ObjectStreamField; import java.io.Serializable; +import java.text.DateFormat; import java.text.MessageFormat; import java.util.concurrent.ConcurrentHashMap; import java.util.spi.LocaleNameProvider; @@ -257,6 +258,74 @@ * locales. For example, {@code Locale.US} is the {@code Locale} object * for the United States. * + *

Default Locale

+ * + *

The default Locale is provided for any locale-sensitive methods if no + * {@code Locale} is explicitly specified as an argument, such as + * {@link DateFormat#getInstance()}. The default Locale is determined at startup + * of the Java runtime and established in the following three phases: + *

    + *
  1. The locale-related system properties listed below are established from the + * host environment. Some system properties (except for {@code user.language}) may + * not have values from the host environment. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
    Shows property keys and associated values
    Locale-related System Properties KeyDescription
    {@systemProperty user.language}{@link ##def_language language} for the default Locale, + * such as "en" (English)
    {@systemProperty user.script}{@link ##def_script script} for the default Locale, + * such as "Latn" (Latin)
    {@systemProperty user.country}{@link ##def_region country} for the default Locale, + * such as "US" (United States)
    {@systemProperty user.variant}{@link ##def_variant variant} for the default Locale, + * such as "POSIX"
    {@systemProperty user.extensions}{@link ##def_extensions extensions} for the default Locale, + * such as "u-ca-japanese" (Japanese Calendar)
    + *
  2. + *
  3. The values of these system properties can be overridden by values designated + * at startup time. If the overriding value of the {@code user.extensions} property + * is unparsable, it is ignored. The overriding values of other properties are not + * checked for syntax or validity and are used directly in the default Locale. + * (Typically, system property values can be provided using the {@code -D} command-line + * option of a launcher. For example, specifying {@code -Duser.extensions=foobarbaz} + * results in a default Locale with no extensions, while specifying + * {@code -Duser.language=foobarbaz} results in a default Locale whose language is + * "foobarbaz".) + *
  4. + *
  5. The default {@code Locale} instance is constructed from the values of these + * system properties. + *
  6. + *
+ *

Altering the system property values with {@link System#setProperties(Properties)}/ + * {@link System#setProperty(String, String)} has no effect on the default Locale. + *

Once the default Locale is established, applications can query the default + * Locale with {@link #getDefault()} and change it with {@link #setDefault(Locale)}. + * If the default Locale is changed with {@link #setDefault(Locale)}, the corresponding + * system properties are not altered. It is not recommended that applications read + * these system properties and parse or interpret them as their values may be out of date. + * + *

There are finer-grained default Locales specific for each {@link Locale.Category}. + * These category specific default Locales can be queried by {@link #getDefault(Category)}, + * and set by {@link #setDefault(Category, Locale)}. Construction of these category + * specific default Locales are determined by the corresponding system properties, + * which consist of the base system properties as listed above, suffixed by either + * {@code ".display"} or {@code ".format"} depending on the category. For example, + * the value of the {@code user.language.display} system property will be used in the + * {@code language} part of the default Locale for the {@link Locale.Category#DISPLAY} + * category. In the absence of category specific system properties, the "category-less" + * system properties are used, such as {@code user.language} in the previous example. + * *

Locale Matching

* *

If an application or a system is internationalized and provides localized @@ -983,14 +1052,14 @@ public int hashCode() { } /** - * Gets the current value of the default locale for this instance - * of the Java Virtual Machine. + * Gets the current value of the {@link ##default_locale default locale} for + * this instance of the Java Virtual Machine. *

* The Java Virtual Machine sets the default locale during startup * based on the host environment. It is used by many locale-sensitive * methods if no locale is explicitly specified. * It can be changed using the - * {@link #setDefault(java.util.Locale) setDefault} method. + * {@link #setDefault(Locale)} method. * * @return the default locale for this instance of the Java Virtual Machine */ @@ -1000,13 +1069,13 @@ public static Locale getDefault() { } /** - * Gets the current value of the default locale for the specified Category - * for this instance of the Java Virtual Machine. + * Gets the current value of the {@link ##default_locale default locale} for + * the specified Category for this instance of the Java Virtual Machine. *

* The Java Virtual Machine sets the default locale during startup based * on the host environment. It is used by many locale-sensitive methods * if no locale is explicitly specified. It can be changed using the - * setDefault(Locale.Category, Locale) method. + * {@link #setDefault(Locale.Category, Locale)} method. * * @param category the specified category to get the default locale * @throws NullPointerException if category is null @@ -1114,8 +1183,9 @@ private static Optional getDefaultExtensions(String extensions } /** - * Sets the default locale for this instance of the Java Virtual Machine. - * This does not affect the host locale. + * Sets the {@link ##default_locale default locale} for + * this instance of the Java Virtual Machine. This does not affect the + * host locale. *

* If there is a security manager, its {@code checkPermission} * method is called with a {@code PropertyPermission("user.language", "write")} @@ -1148,8 +1218,9 @@ public static synchronized void setDefault(Locale newLocale) { } /** - * Sets the default locale for the specified Category for this instance - * of the Java Virtual Machine. This does not affect the host locale. + * Sets the {@link ##default_locale default locale} for the specified + * Category for this instance of the Java Virtual Machine. This does + * not affect the host locale. *

* If there is a security manager, its checkPermission method is called * with a PropertyPermission("user.language", "write") permission before diff --git a/src/java.base/share/classes/java/util/concurrent/LinkedTransferQueue.java b/src/java.base/share/classes/java/util/concurrent/LinkedTransferQueue.java index 5aef5cd12a1..a0d3176c762 100644 --- a/src/java.base/share/classes/java/util/concurrent/LinkedTransferQueue.java +++ b/src/java.base/share/classes/java/util/concurrent/LinkedTransferQueue.java @@ -1143,7 +1143,8 @@ public LinkedTransferQueue(Collection c) { * @throws NullPointerException if the specified element is null */ public void put(E e) { - offer(e); + Objects.requireNonNull(e); + xfer(e, -1L); } /** @@ -1156,7 +1157,9 @@ public void put(E e) { * @throws NullPointerException if the specified element is null */ public boolean offer(E e, long timeout, TimeUnit unit) { - return offer(e); + Objects.requireNonNull(e); + xfer(e, -1L); + return true; } /** @@ -1181,7 +1184,9 @@ public boolean offer(E e) { * @throws NullPointerException if the specified element is null */ public boolean add(E e) { - return offer(e); + Objects.requireNonNull(e); + xfer(e, -1L); + return true; } /** diff --git a/src/java.base/share/classes/javax/crypto/KEM.java b/src/java.base/share/classes/javax/crypto/KEM.java index e05027a7abc..7df7fa236c8 100644 --- a/src/java.base/share/classes/javax/crypto/KEM.java +++ b/src/java.base/share/classes/javax/crypto/KEM.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, 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,6 +29,7 @@ import java.security.*; import java.security.InvalidAlgorithmParameterException; import java.security.spec.AlgorithmParameterSpec; +import java.util.ArrayList; import java.util.List; import java.util.Objects; @@ -539,10 +540,19 @@ public static KEM getInstance(String algorithm) List list = GetInstance.getServices( "KEM", Objects.requireNonNull(algorithm, "null algorithm name")); - if (list.isEmpty()) { - throw new NoSuchAlgorithmException(algorithm + " KEM not available"); + List allowed = new ArrayList<>(); + for (Provider.Service s : list) { + if (!JceSecurity.canUseProvider(s.getProvider())) { + continue; + } + allowed.add(s); + } + if (allowed.isEmpty()) { + throw new NoSuchAlgorithmException + (algorithm + " KEM not available"); } - return new KEM(algorithm, new DelayedKEM(list.toArray(new Provider.Service[0]))); + + return new KEM(algorithm, new DelayedKEM(allowed.toArray(new Provider.Service[0]))); } /** @@ -568,7 +578,7 @@ public static KEM getInstance(String algorithm, Provider provider) if (provider == null) { return getInstance(algorithm); } - GetInstance.Instance instance = GetInstance.getInstance( + GetInstance.Instance instance = JceSecurity.getInstance( "KEM", KEMSpi.class, Objects.requireNonNull(algorithm, "null algorithm name"), @@ -601,7 +611,7 @@ public static KEM getInstance(String algorithm, String provider) if (provider == null) { return getInstance(algorithm); } - GetInstance.Instance instance = GetInstance.getInstance( + GetInstance.Instance instance = JceSecurity.getInstance( "KEM", KEMSpi.class, Objects.requireNonNull(algorithm, "null algorithm name"), diff --git a/src/java.base/share/classes/jdk/internal/foreign/AbstractMemorySegmentImpl.java b/src/java.base/share/classes/jdk/internal/foreign/AbstractMemorySegmentImpl.java index 305594952d4..0efe62c1e4f 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/AbstractMemorySegmentImpl.java +++ b/src/java.base/share/classes/jdk/internal/foreign/AbstractMemorySegmentImpl.java @@ -153,9 +153,7 @@ public final MemorySegment reinterpret(Arena arena, Consumer clea public MemorySegment reinterpretInternal(Class callerClass, long newSize, Scope scope, Consumer cleanup) { Reflection.ensureNativeAccess(callerClass, MemorySegment.class, "reinterpret"); - if (newSize < 0) { - throw new IllegalArgumentException("newSize < 0"); - } + Utils.checkNonNegativeArgument(newSize, "newSize"); if (!isNative()) throw new UnsupportedOperationException("Not a native segment"); Runnable action = cleanup != null ? () -> cleanup.accept(SegmentFactories.makeNativeSegmentUnchecked(address(), newSize)) : @@ -594,6 +592,7 @@ public static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, MemorySegment dstSegment, ValueLayout dstElementLayout, long dstOffset, long elementCount) { + Utils.checkNonNegativeIndex(elementCount, "elementCount"); AbstractMemorySegmentImpl srcImpl = (AbstractMemorySegmentImpl)srcSegment; AbstractMemorySegmentImpl dstImpl = (AbstractMemorySegmentImpl)dstSegment; if (srcElementLayout.byteSize() != dstElementLayout.byteSize()) { @@ -625,7 +624,7 @@ public static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, public static void copy(MemorySegment srcSegment, ValueLayout srcLayout, long srcOffset, Object dstArray, int dstIndex, int elementCount) { - + Utils.checkNonNegativeIndex(elementCount, "elementCount"); var dstInfo = Utils.BaseAndScale.of(dstArray); if (dstArray.getClass().componentType() != srcLayout.carrier()) { throw new IllegalArgumentException("Incompatible value layout: " + srcLayout); @@ -652,7 +651,6 @@ public static void copy(MemorySegment srcSegment, ValueLayout srcLayout, long sr public static void copy(Object srcArray, int srcIndex, MemorySegment dstSegment, ValueLayout dstLayout, long dstOffset, int elementCount) { - var srcInfo = Utils.BaseAndScale.of(srcArray); if (srcArray.getClass().componentType() != dstLayout.carrier()) { throw new IllegalArgumentException("Incompatible value layout: " + dstLayout); diff --git a/src/java.base/share/classes/jdk/internal/foreign/Utils.java b/src/java.base/share/classes/jdk/internal/foreign/Utils.java index d0d5c866f6b..6a081e23eac 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/Utils.java +++ b/src/java.base/share/classes/jdk/internal/foreign/Utils.java @@ -200,11 +200,8 @@ public static long pointeeByteAlign(AddressLayout addressLayout) { } public static void checkAllocationSizeAndAlign(long byteSize, long byteAlignment) { - // size should be >= 0 - if (byteSize < 0) { - throw new IllegalArgumentException("Invalid allocation size : " + byteSize); - } - + // byteSize should be >= 0 + Utils.checkNonNegativeArgument(byteSize, "allocation size"); checkAlign(byteAlignment); } @@ -216,6 +213,20 @@ public static void checkAlign(long byteAlignment) { } } + @ForceInline + public static void checkNonNegativeArgument(long value, String name) { + if (value < 0) { + throw new IllegalArgumentException("The provided " + name + " is negative: " + value); + } + } + + @ForceInline + public static void checkNonNegativeIndex(long value, String name) { + if (value < 0) { + throw new IndexOutOfBoundsException("The provided " + name + " is negative: " + value); + } + } + private static long computePadding(long offset, long align) { boolean isAligned = offset == 0 || offset % align == 0; if (isAligned) { diff --git a/src/java.base/share/classes/jdk/internal/foreign/layout/AbstractLayout.java b/src/java.base/share/classes/jdk/internal/foreign/layout/AbstractLayout.java index e4d931127af..3c0cf3902bb 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/layout/AbstractLayout.java +++ b/src/java.base/share/classes/jdk/internal/foreign/layout/AbstractLayout.java @@ -151,13 +151,8 @@ private static long requirePowerOfTwoAndGreaterOrEqualToOne(long value) { } public long scale(long offset, long index) { - if (offset < 0) { - throw new IllegalArgumentException("Negative offset: " + offset); - } - if (index < 0) { - throw new IllegalArgumentException("Negative index: " + index); - } - + Utils.checkNonNegativeArgument(offset, "offset"); + Utils.checkNonNegativeArgument(index, "index"); return Math.addExact(offset, Math.multiplyExact(byteSize(), index)); } diff --git a/src/java.base/share/classes/jdk/internal/foreign/layout/MemoryLayoutUtil.java b/src/java.base/share/classes/jdk/internal/foreign/layout/MemoryLayoutUtil.java index dce06141028..6b8e7738198 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/layout/MemoryLayoutUtil.java +++ b/src/java.base/share/classes/jdk/internal/foreign/layout/MemoryLayoutUtil.java @@ -30,13 +30,6 @@ public final class MemoryLayoutUtil { private MemoryLayoutUtil() { } - public static long requireNonNegative(long value) { - if (value < 0) { - throw new IllegalArgumentException("The provided value was negative: " + value); - } - return value; - } - public static long requireByteSizeValid(long byteSize, boolean allowZero) { if ((byteSize == 0 && !allowZero) || byteSize < 0) { throw new IllegalArgumentException("Invalid byte size: " + byteSize); diff --git a/src/java.base/share/classes/jdk/internal/io/JdkConsoleImpl.java b/src/java.base/share/classes/jdk/internal/io/JdkConsoleImpl.java index 370fc73fcd0..a75ff582085 100644 --- a/src/java.base/share/classes/jdk/internal/io/JdkConsoleImpl.java +++ b/src/java.base/share/classes/jdk/internal/io/JdkConsoleImpl.java @@ -119,8 +119,17 @@ public char[] readPassword(String fmt, Object ... args) { else ioe.addSuppressed(x); } - if (ioe != null) + if (ioe != null) { + Arrays.fill(passwd, ' '); + try { + if (reader instanceof LineReader lr) { + lr.zeroOut(); + } + } catch (IOException x) { + // ignore + } throw ioe; + } } pw.println(); } diff --git a/src/java.base/share/classes/sun/security/provider/certpath/ForwardBuilder.java b/src/java.base/share/classes/sun/security/provider/certpath/ForwardBuilder.java index 125af069203..b9466074343 100644 --- a/src/java.base/share/classes/sun/security/provider/certpath/ForwardBuilder.java +++ b/src/java.base/share/classes/sun/security/provider/certpath/ForwardBuilder.java @@ -41,6 +41,7 @@ import java.util.*; import javax.security.auth.x500.X500Principal; +import jdk.internal.misc.ThreadTracker; import sun.security.provider.certpath.PKIX.BuilderParams; import sun.security.util.Debug; import sun.security.x509.AccessDescription; @@ -71,6 +72,10 @@ final class ForwardBuilder extends Builder { TrustAnchor trustAnchor; private final boolean searchAllCertStores; + private static class ThreadTrackerHolder { + static final ThreadTracker AIA_TRACKER = new ThreadTracker(); + } + /** * Initialize the builder with the input parameters. * @@ -336,7 +341,7 @@ private void getMatchingCACerts(ForwardState currentState, } /** - * Download Certificates from the given AIA and add them to the + * Download certificates from the given AIA and add them to the * specified Collection. */ // cs.getCertificates(caSelector) returns a collection of X509Certificate's @@ -348,32 +353,47 @@ private boolean getCerts(AuthorityInfoAccessExtension aiaExt, if (!Builder.USE_AIA) { return false; } + List adList = aiaExt.getAccessDescriptions(); if (adList == null || adList.isEmpty()) { return false; } - boolean add = false; - for (AccessDescription ad : adList) { - CertStore cs = URICertStore.getInstance(ad); - if (cs != null) { - try { - if (certs.addAll((Collection) - cs.getCertificates(caSelector))) { - add = true; - if (!searchAllCertStores) { - return true; + Object key = ThreadTrackerHolder.AIA_TRACKER.tryBegin(); + if (key == null) { + // Avoid recursive fetching of certificates + if (debug != null) { + debug.println("Recursive fetching of certs via the AIA " + + "extension detected"); + } + return false; + } + + try { + boolean add = false; + for (AccessDescription ad : adList) { + CertStore cs = URICertStore.getInstance(ad); + if (cs != null) { + try { + if (certs.addAll((Collection) + cs.getCertificates(caSelector))) { + add = true; + if (!searchAllCertStores) { + return true; + } + } + } catch (CertStoreException cse) { + if (debug != null) { + debug.println("exception getting certs from CertStore:"); + cse.printStackTrace(); } - } - } catch (CertStoreException cse) { - if (debug != null) { - debug.println("exception getting certs from CertStore:"); - cse.printStackTrace(); } } } + return add; + } finally { + ThreadTrackerHolder.AIA_TRACKER.end(key); } - return add; } /** diff --git a/src/java.base/share/classes/sun/security/rsa/RSAPrivateCrtKeyImpl.java b/src/java.base/share/classes/sun/security/rsa/RSAPrivateCrtKeyImpl.java index 99365640ec7..218b1f6f4ba 100644 --- a/src/java.base/share/classes/sun/security/rsa/RSAPrivateCrtKeyImpl.java +++ b/src/java.base/share/classes/sun/security/rsa/RSAPrivateCrtKeyImpl.java @@ -301,14 +301,6 @@ public AlgorithmParameterSpec getParams() { return keyParams; } - // return a string representation of this key for debugging - @Override - public String toString() { - return "SunRsaSign " + type.keyAlgo + " private CRT key, " - + n.bitLength() + " bits" + "\n params: " + keyParams - + "\n modulus: " + n + "\n private exponent: " + d; - } - // utility method for parsing DER encoding of RSA private keys in PKCS#1 // format as defined in RFC 8017 Appendix A.1.2, i.e. SEQ of version, n, // e, d, p, q, pe, qe, and coeff, and return the parsed components. diff --git a/src/java.base/share/classes/sun/security/rsa/RSAPrivateKeyImpl.java b/src/java.base/share/classes/sun/security/rsa/RSAPrivateKeyImpl.java index da5474cb26a..aa5297b0040 100644 --- a/src/java.base/share/classes/sun/security/rsa/RSAPrivateKeyImpl.java +++ b/src/java.base/share/classes/sun/security/rsa/RSAPrivateKeyImpl.java @@ -138,14 +138,6 @@ public AlgorithmParameterSpec getParams() { return keyParams; } - // return a string representation of this key for debugging - @Override - public String toString() { - return "Sun " + type.keyAlgo + " private key, " + n.bitLength() - + " bits" + "\n params: " + keyParams + "\n modulus: " + n - + "\n private exponent: " + d; - } - /** * Restores the state of this object from the stream. *

diff --git a/src/java.base/share/classes/sun/security/ssl/SunJSSE.java b/src/java.base/share/classes/sun/security/ssl/SunJSSE.java index 894e26dfad8..dce2aad8400 100644 --- a/src/java.base/share/classes/sun/security/ssl/SunJSSE.java +++ b/src/java.base/share/classes/sun/security/ssl/SunJSSE.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2024, 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,25 +31,6 @@ /** * The JSSE provider. - * - * SunJSSE now supports an experimental FIPS compliant mode when used with an - * appropriate FIPS certified crypto provider. In FIPS mode, we: - * . allow only TLS 1.0 or later - * . allow only FIPS approved ciphersuites - * . perform all crypto in the FIPS crypto provider - * - * It is currently not possible to use both FIPS compliant SunJSSE and - * standard JSSE at the same time because of the various static data structures - * we use. - * - * However, we do want to allow FIPS mode to be enabled at runtime and without - * editing the java.security file. That means we need to allow - * Security.removeProvider("SunJSSE") to work, which creates an instance of - * this class in non-FIPS mode. That is why we delay the selection of the mode - * as long as possible. This is until we open an SSL/TLS connection and the - * data structures need to be initialized or until SunJSSE is initialized in - * FIPS mode. - * */ public class SunJSSE extends java.security.Provider { diff --git a/src/java.base/share/classes/sun/security/util/KeyUtil.java b/src/java.base/share/classes/sun/security/util/KeyUtil.java index 059467779b9..c38889ed494 100644 --- a/src/java.base/share/classes/sun/security/util/KeyUtil.java +++ b/src/java.base/share/classes/sun/security/util/KeyUtil.java @@ -291,13 +291,14 @@ public static final boolean isOracleJCEProvider(String providerName) { * contains the lower of that suggested by the client in the client * hello and the highest supported by the server. * @param encoded the encoded key in its "RAW" encoding format - * @param isFailOver whether the previous decryption of the - * encrypted PreMasterSecret message run into problem + * @param failure true if encoded is incorrect according to previous checks * @return the polished PreMasterSecret key in its "RAW" encoding format */ public static byte[] checkTlsPreMasterSecretKey( int clientVersion, int serverVersion, SecureRandom random, - byte[] encoded, boolean isFailOver) { + byte[] encoded, boolean failure) { + + byte[] tmp; if (random == null) { random = JCAUtil.getSecureRandom(); @@ -305,30 +306,38 @@ public static byte[] checkTlsPreMasterSecretKey( byte[] replacer = new byte[48]; random.nextBytes(replacer); - if (!isFailOver && (encoded != null)) { - // check the length - if (encoded.length != 48) { - // private, don't need to clone the byte array. - return replacer; - } - - int encodedVersion = - ((encoded[0] & 0xFF) << 8) | (encoded[1] & 0xFF); - if (clientVersion != encodedVersion) { - if (clientVersion > 0x0301 || // 0x0301: TLSv1 - serverVersion != encodedVersion) { - encoded = replacer; - } // Otherwise, For compatibility, we maintain the behavior - // that the version in pre_master_secret can be the - // negotiated version for TLS v1.0 and SSL v3.0. - } + if (failure) { + tmp = replacer; + } else { + tmp = encoded; + } + if (tmp == null) { + encoded = replacer; + } else { + encoded = tmp; + } + // check the length + if (encoded.length != 48) { // private, don't need to clone the byte array. - return encoded; + tmp = replacer; + } else { + tmp = encoded; } - // private, don't need to clone the byte array. - return replacer; + int encodedVersion = + ((tmp[0] & 0xFF) << 8) | (tmp[1] & 0xFF); + int check1 = 0; + int check2 = 0; + int check3 = 0; + if (clientVersion != encodedVersion) check1 = 1; + if (clientVersion > 0x0301) check2 = 1; + if (serverVersion != encodedVersion) check3 = 1; + if ((check1 & (check2 | check3)) == 1) { + return replacer; + } else { + return tmp; + } } /** diff --git a/src/java.base/share/classes/sun/util/resources/CurrencyNames.properties b/src/java.base/share/classes/sun/util/resources/CurrencyNames.properties index 76ad70e34c8..3cbbf15ed02 100644 --- a/src/java.base/share/classes/sun/util/resources/CurrencyNames.properties +++ b/src/java.base/share/classes/sun/util/resources/CurrencyNames.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2005, 2022, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2005, 2023, 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 @@ -269,6 +269,7 @@ XBB=XBB XBC=XBC XBD=XBD XCD=XCD +XCG=XCG XDR=XDR XFO=XFO XFU=XFU @@ -494,6 +495,7 @@ xbb=European Monetary Unit xbc=European Unit of Account (XBC) xbd=European Unit of Account (XBD) xcd=East Caribbean Dollar +xcg=Caribbean Guilder xdr=Special Drawing Rights xfo=French Gold Franc xfu=French UIC-Franc diff --git a/src/java.base/share/data/cacerts/certainlyroote1 b/src/java.base/share/data/cacerts/certainlyroote1 new file mode 100644 index 00000000000..3f0d0face0e --- /dev/null +++ b/src/java.base/share/data/cacerts/certainlyroote1 @@ -0,0 +1,20 @@ +Owner: CN=Certainly Root E1, O=Certainly, C=US +Issuer: CN=Certainly Root E1, O=Certainly, C=US +Serial number: 62533b1470333275cf98d9ab9bfccf8 +Valid from: Thu Apr 01 00:00:00 GMT 2021 until: Sun Apr 01 00:00:00 GMT 2046 +Signature algorithm name: SHA384withECDSA +Subject Public Key Algorithm: 384-bit EC (secp384r1) key +Version: 3 +-----BEGIN CERTIFICATE----- +MIIB9zCCAX2gAwIBAgIQBiUzsUcDMydc+Y2aub/M+DAKBggqhkjOPQQDAzA9MQsw +CQYDVQQGEwJVUzESMBAGA1UEChMJQ2VydGFpbmx5MRowGAYDVQQDExFDZXJ0YWlu +bHkgUm9vdCBFMTAeFw0yMTA0MDEwMDAwMDBaFw00NjA0MDEwMDAwMDBaMD0xCzAJ +BgNVBAYTAlVTMRIwEAYDVQQKEwlDZXJ0YWlubHkxGjAYBgNVBAMTEUNlcnRhaW5s +eSBSb290IEUxMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE3m/4fxzf7flHh4axpMCK ++IKXgOqPyEpeKn2IaKcBYhSRJHpcnqMXfYqGITQYUBsQ3tA3SybHGWCA6TS9YBk2 +QNYphwk8kXr2vBMj3VlOBF7PyAIcGFPBMdjaIOlEjeR2o0IwQDAOBgNVHQ8BAf8E +BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU8ygYy2R17ikq6+2uI1g4 +hevIIgcwCgYIKoZIzj0EAwMDaAAwZQIxALGOWiDDshliTd6wT99u0nCK8Z9+aozm +ut6Dacpps6kFtZaSF4fC0urQe87YQVt8rgIwRt7qy12a7DLCZRawTDBcMPPaTnOG +BtjOiQRINzf43TNRnXCve1XYAS59BWQOhriR +-----END CERTIFICATE----- diff --git a/src/java.base/share/data/cacerts/certainlyrootr1 b/src/java.base/share/data/cacerts/certainlyrootr1 new file mode 100644 index 00000000000..dbb99fad32c --- /dev/null +++ b/src/java.base/share/data/cacerts/certainlyrootr1 @@ -0,0 +1,38 @@ +Owner: CN=Certainly Root R1, O=Certainly, C=US +Issuer: CN=Certainly Root R1, O=Certainly, C=US +Serial number: 8e0ff94b907168653354f4d44439b7e0 +Valid from: Thu Apr 01 00:00:00 GMT 2021 until: Sun Apr 01 00:00:00 GMT 2046 +Signature algorithm name: SHA256withRSA +Subject Public Key Algorithm: 4096-bit RSA key +Version: 3 +-----BEGIN CERTIFICATE----- +MIIFRzCCAy+gAwIBAgIRAI4P+UuQcWhlM1T01EQ5t+AwDQYJKoZIhvcNAQELBQAw +PTELMAkGA1UEBhMCVVMxEjAQBgNVBAoTCUNlcnRhaW5seTEaMBgGA1UEAxMRQ2Vy +dGFpbmx5IFJvb3QgUjEwHhcNMjEwNDAxMDAwMDAwWhcNNDYwNDAxMDAwMDAwWjA9 +MQswCQYDVQQGEwJVUzESMBAGA1UEChMJQ2VydGFpbmx5MRowGAYDVQQDExFDZXJ0 +YWlubHkgUm9vdCBSMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANA2 +1B/q3avk0bbm+yLA3RMNansiExyXPGhjZjKcA7WNpIGD2ngwEc/csiu+kr+O5MQT +vqRoTNoCaBZ0vrLdBORrKt03H2As2/X3oXyVtwxwhi7xOu9S98zTm/mLvg7fMbed +aFySpvXl8wo0tf97ouSHocavFwDvA5HtqRxOcT3Si2yJ9HiG5mpJoM610rCrm/b0 +1C7jcvk2xusVtyWMOvwlDbMicyF0yEqWYZL1LwsYpfSt4u5BvQF5+paMjRcCMLT5 +r3gajLQ2EBAHBXDQ9DGQilHFhiZ5shGIXsXwClTNSaa/ApzSRKft43jvRl5tcdF5 +cBxGX1HpyTfcX35pe0HfNEXgO4T0oYoKNp43zGJS4YkNKPl6I7ENPT2a/Z2B7yyQ +wHtETrtJ4A5KVpK8y7XdeReJkd5hiXSSqOMyhb5OhaRLWcsrxXiOcVTQAjeZjOVJ +6uBUcqQRBi8LjMFbvrWhsFNunLhgkR9Za/kt9JQKl7XsxXYDVBtlUrpMklZRNaBA +2CnbrlJ2Oy0wQJuK0EJWtLeIAaSHO1OWzaMWj/Nmqhexx2DgwUMFDO6bW2BvBlyH +Wyf5QBGenDPBt+U1VwV/J84XIIwc/PH72jEpSe31C4SnT8H2TsIonPru4K8H+zMR +eiFPCyEQtkA6qyI6BJyLm4SGcprSp6XEtHWRqSsjAgMBAAGjQjBAMA4GA1UdDwEB +/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTgqj8ljZ9EXME66C6u +d0yEPmcM9DANBgkqhkiG9w0BAQsFAAOCAgEAuVevuBLaV4OPaAszHQNTVfSVcOQr +PbA56/qJYv331hgELyE03fFo8NWWWt7CgKPBjcZq91l3rhVkz1t5BXdm6ozTaw3d +8VkswTOlMIAVRQdFGjEitpIAq5lNOo93r6kiyi9jyhXWx8bwPWz8HA2YEGGeEaIi +1wrykXprOQ4vMMM2SZ/g6Q8CRFA3lFV96p/2O7qUpUzpvD5RtOjKkjZUbVwlKNrd +rRT90+7iIgXr0PK3aBLXWopBGsaSpVo7Y0VPv+E6dyIvXL9G+VoDhRNCX8reU9di +taY1BMJH/5n9hN9czulegChB8n3nHpDYT3Y+gjwN/KUD+nsa2UUeYNrEjvn8K8l7 +lcUq/6qJ34IxD3L/DCfXCh5WAFAeDJDBlrXYFIW7pw0WwfgHJBu6haEaBQmAupVj +yTrsJZ9/nbqkRxWbRHDxakvWOF5D8xh+UG7pWijmZeZ3Gzr9Hb4DJqPb1OG7fpYn +Kx3upPvaJVQTA945xsMfTZDsjxtK0hzthZU4UHlG1sGQUDGpXJpuHfUzVounmdLy +yCwzk5Iwx06MZTMQZBf9JBeW0Y3COmor6xOLRPIh80oat3df1+2IpHLlOR+Vnb5n +wXARPbv0+Em34yaXOp/SX3z7wJl8OSngex2/DaeP0ik0biQVy96QXr8axGbqwua6 +OV+KmalBWQewLK8= +-----END CERTIFICATE----- diff --git a/src/java.base/share/data/currency/CurrencyData.properties b/src/java.base/share/data/currency/CurrencyData.properties index dbfbe799b47..1661b4cccba 100644 --- a/src/java.base/share/data/currency/CurrencyData.properties +++ b/src/java.base/share/data/currency/CurrencyData.properties @@ -32,7 +32,7 @@ formatVersion=3 # Version of the currency code information in this class. # It is a serial number that accompanies with each amendment. -dataVersion=175 +dataVersion=176 # List of all valid ISO 4217 currency codes. # To ensure compatibility, do not remove codes. @@ -55,7 +55,7 @@ all=ADP020-AED784-AFA004-AFN971-ALL008-AMD051-ANG532-AOA973-ARS032-ATS040-AUD036 SRD968-SRG740-SSP728-STD678-STN930-SVC222-SYP760-SZL748-THB764-TJS972-TMM795-TMT934-TND788-TOP776-\ TPE626-TRL792-TRY949-TTD780-TWD901-TZS834-UAH980-UGX800-USD840-USN997-USS998-UYI940-\ UYU858-UZS860-VEB862-VED926-VEF937-VES928-VND704-VUV548-WST882-XAF950-XAG961-XAU959-XBA955-\ - XBB956-XBC957-XBD958-XCD951-XDR960-XFO000-XFU000-XOF952-XPD964-XPF953-\ + XBB956-XBC957-XBD958-XCD951-XCG532-XDR960-XFO000-XFU000-XOF952-XPD964-XPF953-\ XPT962-XSU994-XTS963-XUA965-XXX999-YER886-YUM891-ZAR710-ZMK894-ZMW967-ZWD716-ZWL932-\ ZWN942-ZWR935 @@ -189,11 +189,11 @@ CR=CRC # COTE D'IVOIRE CI=XOF # CROATIA -HR=HRK;2022-12-31-23-00-00;EUR +HR=EUR # CUBA CU=CUP # Curaçao -CW=ANG +CW=ANG;2025-04-01-04-00-00;XCG # CYPRUS CY=EUR # CZECHIA @@ -510,7 +510,7 @@ SR=SRD # SVALBARD AND JAN MAYEN SJ=NOK # Sint Maarten (Dutch part) -SX=ANG +SX=ANG;2025-04-01-04-00-00;XCG # ESWATINI SZ=SZL # SWEDEN diff --git a/src/java.base/share/data/tzdata/VERSION b/src/java.base/share/data/tzdata/VERSION index 66bd061e8bc..b138ed7fa78 100644 --- a/src/java.base/share/data/tzdata/VERSION +++ b/src/java.base/share/data/tzdata/VERSION @@ -21,4 +21,4 @@ # or visit www.oracle.com if you need additional information or have any # questions. # -tzdata2023c +tzdata2024a diff --git a/src/java.base/share/data/tzdata/africa b/src/java.base/share/data/tzdata/africa index a73405fdb01..72b188f074d 100644 --- a/src/java.base/share/data/tzdata/africa +++ b/src/java.base/share/data/tzdata/africa @@ -53,6 +53,10 @@ # Milne J. Civil time. Geogr J. 1899 Feb;13(2):173-94. # https://www.jstor.org/stable/1774359 # +# For the 1911/1912 establishment of standard time in French possessions, see: +# Société Française de Physique, Recueil de constantes physiques (1913), +# page 752, 18b. +# # European-style abbreviations are commonly used along the Mediterranean. # For sub-Saharan Africa abbreviations were less standardized. # Previous editions of this database used WAT, CAT, SAT, and EAT @@ -136,7 +140,7 @@ Zone Atlantic/Cape_Verde -1:34:04 - LMT 1912 Jan 01 2:00u # Praia # Chad # Zone NAME STDOFF RULES FORMAT [UNTIL] -Zone Africa/Ndjamena 1:00:12 - LMT 1912 # N'Djamena +Zone Africa/Ndjamena 1:00:12 - LMT 1912 Jan 1 # N'Djamena 1:00 - WAT 1979 Oct 14 1:00 1:00 WAST 1980 Mar 8 1:00 - WAT @@ -162,7 +166,7 @@ Zone Africa/Ndjamena 1:00:12 - LMT 1912 # N'Djamena # Inaccessible, Nightingale: uninhabited # Zone NAME STDOFF RULES FORMAT [UNTIL] -Zone Africa/Abidjan -0:16:08 - LMT 1912 +Zone Africa/Abidjan -0:16:08 - LMT 1912 Jan 1 0:00 - GMT ############################################################################### @@ -308,13 +312,6 @@ Rule Egypt 2007 only - Sep Thu>=1 24:00 0 - # reproduced by other (more accessible) sites[, e.g.,]... # http://elgornal.net/news/news.aspx?id=4699258 -# From Paul Eggert (2014-06-04): -# Sarah El Deeb and Lee Keath of AP report that the Egyptian government says -# the change is because of blackouts in Cairo, even though Ahram Online (cited -# above) says DST had no affect on electricity consumption. There is -# no information about when DST will end this fall. See: -# http://abcnews.go.com/International/wireStory/el-sissi-pushes-egyptians-line-23614833 - # From Steffen Thorsen (2015-04-08): # Egypt will start DST on midnight after Thursday, April 30, 2015. # This is based on a law (no 35) from May 15, 2014 saying it starts the last diff --git a/src/java.base/share/data/tzdata/antarctica b/src/java.base/share/data/tzdata/antarctica index 3de5e726eb4..fc7176cd0d5 100644 --- a/src/java.base/share/data/tzdata/antarctica +++ b/src/java.base/share/data/tzdata/antarctica @@ -103,6 +103,11 @@ # - 2018 Oct 7 4:00 - 2019 Mar 17 3:00 - 2019 Oct 4 3:00 - 2020 Mar 8 3:00 # and now - 2020 Oct 4 0:01 +# From Paul Eggert (2023-12-20): +# Transitions from 2021 on are taken from: +# https://www.timeanddate.com/time/zone/antarctica/casey +# retrieved at various dates. + # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Antarctica/Casey 0 - -00 1969 8:00 - +08 2009 Oct 18 2:00 @@ -116,7 +121,12 @@ Zone Antarctica/Casey 0 - -00 1969 8:00 - +08 2019 Oct 4 3:00 11:00 - +11 2020 Mar 8 3:00 8:00 - +08 2020 Oct 4 0:01 - 11:00 - +11 + 11:00 - +11 2021 Mar 14 0:00 + 8:00 - +08 2021 Oct 3 0:01 + 11:00 - +11 2022 Mar 13 0:00 + 8:00 - +08 2022 Oct 2 0:01 + 11:00 - +11 2023 Mar 9 3:00 + 8:00 - +08 Zone Antarctica/Davis 0 - -00 1957 Jan 13 7:00 - +07 1964 Nov 0 - -00 1969 Feb @@ -263,7 +273,50 @@ Zone Antarctica/Troll 0 - -00 2005 Feb 12 # year-round from 1960/61 to 1992 # Vostok, since 1957-12-16, temporarily closed 1994-02/1994-11 -# See Asia/Urumqi. +# From Craig Mundell (1994-12-15): +# http://quest.arc.nasa.gov/antarctica/QA/computers/Directions,Time,ZIP +# Vostok, which is one of the Russian stations, is set on the same +# time as Moscow, Russia. +# +# From Lee Hotz (2001-03-08): +# I queried the folks at Columbia who spent the summer at Vostok and this is +# what they had to say about time there: +# "in the US Camp (East Camp) we have been on New Zealand (McMurdo) +# time, which is 12 hours ahead of GMT. The Russian Station Vostok was +# 6 hours behind that (although only 2 miles away, i.e. 6 hours ahead +# of GMT). This is a time zone I think two hours east of Moscow. The +# natural time zone is in between the two: 8 hours ahead of GMT." +# +# From Paul Eggert (2001-05-04): +# This seems to be hopelessly confusing, so I asked Lee Hotz about it +# in person. He said that some Antarctic locations set their local +# time so that noon is the warmest part of the day, and that this +# changes during the year and does not necessarily correspond to mean +# solar noon. So the Vostok time might have been whatever the clocks +# happened to be during their visit. So we still don't really know what time +# it is at Vostok. +# +# From Zakhary V. Akulov (2023-12-17 22:00:48 +0700): +# ... from December, 18, 2023 00:00 by my decision the local time of +# the Antarctic research base Vostok will correspond to UTC+5. +# (2023-12-19): We constantly interact with Progress base, with company who +# builds new wintering station, with sledge convoys, with aviation - they all +# use UTC+5. Besides, difference between Moscow time is just 2 hours now, not 4. +# (2023-12-19, in response to the question "Has local time at Vostok +# been UTC+6 ever since 1957, or has it changed before?"): No. At least +# since my antarctic career start, 10 years ago, Vostok base has UTC+7. +# (In response to a 2023-12-18 question "from 02:00 to 00:00 today"): This. +# +# From Paul Eggert (2023-12-18): +# For lack of better info, guess Vostok was at +07 from founding through today, +# except when closed. + +# Zone NAME STDOFF RULES FORMAT [UNTIL] +Zone Antarctica/Vostok 0 - -00 1957 Dec 16 + 7:00 - +07 1994 Feb + 0 - -00 1994 Nov + 7:00 - +07 2023 Dec 18 2:00 + 5:00 - +05 # S Africa - year-round bases # Marion Island, -4653+03752 diff --git a/src/java.base/share/data/tzdata/asia b/src/java.base/share/data/tzdata/asia index 6a048c3ad28..3a54291919d 100644 --- a/src/java.base/share/data/tzdata/asia +++ b/src/java.base/share/data/tzdata/asia @@ -678,7 +678,6 @@ Zone Asia/Shanghai 8:05:43 - LMT 1901 8:00 PRC C%sT # Xinjiang time, used by many in western China; represented by Ürümqi / Ürümchi # / Wulumuqi. (Please use Asia/Shanghai if you prefer Beijing time.) -# Vostok base in Antarctica matches this since 1970. Zone Asia/Urumqi 5:50:20 - LMT 1928 6:00 - +06 @@ -2481,18 +2480,33 @@ Zone Asia/Amman 2:23:44 - LMT 1931 # effective December 21st, 2018.... # http://adilet.zan.kz/rus/docs/P1800000817 (russian language). +# From Zhanbolat Raimbekov (2024-01-19): +# Kazakhstan (all parts) switching to UTC+5 on March 1, 2024 +# https://www.gov.kz/memleket/entities/mti/press/news/details/688998?lang=ru +# [in Russian] +# (2024-01-20): https://primeminister.kz/ru/decisions/19012024-20 +# +# From Alexander Krivenyshev (2024-01-19): +# According to a different news and the official web site for the Ministry of +# Trade and Integration of the Republic of Kazakhstan: +# https://en.inform.kz/news/kazakhstan-to-switch-to-single-hour-zone-mar-1-54ad0b/ + # Zone NAME STDOFF RULES FORMAT [UNTIL] # # Almaty (formerly Alma-Ata), representing most locations in Kazakhstan -# This includes KZ-AKM, KZ-ALA, KZ-ALM, KZ-AST, KZ-BAY, KZ-VOS, KZ-ZHA, -# KZ-KAR, KZ-SEV, KZ-PAV, and KZ-YUZ. +# This includes Abai/Abay (ISO 3166-2 code KZ-10), Aqmola/Akmola (KZ-11), +# Almaty (KZ-19), Almaty city (KZ-75), Astana city (KZ-71), +# East Kazkhstan (KZ-63), Jambyl/Zhambyl (KZ-31), Jetisu/Zhetysu (KZ-33), +# Karaganda (KZ-35), North Kazakhstan (KZ-59), Pavlodar (KZ-55), +# Shyumkent city (KZ-79), Turkistan (KZ-61), and Ulytau (KZ-62). Zone Asia/Almaty 5:07:48 - LMT 1924 May 2 # or Alma-Ata 5:00 - +05 1930 Jun 21 6:00 RussiaAsia +06/+07 1991 Mar 31 2:00s 5:00 RussiaAsia +05/+06 1992 Jan 19 2:00s 6:00 RussiaAsia +06/+07 2004 Oct 31 2:00s - 6:00 - +06 -# Qyzylorda (aka Kyzylorda, Kizilorda, Kzyl-Orda, etc.) (KZ-KZY) + 6:00 - +06 2024 Mar 1 0:00 + 5:00 - +05 +# Qyzylorda (aka Kyzylorda, Kizilorda, Kzyl-Orda, etc.) (KZ-43) Zone Asia/Qyzylorda 4:21:52 - LMT 1924 May 2 4:00 - +04 1930 Jun 21 5:00 - +05 1981 Apr 1 @@ -2505,8 +2519,7 @@ Zone Asia/Qyzylorda 4:21:52 - LMT 1924 May 2 5:00 RussiaAsia +05/+06 2004 Oct 31 2:00s 6:00 - +06 2018 Dec 21 0:00 5:00 - +05 -# -# Qostanay (aka Kostanay, Kustanay) (KZ-KUS) +# Qostanay (aka Kostanay, Kustanay) (KZ-39) # The 1991/2 rules are unclear partly because of the 1997 Turgai # reorganization. Zone Asia/Qostanay 4:14:28 - LMT 1924 May 2 @@ -2517,9 +2530,9 @@ Zone Asia/Qostanay 4:14:28 - LMT 1924 May 2 5:00 RussiaAsia +05/+06 1991 Mar 31 2:00s 4:00 RussiaAsia +04/+05 1992 Jan 19 2:00s 5:00 RussiaAsia +05/+06 2004 Oct 31 2:00s - 6:00 - +06 - -# Aqtöbe (aka Aktobe, formerly Aktyubinsk) (KZ-AKT) + 6:00 - +06 2024 Mar 1 0:00 + 5:00 - +05 +# Aqtöbe (aka Aktobe, formerly Aktyubinsk) (KZ-15) Zone Asia/Aqtobe 3:48:40 - LMT 1924 May 2 4:00 - +04 1930 Jun 21 5:00 - +05 1981 Apr 1 @@ -2529,7 +2542,7 @@ Zone Asia/Aqtobe 3:48:40 - LMT 1924 May 2 4:00 RussiaAsia +04/+05 1992 Jan 19 2:00s 5:00 RussiaAsia +05/+06 2004 Oct 31 2:00s 5:00 - +05 -# Mangghystaū (KZ-MAN) +# Mangghystaū (KZ-47) # Aqtau was not founded until 1963, but it represents an inhabited region, # so include timestamps before 1963. Zone Asia/Aqtau 3:21:04 - LMT 1924 May 2 @@ -2541,7 +2554,7 @@ Zone Asia/Aqtau 3:21:04 - LMT 1924 May 2 5:00 RussiaAsia +05/+06 1994 Sep 25 2:00s 4:00 RussiaAsia +04/+05 2004 Oct 31 2:00s 5:00 - +05 -# Atyraū (KZ-ATY) is like Mangghystaū except it switched from +# Atyraū (KZ-23) is like Mangghystaū except it switched from # +04/+05 to +05/+06 in spring 1999, not fall 1994. Zone Asia/Atyrau 3:27:44 - LMT 1924 May 2 3:00 - +03 1930 Jun 21 @@ -2552,7 +2565,7 @@ Zone Asia/Atyrau 3:27:44 - LMT 1924 May 2 5:00 RussiaAsia +05/+06 1999 Mar 28 2:00s 4:00 RussiaAsia +04/+05 2004 Oct 31 2:00s 5:00 - +05 -# West Kazakhstan (KZ-ZAP) +# West Kazakhstan (KZ-27) # From Paul Eggert (2016-03-18): # The 1989 transition is from USSR act No. 227 (1989-03-14). Zone Asia/Oral 3:25:24 - LMT 1924 May 2 # or Ural'sk @@ -3450,20 +3463,30 @@ Zone Asia/Karachi 4:28:12 - LMT 1907 # From Heba Hamad (2023-03-22): # ... summer time will begin in Palestine from Saturday 04-29-2023, # 02:00 AM by 60 minutes forward. -# -# From Paul Eggert (2023-03-22): +# From Heba Hemad (2023-10-09): +# ... winter time will begin in Palestine from Saturday 10-28-2023, +# 02:00 AM by 60 minutes back. +# +# From Heba Hamad (2024-01-25): +# the summer time for the years 2024,2025 will begin in Palestine +# from Saturday at 02:00 AM by 60 minutes forward as shown below: +# year date +# 2024 2024-04-20 +# 2025 2025-04-12 +# +# From Paul Eggert (2024-01-25): # For now, guess that spring and fall transitions will normally # continue to use 2022's rules, that during DST Palestine will switch # to standard time at 02:00 the last Saturday before Ramadan and back -# to DST at 02:00 the first Saturday after Ramadan, and that +# to DST at 02:00 the second Saturday after Ramadan, and that # if the normal spring-forward or fall-back transition occurs during # Ramadan the former is delayed and the latter advanced. # To implement this, I predicted Ramadan-oriented transition dates for -# 2023 through 2086 by running the following program under GNU Emacs 28.2, +# 2026 through 2086 by running the following program under GNU Emacs 29.2, # with the results integrated by hand into the table below. # Predictions after 2086 are approximated without Ramadan. # -# (let ((islamic-year 1444)) +# (let ((islamic-year 1447)) # (require 'cal-islam) # (while (< islamic-year 1510) # (let ((a (calendar-islamic-to-absolute (list 9 1 islamic-year))) @@ -3472,6 +3495,7 @@ Zone Asia/Karachi 4:28:12 - LMT 1907 # (while (/= saturday (mod (setq a (1- a)) 7))) # (while (/= saturday (mod b 7)) # (setq b (1+ b))) +# (setq b (+ 7 b)) # (setq a (calendar-gregorian-from-absolute a)) # (setq b (calendar-gregorian-from-absolute b)) # (insert @@ -3522,84 +3546,84 @@ Rule Palestine 2021 only - Oct 29 1:00 0 - Rule Palestine 2022 only - Mar 27 0:00 1:00 S Rule Palestine 2022 2035 - Oct Sat<=30 2:00 0 - Rule Palestine 2023 only - Apr 29 2:00 1:00 S -Rule Palestine 2024 only - Apr 13 2:00 1:00 S -Rule Palestine 2025 only - Apr 5 2:00 1:00 S +Rule Palestine 2024 only - Apr 20 2:00 1:00 S +Rule Palestine 2025 only - Apr 12 2:00 1:00 S Rule Palestine 2026 2054 - Mar Sat<=30 2:00 1:00 S Rule Palestine 2036 only - Oct 18 2:00 0 - Rule Palestine 2037 only - Oct 10 2:00 0 - Rule Palestine 2038 only - Sep 25 2:00 0 - Rule Palestine 2039 only - Sep 17 2:00 0 - -Rule Palestine 2039 only - Oct 22 2:00 1:00 S -Rule Palestine 2039 2067 - Oct Sat<=30 2:00 0 - Rule Palestine 2040 only - Sep 1 2:00 0 - -Rule Palestine 2040 only - Oct 13 2:00 1:00 S +Rule Palestine 2040 only - Oct 20 2:00 1:00 S +Rule Palestine 2040 2067 - Oct Sat<=30 2:00 0 - Rule Palestine 2041 only - Aug 24 2:00 0 - -Rule Palestine 2041 only - Sep 28 2:00 1:00 S +Rule Palestine 2041 only - Oct 5 2:00 1:00 S Rule Palestine 2042 only - Aug 16 2:00 0 - -Rule Palestine 2042 only - Sep 20 2:00 1:00 S +Rule Palestine 2042 only - Sep 27 2:00 1:00 S Rule Palestine 2043 only - Aug 1 2:00 0 - -Rule Palestine 2043 only - Sep 12 2:00 1:00 S +Rule Palestine 2043 only - Sep 19 2:00 1:00 S Rule Palestine 2044 only - Jul 23 2:00 0 - -Rule Palestine 2044 only - Aug 27 2:00 1:00 S +Rule Palestine 2044 only - Sep 3 2:00 1:00 S Rule Palestine 2045 only - Jul 15 2:00 0 - -Rule Palestine 2045 only - Aug 19 2:00 1:00 S +Rule Palestine 2045 only - Aug 26 2:00 1:00 S Rule Palestine 2046 only - Jun 30 2:00 0 - -Rule Palestine 2046 only - Aug 11 2:00 1:00 S +Rule Palestine 2046 only - Aug 18 2:00 1:00 S Rule Palestine 2047 only - Jun 22 2:00 0 - -Rule Palestine 2047 only - Jul 27 2:00 1:00 S +Rule Palestine 2047 only - Aug 3 2:00 1:00 S Rule Palestine 2048 only - Jun 6 2:00 0 - -Rule Palestine 2048 only - Jul 18 2:00 1:00 S +Rule Palestine 2048 only - Jul 25 2:00 1:00 S Rule Palestine 2049 only - May 29 2:00 0 - -Rule Palestine 2049 only - Jul 3 2:00 1:00 S +Rule Palestine 2049 only - Jul 10 2:00 1:00 S Rule Palestine 2050 only - May 21 2:00 0 - -Rule Palestine 2050 only - Jun 25 2:00 1:00 S +Rule Palestine 2050 only - Jul 2 2:00 1:00 S Rule Palestine 2051 only - May 6 2:00 0 - -Rule Palestine 2051 only - Jun 17 2:00 1:00 S +Rule Palestine 2051 only - Jun 24 2:00 1:00 S Rule Palestine 2052 only - Apr 27 2:00 0 - -Rule Palestine 2052 only - Jun 1 2:00 1:00 S +Rule Palestine 2052 only - Jun 8 2:00 1:00 S Rule Palestine 2053 only - Apr 12 2:00 0 - -Rule Palestine 2053 only - May 24 2:00 1:00 S +Rule Palestine 2053 only - May 31 2:00 1:00 S Rule Palestine 2054 only - Apr 4 2:00 0 - -Rule Palestine 2054 only - May 16 2:00 1:00 S -Rule Palestine 2055 only - May 1 2:00 1:00 S -Rule Palestine 2056 only - Apr 22 2:00 1:00 S -Rule Palestine 2057 only - Apr 7 2:00 1:00 S -Rule Palestine 2058 max - Mar Sat<=30 2:00 1:00 S +Rule Palestine 2054 only - May 23 2:00 1:00 S +Rule Palestine 2055 only - May 8 2:00 1:00 S +Rule Palestine 2056 only - Apr 29 2:00 1:00 S +Rule Palestine 2057 only - Apr 14 2:00 1:00 S +Rule Palestine 2058 only - Apr 6 2:00 1:00 S +Rule Palestine 2059 max - Mar Sat<=30 2:00 1:00 S Rule Palestine 2068 only - Oct 20 2:00 0 - Rule Palestine 2069 only - Oct 12 2:00 0 - Rule Palestine 2070 only - Oct 4 2:00 0 - Rule Palestine 2071 only - Sep 19 2:00 0 - Rule Palestine 2072 only - Sep 10 2:00 0 - -Rule Palestine 2072 only - Oct 15 2:00 1:00 S +Rule Palestine 2072 only - Oct 22 2:00 1:00 S +Rule Palestine 2072 max - Oct Sat<=30 2:00 0 - Rule Palestine 2073 only - Sep 2 2:00 0 - -Rule Palestine 2073 only - Oct 7 2:00 1:00 S +Rule Palestine 2073 only - Oct 14 2:00 1:00 S Rule Palestine 2074 only - Aug 18 2:00 0 - -Rule Palestine 2074 only - Sep 29 2:00 1:00 S +Rule Palestine 2074 only - Oct 6 2:00 1:00 S Rule Palestine 2075 only - Aug 10 2:00 0 - -Rule Palestine 2075 only - Sep 14 2:00 1:00 S -Rule Palestine 2075 max - Oct Sat<=30 2:00 0 - +Rule Palestine 2075 only - Sep 21 2:00 1:00 S Rule Palestine 2076 only - Jul 25 2:00 0 - -Rule Palestine 2076 only - Sep 5 2:00 1:00 S +Rule Palestine 2076 only - Sep 12 2:00 1:00 S Rule Palestine 2077 only - Jul 17 2:00 0 - -Rule Palestine 2077 only - Aug 28 2:00 1:00 S +Rule Palestine 2077 only - Sep 4 2:00 1:00 S Rule Palestine 2078 only - Jul 9 2:00 0 - -Rule Palestine 2078 only - Aug 13 2:00 1:00 S +Rule Palestine 2078 only - Aug 20 2:00 1:00 S Rule Palestine 2079 only - Jun 24 2:00 0 - -Rule Palestine 2079 only - Aug 5 2:00 1:00 S +Rule Palestine 2079 only - Aug 12 2:00 1:00 S Rule Palestine 2080 only - Jun 15 2:00 0 - -Rule Palestine 2080 only - Jul 20 2:00 1:00 S +Rule Palestine 2080 only - Jul 27 2:00 1:00 S Rule Palestine 2081 only - Jun 7 2:00 0 - -Rule Palestine 2081 only - Jul 12 2:00 1:00 S +Rule Palestine 2081 only - Jul 19 2:00 1:00 S Rule Palestine 2082 only - May 23 2:00 0 - -Rule Palestine 2082 only - Jul 4 2:00 1:00 S +Rule Palestine 2082 only - Jul 11 2:00 1:00 S Rule Palestine 2083 only - May 15 2:00 0 - -Rule Palestine 2083 only - Jun 19 2:00 1:00 S +Rule Palestine 2083 only - Jun 26 2:00 1:00 S Rule Palestine 2084 only - Apr 29 2:00 0 - -Rule Palestine 2084 only - Jun 10 2:00 1:00 S +Rule Palestine 2084 only - Jun 17 2:00 1:00 S Rule Palestine 2085 only - Apr 21 2:00 0 - -Rule Palestine 2085 only - Jun 2 2:00 1:00 S +Rule Palestine 2085 only - Jun 9 2:00 1:00 S Rule Palestine 2086 only - Apr 13 2:00 0 - -Rule Palestine 2086 only - May 18 2:00 1:00 S +Rule Palestine 2086 only - May 25 2:00 1:00 S # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Asia/Gaza 2:17:52 - LMT 1900 Oct @@ -3627,7 +3651,7 @@ Zone Asia/Hebron 2:20:23 - LMT 1900 Oct # Philippines -# From Paul Eggert (2018-11-18): +# From Paul Eggert (2024-01-21): # The Spanish initially used American (west-of-Greenwich) time. # It is unknown what time Manila kept when the British occupied it from # 1762-10-06 through 1764-04; for now assume it kept American time. @@ -3635,7 +3659,7 @@ Zone Asia/Hebron 2:20:23 - LMT 1900 Oct # Philippines, issued a proclamation announcing that 1844-12-30 was to # be immediately followed by 1845-01-01; see R.H. van Gent's # History of the International Date Line -# https://www.staff.science.uu.nl/~gent0113/idl/idl_philippines.htm +# https://webspace.science.uu.nl/~gent0113/idl/idl_philippines.htm # The rest of the data entries are from Shanks & Pottenger. # From Jesper Nørgaard Welen (2006-04-26): @@ -4062,7 +4086,8 @@ Zone Asia/Tashkent 4:37:11 - LMT 1924 May 2 # The English-language name of Vietnam's most populous city is "Ho Chi Minh # City"; use Ho_Chi_Minh below to avoid a name of more than 14 characters. -# From Paul Eggert (2022-07-27) after a 2014 heads-up from Trần Ngọc Quân: +# From Paul Eggert (2024-01-14) after a 2014 heads-up from Trần Ngọc Quân +# and a 2024-01-14 heads-up from Đoàn Trần Công Danh: # Trần Tiến Bình's authoritative book "Lịch Việt Nam: thế kỷ XX-XXI (1901-2100)" # (Nhà xuất bản Văn Hoá - Thông Tin, Hanoi, 2005), pp 49-50, # is quoted verbatim in: @@ -4092,14 +4117,35 @@ Zone Asia/Tashkent 4:37:11 - LMT 1924 May 2 # # Trần cites the following sources; it's unclear which supplied the info above. # -# Hoàng Xuân Hãn: "Lịch và lịch Việt Nam". Tập san Khoa học Xã hội, -# No. 9, Paris, February 1982. +# Hoàng Xuân Hãn: "Lịch và lịch Việt Nam". Tập san Khoa học Xã hội, +# No. 9, Paris, February 1982. +# +# Lê Thành Lân: "Lịch và niên biểu lịch sử hai mươi thế kỷ (0001-2010)", +# NXB Thống kê, Hanoi, 2000. # -# Lê Thành Lân: "Lịch và niên biểu lịch sử hai mươi thế kỷ (0001-2010)", -# NXB Thống kê, Hanoi, 2000. +# Lê Thành Lân: "Lịch hai thế kỷ (1802-2010) và các lịch vĩnh cửu", +# NXB Thuận Hoá, Huế, 1995. # -# Lê Thành Lân: "Lịch hai thế kỷ (1802-2010) và các lịch vĩnh cửu", -# NXB Thuận Hoá, Huế, 1995. +# Here is the decision for the September 1945 transition: +# Võ Nguyên Giáp, Việt Nam Dân Quốc Công Báo, No. 1 (1945-09-29), page 13 +# http://baochi.nlv.gov.vn/baochi/cgi-bin/baochi?a=d&d=JwvzO19450929.2.5&dliv=none +# It says that on 1945-09-01 at 24:00, Vietnam moved back two hours, to +07. +# It also mentions a 1945-03-29 decree (by a Japanese Goveror-General) +# to set the time zone to +09, but does not say whether that decree +# merely legalized an earlier change to +09. +# +# July 1955 transition: +# Ngô Đình Diệm, Công Báo Việt Nam, No. 92 (1955-07-02), page 1780-1781 +# Ordinance (Dụ) No. 46 (1955-06-25) +# http://ddsnext.crl.edu/titles/32341#?c=0&m=29&s=0&cv=4&r=0&xywh=-89%2C342%2C1724%2C1216 +# It says that on 1955-07-01 at 01:00, South Vietnam moved back 1 hour (to +07). +# +# December 1959 transition: +# Ngô Đình Diệm, Công Báo Việt Nam Cộng Hòa, 1960 part 1 (1960-01-02), page 62 +# Decree (Sắc lệnh) No. 362-TTP (1959-12-30) +# http://ddsnext.crl.edu/titles/32341#?c=0&m=138&s=0&cv=793&r=0&xywh=-54%2C1504%2C1705%2C1202 +# It says that on 1959-12-31 at 23:00, South Vietnam moved forward 1 hour (to +08). + # Zone NAME STDOFF RULES FORMAT [UNTIL] #STDOFF 7:06:30.13 @@ -4107,9 +4153,9 @@ Zone Asia/Ho_Chi_Minh 7:06:30 - LMT 1906 Jul 1 7:06:30 - PLMT 1911 May 1 # Phù Liễn MT 7:00 - +07 1942 Dec 31 23:00 8:00 - +08 1945 Mar 14 23:00 - 9:00 - +09 1945 Sep 2 + 9:00 - +09 1945 Sep 1 24:00 7:00 - +07 1947 Apr 1 - 8:00 - +08 1955 Jul 1 + 8:00 - +08 1955 Jul 1 01:00 7:00 - +07 1959 Dec 31 23:00 8:00 - +08 1975 Jun 13 7:00 - +07 diff --git a/src/java.base/share/data/tzdata/australasia b/src/java.base/share/data/tzdata/australasia index 893d7055eab..624735be652 100644 --- a/src/java.base/share/data/tzdata/australasia +++ b/src/java.base/share/data/tzdata/australasia @@ -414,8 +414,14 @@ Zone Antarctica/Macquarie 0 - -00 1899 Nov # Please note that there will not be any daylight savings time change # in Fiji for 2022-2023.... # https://www.facebook.com/FijianGovernment/posts/pfbid0mmWVTYmTibn66ybpFda75pDcf34SSpoSaskJW5gXwaKo5Sgc7273Q4fXWc6kQV6Hl + +# From Almaz Mingaleev (2023-10-06): +# Cabinet approved the suspension of Daylight Saving and appropriate +# legislative changes will be considered including the repeal of the +# Daylight Saving Act 1998 +# https://www.fiji.gov.fj/Media-Centre/Speeches/English/CABINET-DECISIONS-3-OCTOBER-2023 # -# From Paul Eggert (2022-10-27): +# From Paul Eggert (2023-10-06): # For now, assume DST is suspended indefinitely. # Rule NAME FROM TO - IN ON AT SAVE LETTER/S @@ -437,11 +443,11 @@ Zone Pacific/Fiji 11:55:44 - LMT 1915 Oct 26 # Suva # French Polynesia # Zone NAME STDOFF RULES FORMAT [UNTIL] -Zone Pacific/Gambier -8:59:48 - LMT 1912 Oct # Rikitea +Zone Pacific/Gambier -8:59:48 - LMT 1912 Oct 1 # Rikitea -9:00 - -09 -Zone Pacific/Marquesas -9:18:00 - LMT 1912 Oct +Zone Pacific/Marquesas -9:18:00 - LMT 1912 Oct 1 -9:30 - -0930 -Zone Pacific/Tahiti -9:58:16 - LMT 1912 Oct # Papeete +Zone Pacific/Tahiti -9:58:16 - LMT 1912 Oct 1 # Papeete -10:00 - -10 # Clipperton (near North America) is administered from French Polynesia; # it is uninhabited. @@ -819,7 +825,7 @@ Zone Pacific/Apia 12:33:04 - LMT 1892 Jul 5 # Solomon Is # excludes Bougainville, for which see Papua New Guinea # Zone NAME STDOFF RULES FORMAT [UNTIL] -Zone Pacific/Guadalcanal 10:39:48 - LMT 1912 Oct # Honiara +Zone Pacific/Guadalcanal 10:39:48 - LMT 1912 Oct 1 # Honiara 11:00 - +11 # Tokelau @@ -980,6 +986,10 @@ Zone Pacific/Efate 11:13:16 - LMT 1912 Jan 13 # Vila # Milne J. Civil time. Geogr J. 1899 Feb;13(2):173-94. # https://www.jstor.org/stable/1774359 # +# For the 1911/1912 establishment of standard time in French possessions, see: +# Société Française de Physique, Recueil de constantes physiques (1913), +# page 752, 18b. +# # A reliable and entertaining source about time zones is # Derek Howse, Greenwich time and longitude, Philip Wilson Publishers (1997). # @@ -2056,7 +2066,7 @@ Zone Pacific/Efate 11:13:16 - LMT 1912 Jan 13 # Vila # ordaining - by a masterpiece of diplomatic flattery - that # the Fourth of July should be celebrated twice in that year." # This happened in 1892, according to the Evening News (Sydney) of 1892-07-20. -# https://www.staff.science.uu.nl/~gent0113/idl/idl.htm +# https://webspace.science.uu.nl/~gent0113/idl/idl_alaska_samoa.htm # Although Shanks & Pottenger says they both switched to UT -11:30 # in 1911, and to -11 in 1950. many earlier sources give -11 diff --git a/src/java.base/share/data/tzdata/backward b/src/java.base/share/data/tzdata/backward index c0746d6dd1b..7ddc6cc3d93 100644 --- a/src/java.base/share/data/tzdata/backward +++ b/src/java.base/share/data/tzdata/backward @@ -228,7 +228,6 @@ Link America/Puerto_Rico America/Tortola Link Pacific/Port_Moresby Antarctica/DumontDUrville Link Pacific/Auckland Antarctica/McMurdo Link Asia/Riyadh Antarctica/Syowa -Link Asia/Urumqi Antarctica/Vostok Link Europe/Berlin Arctic/Longyearbyen Link Asia/Riyadh Asia/Aden Link Asia/Qatar Asia/Bahrain diff --git a/src/java.base/share/data/tzdata/etcetera b/src/java.base/share/data/tzdata/etcetera index 8ae294f524a..27147715ef6 100644 --- a/src/java.base/share/data/tzdata/etcetera +++ b/src/java.base/share/data/tzdata/etcetera @@ -28,7 +28,7 @@ # These entries are for uses not otherwise covered by the tz database. # Their main practical use is for platforms like Android that lack -# support for POSIX-style TZ strings. On such platforms these entries +# support for POSIX.1-2017-style TZ strings. On such platforms these entries # can be useful if the timezone database is wrong or if a ship or # aircraft at sea is not in a timezone. diff --git a/src/java.base/share/data/tzdata/europe b/src/java.base/share/data/tzdata/europe index 446d2e1e658..18865f33b6c 100644 --- a/src/java.base/share/data/tzdata/europe +++ b/src/java.base/share/data/tzdata/europe @@ -1013,9 +1013,34 @@ Zone Europe/Sofia 1:33:16 - LMT 1880 # Czech Republic (Czechia) # Slovakia # -# From Paul Eggert (2018-04-15): -# The source for Czech data is: Kdy začíná a končí letní čas. 2018-04-15. +# From Ivan Benovic (2024-01-30): +# https://www.slov-lex.sk/pravne-predpisy/SK/ZZ/1946/54/ +# (This is an official link to the Czechoslovak Summer Time Act of +# March 8, 1946 that authorizes the Czechoslovak government to set the +# exact dates of change to summer time and back to Central European Time. +# The act also implicitly confirms Central European Time as the +# official time zone of Czechoslovakia and currently remains in force +# in both the Czech Republic and Slovakia.) +# https://www.psp.cz/eknih/1945pns/tisky/t0216_00.htm +# (This is a link to the original legislative proposal dating back to +# February 22, 1946. The accompanying memorandum to the proposal says +# that an advisory committee on European railroad transportation that +# met in Brussels in October 1945 decided that the change of time +# should be carried out in all participating countries in a strictly +# coordinated manner....) +# +# From Paul Eggert (2024-01-30): +# The source for Czech data is: Kdy začíná a končí letní čas. # https://kalendar.beda.cz/kdy-zacina-a-konci-letni-cas +# Its main text disagrees with its quoted sources only in 1918, +# where the main text says spring and autumn transitions +# occurred at 02:00 and 03:00 respectively (as usual), +# whereas the 1918 source "Oznámení o zavedení letního času v roce 1918" +# says transitions were at 01:00 and 02:00 respectively. +# As the 1918 source appears to be a humorous piece, and it is +# unlikely that Prague would have disagreed with its neighbors by an hour, +# go with the main text for now. +# # We know of no English-language name for historical Czech winter time; # abbreviate it as "GMT", as it happened to be GMT. # @@ -1146,6 +1171,23 @@ Zone Atlantic/Faroe -0:27:04 - LMT 1908 Jan 11 # Tórshavn # 2. The shift *from* DST in 2023 happens as normal, but coincides with the # shift to UTC-02 normaltime (people will not change their clocks here). # 3. After this, DST is still observed, but as -02/-01 instead of -03/-02. +# +# From Múte Bourup Egede via Jógvan Svabo Samuelsen (2023-03-15): +# Greenland will not switch to Daylight Saving Time this year, 2023, +# because the standard time for Greenland will change from UTC -3 to UTC -2. +# However, Greenland will change to Daylight Saving Time again in 2024 +# and onwards. + +# From a contributor who wishes to remain anonymous for now (2023-10-29): +# https://www.dr.dk/nyheder/seneste/i-nat-skal-uret-stilles-en-time-tilbage-men-foerste-gang-sker-det-ikke-i-groenland +# with a link to that page: +# https://naalakkersuisut.gl/Nyheder/2023/10/2710_sommertid +# ... Ittoqqortoormiit joins the time of Nuuk at March 2024. +# What would mean that America/Scoresbysund would either be in -01 year round +# or in -02/-01 like America/Nuuk, but no longer in -01/+00. +# +# From Paul Eggert (2023-10-29): +# For now, assume it will be like America/Nuuk. # Rule NAME FROM TO - IN ON AT SAVE LETTER/S Rule Thule 1991 1992 - Mar lastSun 2:00 1:00 D @@ -1166,10 +1208,12 @@ Zone America/Danmarkshavn -1:14:40 - LMT 1916 Jul 28 Zone America/Scoresbysund -1:27:52 - LMT 1916 Jul 28 # Ittoqqortoormiit -2:00 - -02 1980 Apr 6 2:00 -2:00 C-Eur -02/-01 1981 Mar 29 - -1:00 EU -01/+00 + -1:00 EU -01/+00 2024 Mar 31 + -2:00 EU -02/-01 Zone America/Nuuk -3:26:56 - LMT 1916 Jul 28 # Godthåb -3:00 - -03 1980 Apr 6 2:00 - -3:00 EU -03/-02 2023 Oct 29 1:00u + -3:00 EU -03/-02 2023 Mar 26 1:00u + -2:00 - -02 2023 Oct 29 1:00u -2:00 EU -02/-01 Zone America/Thule -4:35:08 - LMT 1916 Jul 28 # Pituffik -4:00 Thule A%sT @@ -3734,11 +3778,7 @@ Zone Europe/Istanbul 1:55:52 - LMT 1880 # and not at 3:00 as would have been under EU rules. # This is why I have set the change to EU rules into May 1996, # so that the change in March is stil covered by the Ukraine rule. -# The next change in October 1996 happened under EU rules.... -# TZ database holds three other zones for Ukraine.... I have not yet -# worked out the consequences for these three zones, as we (me and my -# US colleague David Cochrane) are still trying to get more -# information upon these local deviations from Kiev rules. +# The next change in October 1996 happened under EU rules. # # From Paul Eggert (2022-08-27): # For now, assume that Ukraine's zones all followed the same rules, diff --git a/src/java.base/share/data/tzdata/iso3166.tab b/src/java.base/share/data/tzdata/iso3166.tab index cea17732dd1..7fa350ecbe3 100644 --- a/src/java.base/share/data/tzdata/iso3166.tab +++ b/src/java.base/share/data/tzdata/iso3166.tab @@ -26,17 +26,22 @@ # This file is in the public domain, so clarified as of # 2009-05-17 by Arthur David Olson. # -# From Paul Eggert (2022-11-18): +# From Paul Eggert (2023-09-06): # This file contains a table of two-letter country codes. Columns are # separated by a single tab. Lines beginning with '#' are comments. # All text uses UTF-8 encoding. The columns of the table are as follows: # # 1. ISO 3166-1 alpha-2 country code, current as of -# ISO 3166-1 N1087 (2022-09-02). See: Updates on ISO 3166-1 -# https://isotc.iso.org/livelink/livelink/Open/16944257 -# 2. The usual English name for the coded region, -# chosen so that alphabetic sorting of subsets produces helpful lists. -# This is not the same as the English name in the ISO 3166 tables. +# ISO/TC 46 N1108 (2023-04-05). See: ISO/TC 46 Documents +# https://www.iso.org/committee/48750.html?view=documents +# 2. The usual English name for the coded region. This sometimes +# departs from ISO-listed names, sometimes so that sorted subsets +# of names are useful (e.g., "Samoa (American)" and "Samoa +# (western)" rather than "American Samoa" and "Samoa"), +# sometimes to avoid confusion among non-experts (e.g., +# "Czech Republic" and "Turkey" rather than "Czechia" and "Türkiye"), +# and sometimes to omit needless detail or churn (e.g., "Netherlands" +# rather than "Netherlands (the)" or "Netherlands (Kingdom of the)"). # # The table is sorted by country code. # diff --git a/src/java.base/share/data/tzdata/leapseconds b/src/java.base/share/data/tzdata/leapseconds index 89ce8b89cd2..8e7df3de984 100644 --- a/src/java.base/share/data/tzdata/leapseconds +++ b/src/java.base/share/data/tzdata/leapseconds @@ -26,13 +26,10 @@ # This file is in the public domain. # This file is generated automatically from the data in the public-domain -# NIST format leap-seconds.list file, which can be copied from -# -# or . -# The NIST file is used instead of its IERS upstream counterpart +# NIST/IERS format leap-seconds.list file, which can be copied from # -# because under US law the NIST file is public domain -# whereas the IERS file's copyright and license status is unclear. +# or, in a variant with different comments, from +# . # For more about leap-seconds.list, please see # The NTP Timescale and Leap Seconds # . @@ -95,11 +92,11 @@ Leap 2016 Dec 31 23:59:60 + S # Any additional leap seconds will come after this. # This Expires line is commented out for now, # so that pre-2020a zic implementations do not reject this file. -#Expires 2023 Dec 28 00:00:00 +#Expires 2024 Dec 28 00:00:00 # POSIX timestamps for the data in this file: -#updated 1467936000 (2016-07-08 00:00:00 UTC) -#expires 1703721600 (2023-12-28 00:00:00 UTC) +#updated 1704708379 (2024-01-08 10:06:19 UTC) +#expires 1735344000 (2024-12-28 00:00:00 UTC) -# Updated through IERS Bulletin C65 -# File expires on: 28 December 2023 +# Updated through IERS Bulletin C (https://hpiers.obspm.fr/iers/bul/bulc/bulletinc.dat) +# File expires on 28 December 2024 diff --git a/src/java.base/share/data/tzdata/northamerica b/src/java.base/share/data/tzdata/northamerica index e240cf35103..a8b2ef3f7fa 100644 --- a/src/java.base/share/data/tzdata/northamerica +++ b/src/java.base/share/data/tzdata/northamerica @@ -1,3 +1,4 @@ +# # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -1290,6 +1291,10 @@ Zone America/Menominee -5:50:27 - LMT 1885 Sep 18 12:00 # # [PDF] (1914-03) # +# For the 1911/1912 establishment of standard time in French possessions, see: +# Société Française de Physique, Recueil de constantes physiques (1913), +# page 752, 18b. +# # See the 'europe' file for Greenland. # Canada @@ -1376,7 +1381,7 @@ Zone America/Menominee -5:50:27 - LMT 1885 Sep 18 12:00 # From Paul Eggert (2014-10-18): # H. David Matthews and Mary Vincent's map # "It's about TIME", _Canadian Geographic_ (September-October 1998) -# http://www.canadiangeographic.ca/Magazine/SO98/alacarte.asp +# https://web.archive.org/web/19990827055050/https://canadiangeographic.ca/SO98/geomap.htm # contains detailed boundaries for regions observing nonstandard # time and daylight saving time arrangements in Canada circa 1998. # @@ -1475,7 +1480,7 @@ Rule StJohns 1989 2006 - Apr Sun>=1 0:01 1:00 D Rule StJohns 2007 2011 - Mar Sun>=8 0:01 1:00 D Rule StJohns 2007 2010 - Nov Sun>=1 0:01 0 S # -# St John's has an apostrophe, but Posix file names can't have apostrophes. +# St John's has an apostrophe, but POSIX file names can't have apostrophes. # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone America/St_Johns -3:30:52 - LMT 1884 -3:30:52 StJohns N%sT 1918 @@ -1664,6 +1669,15 @@ Zone America/Moncton -4:19:08 - LMT 1883 Dec 9 # Some cities in the United States have pushed the deadline back # three weeks and will change over from daylight saving in October. +# From Chris Walton (2024-01-09): +# The [Toronto] changes in 1947, 1948, and 1949 took place at 2:00 a.m. local +# time instead of midnight.... Toronto Daily Star - ... +# April 2, 1947 - Page 39 ... April 7, 1948 - Page 13 ... +# April 2, 1949 - Page 1 ... April 7, 1949 - Page 24 ... +# November 25, 1949 - Page 52 ... April 21, 1950 - Page 14 ... +# September 19, 1950 - Page 46 ... September 20, 1950 - Page 3 ... +# November 24, 1950 - Page 21 + # From Arthur David Olson (2010-07-17): # # "Standard Time and Time Zones in Canada" appeared in @@ -1725,13 +1739,9 @@ Rule Toronto 1927 1937 - Sep Sun>=25 2:00 0 S Rule Toronto 1928 1937 - Apr Sun>=25 2:00 1:00 D Rule Toronto 1938 1940 - Apr lastSun 2:00 1:00 D Rule Toronto 1938 1939 - Sep lastSun 2:00 0 S -Rule Toronto 1945 1946 - Sep lastSun 2:00 0 S -Rule Toronto 1946 only - Apr lastSun 2:00 1:00 D -Rule Toronto 1947 1949 - Apr lastSun 0:00 1:00 D -Rule Toronto 1947 1948 - Sep lastSun 0:00 0 S -Rule Toronto 1949 only - Nov lastSun 0:00 0 S -Rule Toronto 1950 1973 - Apr lastSun 2:00 1:00 D -Rule Toronto 1950 only - Nov lastSun 2:00 0 S +Rule Toronto 1945 1948 - Sep lastSun 2:00 0 S +Rule Toronto 1946 1973 - Apr lastSun 2:00 1:00 D +Rule Toronto 1949 1950 - Nov lastSun 2:00 0 S Rule Toronto 1951 1956 - Sep lastSun 2:00 0 S # Shanks & Pottenger say Toronto ended DST a week early in 1971, # namely on 1971-10-24, but Mark Brader wrote (2003-05-31) that this @@ -3454,7 +3464,7 @@ Zone America/Jamaica -5:07:10 - LMT 1890 # Kingston # Martinique # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone America/Martinique -4:04:20 - LMT 1890 # Fort-de-France - -4:04:20 - FFMT 1911 May # Fort-de-France MT + -4:04:20 - FFMT 1911 May 1 # Fort-de-France MT -4:00 - AST 1980 Apr 6 -4:00 1:00 ADT 1980 Sep 28 -4:00 - AST @@ -3561,7 +3571,7 @@ Zone America/Puerto_Rico -4:24:25 - LMT 1899 Mar 28 12:00 # San Juan # St Pierre and Miquelon # There are too many St Pierres elsewhere, so we'll use 'Miquelon'. # Zone NAME STDOFF RULES FORMAT [UNTIL] -Zone America/Miquelon -3:44:40 - LMT 1911 May 15 # St Pierre +Zone America/Miquelon -3:44:40 - LMT 1911 Jun 15 # St Pierre -4:00 - AST 1980 May -3:00 - -03 1987 -3:00 Canada -03/-02 diff --git a/src/java.base/share/data/tzdata/southamerica b/src/java.base/share/data/tzdata/southamerica index 4024e7180cd..d77acc08857 100644 --- a/src/java.base/share/data/tzdata/southamerica +++ b/src/java.base/share/data/tzdata/southamerica @@ -1593,8 +1593,11 @@ Zone Atlantic/Stanley -3:51:24 - LMT 1890 -3:00 - -03 # French Guiana +# For the 1911/1912 establishment of standard time in French possessions, see: +# Société Française de Physique, Recueil de constantes physiques (1913), +# page 752, 18b. # Zone NAME STDOFF RULES FORMAT [UNTIL] -Zone America/Cayenne -3:29:20 - LMT 1911 Jul +Zone America/Cayenne -3:29:20 - LMT 1911 Jul 1 -4:00 - -04 1967 Oct -3:00 - -03 @@ -1720,6 +1723,12 @@ Rule Para 2010 2012 - Apr Sun>=8 0:00 0 - # From Carlos Raúl Perasso (2014-02-28): # Decree 1264 can be found at: # http://www.presidencia.gov.py/archivos/documentos/DECRETO1264_ey9r8zai.pdf +# +# From Paul Eggert (2023-07-26): +# Transition dates are now set by Law No. 7115, not by presidential decree. +# https://www.abc.com.py/politica/2023/07/12/promulgacion-el-cambio-de-hora-sera-por-ley/ +# From Carlos Raúl Perasso (2023-07-27): +# http://silpy.congreso.gov.py/descarga/ley-144138 Rule Para 2013 max - Mar Sun>=22 0:00 0 - # Zone NAME STDOFF RULES FORMAT [UNTIL] diff --git a/src/java.base/share/data/tzdata/zone.tab b/src/java.base/share/data/tzdata/zone.tab index 3edb0d61c80..0a01e8777dd 100644 --- a/src/java.base/share/data/tzdata/zone.tab +++ b/src/java.base/share/data/tzdata/zone.tab @@ -71,7 +71,7 @@ AR -3124-06411 America/Argentina/Cordoba Argentina (most areas: CB, CC, CN, ER, AR -2447-06525 America/Argentina/Salta Salta (SA, LP, NQ, RN) AR -2411-06518 America/Argentina/Jujuy Jujuy (JY) AR -2649-06513 America/Argentina/Tucuman Tucuman (TM) -AR -2828-06547 America/Argentina/Catamarca Catamarca (CT); Chubut (CH) +AR -2828-06547 America/Argentina/Catamarca Catamarca (CT), Chubut (CH) AR -2926-06651 America/Argentina/La_Rioja La Rioja (LR) AR -3132-06831 America/Argentina/San_Juan San Juan (SJ) AR -3253-06849 America/Argentina/Mendoza Mendoza (MZ) @@ -110,7 +110,7 @@ BN +0456+11455 Asia/Brunei BO -1630-06809 America/La_Paz BQ +120903-0681636 America/Kralendijk BR -0351-03225 America/Noronha Atlantic islands -BR -0127-04829 America/Belem Para (east); Amapa +BR -0127-04829 America/Belem Para (east), Amapa BR -0343-03830 America/Fortaleza Brazil (northeast: MA, PI, CE, RN, PB) BR -0803-03454 America/Recife Pernambuco BR -0712-04812 America/Araguaina Tocantins @@ -130,21 +130,21 @@ BT +2728+08939 Asia/Thimphu BW -2439+02555 Africa/Gaborone BY +5354+02734 Europe/Minsk BZ +1730-08812 America/Belize -CA +4734-05243 America/St_Johns Newfoundland; Labrador (southeast) -CA +4439-06336 America/Halifax Atlantic - NS (most areas); PE +CA +4734-05243 America/St_Johns Newfoundland, Labrador (SE) +CA +4439-06336 America/Halifax Atlantic - NS (most areas), PE CA +4612-05957 America/Glace_Bay Atlantic - NS (Cape Breton) CA +4606-06447 America/Moncton Atlantic - New Brunswick CA +5320-06025 America/Goose_Bay Atlantic - Labrador (most areas) CA +5125-05707 America/Blanc-Sablon AST - QC (Lower North Shore) -CA +4339-07923 America/Toronto Eastern - ON, QC (most areas) +CA +4339-07923 America/Toronto Eastern - ON & QC (most areas) CA +6344-06828 America/Iqaluit Eastern - NU (most areas) -CA +484531-0913718 America/Atikokan EST - ON (Atikokan); NU (Coral H) -CA +4953-09709 America/Winnipeg Central - ON (west); Manitoba +CA +484531-0913718 America/Atikokan EST - ON (Atikokan), NU (Coral H) +CA +4953-09709 America/Winnipeg Central - ON (west), Manitoba CA +744144-0944945 America/Resolute Central - NU (Resolute) CA +624900-0920459 America/Rankin_Inlet Central - NU (central) CA +5024-10439 America/Regina CST - SK (most areas) CA +5017-10750 America/Swift_Current CST - SK (midwest) -CA +5333-11328 America/Edmonton Mountain - AB; BC (E); NT (E); SK (W) +CA +5333-11328 America/Edmonton Mountain - AB, BC(E), NT(E), SK(W) CA +690650-1050310 America/Cambridge_Bay Mountain - NU (west) CA +682059-1334300 America/Inuvik Mountain - NT (west) CA +4906-11631 America/Creston MST - BC (Creston) @@ -230,8 +230,8 @@ HT +1832-07220 America/Port-au-Prince HU +4730+01905 Europe/Budapest ID -0610+10648 Asia/Jakarta Java, Sumatra ID -0002+10920 Asia/Pontianak Borneo (west, central) -ID -0507+11924 Asia/Makassar Borneo (east, south); Sulawesi/Celebes, Bali, Nusa Tengarra; Timor (west) -ID -0232+14042 Asia/Jayapura New Guinea (West Papua / Irian Jaya); Malukus/Moluccas +ID -0507+11924 Asia/Makassar Borneo (east, south), Sulawesi/Celebes, Bali, Nusa Tengarra, Timor (west) +ID -0232+14042 Asia/Jayapura New Guinea (West Papua / Irian Jaya), Malukus/Moluccas IE +5320-00615 Europe/Dublin IL +314650+0351326 Asia/Jerusalem IM +5409-00428 Europe/Isle_of_Man @@ -378,7 +378,7 @@ RU +4310+13156 Asia/Vladivostok MSK+07 - Amur River RU +643337+1431336 Asia/Ust-Nera MSK+07 - Oymyakonsky RU +5934+15048 Asia/Magadan MSK+08 - Magadan RU +4658+14242 Asia/Sakhalin MSK+08 - Sakhalin Island -RU +6728+15343 Asia/Srednekolymsk MSK+08 - Sakha (E); N Kuril Is +RU +6728+15343 Asia/Srednekolymsk MSK+08 - Sakha (E), N Kuril Is RU +5301+15839 Asia/Kamchatka MSK+09 - Kamchatka RU +6445+17729 Asia/Anadyr MSK+09 - Bering Sea RW -0157+03004 Africa/Kigali @@ -441,7 +441,7 @@ US +470659-1011757 America/North_Dakota/Center Central - ND (Oliver) US +465042-1012439 America/North_Dakota/New_Salem Central - ND (Morton rural) US +471551-1014640 America/North_Dakota/Beulah Central - ND (Mercer) US +394421-1045903 America/Denver Mountain (most areas) -US +433649-1161209 America/Boise Mountain - ID (south); OR (east) +US +433649-1161209 America/Boise Mountain - ID (south), OR (east) US +332654-1120424 America/Phoenix MST - AZ (except Navajo) US +340308-1181434 America/Los_Angeles Pacific US +611305-1495401 America/Anchorage Alaska (most areas) diff --git a/src/java.base/share/legal/zlib.md b/src/java.base/share/legal/zlib.md index d856af6ccd4..93c9d305a46 100644 --- a/src/java.base/share/legal/zlib.md +++ b/src/java.base/share/legal/zlib.md @@ -1,9 +1,9 @@ -## zlib v1.2.13 +## zlib v1.3 ### zlib License

 
-Copyright (C) 1995-2022 Jean-loup Gailly and Mark Adler
+Copyright (C) 1995-2023 Jean-loup Gailly and Mark Adler
 
 This software is provided 'as-is', without any express or implied
 warranty.  In no event will the authors be held liable for any damages
diff --git a/src/java.base/share/man/java.1 b/src/java.base/share/man/java.1
index 857d6e2ed67..320ee2869a7 100644
--- a/src/java.base/share/man/java.1
+++ b/src/java.base/share/man/java.1
@@ -1,4 +1,4 @@
-.\" Copyright (c) 1994, 2023, Oracle and/or its affiliates. All rights reserved.
+.\" Copyright (c) 1994, 2024, Oracle and/or its affiliates. All rights reserved.
 .\" DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 .\"
 .\" This code is free software; you can redistribute it and/or modify it
@@ -36,7 +36,7 @@
 . ftr VB CB
 . ftr VBI CBI
 .\}
-.TH "JAVA" "1" "2024" "JDK 22-ea" "JDK Commands"
+.TH "JAVA" "1" "2024" "JDK 22" "JDK Commands"
 .hy
 .SH NAME
 .PP
@@ -63,7 +63,7 @@ or
 \f[V]java\f[R] [\f[I]options\f[R]] \f[V]--module\f[R]
 \f[I]module\f[R][\f[V]/\f[R]\f[I]mainclass\f[R]] [\f[I]args\f[R] ...]
 .PP
-To launch a single source-file program:
+To launch a source-file program:
 .PP
 \f[V]java\f[R] [\f[I]options\f[R]] \f[I]source-file\f[R] [\f[I]args\f[R]
 \&...]
@@ -100,11 +100,10 @@ See \f[B]Standard Options for Java\f[R].
 .RE
 .TP
 \f[I]source-file\f[R]
-Only used to launch a single source-file program.
+Only used to launch a source-file program.
 Specifies the source file that contains the main class when using
 source-file mode.
-See \f[B]Using Source-File Mode to Launch Single-File Source-Code
-Programs\f[R]
+See \f[B]Using Source-File Mode to Launch Source-Code Programs\f[R]
 .TP
 \f[I]args\f[R] ...
 Optional: Arguments following \f[I]mainclass\f[R],
@@ -128,8 +127,8 @@ The method declaration has the following form:
 .PP
 In source-file mode, the \f[V]java\f[R] command can launch a class
 declared in a source file.
-See \f[B]Using Source-File Mode to Launch Single-File Source-Code
-Programs\f[R] for a description of using the source-file mode.
+See \f[B]Using Source-File Mode to Launch Source-Code Programs\f[R] for
+a description of using the source-file mode.
 .RS
 .PP
 \f[B]Note:\f[R] You can use the \f[V]JDK_JAVA_OPTIONS\f[R] launcher
@@ -157,7 +156,7 @@ Use \f[V]javaw\f[R] when you don\[aq]t want a command prompt window to
 appear.
 The \f[V]javaw\f[R] launcher will, however, display a dialog box with
 error information if a launch fails.
-.SH USING SOURCE-FILE MODE TO LAUNCH SINGLE-FILE SOURCE-CODE PROGRAMS
+.SH USING SOURCE-FILE MODE TO LAUNCH SOURCE-CODE PROGRAMS
 .PP
 To launch a class declared in a source file, run the \f[V]java\f[R]
 launcher in source-file mode.
@@ -205,26 +204,25 @@ Any arguments placed after the name of the source file in the original
 command line are passed to the compiled class when it is executed.
 .PP
 For example, if a file were named \f[V]HelloWorld.java\f[R] and
-contained a class named \f[V]hello.World\f[R], then the source-file mode
+contained a class named \f[V]HelloWorld\f[R], then the source-file mode
 command to launch the class would be:
 .RS
 .PP
 \f[V]java HelloWorld.java\f[R]
 .RE
 .PP
-The example illustrates that the class can be in a named package, and
-does not need to be in the unnamed package.
 This use of source-file mode is informally equivalent to using the
-following two commands where \f[V]hello.World\f[R] is the name of the
-class in the package:
+following two commands:
 .IP
 .nf
 \f[CB]
-javac -d  HelloWorld.java
-java -cp  hello.World
+javac -d  --source-path  HelloWorld.java
+java --class-path  HelloWorld
 \f[R]
 .fi
 .PP
+where \f[V]\f[R] is computed
+.PP
 \f[B]In source-file mode, any additional command-line options are
 processed as follows:\f[R]
 .IP \[bu] 2
@@ -253,9 +251,24 @@ filename with an \f[V]\[at]\f[R] character.
 .IP \[bu] 2
 Any command-line options that are relevant to the compilation
 environment are taken into account.
-.IP \[bu] 2
-No other source files are found and compiled, as if the source path is
-set to an empty value.
+These include:
+\f[V]--class-path\f[R]/\f[V]-classpath\f[R]/\f[V]-cp\f[R],
+\f[V]--module-path\f[R]/\f[V]-p\f[R], \f[V]--add-exports\f[R],
+\f[V]--add-modules\f[R], \f[V]--limit-modules\f[R],
+\f[V]--patch-module\f[R], \f[V]--upgrade-module-path\f[R],
+\f[V]--enable-preview\f[R].
+.IP \[bu] 2
+The root of the source tree, \f[V]\f[R] is computed from
+the package of the class being launched.
+For example, if \f[V]HelloWorld.java\f[R] declared its classes to be in
+the \f[V]hello\f[R] package, then the file \f[V]HelloWorld.java\f[R] is
+expected to reside in the directory \f[V]somedir/hello/\f[R].
+In this case, \f[V]somedir\f[R] is computed to be the root of the source
+tree.
+.IP \[bu] 2
+The root of the source tree serves as the source-path for compilation,
+so that other source files found in that tree and are needed by
+\f[V]HelloWorld\f[R] could be compiled.
 .IP \[bu] 2
 Annotation processing is disabled, as if \f[V]-proc:none\f[R] is in
 effect.
@@ -266,45 +279,54 @@ the compilation.
 This sets both the source version accepted by compiler and the system
 API that may be used by the code in the source file.
 .IP \[bu] 2
-The source file is compiled in the context of an unnamed module.
+If a \f[V]module-info.java\f[R] file exists in the
+\f[V]\f[R] directory, its module declaration is used to
+define a named module that will contain all the classes compiled from
+\f[V].java\f[R] files in the source tree.
+If \f[V]module-info.java\f[R] does not exist, all the classes compiled
+from source files will be compiled in the context of the unnamed module.
 .IP \[bu] 2
-The source file should contain one or more top-level classes, the first
-of which is taken as the class to be executed.
+The source file that is launched should contain one or more top-level
+classes, the first of which is taken as the class to be executed.
 .IP \[bu] 2
-The compiler does not enforce the optional restriction defined at the
-end of JLS 7.6, that a type in a named package should exist in a file
-whose name is composed from the type name followed by the
-\f[V].java\f[R] extension.
+For the source file that is launched, the compiler does not enforce the
+optional restriction defined at the end of JLS 7.6, that a type in a
+named package should exist in a file whose name is composed from the
+type name followed by the \f[V].java\f[R] extension.
 .IP \[bu] 2
-If the source file contains errors, appropriate error messages are
-written to the standard error stream, and the launcher exits with a
-non-zero exit code.
+If a source file contains errors, appropriate error messages are written
+to the standard error stream, and the launcher exits with a non-zero
+exit code.
 .PP
 \f[B]In source-file mode, execution proceeds as follows:\f[R]
 .IP \[bu] 2
 The class to be executed is the first top-level class found in the
 source file.
-It must contain a declaration of the standard
-\f[V]public static void main(String[])\f[R] method.
+It must contain a declaration of an entry \f[V]main\f[R] method.
 .IP \[bu] 2
 The compiled classes are loaded by a custom class loader, that delegates
 to the application class loader.
 This implies that classes appearing on the application class path cannot
-refer to any classes declared in the source file.
-.IP \[bu] 2
-The compiled classes are executed in the context of an unnamed module,
-as though \f[V]--add-modules=ALL-DEFAULT\f[R] is in effect.
+refer to any classes declared in source files.
+.IP \[bu] 2
+If a \f[V]module-info.java\f[R] file exists in the
+\f[V]\f[R] directory, then all the classes compiled from
+\f[V].java\f[R] files in the source tree will be in that module, which
+will serve as the root module for the execution of the program.
+If \f[V]module-info.java\f[R] does not exist, the compiled classes are
+executed in the context of an unnamed module, as though
+\f[V]--add-modules=ALL-DEFAULT\f[R] is in effect.
 This is in addition to any other \f[V]--add-module\f[R] options that may
 be have been specified on the command line.
 .IP \[bu] 2
 Any arguments appearing after the name of the file on the command line
-are passed to the standard main method in the obvious way.
+are passed to the main method in the obvious way.
 .IP \[bu] 2
 It is an error if there is a class on the application class path whose
 name is the same as that of the class to be executed.
 .PP
-See \f[B]JEP 330: Launch Single-File Source-Code Programs\f[R]
-[https://openjdk.org/jeps/330] for complete details.
+See \f[B]JEP 458: Launch Multi-File Source-Code Programs\f[R]
+[https://openjdk.org/jeps/458] for complete details.
 .SH USING THE JDK_JAVA_OPTIONS LAUNCHER ENVIRONMENT VARIABLE
 .PP
 \f[V]JDK_JAVA_OPTIONS\f[R] prepends its content to the options parsed
@@ -1460,6 +1482,17 @@ usage by individual \f[V]CallSite\f[R], individual virtual memory region
 and its committed regions.
 .RE
 .TP
+\f[V]-XX:TrimNativeHeapInterval=\f[R]\f[I]millis\f[R]
+Interval, in ms, at which the JVM will trim the native heap.
+Lower values will reclaim memory more eagerly at the cost of higher
+overhead.
+A value of 0 (default) disables native heap trimming.
+Native heap trimming is performed in a dedicated thread.
+.RS
+.PP
+This option is only supported on Linux with GNU C Library (glibc).
+.RE
+.TP
 \f[V]-XX:+NeverActAsServerClassMachine\f[R]
 Enable the \[dq]Client VM emulation\[dq] mode which only uses the C1 JIT
 compiler, a 32Mb CodeCache and the Serial GC.
diff --git a/src/java.base/share/man/keytool.1 b/src/java.base/share/man/keytool.1
index 8a93ac50c0d..5dfe0d5889e 100644
--- a/src/java.base/share/man/keytool.1
+++ b/src/java.base/share/man/keytool.1
@@ -36,7 +36,7 @@
 . ftr VB CB
 . ftr VBI CBI
 .\}
-.TH "KEYTOOL" "1" "2024" "JDK 22-ea" "JDK Commands"
+.TH "KEYTOOL" "1" "2024" "JDK 22" "JDK Commands"
 .hy
 .SH NAME
 .PP
@@ -452,17 +452,32 @@ The certificate chain and private key are stored in a new keystore entry
 that is identified by its alias.
 .PP
 The \f[V]-keyalg\f[R] value specifies the algorithm to be used to
-generate the key pair, and the \f[V]-keysize\f[R] value specifies the
-size of each key to be generated.
-The \f[V]-sigalg\f[R] value specifies the algorithm that should be used
-to sign the certificate.
-This algorithm must be compatible with the \f[V]-keyalg\f[R] value.
-.PP
+generate the key pair.
+The \f[V]-keysize\f[R] value specifies the size of each key to be
+generated.
 The \f[V]-groupname\f[R] value specifies the named group (for example,
 the standard or predefined name of an Elliptic Curve) of the key to be
 generated.
+.PP
+When a \f[V]-keysize\f[R] value is provided, it will be used to
+initialize a \f[V]KeyPairGenerator\f[R] object using the
+\f[V]initialize(int keysize)\f[R] method.
+When a \f[V]-groupname\f[R] value is provided, it will be used to
+initialize a \f[V]KeyPairGenerator\f[R] object using the
+\f[V]initialize(AlgorithmParameterSpec params)\f[R] method where
+\f[V]params\f[R] is \f[V]new NamedParameterSpec(groupname)\f[R].
+.PP
 Only one of \f[V]-groupname\f[R] and \f[V]-keysize\f[R] can be
 specified.
+If an algorithm has multiple named groups that have the same key size,
+the \f[V]-groupname\f[R] option should usually be used.
+In this case, if \f[V]-keysize\f[R] is specified, it\[aq]s up to the
+security provider to determine which named group is chosen when
+generating a key pair.
+.PP
+The \f[V]-sigalg\f[R] value specifies the algorithm that should be used
+to sign the certificate.
+This algorithm must be compatible with the \f[V]-keyalg\f[R] value.
 .PP
 The \f[V]-signer\f[R] value specifies the alias of a
 \f[V]PrivateKeyEntry\f[R] for the signer that already exists in the
@@ -1570,10 +1585,13 @@ The following examples show the defaults for various option values:
     2048 (when using -genkeypair and -keyalg is \[dq]DSA\[dq])
     3072 (when using -genkeypair and -keyalg is \[dq]RSA\[dq], \[dq]RSASSA-PSS\[dq], or \[dq]DH\[dq])
     384 (when using -genkeypair and -keyalg is \[dq]EC\[dq])
-    255 (when using -genkeypair and -keyalg is \[dq]EdDSA\[dq], or \[dq]XDH)
     56 (when using -genseckey and -keyalg is \[dq]DES\[dq])
     168 (when using -genseckey and -keyalg is \[dq]DESede\[dq])
 
+-groupname
+    ed25519 (when using -genkeypair and -keyalg is \[dq]EdDSA\[dq], key size is 255)
+    x25519 (when using -genkeypair and -keyalg is \[dq]XDH\[dq], key size is 255)
+
 -validity 90
 
 -keystore 
@@ -1604,7 +1622,7 @@ l l l.
 T{
 keyalg
 T}@T{
-keysize
+key size
 T}@T{
 default sigalg
 T}
@@ -1621,7 +1639,7 @@ RSA
 T}@T{
 < 624
 T}@T{
-SHA256withRSA (keysize is too small for using SHA-384)
+SHA256withRSA (key size is too small for using SHA-384)
 T}
 T{
 T}@T{
@@ -1653,7 +1671,7 @@ RSASSA-PSS
 T}@T{
 < 624
 T}@T{
-RSASSA-PSS (with SHA-256, keysize is too small for
+RSASSA-PSS (with SHA-256, key size is too small for
 T}
 T{
 T}@T{
@@ -1701,28 +1719,29 @@ Ed448
 T}
 .TE
 .IP \[bu] 2
+The key size, measured in bits, corresponds to the size of the private
+key.
+This size is determined by the value of the \f[V]-keysize\f[R] or
+\f[V]-groupname\f[R] options or the value derived from a default
+setting.
+.IP \[bu] 2
 An RSASSA-PSS signature algorithm uses a \f[V]MessageDigest\f[R]
 algorithm as its hash and MGF1 algorithms.
 .IP \[bu] 2
-EdDSA supports 2 key sizes: Ed25519 and Ed448.
-When generating an EdDSA key pair using \f[V]-keyalg EdDSA\f[R], a user
-can specify \f[V]-keysize 255\f[R] or \f[V]-keysize 448\f[R] to generate
-Ed25519 or Ed448 key pairs.
-When no \f[V]-keysize\f[R] is specified, an Ed25519 key pair is
-generated.
-A user can also directly specify \f[V]-keyalg Ed25519\f[R] or
-\f[V]-keyalg Ed448\f[R] to generate a key pair with the expected key
-size.
+If neither a default \f[V]-keysize\f[R] or \f[V]-groupname\f[R] is
+defined for an algorithm, the security provider will choose a default
+setting.
 .PP
 \f[B]Note:\f[R]
 .PP
-To improve out of the box security, default key size and signature
-algorithm names are periodically updated to stronger values with each
-release of the JDK.
+To improve out of the box security, default keysize, groupname, and
+signature algorithm names are periodically updated to stronger values
+with each release of the JDK.
 If interoperability with older releases of the JDK is important, make
 sure that the defaults are supported by those releases.
-Alternatively, you can use the \f[V]-keysize\f[R] or \f[V]-sigalg\f[R]
-options to override the default values at your own risk.
+Alternatively, you can use the \f[V]-keysize\f[R], \f[V]-groupname\f[R],
+or \f[V]-sigalg\f[R] options to override the default values at your own
+risk.
 .SH SUPPORTED NAMED EXTENSIONS
 .PP
 The \f[V]keytool\f[R] command supports these named extensions.
diff --git a/src/java.base/share/native/libjava/VirtualThread.c b/src/java.base/share/native/libjava/VirtualThread.c
index a0b3e082087..94dbe0b7e37 100644
--- a/src/java.base/share/native/libjava/VirtualThread.c
+++ b/src/java.base/share/native/libjava/VirtualThread.c
@@ -32,11 +32,12 @@
 #define VIRTUAL_THREAD  "Ljava/lang/VirtualThread;"
 
 static JNINativeMethod methods[] = {
-    { "notifyJvmtiStart",        "()V",  (void *)&JVM_VirtualThreadStart },
-    { "notifyJvmtiEnd",          "()V",  (void *)&JVM_VirtualThreadEnd },
-    { "notifyJvmtiMount",        "(Z)V", (void *)&JVM_VirtualThreadMount },
-    { "notifyJvmtiUnmount",      "(Z)V", (void *)&JVM_VirtualThreadUnmount },
-    { "notifyJvmtiHideFrames",   "(Z)V", (void *)&JVM_VirtualThreadHideFrames },
+    { "notifyJvmtiStart",          "()V",  (void *)&JVM_VirtualThreadStart },
+    { "notifyJvmtiEnd",            "()V",  (void *)&JVM_VirtualThreadEnd },
+    { "notifyJvmtiMount",          "(Z)V", (void *)&JVM_VirtualThreadMount },
+    { "notifyJvmtiUnmount",        "(Z)V", (void *)&JVM_VirtualThreadUnmount },
+    { "notifyJvmtiHideFrames",     "(Z)V", (void *)&JVM_VirtualThreadHideFrames },
+    { "notifyJvmtiDisableSuspend", "(Z)V", (void *)&JVM_VirtualThreadDisableSuspend },
 };
 
 JNIEXPORT void JNICALL
diff --git a/src/java.base/share/native/libverify/check_code.c b/src/java.base/share/native/libverify/check_code.c
index a0c427a7e4b..d1ebd3d5b94 100644
--- a/src/java.base/share/native/libverify/check_code.c
+++ b/src/java.base/share/native/libverify/check_code.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1994, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1994, 2023, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -81,6 +81,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #include "jni.h"
 #include "jni_util.h"
@@ -1195,7 +1196,7 @@ verify_opcode_operands(context_type *context, unsigned int inumber, int offset)
             }
         }
         if (opcode == JVM_OPC_tableswitch) {
-            keys = _ck_ntohl(lpc[2]) -  _ck_ntohl(lpc[1]) + 1;
+            keys = _ck_ntohl(lpc[2]) - _ck_ntohl(lpc[1]) + 1;
             delta = 1;
         } else {
             keys = _ck_ntohl(lpc[1]); /* number of pairs */
@@ -1677,11 +1678,14 @@ static int instruction_length(unsigned char *iptr, unsigned char *end)
     switch (instruction) {
         case JVM_OPC_tableswitch: {
             int *lpc = (int *)UCALIGN(iptr + 1);
-            int index;
+            int64_t low, high, index;
             if (lpc + 2 >= (int *)end) {
                 return -1; /* do not read pass the end */
             }
-            index = _ck_ntohl(lpc[2]) - _ck_ntohl(lpc[1]);
+            low  = _ck_ntohl(lpc[1]);
+            high = _ck_ntohl(lpc[2]);
+            index = high - low;
+            // The value of low must be less than or equal to high - i.e. index >= 0
             if ((index < 0) || (index > 65535)) {
                 return -1;      /* illegal */
             } else {
diff --git a/src/java.desktop/share/legal/lcms.md b/src/java.desktop/share/legal/lcms.md
index da86a9c47ca..02af4fff000 100644
--- a/src/java.desktop/share/legal/lcms.md
+++ b/src/java.desktop/share/legal/lcms.md
@@ -1,34 +1,29 @@
-## Little Color Management System (LCMS) v2.15
+## Little Color Management System (LCMS) v2.16
 
 ### LCMS License
 
-README.1ST file information
 
-LittleCMS core is released under MIT License
+MIT License
 
----------------------------------
-
-Little CMS
-Copyright (c) 1998-2023 Marti Maria Saguer
+Copyright (C) 1998-2023 Marti Maria Saguer
 
 Permission is hereby granted, free of charge, to any person obtaining
-a copy of this software and associated documentation files (the
-"Software"), to deal in the Software without restriction, including
-without limitation the rights to use, copy, modify, merge, publish,
-distribute, sublicense, and/or sell copies of the Software, and to
-permit persons to whom the Software is furnished to do so, subject
-to the following conditions:
+a copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the Software
+is furnished to do so, subject to the following conditions:
 
-The above copyright notice and this permission notice shall be
-included in all copies or substantial portions of the Software.
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
 
 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
-CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
-TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
 ---------------------------------
 The below license applies to the following files:
@@ -47,7 +42,6 @@ Users of this code must verify correctness for their application.
 ### AUTHORS File Information
 ```
 
-
 Main Author
 ------------
 Marti Maria
@@ -91,6 +85,7 @@ Philipp Knechtges
 Amyspark
 Lovell Fuller
 Eli Schwartz
+Diogo Teles Sant'Anna
 
 Special Thanks
 --------------
diff --git a/src/java.desktop/share/native/liblcms/LCMS.c b/src/java.desktop/share/native/liblcms/LCMS.c
index 1295d6df356..5cf7ee6c436 100644
--- a/src/java.desktop/share/native/liblcms/LCMS.c
+++ b/src/java.desktop/share/native/liblcms/LCMS.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2024, 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
@@ -177,8 +177,13 @@ JNIEXPORT jlong JNICALL Java_sun_java2d_cmm_lcms_LCMS_createNativeTransform
         }
     }
 
+    cmsUInt32Number dwFlags = 0;
+    if (T_EXTRA(inFormatter) > 0 && T_EXTRA(outFormatter) > 0) {
+        dwFlags |= cmsFLAGS_COPY_ALPHA;
+    }
+
     sTrans = cmsCreateMultiprofileTransform(iccArray, j,
-        inFormatter, outFormatter, renderingIntent, cmsFLAGS_COPY_ALPHA);
+        inFormatter, outFormatter, renderingIntent, dwFlags);
 
     (*env)->ReleaseLongArrayElements(env, profileIDs, ids, 0);
 
diff --git a/src/java.desktop/share/native/liblcms/cmsalpha.c b/src/java.desktop/share/native/liblcms/cmsalpha.c
index e69259e8a51..78d3ca6b671 100644
--- a/src/java.desktop/share/native/liblcms/cmsalpha.c
+++ b/src/java.desktop/share/native/liblcms/cmsalpha.c
@@ -431,7 +431,7 @@ static cmsFormatterAlphaFn FormattersAlpha[6][6] = {
 
 // This function computes the distance from each component to the next one in bytes.
 static
-void ComputeIncrementsForChunky(cmsUInt32Number Format,
+cmsBool ComputeIncrementsForChunky(cmsUInt32Number Format,
                                 cmsUInt32Number ComponentStartingOrder[],
                                 cmsUInt32Number ComponentPointerIncrements[])
 {
@@ -445,7 +445,7 @@ void ComputeIncrementsForChunky(cmsUInt32Number Format,
 
        // Sanity check
        if (total_chans <= 0 || total_chans >= cmsMAXCHANNELS)
-           return;
+           return FALSE;
 
         memset(channels, 0, sizeof(channels));
 
@@ -482,13 +482,15 @@ void ComputeIncrementsForChunky(cmsUInt32Number Format,
 
        for (i = 0; i < extra; i++)
               ComponentStartingOrder[i] = channels[i + nchannels];
+
+       return TRUE;
 }
 
 
 
 //  On planar configurations, the distance is the stride added to any non-negative
 static
-void ComputeIncrementsForPlanar(cmsUInt32Number Format,
+cmsBool ComputeIncrementsForPlanar(cmsUInt32Number Format,
                                 cmsUInt32Number BytesPerPlane,
                                 cmsUInt32Number ComponentStartingOrder[],
                                 cmsUInt32Number ComponentPointerIncrements[])
@@ -502,7 +504,7 @@ void ComputeIncrementsForPlanar(cmsUInt32Number Format,
 
        // Sanity check
        if (total_chans <= 0 || total_chans >= cmsMAXCHANNELS)
-           return;
+           return FALSE;
 
        memset(channels, 0, sizeof(channels));
 
@@ -538,29 +540,29 @@ void ComputeIncrementsForPlanar(cmsUInt32Number Format,
 
        for (i = 0; i < extra; i++)
               ComponentStartingOrder[i] = channels[i + nchannels];
+
+       return TRUE;
 }
 
 
 
 // Dispatcher por chunky and planar RGB
 static
-void  ComputeComponentIncrements(cmsUInt32Number Format,
+cmsBool ComputeComponentIncrements(cmsUInt32Number Format,
                                  cmsUInt32Number BytesPerPlane,
                                  cmsUInt32Number ComponentStartingOrder[],
                                  cmsUInt32Number ComponentPointerIncrements[])
 {
        if (T_PLANAR(Format)) {
 
-              ComputeIncrementsForPlanar(Format,  BytesPerPlane, ComponentStartingOrder, ComponentPointerIncrements);
+              return ComputeIncrementsForPlanar(Format,  BytesPerPlane, ComponentStartingOrder, ComponentPointerIncrements);
        }
        else {
-              ComputeIncrementsForChunky(Format,  ComponentStartingOrder, ComponentPointerIncrements);
+              return ComputeIncrementsForChunky(Format,  ComponentStartingOrder, ComponentPointerIncrements);
        }
 
 }
 
-
-
 // Handles extra channels copying alpha if requested by the flags
 void _cmsHandleExtraChannels(_cmsTRANSFORM* p, const void* in,
                                                void* out,
@@ -595,8 +597,10 @@ void _cmsHandleExtraChannels(_cmsTRANSFORM* p, const void* in,
         return;
 
     // Compute the increments
-    ComputeComponentIncrements(p->InputFormat, Stride->BytesPerPlaneIn, SourceStartingOrder, SourceIncrements);
-    ComputeComponentIncrements(p->OutputFormat, Stride->BytesPerPlaneOut, DestStartingOrder, DestIncrements);
+    if (!ComputeComponentIncrements(p->InputFormat, Stride->BytesPerPlaneIn, SourceStartingOrder, SourceIncrements))
+        return;
+    if (!ComputeComponentIncrements(p->OutputFormat, Stride->BytesPerPlaneOut, DestStartingOrder, DestIncrements))
+        return;
 
     // Check for conversions 8, 16, half, float, dbl
     copyValueFn = _cmsGetFormatterAlpha(p->ContextID, p->InputFormat, p->OutputFormat);
diff --git a/src/java.desktop/share/native/liblcms/cmscgats.c b/src/java.desktop/share/native/liblcms/cmscgats.c
index 9d0aea27d73..57725ae4731 100644
--- a/src/java.desktop/share/native/liblcms/cmscgats.c
+++ b/src/java.desktop/share/native/liblcms/cmscgats.c
@@ -87,7 +87,7 @@ typedef enum {
         SEOF,       // End of stream
         SSYNERROR,  // Syntax error found on stream
 
-        // Keywords
+        // IT8 symbols
 
         SBEGIN_DATA,
         SBEGIN_DATA_FORMAT,
@@ -95,7 +95,19 @@ typedef enum {
         SEND_DATA_FORMAT,
         SKEYWORD,
         SDATA_FORMAT_ID,
-        SINCLUDE
+        SINCLUDE,
+
+        // Cube symbols
+
+        SDOMAIN_MAX,
+        SDOMAIN_MIN,
+        S_LUT1D_SIZE,
+        S_LUT1D_INPUT_RANGE,
+        S_LUT3D_SIZE,
+        S_LUT3D_INPUT_RANGE,
+        S_LUT_IN_VIDEO_RANGE,
+        S_LUT_OUT_VIDEO_RANGE,
+        STITLE
 
     } SYMBOL;
 
@@ -178,6 +190,10 @@ typedef struct struct_it8 {
         cmsUInt32Number  TablesCount;                     // How many tables in this stream
         cmsUInt32Number  nTable;                          // The actual table
 
+        // Partser type
+        cmsBool        IsCUBE;
+
+        // Tables
         TABLE Tab[MAXTABLES];
 
         // Memory management
@@ -237,8 +253,8 @@ typedef struct {
 
    } KEYWORD;
 
-// The keyword->symbol translation table. Sorting is required.
-static const KEYWORD TabKeys[] = {
+// The keyword->symbol translation tables. Sorting is required.
+static const KEYWORD TabKeysIT8[] = {
 
         {"$INCLUDE",               SINCLUDE},   // This is an extension!
         {".INCLUDE",               SINCLUDE},   // This is an extension!
@@ -251,7 +267,25 @@ static const KEYWORD TabKeys[] = {
         {"KEYWORD",                SKEYWORD}
         };
 
-#define NUMKEYS (sizeof(TabKeys)/sizeof(KEYWORD))
+#define NUMKEYS_IT8 (sizeof(TabKeysIT8)/sizeof(KEYWORD))
+
+static const KEYWORD TabKeysCUBE[] = {
+
+        {"DOMAIN_MAX",             SDOMAIN_MAX },
+        {"DOMAIN_MIN",             SDOMAIN_MIN },
+        {"LUT_1D_SIZE",            S_LUT1D_SIZE },
+        {"LUT_1D_INPUT_RANGE",     S_LUT1D_INPUT_RANGE },
+        {"LUT_3D_SIZE",            S_LUT3D_SIZE },
+        {"LUT_3D_INPUT_RANGE",     S_LUT3D_INPUT_RANGE },
+        {"LUT_IN_VIDEO_RANGE",     S_LUT_IN_VIDEO_RANGE },
+        {"LUT_OUT_VIDEO_RANGE",    S_LUT_OUT_VIDEO_RANGE },
+        {"TITLE",                  STITLE }
+
+};
+
+#define NUMKEYS_CUBE (sizeof(TabKeysCUBE)/sizeof(KEYWORD))
+
+
 
 // Predefined properties
 
@@ -455,7 +489,7 @@ void StringCat(string* s, const char* c)
 static
 cmsBool isseparator(int c)
 {
-    return (c == ' ') || (c == '\t') ;
+    return (c == ' ') || (c == '\t');
 }
 
 // Checks whatever c is a valid identifier char
@@ -476,7 +510,7 @@ cmsBool isidchar(int c)
 static
 cmsBool isfirstidchar(int c)
 {
-     return !isdigit(c) && ismiddle(c);
+     return c != '-' && !isdigit(c) && ismiddle(c);
 }
 
 // Guess whether the supplied path looks like an absolute path
@@ -515,13 +549,13 @@ cmsBool BuildAbsolutePath(const char *relPath, const char *basePath, char *buffe
     // Already absolute?
     if (isabsolutepath(relPath)) {
 
-        strncpy(buffer, relPath, MaxLen);
+        memcpy(buffer, relPath, MaxLen);
         buffer[MaxLen-1] = 0;
         return TRUE;
     }
 
     // No, search for last
-    strncpy(buffer, basePath, MaxLen);
+    memcpy(buffer, basePath, MaxLen);
     buffer[MaxLen-1] = 0;
 
     tail = strrchr(buffer, DIR_CHAR);
@@ -603,10 +637,10 @@ void NextCh(cmsIT8* it8)
 
 // Try to see if current identifier is a keyword, if so return the referred symbol
 static
-SYMBOL BinSrchKey(const char *id)
+SYMBOL BinSrchKey(const char *id, int NumKeys, const KEYWORD* TabKeys)
 {
     int l = 1;
-    int r = NUMKEYS;
+    int r = NumKeys;
     int x, res;
 
     while (r >= l)
@@ -776,7 +810,7 @@ cmsFloat64Number ParseFloatNumber(const char *Buffer)
 }
 
 
-// Reads a string, special case to avoid infinite resursion on .include
+// Reads a string, special case to avoid infinite recursion on .include
 static
 void InStringSymbol(cmsIT8* it8)
 {
@@ -833,7 +867,9 @@ void InSymbol(cmsIT8* it8)
             } while (isidchar(it8->ch));
 
 
-            key = BinSrchKey(StringPtr(it8->id));
+            key = BinSrchKey(StringPtr(it8->id),
+                    it8->IsCUBE ? NUMKEYS_CUBE : NUMKEYS_IT8,
+                    it8->IsCUBE ? TabKeysCUBE : TabKeysIT8);
             if (key == SUNDEFINED) it8->sy = SIDENT;
             else it8->sy = key;
 
@@ -942,6 +978,7 @@ void InSymbol(cmsIT8* it8)
                         snprintf(buffer, sizeof(buffer), it8 ->DoubleFormatter, it8->dnum);
                     }
 
+                    StringClear(it8->id);
                     StringCat(it8->id, buffer);
 
                     do {
@@ -971,7 +1008,7 @@ void InSymbol(cmsIT8* it8)
         // Next line
         case '\r':
             NextCh(it8);
-            if (it8 ->ch == '\n')
+            if (it8->ch == '\n')
                 NextCh(it8);
             it8->sy = SEOLN;
             it8->lineno++;
@@ -1292,7 +1329,12 @@ KEYVALUE* AddToList(cmsIT8* it8, KEYVALUE** Head, const char *Key, const char *S
 
         // This may work for editing properties
 
-        //     return SynError(it8, "duplicate key <%s>", Key);
+        if (cmsstrcasecmp(Key, "NUMBER_OF_FIELDS") == 0 ||
+            cmsstrcasecmp(Key, "NUMBER_OF_SETS") == 0) {
+
+            SynError(it8, "duplicate key <%s>", Key);
+            return NULL;
+        }
     }
     else {
 
@@ -1413,6 +1455,8 @@ cmsHANDLE  CMSEXPORT cmsIT8Alloc(cmsContext ContextID)
     it8->MemoryBlock = NULL;
     it8->MemorySink  = NULL;
 
+    it8->IsCUBE = FALSE;
+
     it8 ->nTable = 0;
 
     it8->ContextID = ContextID;
@@ -1694,7 +1738,7 @@ char* GetData(cmsIT8* it8, int nSet, int nField)
     int nSamples    = t -> nSamples;
     int nPatches    = t -> nPatches;
 
-    if (nSet >= nPatches || nField >= nSamples)
+    if (nSet < 0 || nSet >= nPatches || nField < 0 || nField >= nSamples)
         return NULL;
 
     if (!t->Data) return NULL;
@@ -1879,11 +1923,14 @@ void WriteDataFormat(SAVESTREAM* fp, cmsIT8* it8)
        WriteStr(fp, " ");
        nSamples = satoi(cmsIT8GetProperty(it8, "NUMBER_OF_FIELDS"));
 
-       for (i = 0; i < nSamples; i++) {
+       if (nSamples <= t->nSamples) {
 
-              WriteStr(fp, t->DataFormat[i]);
-              WriteStr(fp, ((i == (nSamples-1)) ? "\n" : "\t"));
-          }
+           for (i = 0; i < nSamples; i++) {
+
+               WriteStr(fp, t->DataFormat[i]);
+               WriteStr(fp, ((i == (nSamples - 1)) ? "\n" : "\t"));
+           }
+       }
 
        WriteStr (fp, "END_DATA_FORMAT\n");
 }
@@ -1893,39 +1940,42 @@ void WriteDataFormat(SAVESTREAM* fp, cmsIT8* it8)
 static
 void WriteData(SAVESTREAM* fp, cmsIT8* it8)
 {
-       int  i, j;
+       int  i, j, nPatches;
        TABLE* t = GetTable(it8);
 
        if (!t->Data) return;
 
        WriteStr (fp, "BEGIN_DATA\n");
 
-       t->nPatches = satoi(cmsIT8GetProperty(it8, "NUMBER_OF_SETS"));
+       nPatches = satoi(cmsIT8GetProperty(it8, "NUMBER_OF_SETS"));
 
-       for (i = 0; i < t-> nPatches; i++) {
+       if (nPatches <= t->nPatches) {
 
-              WriteStr(fp, " ");
+           for (i = 0; i < nPatches; i++) {
 
-              for (j = 0; j < t->nSamples; j++) {
+               WriteStr(fp, " ");
 
-                     char *ptr = t->Data[i*t->nSamples+j];
+               for (j = 0; j < t->nSamples; j++) {
 
-                     if (ptr == NULL) WriteStr(fp, "\"\"");
-                     else {
-                         // If value contains whitespace, enclose within quote
+                   char* ptr = t->Data[i * t->nSamples + j];
 
-                         if (strchr(ptr, ' ') != NULL) {
+                   if (ptr == NULL) WriteStr(fp, "\"\"");
+                   else {
+                       // If value contains whitespace, enclose within quote
 
-                             WriteStr(fp, "\"");
-                             WriteStr(fp, ptr);
-                             WriteStr(fp, "\"");
-                         }
-                         else
-                            WriteStr(fp, ptr);
-                     }
+                       if (strchr(ptr, ' ') != NULL) {
 
-                     WriteStr(fp, ((j == (t->nSamples-1)) ? "\n" : "\t"));
-              }
+                           WriteStr(fp, "\"");
+                           WriteStr(fp, ptr);
+                           WriteStr(fp, "\"");
+                       }
+                       else
+                           WriteStr(fp, ptr);
+                   }
+
+                   WriteStr(fp, ((j == (t->nSamples - 1)) ? "\n" : "\t"));
+               }
+           }
        }
        WriteStr (fp, "END_DATA\n");
 }
@@ -1946,15 +1996,29 @@ cmsBool CMSEXPORT cmsIT8SaveToFile(cmsHANDLE hIT8, const char* cFileName)
 
     for (i=0; i < it8 ->TablesCount; i++) {
 
-            cmsIT8SetTable(hIT8, i);
-            WriteHeader(it8, &sd);
-            WriteDataFormat(&sd, it8);
-            WriteData(&sd, it8);
+        TABLE* t;
+
+        if (cmsIT8SetTable(hIT8, i) < 0) goto Error;
+
+        /**
+        * Check for wrong data
+        */
+        t = GetTable(it8);
+        if (t->Data == NULL) goto Error;
+        if (t->DataFormat == NULL) goto Error;
+
+        WriteHeader(it8, &sd);
+        WriteDataFormat(&sd, it8);
+        WriteData(&sd, it8);
     }
 
     if (fclose(sd.stream) != 0) return FALSE;
-
     return TRUE;
+
+Error:
+    fclose(sd.stream);
+    return FALSE;
+
 }
 
 
@@ -2331,78 +2395,72 @@ void CookPointers(cmsIT8* it8)
     int idField, i;
     char* Fld;
     cmsUInt32Number j;
-    cmsUInt32Number nOldTable = it8 ->nTable;
+    cmsUInt32Number nOldTable = it8->nTable;
 
-    for (j=0; j < it8 ->TablesCount; j++) {
+    for (j = 0; j < it8->TablesCount; j++) {
 
-    TABLE* t = it8 ->Tab + j;
+        TABLE* t = it8->Tab + j;
 
-    t -> SampleID = 0;
-    it8 ->nTable = j;
+        t->SampleID = 0;
+        it8->nTable = j;
 
-    for (idField = 0; idField < t -> nSamples; idField++)
-    {
-        if (t ->DataFormat == NULL){
-            SynError(it8, "Undefined DATA_FORMAT");
-            return;
-        }
+        for (idField = 0; idField < t->nSamples; idField++)
+        {
+            if (t->DataFormat == NULL) {
+                SynError(it8, "Undefined DATA_FORMAT");
+                return;
+            }
 
-        Fld = t->DataFormat[idField];
-        if (!Fld) continue;
+            Fld = t->DataFormat[idField];
+            if (!Fld) continue;
 
 
-        if (cmsstrcasecmp(Fld, "SAMPLE_ID") == 0) {
+            if (cmsstrcasecmp(Fld, "SAMPLE_ID") == 0) {
 
-            t -> SampleID = idField;
-        }
+                t->SampleID = idField;
+            }
 
-        // "LABEL" is an extension. It keeps references to forward tables
+            // "LABEL" is an extension. It keeps references to forward tables
 
-        if ((cmsstrcasecmp(Fld, "LABEL") == 0) || Fld[0] == '$') {
+            if ((cmsstrcasecmp(Fld, "LABEL") == 0) || Fld[0] == '$') {
 
-            // Search for table references...
-            for (i = 0; i < t->nPatches; i++) {
+                // Search for table references...
+                for (i = 0; i < t->nPatches; i++) {
 
-                char* Label = GetData(it8, i, idField);
+                    char* Label = GetData(it8, i, idField);
 
-                if (Label) {
+                    if (Label) {
 
-                    cmsUInt32Number k;
+                        cmsUInt32Number k;
 
-                    // This is the label, search for a table containing
-                    // this property
+                        // This is the label, search for a table containing
+                        // this property
 
-                    for (k = 0; k < it8->TablesCount; k++) {
+                        for (k = 0; k < it8->TablesCount; k++) {
 
-                        TABLE* Table = it8->Tab + k;
-                        KEYVALUE* p;
+                            TABLE* Table = it8->Tab + k;
+                            KEYVALUE* p;
 
-                        if (IsAvailableOnList(Table->HeaderList, Label, NULL, &p)) {
+                            if (IsAvailableOnList(Table->HeaderList, Label, NULL, &p)) {
 
-                            // Available, keep type and table
-                            char Buffer[256];
+                                // Available, keep type and table
+                                char Buffer[256];
 
-                            char* Type = p->Value;
-                            int  nTable = (int)k;
+                                char* Type = p->Value;
+                                int  nTable = (int)k;
 
-                            snprintf(Buffer, 255, "%s %d %s", Label, nTable, Type);
+                                snprintf(Buffer, 255, "%s %d %s", Label, nTable, Type);
 
-                            SetData(it8, i, idField, Buffer);
+                                SetData(it8, i, idField, Buffer);
+                            }
                         }
                     }
-
-
                 }
-
             }
-
-
         }
-
-    }
     }
 
-    it8 ->nTable = nOldTable;
+    it8->nTable = nOldTable;
 }
 
 // Try to infere if the file is a CGATS/IT8 file at all. Read first line
@@ -2493,7 +2551,7 @@ cmsHANDLE  CMSEXPORT cmsIT8LoadFromMem(cmsContext ContextID, const void *Ptr, cm
     if (it8->MemoryBlock == NULL)
     {
         cmsIT8Free(hIT8);
-        return FALSE;
+        return NULL;
     }
 
     strncpy(it8 ->MemoryBlock, (const char*) Ptr, len);
@@ -2505,7 +2563,7 @@ cmsHANDLE  CMSEXPORT cmsIT8LoadFromMem(cmsContext ContextID, const void *Ptr, cm
     if (!ParseIT8(it8, type-1)) {
 
         cmsIT8Free(hIT8);
-        return FALSE;
+        return NULL;
     }
 
     CookPointers(it8);
@@ -2602,17 +2660,17 @@ cmsUInt32Number CMSEXPORT cmsIT8EnumProperties(cmsHANDLE hIT8, char ***PropertyN
     }
 
 
-        Props = (char**)AllocChunk(it8, sizeof(char*) * n);
-        if (Props != NULL) {
-
-                // Pass#2 - Fill pointers
-                n = 0;
-                for (p = t->HeaderList; p != NULL; p = p->Next) {
-                        Props[n++] = p->Keyword;
-                }
+    Props = (char**)AllocChunk(it8, sizeof(char*) * n);
+    if (Props != NULL) {
 
+        // Pass#2 - Fill pointers
+        n = 0;
+        for (p = t->HeaderList; p != NULL; p = p->Next) {
+            Props[n++] = p->Keyword;
         }
-        *PropertyNames = Props;
+
+    }
+    *PropertyNames = Props;
 
     return n;
 }
@@ -2972,3 +3030,236 @@ void CMSEXPORT cmsIT8DefineDblFormat(cmsHANDLE hIT8, const char* Formatter)
     it8 ->DoubleFormatter[sizeof(it8 ->DoubleFormatter)-1] = 0;
 }
 
+
+static
+cmsBool ReadNumbers(cmsIT8* cube, int n, cmsFloat64Number* arr)
+{
+    int i;
+
+    for (i = 0; i < n; i++) {
+
+        if (cube->sy == SINUM)
+            arr[i] = cube->inum;
+        else
+            if (cube->sy == SDNUM)
+                arr[i] = cube->dnum;
+            else
+                return SynError(cube, "Number expected");
+
+        InSymbol(cube);
+    }
+
+    return CheckEOLN(cube);
+}
+
+static
+cmsBool ParseCube(cmsIT8* cube, cmsStage** Shaper, cmsStage** CLUT, char title[])
+{
+    cmsFloat64Number domain_min[3] = { 0, 0, 0 };
+    cmsFloat64Number domain_max[3] = { 1.0, 1.0, 1.0 };
+    cmsFloat64Number check_0_1[2] = { 0, 1.0 };
+    int shaper_size = 0;
+    int lut_size = 0;
+    int i;
+
+    InSymbol(cube);
+
+    while (cube->sy != SEOF) {
+        switch (cube->sy)
+        {
+        // Set profile description
+        case STITLE:
+            InSymbol(cube);
+            if (!Check(cube, SSTRING, "Title string expected")) return FALSE;
+            memcpy(title, StringPtr(cube->str), MAXSTR);
+            title[MAXSTR - 1] = 0;
+            InSymbol(cube);
+            break;
+
+        // Define domain
+        case SDOMAIN_MIN:
+            InSymbol(cube);
+            if (!ReadNumbers(cube, 3, domain_min)) return FALSE;
+            break;
+
+        case SDOMAIN_MAX:
+            InSymbol(cube);
+            if (!ReadNumbers(cube, 3, domain_max)) return FALSE;
+            break;
+
+        // Define shaper
+        case S_LUT1D_SIZE:
+            InSymbol(cube);
+            if (!Check(cube, SINUM, "Shaper size expected")) return FALSE;
+            shaper_size = cube->inum;
+            InSymbol(cube);
+            break;
+
+        // Deefine CLUT
+        case S_LUT3D_SIZE:
+            InSymbol(cube);
+            if (!Check(cube, SINUM, "LUT size expected")) return FALSE;
+            lut_size = cube->inum;
+            InSymbol(cube);
+            break;
+
+        // Range. If present, has to be 0..1.0
+        case S_LUT1D_INPUT_RANGE:
+        case S_LUT3D_INPUT_RANGE:
+            InSymbol(cube);
+            if (!ReadNumbers(cube, 2, check_0_1)) return FALSE;
+            if (check_0_1[0] != 0 || check_0_1[1] != 1.0) {
+                return SynError(cube, "Unsupported format");
+            }
+            break;
+
+        case SEOLN:
+            InSymbol(cube);
+            break;
+
+        default:
+        case S_LUT_IN_VIDEO_RANGE:
+        case S_LUT_OUT_VIDEO_RANGE:
+            return SynError(cube, "Unsupported format");
+
+            // Read and create tables
+        case SINUM:
+        case SDNUM:
+
+            if (shaper_size > 0) {
+
+                cmsToneCurve* curves[3];
+                cmsFloat32Number* shapers = (cmsFloat32Number*)_cmsMalloc(cube->ContextID, 3 * shaper_size * sizeof(cmsFloat32Number));
+                if (shapers == NULL) return FALSE;
+
+                for (i = 0; i < shaper_size; i++) {
+
+                    cmsFloat64Number nums[3];
+
+                    if (!ReadNumbers(cube, 3, nums)) return FALSE;
+
+                    shapers[i + 0]               = (cmsFloat32Number) ((nums[0] - domain_min[0]) / (domain_max[0] - domain_min[0]));
+                    shapers[i + 1 * shaper_size] = (cmsFloat32Number) ((nums[1] - domain_min[1]) / (domain_max[1] - domain_min[1]));
+                    shapers[i + 2 * shaper_size] = (cmsFloat32Number) ((nums[2] - domain_min[2]) / (domain_max[2] - domain_min[2]));
+                }
+
+                for (i = 0; i < 3; i++) {
+
+                    curves[i] = cmsBuildTabulatedToneCurveFloat(cube->ContextID, shaper_size,
+                        &shapers[i * shaper_size]);
+                    if (curves[i] == NULL) return FALSE;
+                }
+
+                *Shaper = cmsStageAllocToneCurves(cube->ContextID, 3, curves);
+
+                cmsFreeToneCurveTriple(curves);
+            }
+
+            if (lut_size > 0) {
+
+                int nodes = lut_size * lut_size * lut_size;
+
+                cmsFloat32Number* lut_table = _cmsMalloc(cube->ContextID, nodes * 3 * sizeof(cmsFloat32Number));
+                if (lut_table == NULL) return FALSE;
+
+                for (i = 0; i < nodes; i++) {
+
+                    cmsFloat64Number nums[3];
+
+                    if (!ReadNumbers(cube, 3, nums)) return FALSE;
+
+                    lut_table[i * 3 + 2] = (cmsFloat32Number) ((nums[0] - domain_min[0]) / (domain_max[0] - domain_min[0]));
+                    lut_table[i * 3 + 1] = (cmsFloat32Number) ((nums[1] - domain_min[1]) / (domain_max[1] - domain_min[1]));
+                    lut_table[i * 3 + 0] = (cmsFloat32Number) ((nums[2] - domain_min[2]) / (domain_max[2] - domain_min[2]));
+                }
+
+                *CLUT = cmsStageAllocCLutFloat(cube->ContextID, lut_size, 3, 3, lut_table);
+                _cmsFree(cube->ContextID, lut_table);
+            }
+
+            if (!Check(cube, SEOF, "Extra symbols found in file")) return FALSE;
+        }
+    }
+
+    return TRUE;
+}
+
+// Share the parser to read .cube format and create RGB devicelink profiles
+cmsHPROFILE CMSEXPORT cmsCreateDeviceLinkFromCubeFileTHR(cmsContext ContextID, const char* cFileName)
+{
+    cmsHPROFILE hProfile = NULL;
+    cmsIT8* cube = NULL;
+    cmsPipeline* Pipeline = NULL;
+    cmsStage* CLUT = NULL;
+    cmsStage* Shaper = NULL;
+    cmsMLU* DescriptionMLU = NULL;
+    char title[MAXSTR];
+
+    _cmsAssert(cFileName != NULL);
+
+    cube = (cmsIT8*) cmsIT8Alloc(ContextID);
+    if (!cube) return NULL;
+
+    cube->IsCUBE = TRUE;
+    cube->FileStack[0]->Stream = fopen(cFileName, "rt");
+
+    if (!cube->FileStack[0]->Stream) goto Done;
+
+    strncpy(cube->FileStack[0]->FileName, cFileName, cmsMAX_PATH - 1);
+    cube->FileStack[0]->FileName[cmsMAX_PATH - 1] = 0;
+
+    if (!ParseCube(cube, &Shaper, &CLUT, title)) goto Done;
+
+    // Success on parsing, let's create the profile
+    hProfile = cmsCreateProfilePlaceholder(ContextID);
+    if (!hProfile) goto Done;
+
+    cmsSetProfileVersion(hProfile, 4.4);
+
+    cmsSetDeviceClass(hProfile, cmsSigLinkClass);
+    cmsSetColorSpace(hProfile,  cmsSigRgbData);
+    cmsSetPCS(hProfile,         cmsSigRgbData);
+
+    cmsSetHeaderRenderingIntent(hProfile, INTENT_PERCEPTUAL);
+
+    // Creates a Pipeline to hold CLUT and shaper
+    Pipeline = cmsPipelineAlloc(ContextID, 3, 3);
+    if (Pipeline == NULL) goto Done;
+
+    // Populates the pipeline
+    if (Shaper != NULL) {
+        if (!cmsPipelineInsertStage(Pipeline, cmsAT_BEGIN, Shaper))
+            goto Done;
+    }
+
+    if (CLUT != NULL) {
+        if (!cmsPipelineInsertStage(Pipeline, cmsAT_END, CLUT))
+            goto Done;
+    }
+
+    // Propagate the description. We put no copyright because we know
+    // nothing on the copyrighted state of the .cube
+    DescriptionMLU = cmsMLUalloc(ContextID, 1);
+    if (!cmsMLUsetUTF8(DescriptionMLU, cmsNoLanguage, cmsNoCountry, title)) goto Done;
+
+    // Flush the tags
+    if (!cmsWriteTag(hProfile, cmsSigProfileDescriptionTag, DescriptionMLU)) goto Done;
+    if (!cmsWriteTag(hProfile, cmsSigAToB0Tag, (void*)Pipeline)) goto Done;
+
+Done:
+
+    if (DescriptionMLU != NULL)
+        cmsMLUfree(DescriptionMLU);
+
+    if (Pipeline != NULL)
+        cmsPipelineFree(Pipeline);
+
+    cmsIT8Free((cmsHANDLE) cube);
+
+    return hProfile;
+}
+
+cmsHPROFILE CMSEXPORT cmsCreateDeviceLinkFromCubeFile(const char* cFileName)
+{
+    return cmsCreateDeviceLinkFromCubeFileTHR(NULL, cFileName);
+}
diff --git a/src/java.desktop/share/native/liblcms/cmscnvrt.c b/src/java.desktop/share/native/liblcms/cmscnvrt.c
index b73d594f2ec..d18865b15b9 100644
--- a/src/java.desktop/share/native/liblcms/cmscnvrt.c
+++ b/src/java.desktop/share/native/liblcms/cmscnvrt.c
@@ -263,7 +263,7 @@ cmsFloat64Number CHAD2Temp(const cmsMAT3* Chad)
 
 // Compute a CHAD based on a given temperature
 static
-    void Temp2CHAD(cmsMAT3* Chad, cmsFloat64Number Temp)
+void Temp2CHAD(cmsMAT3* Chad, cmsFloat64Number Temp)
 {
     cmsCIEXYZ White;
     cmsCIExyY ChromaticityOfWhite;
@@ -744,6 +744,16 @@ int BlackPreservingGrayOnlySampler(CMSREGISTER const cmsUInt16Number In[], CMSRE
     return TRUE;
 }
 
+
+// Check whatever the profile is a CMYK->CMYK devicelink
+static
+cmsBool is_cmyk_devicelink(cmsHPROFILE hProfile)
+{
+    return cmsGetDeviceClass(hProfile) == cmsSigLinkClass &&
+            cmsGetColorSpace(hProfile) == cmsSigCmykData &&
+            cmsGetColorSpace(hProfile) == cmsSigCmykData;
+}
+
 // This is the entry for black-preserving K-only intents, which are non-ICC
 static
 cmsPipeline*  BlackPreservingKOnlyIntents(cmsContext     ContextID,
@@ -776,14 +786,16 @@ cmsPipeline*  BlackPreservingKOnlyIntents(cmsContext     ContextID,
     lastProfilePos = nProfiles - 1;
     hLastProfile = hProfiles[lastProfilePos];
 
-    while (lastProfilePos > 1)
+    // Skip CMYK->CMYK devicelinks on ending
+    while (is_cmyk_devicelink(hLastProfile))
     {
-        hLastProfile = hProfiles[--lastProfilePos];
-        if (cmsGetColorSpace(hLastProfile) != cmsSigCmykData ||
-            cmsGetDeviceClass(hLastProfile) != cmsSigLinkClass)
+        if (lastProfilePos < 2)
             break;
+
+        hLastProfile = hProfiles[--lastProfilePos];
     }
 
+
     preservationProfilesCount = lastProfilePos + 1;
 
     // Check for non-cmyk profiles
@@ -800,7 +812,7 @@ cmsPipeline*  BlackPreservingKOnlyIntents(cmsContext     ContextID,
 
     // Create a LUT holding normal ICC transform
     bp.cmyk2cmyk = DefaultICCintents(ContextID,
-                                     preservationProfilesCount,
+        preservationProfilesCount,
         ICCIntents,
         hProfiles,
         BPC,
@@ -812,7 +824,7 @@ cmsPipeline*  BlackPreservingKOnlyIntents(cmsContext     ContextID,
     // Now, compute the tone curve
     bp.KTone = _cmsBuildKToneCurve(ContextID,
         4096,
-                                    preservationProfilesCount,
+        preservationProfilesCount,
         ICCIntents,
         hProfiles,
         BPC,
@@ -1002,12 +1014,13 @@ cmsPipeline* BlackPreservingKPlaneIntents(cmsContext     ContextID,
     lastProfilePos = nProfiles - 1;
     hLastProfile = hProfiles[lastProfilePos];
 
-    while (lastProfilePos > 1)
+    // Skip CMYK->CMYK devicelinks on ending
+    while (is_cmyk_devicelink(hLastProfile))
     {
-        hLastProfile = hProfiles[--lastProfilePos];
-        if (cmsGetColorSpace(hLastProfile) != cmsSigCmykData ||
-            cmsGetDeviceClass(hLastProfile) != cmsSigLinkClass)
+        if (lastProfilePos < 2)
             break;
+
+        hLastProfile = hProfiles[--lastProfilePos];
     }
 
     preservationProfilesCount = lastProfilePos + 1;
@@ -1177,8 +1190,7 @@ cmsUInt32Number CMSEXPORT cmsGetSupportedIntentsTHR(cmsContext ContextID, cmsUIn
     cmsIntentsList* pt;
     cmsUInt32Number nIntents;
 
-
-    for (nIntents=0, pt = ctx->Intents; pt != NULL; pt = pt -> Next)
+    for (nIntents=0, pt = DefaultIntents; pt != NULL; pt = pt -> Next)
     {
         if (nIntents < nMax) {
             if (Codes != NULL)
@@ -1191,7 +1203,7 @@ cmsUInt32Number CMSEXPORT cmsGetSupportedIntentsTHR(cmsContext ContextID, cmsUIn
         nIntents++;
     }
 
-    for (nIntents=0, pt = DefaultIntents; pt != NULL; pt = pt -> Next)
+    for (pt = ctx->Intents; pt != NULL; pt = pt -> Next)
     {
         if (nIntents < nMax) {
             if (Codes != NULL)
@@ -1203,6 +1215,7 @@ cmsUInt32Number CMSEXPORT cmsGetSupportedIntentsTHR(cmsContext ContextID, cmsUIn
 
         nIntents++;
     }
+
     return nIntents;
 }
 
diff --git a/src/java.desktop/share/native/liblcms/cmserr.c b/src/java.desktop/share/native/liblcms/cmserr.c
index 739cc0b2c98..9fb7db89c9a 100644
--- a/src/java.desktop/share/native/liblcms/cmserr.c
+++ b/src/java.desktop/share/native/liblcms/cmserr.c
@@ -101,7 +101,7 @@ long int CMSEXPORT cmsfilelength(FILE* f)
 //
 // This is the interface to low-level memory management routines. By default a simple
 // wrapping to malloc/free/realloc is provided, although there is a limit on the max
-// amount of memoy that can be reclaimed. This is mostly as a safety feature to prevent
+// amount of memory that can be reclaimed. This is mostly as a safety feature to prevent
 // bogus or evil code to allocate huge blocks that otherwise lcms would never need.
 
 #define MAX_MEMORY_FOR_ALLOC  ((cmsUInt32Number)(1024U*1024U*512U))
@@ -121,7 +121,8 @@ cmsBool   _cmsRegisterMemHandlerPlugin(cmsContext ContextID, cmsPluginBase* Plug
 static
 void* _cmsMallocDefaultFn(cmsContext ContextID, cmsUInt32Number size)
 {
-    if (size > MAX_MEMORY_FOR_ALLOC) return NULL;  // Never allow over maximum
+    // Never allow 0 or over maximum
+    if (size == 0 || size > MAX_MEMORY_FOR_ALLOC) return NULL;
 
     return (void*) malloc(size);
 
@@ -263,7 +264,7 @@ cmsBool  _cmsRegisterMemHandlerPlugin(cmsContext ContextID, cmsPluginBase *Data)
 
     // NULL forces to reset to defaults. In this special case, the defaults are stored in the context structure.
     // Remaining plug-ins does NOT have any copy in the context structure, but this is somehow special as the
-    // context internal data should be malloce'd by using those functions.
+    // context internal data should be malloc'ed by using those functions.
     if (Data == NULL) {
 
        struct _cmsContext_struct* ctx = ( struct _cmsContext_struct*) ContextID;
diff --git a/src/java.desktop/share/native/liblcms/cmsgamma.c b/src/java.desktop/share/native/liblcms/cmsgamma.c
index 08409434064..8e489a43c55 100644
--- a/src/java.desktop/share/native/liblcms/cmsgamma.c
+++ b/src/java.desktop/share/native/liblcms/cmsgamma.c
@@ -329,6 +329,10 @@ cmsToneCurve* AllocateToneCurveStruct(cmsContext ContextID, cmsUInt32Number nEnt
         return p;
 
 Error:
+    for (i=0; i < nSegments; i++) {
+        if (p ->Segments && p ->Segments[i].SampledPoints) _cmsFree(ContextID, p ->Segments[i].SampledPoints);
+        if (p ->SegInterp && p ->SegInterp[i]) _cmsFree(ContextID, p ->SegInterp[i]);
+    }
     if (p -> SegInterp) _cmsFree(ContextID, p -> SegInterp);
     if (p -> Segments) _cmsFree(ContextID, p -> Segments);
     if (p -> Evals) _cmsFree(ContextID, p -> Evals);
@@ -622,10 +626,16 @@ cmsFloat64Number DefaultEvalParametricFn(cmsInt32Number Type, const cmsFloat64Nu
     case 6:
         e = Params[1]*R + Params[2];
 
-        if (e < 0)
-            Val = Params[3];
-        else
-            Val = pow(e, Params[0]) + Params[3];
+        // On gamma 1.0, don't clamp
+        if (Params[0] == 1.0) {
+            Val = e + Params[3];
+        }
+        else {
+            if (e < 0)
+                Val = Params[3];
+            else
+                Val = pow(e, Params[0]) + Params[3];
+        }
         break;
 
     // ((Y - c) ^1/Gamma - b) / a
@@ -1520,13 +1530,13 @@ cmsFloat64Number CMSEXPORT cmsEstimateGamma(const cmsToneCurve* t, cmsFloat64Num
     return (sum / n);   // The mean
 }
 
+// Retrieve segments on tone curves
 
-// Retrieve parameters on one-segment tone curves
-
-cmsFloat64Number* CMSEXPORT cmsGetToneCurveParams(const cmsToneCurve* t)
+const cmsCurveSegment* CMSEXPORT cmsGetToneCurveSegment(cmsInt32Number n, const cmsToneCurve* t)
 {
     _cmsAssert(t != NULL);
 
-    if (t->nSegments != 1) return NULL;
-    return t->Segments[0].Params;
+    if (n < 0 || n >= (cmsInt32Number) t->nSegments) return NULL;
+    return t->Segments + n;
 }
+
diff --git a/src/java.desktop/share/native/liblcms/cmsgmt.c b/src/java.desktop/share/native/liblcms/cmsgmt.c
index 60a01aa5088..e9ee73b52cd 100644
--- a/src/java.desktop/share/native/liblcms/cmsgmt.c
+++ b/src/java.desktop/share/native/liblcms/cmsgmt.c
@@ -248,7 +248,7 @@ int GamutSampler(CMSREGISTER const cmsUInt16Number In[], CMSREGISTER cmsUInt16Nu
     cmsUInt16Number Proof[cmsMAXCHANNELS], Proof2[cmsMAXCHANNELS];
     cmsFloat64Number dE1, dE2, ErrorRatio;
 
-    // Assume in-gamut by default.
+    // Assume in-gamut by default. NEVER READ, USED FOR DEBUG PURPOSES.
     ErrorRatio = 1.0;
 
     // Convert input to Lab
@@ -625,7 +625,7 @@ cmsBool CMSEXPORT cmsDesaturateLab(cmsCIELab* Lab,
 // Actually, doing that "well" is quite hard, since every component may behave completely different.
 // Since the true point of this function is to detect suitable optimizations, I am imposing some requirements
 // that simplifies things: only RGB, and only profiles that can got in both directions.
-// The algorithm obtains Y from a syntetical gray R=G=B. Then least squares fitting is used to estimate gamma.
+// The algorithm obtains Y from a synthetical gray R=G=B. Then least squares fitting is used to estimate gamma.
 // For gamma close to 1.0, RGB is linear. On profiles not supported, -1 is returned.
 
 cmsFloat64Number CMSEXPORT cmsDetectRGBProfileGamma(cmsHPROFILE hProfile, cmsFloat64Number threshold)
diff --git a/src/java.desktop/share/native/liblcms/cmsio0.c b/src/java.desktop/share/native/liblcms/cmsio0.c
index 6763970f619..05baa9392e2 100644
--- a/src/java.desktop/share/native/liblcms/cmsio0.c
+++ b/src/java.desktop/share/native/liblcms/cmsio0.c
@@ -560,6 +560,20 @@ cmsHPROFILE CMSEXPORT cmsCreateProfilePlaceholder(cmsContext ContextID)
     // Set default version
     Icc ->Version =  0x02100000;
 
+    // Set default CMM (that's me!)
+    Icc ->CMM = lcmsSignature;
+
+    // Set default creator
+    // Created by LittleCMS (that's me!)
+    Icc ->creator = lcmsSignature;
+
+    // Set default platform
+#ifdef CMS_IS_WINDOWS_
+    Icc ->platform = cmsSigMicrosoft;
+#else
+    Icc ->platform = cmsSigMacintosh;
+#endif
+
     // Set default device class
     Icc->DeviceClass = cmsSigDisplayClass;
 
@@ -813,11 +827,13 @@ cmsBool _cmsReadHeader(_cmsICCPROFILE* Icc)
     }
 
     // Adjust endianness of the used parameters
+    Icc -> CMM             = _cmsAdjustEndianess32(Header.cmmId);
     Icc -> DeviceClass     = (cmsProfileClassSignature) _cmsAdjustEndianess32(Header.deviceClass);
     Icc -> ColorSpace      = (cmsColorSpaceSignature)   _cmsAdjustEndianess32(Header.colorSpace);
     Icc -> PCS             = (cmsColorSpaceSignature)   _cmsAdjustEndianess32(Header.pcs);
 
     Icc -> RenderingIntent = _cmsAdjustEndianess32(Header.renderingIntent);
+    Icc -> platform        = (cmsPlatformSignature)_cmsAdjustEndianess32(Header.platform);
     Icc -> flags           = _cmsAdjustEndianess32(Header.flags);
     Icc -> manufacturer    = _cmsAdjustEndianess32(Header.manufacturer);
     Icc -> model           = _cmsAdjustEndianess32(Header.model);
@@ -922,7 +938,7 @@ cmsBool _cmsWriteHeader(_cmsICCPROFILE* Icc, cmsUInt32Number UsedSpace)
     cmsUInt32Number Count;
 
     Header.size        = _cmsAdjustEndianess32(UsedSpace);
-    Header.cmmId       = _cmsAdjustEndianess32(lcmsSignature);
+    Header.cmmId       = _cmsAdjustEndianess32(Icc ->CMM);
     Header.version     = _cmsAdjustEndianess32(Icc ->Version);
 
     Header.deviceClass = (cmsProfileClassSignature) _cmsAdjustEndianess32(Icc -> DeviceClass);
@@ -934,11 +950,7 @@ cmsBool _cmsWriteHeader(_cmsICCPROFILE* Icc, cmsUInt32Number UsedSpace)
 
     Header.magic       = _cmsAdjustEndianess32(cmsMagicNumber);
 
-#ifdef CMS_IS_WINDOWS_
-    Header.platform    = (cmsPlatformSignature) _cmsAdjustEndianess32(cmsSigMicrosoft);
-#else
-    Header.platform    = (cmsPlatformSignature) _cmsAdjustEndianess32(cmsSigMacintosh);
-#endif
+    Header.platform    = (cmsPlatformSignature) _cmsAdjustEndianess32(Icc -> platform);
 
     Header.flags        = _cmsAdjustEndianess32(Icc -> flags);
     Header.manufacturer = _cmsAdjustEndianess32(Icc -> manufacturer);
@@ -954,8 +966,7 @@ cmsBool _cmsWriteHeader(_cmsICCPROFILE* Icc, cmsUInt32Number UsedSpace)
     Header.illuminant.Y = (cmsS15Fixed16Number) _cmsAdjustEndianess32((cmsUInt32Number) _cmsDoubleTo15Fixed16(cmsD50_XYZ()->Y));
     Header.illuminant.Z = (cmsS15Fixed16Number) _cmsAdjustEndianess32((cmsUInt32Number) _cmsDoubleTo15Fixed16(cmsD50_XYZ()->Z));
 
-    // Created by LittleCMS (that's me!)
-    Header.creator      = _cmsAdjustEndianess32(lcmsSignature);
+    Header.creator      = _cmsAdjustEndianess32(Icc ->creator);
 
     memset(&Header.reserved, 0, sizeof(Header.reserved));
 
diff --git a/src/java.desktop/share/native/liblcms/cmsio1.c b/src/java.desktop/share/native/liblcms/cmsio1.c
index bd8a832ac40..e42d4d38987 100644
--- a/src/java.desktop/share/native/liblcms/cmsio1.c
+++ b/src/java.desktop/share/native/liblcms/cmsio1.c
@@ -607,7 +607,7 @@ cmsPipeline* _cmsReadFloatOutputTag(cmsHPROFILE hProfile, cmsTagSignature tagFlo
     return NULL;
 }
 
-// Create an output MPE LUT from agiven profile. Version mismatches are handled here
+// Create an output MPE LUT from a given profile. Version mismatches are handled here
 cmsPipeline* CMSEXPORT _cmsReadOutputLUT(cmsHPROFILE hProfile, cmsUInt32Number Intent)
 {
     cmsTagTypeSignature OriginalType;
@@ -1056,3 +1056,13 @@ cmsUInt32Number  CMSEXPORT cmsGetProfileInfoASCII(cmsHPROFILE hProfile, cmsInfoT
 
     return cmsMLUgetASCII(mlu, LanguageCode, CountryCode, Buffer, BufferSize);
 }
+
+cmsUInt32Number  CMSEXPORT cmsGetProfileInfoUTF8(cmsHPROFILE hProfile, cmsInfoType Info,
+                                                          const char LanguageCode[3], const char CountryCode[3],
+                                                          char* Buffer, cmsUInt32Number BufferSize)
+{
+    const cmsMLU* mlu = GetInfo(hProfile, Info);
+    if (mlu == NULL) return 0;
+
+    return cmsMLUgetUTF8(mlu, LanguageCode, CountryCode, Buffer, BufferSize);
+}
diff --git a/src/java.desktop/share/native/liblcms/cmslut.c b/src/java.desktop/share/native/liblcms/cmslut.c
index 24114632ad0..b544c948625 100644
--- a/src/java.desktop/share/native/liblcms/cmslut.c
+++ b/src/java.desktop/share/native/liblcms/cmslut.c
@@ -504,6 +504,9 @@ cmsUInt32Number CubeSize(const cmsUInt32Number Dims[], cmsUInt32Number b)
         if (rv > UINT_MAX / dim) return 0;
     }
 
+    // Again, prevent overflow
+    if (rv > UINT_MAX / 15) return 0;
+
     return rv;
 }
 
@@ -843,7 +846,13 @@ cmsBool CMSEXPORT cmsStageSampleCLutFloat(cmsStage* mpe, cmsSAMPLERFLOAT Sampler
     cmsUInt32Number nInputs, nOutputs;
     cmsUInt32Number* nSamples;
     cmsFloat32Number In[MAX_INPUT_DIMENSIONS+1], Out[MAX_STAGE_CHANNELS];
-    _cmsStageCLutData* clut = (_cmsStageCLutData*) mpe->Data;
+    _cmsStageCLutData* clut;
+
+    if (mpe == NULL) return FALSE;
+
+    clut = (_cmsStageCLutData*)mpe->Data;
+
+    if (clut == NULL) return FALSE;
 
     nSamples = clut->Params ->nSamples;
     nInputs  = clut->Params ->nInputs;
diff --git a/src/java.desktop/share/native/liblcms/cmsnamed.c b/src/java.desktop/share/native/liblcms/cmsnamed.c
index 04280180230..d3cd97d4aea 100644
--- a/src/java.desktop/share/native/liblcms/cmsnamed.c
+++ b/src/java.desktop/share/native/liblcms/cmsnamed.c
@@ -229,17 +229,145 @@ void strFrom16(char str[3], cmsUInt16Number n)
     str[0] = (char)(n >> 8);
     str[1] = (char)n;
     str[2] = (char)0;
+}
+
+
+// Convert from UTF8 to wchar, returns len.
+static
+cmsUInt32Number decodeUTF8(wchar_t* out, const char* in)
+{
+    cmsUInt32Number codepoint = 0;
+    cmsUInt32Number size = 0;
+
+    while (*in)
+    {
+        cmsUInt8Number ch = (cmsUInt8Number) *in;
+
+        if (ch <= 0x7f)
+        {
+            codepoint = ch;
+        }
+        else if (ch <= 0xbf)
+        {
+            codepoint = (codepoint << 6) | (ch & 0x3f);
+        }
+        else if (ch <= 0xdf)
+        {
+            codepoint = ch & 0x1f;
+        }
+        else if (ch <= 0xef)
+        {
+            codepoint = ch & 0x0f;
+        }
+        else
+        {
+            codepoint = ch & 0x07;
+        }
+
+        in++;
 
+        if (((*in & 0xc0) != 0x80) && (codepoint <= 0x10ffff))
+        {
+            if (sizeof(wchar_t) > 2)
+            {
+                if (out) *out++ = (wchar_t) codepoint;
+                size++;
+            }
+            else
+                if (codepoint > 0xffff)
+                {
+                    if (out)
+                    {
+                        *out++ = (wchar_t)(0xd800 + (codepoint >> 10));
+                        *out++ = (wchar_t)(0xdc00 + (codepoint & 0x03ff));
+                        size += 2;
+                    }
+                }
+                else
+                    if (codepoint < 0xd800 || codepoint >= 0xe000)
+                    {
+                        if (out) *out++ = (wchar_t) codepoint;
+                        size++;
+                    }
+        }
+    }
+
+    return size;
+}
+
+// Convert from wchar_t to UTF8
+static
+cmsUInt32Number encodeUTF8(char* out, const wchar_t* in, cmsUInt32Number max_wchars, cmsUInt32Number max_chars)
+{
+    cmsUInt32Number codepoint = 0;
+    cmsUInt32Number size = 0;
+    cmsUInt32Number len_w = 0;
+
+    while (*in && len_w < max_wchars)
+    {
+        if (*in >= 0xd800 && *in <= 0xdbff)
+            codepoint = ((*in - 0xd800) << 10) + 0x10000;
+        else
+        {
+            if (*in >= 0xdc00 && *in <= 0xdfff)
+                codepoint |= *in - 0xdc00;
+            else
+                codepoint = *in;
+
+            if (codepoint <= 0x7f)
+            {
+                if (out && (size + 1 < max_chars)) *out++ = (char)codepoint;
+                size++;
+            }
+
+            else if (codepoint <= 0x7ff)
+            {
+                if (out && (max_chars > 0) && (size + 2 < max_chars))
+                {
+                    *out++ = (char)(cmsUInt32Number)(0xc0 | ((codepoint >> 6) & 0x1f));
+                    *out++ = (char)(cmsUInt32Number)(0x80 | (codepoint & 0x3f));
+                }
+                size += 2;
+            }
+            else if (codepoint <= 0xffff)
+            {
+                if (out && (max_chars > 0) && (size + 3 < max_chars))
+                {
+                    *out++ = (char)(cmsUInt32Number)(0xe0 | ((codepoint >> 12) & 0x0f));
+                    *out++ = (char)(cmsUInt32Number)(0x80 | ((codepoint >> 6) & 0x3f));
+                    *out++ = (char)(cmsUInt32Number)(0x80 | (codepoint & 0x3f));
+                }
+                size += 3;
+            }
+            else
+            {
+                if (out && (max_chars > 0) && (size + 4 < max_chars))
+                {
+                    *out++ = (char)(cmsUInt32Number)(0xf0 | ((codepoint >> 18) & 0x07));
+                    *out++ = (char)(cmsUInt32Number)(0x80 | ((codepoint >> 12) & 0x3f));
+                    *out++ = (char)(cmsUInt32Number)(0x80 | ((codepoint >> 6) & 0x3f));
+                    *out++ = (char)(cmsUInt32Number)(0x80 | (codepoint & 0x3f));
+                }
+                size += 4;
+            }
+
+            codepoint = 0;
+        }
+
+        in++; len_w++;
+    }
+
+    return size;
 }
 
 // Add an ASCII entry. Do not add any \0 termination (ICC1v43_2010-12.pdf page 61)
 // In the case the user explicitly sets an empty string, we force a \0
 cmsBool CMSEXPORT cmsMLUsetASCII(cmsMLU* mlu, const char LanguageCode[3], const char CountryCode[3], const char* ASCIIString)
 {
-    cmsUInt32Number i, len = (cmsUInt32Number) strlen(ASCIIString);
+    cmsUInt32Number i, len = (cmsUInt32Number)strlen(ASCIIString);
     wchar_t* WStr;
     cmsBool  rc;
-    cmsUInt16Number Lang  = strTo16(LanguageCode);
+    cmsUInt16Number Lang = strTo16(LanguageCode);
     cmsUInt16Number Cntry = strTo16(CountryCode);
 
     if (mlu == NULL) return FALSE;
@@ -247,22 +375,56 @@ cmsBool CMSEXPORT cmsMLUsetASCII(cmsMLU* mlu, const char LanguageCode[3], const
     // len == 0 would prevent operation, so we set a empty string pointing to zero
     if (len == 0)
     {
-        len = 1;
+        wchar_t empty = 0;
+        return AddMLUBlock(mlu, sizeof(wchar_t), &empty, Lang, Cntry);
     }
 
-    WStr = (wchar_t*) _cmsCalloc(mlu ->ContextID, len,  sizeof(wchar_t));
+    WStr = (wchar_t*)_cmsCalloc(mlu->ContextID, len, sizeof(wchar_t));
     if (WStr == NULL) return FALSE;
 
-    for (i=0; i < len; i++)
-        WStr[i] = (wchar_t) ASCIIString[i];
+    for (i = 0; i < len; i++)
+        WStr[i] = (wchar_t)ASCIIString[i];
 
-    rc = AddMLUBlock(mlu, len  * sizeof(wchar_t), WStr, Lang, Cntry);
+    rc = AddMLUBlock(mlu, len * sizeof(wchar_t), WStr, Lang, Cntry);
 
-    _cmsFree(mlu ->ContextID, WStr);
+    _cmsFree(mlu->ContextID, WStr);
     return rc;
 
 }
 
+// Add an UTF8 entry. Do not add any \0 termination (ICC1v43_2010-12.pdf page 61)
+// In the case the user explicitly sets an empty string, we force a \0
+cmsBool CMSEXPORT cmsMLUsetUTF8(cmsMLU* mlu, const char LanguageCode[3], const char CountryCode[3], const char* UTF8String)
+{
+    cmsUInt32Number UTF8len;
+    wchar_t* WStr;
+    cmsBool  rc;
+    cmsUInt16Number Lang  = strTo16(LanguageCode);
+    cmsUInt16Number Cntry = strTo16(CountryCode);
+
+    if (mlu == NULL) return FALSE;
+
+    if (*UTF8String == '\0')
+    {
+        wchar_t empty = 0;
+        return AddMLUBlock(mlu, sizeof(wchar_t), &empty, Lang, Cntry);
+    }
+
+    // Len excluding terminator 0
+    UTF8len = decodeUTF8(NULL, UTF8String);
+
+    // Get space for dest
+    WStr = (wchar_t*) _cmsCalloc(mlu ->ContextID, UTF8len,  sizeof(wchar_t));
+    if (WStr == NULL) return FALSE;
+
+    decodeUTF8(WStr, UTF8String);
+
+    rc = AddMLUBlock(mlu, UTF8len  * sizeof(wchar_t), WStr, Lang, Cntry);
+
+    _cmsFree(mlu ->ContextID, WStr);
+    return rc;
+}
+
 // We don't need any wcs support library
 static
 cmsUInt32Number mywcslen(const wchar_t *s)
@@ -401,7 +563,7 @@ const wchar_t* _cmsMLUgetWide(const cmsMLU* mlu,
 
     if (v->StrW + v->Len > mlu->PoolSize) return NULL;
 
-    return(wchar_t*) ((cmsUInt8Number*) mlu ->MemPool + v ->StrW);
+    return (wchar_t*) ((cmsUInt8Number*) mlu ->MemPool + v ->StrW);
 }
 
 
@@ -439,10 +601,12 @@ cmsUInt32Number CMSEXPORT cmsMLUgetASCII(const cmsMLU* mlu,
     // Precess each character
     for (i=0; i < ASCIIlen; i++) {
 
-        if (Wide[i] == 0)
-            Buffer[i] = 0;
+        wchar_t wc = Wide[i];
+
+        if (wc < 0xff)
+            Buffer[i] = (char)wc;
         else
-            Buffer[i] = (char) Wide[i];
+            Buffer[i] = '?';
     }
 
     // We put a termination "\0"
@@ -450,6 +614,46 @@ cmsUInt32Number CMSEXPORT cmsMLUgetASCII(const cmsMLU* mlu,
     return ASCIIlen + 1;
 }
 
+
+// Obtain a UTF8 representation of the wide string. Setting buffer to NULL returns the len
+cmsUInt32Number CMSEXPORT cmsMLUgetUTF8(const cmsMLU* mlu,
+                                       const char LanguageCode[3], const char CountryCode[3],
+                                       char* Buffer, cmsUInt32Number BufferSize)
+{
+    const wchar_t *Wide;
+    cmsUInt32Number  StrLen = 0;
+    cmsUInt32Number UTF8len;
+
+    cmsUInt16Number Lang  = strTo16(LanguageCode);
+    cmsUInt16Number Cntry = strTo16(CountryCode);
+
+    // Sanitize
+    if (mlu == NULL) return 0;
+
+    // Get WideChar
+    Wide = _cmsMLUgetWide(mlu, &StrLen, Lang, Cntry, NULL, NULL);
+    if (Wide == NULL) return 0;
+
+    UTF8len = encodeUTF8(NULL, Wide, StrLen / sizeof(wchar_t), BufferSize);
+
+    // Maybe we want only to know the len?
+    if (Buffer == NULL) return UTF8len + 1; // Note the zero at the end
+
+    // No buffer size means no data
+    if (BufferSize <= 0) return 0;
+
+    // Some clipping may be required
+    if (BufferSize < UTF8len + 1)
+        UTF8len = BufferSize - 1;
+
+    // Process it
+    encodeUTF8(Buffer, Wide, StrLen / sizeof(wchar_t), BufferSize);
+
+    // We put a termination "\0"
+    Buffer[UTF8len] = 0;
+    return UTF8len + 1;
+}
+
 // Obtain a wide representation of the MLU, on depending on current locale settings
 cmsUInt32Number CMSEXPORT cmsMLUgetWide(const cmsMLU* mlu,
                                       const char LanguageCode[3], const char CountryCode[3],
@@ -470,12 +674,12 @@ cmsUInt32Number CMSEXPORT cmsMLUgetWide(const cmsMLU* mlu,
     // Maybe we want only to know the len?
     if (Buffer == NULL) return StrLen + sizeof(wchar_t);
 
-  // No buffer size means no data
-    if (BufferSize <= 0) return 0;
+    // Invalid buffer size means no data
+    if (BufferSize < sizeof(wchar_t)) return 0;
 
     // Some clipping may be required
     if (BufferSize < StrLen + sizeof(wchar_t))
-        StrLen = BufferSize - + sizeof(wchar_t);
+        StrLen = BufferSize - sizeof(wchar_t);
 
     memmove(Buffer, Wide, StrLen);
     Buffer[StrLen / sizeof(wchar_t)] = 0;
@@ -843,13 +1047,19 @@ void CMSEXPORT cmsFreeProfileSequenceDescription(cmsSEQ* pseq)
 {
     cmsUInt32Number i;
 
-    for (i=0; i < pseq ->n; i++) {
-        if (pseq ->seq[i].Manufacturer != NULL) cmsMLUfree(pseq ->seq[i].Manufacturer);
-        if (pseq ->seq[i].Model != NULL) cmsMLUfree(pseq ->seq[i].Model);
-        if (pseq ->seq[i].Description != NULL) cmsMLUfree(pseq ->seq[i].Description);
+    if (pseq == NULL)
+        return;
+
+    if (pseq ->seq != NULL) {
+        for (i=0; i < pseq ->n; i++) {
+            if (pseq ->seq[i].Manufacturer != NULL) cmsMLUfree(pseq ->seq[i].Manufacturer);
+            if (pseq ->seq[i].Model != NULL) cmsMLUfree(pseq ->seq[i].Model);
+            if (pseq ->seq[i].Description != NULL) cmsMLUfree(pseq ->seq[i].Description);
+        }
+
+        _cmsFree(pseq ->ContextID, pseq ->seq);
     }
 
-    if (pseq ->seq != NULL) _cmsFree(pseq ->ContextID, pseq ->seq);
     _cmsFree(pseq -> ContextID, pseq);
 }
 
diff --git a/src/java.desktop/share/native/liblcms/cmsopt.c b/src/java.desktop/share/native/liblcms/cmsopt.c
index 3e81ae1df1b..421a4f4a701 100644
--- a/src/java.desktop/share/native/liblcms/cmsopt.c
+++ b/src/java.desktop/share/native/liblcms/cmsopt.c
@@ -212,6 +212,7 @@ cmsBool  isFloatMatrixIdentity(const cmsMAT3* a)
 
        return TRUE;
 }
+
 // if two adjacent matrices are found, multiply them.
 static
 cmsBool _MultiplyMatrix(cmsPipeline* Lut)
@@ -1142,14 +1143,17 @@ cmsBool OptimizeByComputingLinearization(cmsPipeline** Lut, cmsUInt32Number Inte
 
         // Store result in curve
         for (t=0; t < OriginalLut ->InputChannels; t++)
-            Trans[t] ->Table16[i] = _cmsQuickSaturateWord(Out[t] * 65535.0);
+        {
+            if (Trans[t]->Table16 != NULL)
+                Trans[t] ->Table16[i] = _cmsQuickSaturateWord(Out[t] * 65535.0);
+        }
     }
 
     // Slope-limit the obtained curves
     for (t = 0; t < OriginalLut ->InputChannels; t++)
         SlopeLimiting(Trans[t]);
 
-    // Check for validity
+    // Check for validity. lIsLinear is here for debug purposes
     lIsSuitable = TRUE;
     lIsLinear   = TRUE;
     for (t=0; (lIsSuitable && (t < OriginalLut ->InputChannels)); t++) {
@@ -1753,6 +1757,8 @@ cmsBool OptimizeMatrixShaper(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt3
 
                      _cmsStageMatrixData* Data = (_cmsStageMatrixData*)cmsStageData(Matrix1);
 
+                     if (Matrix1->InputChannels != 3 || Matrix1->OutputChannels != 3) return FALSE;
+
                      // Copy the matrix to our result
                      memcpy(&res, Data->Double, sizeof(res));
 
@@ -1797,7 +1803,7 @@ cmsBool OptimizeMatrixShaper(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt3
         _cmsStageToneCurvesData* mpeC2 = (_cmsStageToneCurvesData*) cmsStageData(Curve2);
 
         // In this particular optimization, cache does not help as it takes more time to deal with
-        // the cache that with the pixel handling
+        // the cache than with the pixel handling
         *dwFlags |= cmsFLAGS_NOCACHE;
 
         // Setup the optimizarion routines
@@ -1954,7 +1960,7 @@ cmsBool CMSEXPORT _cmsOptimizePipeline(cmsContext ContextID,
     for (mpe = cmsPipelineGetPtrToFirstStage(*PtrLut);
         mpe != NULL;
         mpe = cmsStageNext(mpe)) {
-        if (cmsStageType(mpe) == cmsSigNamedColorElemType) return FALSE;
+            if (cmsStageType(mpe) == cmsSigNamedColorElemType) return FALSE;
     }
 
     // Try to get rid of identities and trivial conversions.
diff --git a/src/java.desktop/share/native/liblcms/cmspack.c b/src/java.desktop/share/native/liblcms/cmspack.c
index da5fc6019d3..fc875995a80 100644
--- a/src/java.desktop/share/native/liblcms/cmspack.c
+++ b/src/java.desktop/share/native/liblcms/cmspack.c
@@ -2980,6 +2980,108 @@ cmsUInt8Number* PackFloatFrom16(CMSREGISTER _cmsTRANSFORM* info,
 
 // --------------------------------------------------------------------------------------------------------
 
+static
+cmsUInt8Number* PackBytesFromFloat(_cmsTRANSFORM* info,
+                                    cmsFloat32Number wOut[],
+                                    cmsUInt8Number* output,
+                                    cmsUInt32Number Stride)
+{
+    cmsUInt32Number nChan = T_CHANNELS(info->OutputFormat);
+    cmsUInt32Number DoSwap = T_DOSWAP(info->OutputFormat);
+    cmsUInt32Number Reverse = T_FLAVOR(info->OutputFormat);
+    cmsUInt32Number Extra = T_EXTRA(info->OutputFormat);
+    cmsUInt32Number SwapFirst = T_SWAPFIRST(info->OutputFormat);
+    cmsUInt32Number Planar = T_PLANAR(info->OutputFormat);
+    cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst;
+    cmsUInt8Number* swap1 = (cmsUInt8Number*)output;
+    cmsFloat64Number v = 0;
+    cmsUInt8Number vv = 0;
+    cmsUInt32Number i, start = 0;
+
+    if (ExtraFirst)
+        start = Extra;
+
+    for (i = 0; i < nChan; i++) {
+
+        cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i;
+
+        v = wOut[index] * 65535.0;
+
+        if (Reverse)
+            v = 65535.0 - v;
+
+        vv =  FROM_16_TO_8(_cmsQuickSaturateWord(v));
+
+        if (Planar)
+            ((cmsUInt8Number*)output)[(i + start) * Stride] = vv;
+        else
+            ((cmsUInt8Number*)output)[i + start] = vv;
+    }
+
+
+    if (Extra == 0 && SwapFirst) {
+
+        memmove(swap1 + 1, swap1, (nChan - 1) * sizeof(cmsUInt8Number));
+        *swap1 = vv;
+    }
+
+    if (T_PLANAR(info->OutputFormat))
+        return output + sizeof(cmsUInt8Number);
+    else
+        return output + (nChan + Extra) * sizeof(cmsUInt8Number);
+}
+
+static
+cmsUInt8Number* PackWordsFromFloat(_cmsTRANSFORM* info,
+                                    cmsFloat32Number wOut[],
+                                    cmsUInt8Number* output,
+                                    cmsUInt32Number Stride)
+{
+    cmsUInt32Number nChan = T_CHANNELS(info->OutputFormat);
+    cmsUInt32Number DoSwap = T_DOSWAP(info->OutputFormat);
+    cmsUInt32Number Reverse = T_FLAVOR(info->OutputFormat);
+    cmsUInt32Number Extra = T_EXTRA(info->OutputFormat);
+    cmsUInt32Number SwapFirst = T_SWAPFIRST(info->OutputFormat);
+    cmsUInt32Number Planar = T_PLANAR(info->OutputFormat);
+    cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst;
+    cmsUInt16Number* swap1 = (cmsUInt16Number*)output;
+    cmsFloat64Number v = 0;
+    cmsUInt16Number vv = 0;
+    cmsUInt32Number i, start = 0;
+
+    if (ExtraFirst)
+        start = Extra;
+
+    for (i = 0; i < nChan; i++) {
+
+        cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i;
+
+        v = wOut[index] * 65535.0;
+
+        if (Reverse)
+            v = 65535.0 - v;
+
+        vv = _cmsQuickSaturateWord(v);
+
+        if (Planar)
+            ((cmsUInt16Number*)output)[(i + start) * Stride] = vv;
+        else
+            ((cmsUInt16Number*)output)[i + start] = vv;
+    }
+
+    if (Extra == 0 && SwapFirst) {
+
+        memmove(swap1 + 1, swap1, (nChan - 1) * sizeof(cmsUInt16Number));
+        *swap1 = vv;
+    }
+
+    if (T_PLANAR(info->OutputFormat))
+        return output + sizeof(cmsUInt16Number);
+    else
+        return output + (nChan + Extra) * sizeof(cmsUInt16Number);
+}
+
+
 static
 cmsUInt8Number* PackFloatsFromFloat(_cmsTRANSFORM* info,
                                     cmsFloat32Number wOut[],
@@ -3143,6 +3245,77 @@ cmsUInt8Number* PackLabDoubleFromFloat(_cmsTRANSFORM* Info,
 }
 
 
+static
+cmsUInt8Number* PackEncodedBytesLabV2FromFloat(_cmsTRANSFORM* Info,
+                                           cmsFloat32Number wOut[],
+                                           cmsUInt8Number* output,
+                                           cmsUInt32Number Stride)
+{
+    cmsCIELab Lab;
+    cmsUInt16Number wlab[3];
+
+    Lab.L = (cmsFloat64Number)(wOut[0] * 100.0);
+    Lab.a = (cmsFloat64Number)(wOut[1] * 255.0 - 128.0);
+    Lab.b = (cmsFloat64Number)(wOut[2] * 255.0 - 128.0);
+
+    cmsFloat2LabEncoded(wlab, &Lab);
+
+    if (T_PLANAR(Info -> OutputFormat)) {
+
+        Stride /= PixelSize(Info->OutputFormat);
+
+        output[0]        = wlab[0] >> 8;
+        output[Stride]   = wlab[1] >> 8;
+        output[Stride*2] = wlab[2] >> 8;
+
+        return output + 1;
+    }
+    else {
+
+        output[0] = wlab[0] >> 8;
+        output[1] = wlab[1] >> 8;
+        output[2] = wlab[2] >> 8;
+
+        return output + (3 + T_EXTRA(Info ->OutputFormat));
+    }
+}
+
+static
+cmsUInt8Number* PackEncodedWordsLabV2FromFloat(_cmsTRANSFORM* Info,
+                                           cmsFloat32Number wOut[],
+                                           cmsUInt8Number* output,
+                                           cmsUInt32Number Stride)
+{
+    cmsCIELab Lab;
+    cmsUInt16Number wlab[3];
+
+    Lab.L = (cmsFloat64Number)(wOut[0] * 100.0);
+    Lab.a = (cmsFloat64Number)(wOut[1] * 255.0 - 128.0);
+    Lab.b = (cmsFloat64Number)(wOut[2] * 255.0 - 128.0);
+
+    cmsFloat2LabEncodedV2(wlab, &Lab);
+
+    if (T_PLANAR(Info -> OutputFormat)) {
+
+        Stride /= PixelSize(Info->OutputFormat);
+
+        ((cmsUInt16Number*) output)[0]        = wlab[0];
+        ((cmsUInt16Number*) output)[Stride]   = wlab[1];
+        ((cmsUInt16Number*) output)[Stride*2] = wlab[2];
+
+        return output + sizeof(cmsUInt16Number);
+    }
+    else {
+
+         ((cmsUInt16Number*) output)[0] = wlab[0];
+         ((cmsUInt16Number*) output)[1] = wlab[1];
+         ((cmsUInt16Number*) output)[2] = wlab[2];
+
+        return output + (3 + T_EXTRA(Info ->OutputFormat)) * sizeof(cmsUInt16Number);
+    }
+}
+
+
 // From 0..1 range to 0..MAX_ENCODEABLE_XYZ
 static
 cmsUInt8Number* PackXYZFloatFromFloat(_cmsTRANSFORM* Info,
@@ -3676,10 +3849,20 @@ static const cmsFormattersFloat OutputFormattersFloat[] = {
     {     TYPE_Lab_DBL,                                                ANYPLANAR|ANYEXTRA,   PackLabDoubleFromFloat},
     {     TYPE_XYZ_DBL,                                                ANYPLANAR|ANYEXTRA,   PackXYZDoubleFromFloat},
 
+    {     TYPE_LabV2_8,                                                ANYPLANAR|ANYEXTRA,   PackEncodedBytesLabV2FromFloat},
+    {     TYPE_LabV2_16,                                               ANYPLANAR|ANYEXTRA,   PackEncodedWordsLabV2FromFloat},
+
     {     FLOAT_SH(1)|BYTES_SH(4), ANYPLANAR|
                              ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE,   PackFloatsFromFloat },
     {     FLOAT_SH(1)|BYTES_SH(0), ANYPLANAR|
                              ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE,   PackDoublesFromFloat },
+
+    {     BYTES_SH(2), ANYPLANAR|
+                             ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE,   PackWordsFromFloat },
+
+    {     BYTES_SH(1), ANYPLANAR|
+                             ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE,   PackBytesFromFloat },
+
 #ifndef CMS_NO_HALF_SUPPORT
     {     FLOAT_SH(1)|BYTES_SH(2),
                              ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE,   PackHalfFromFloat },
@@ -3890,7 +4073,7 @@ cmsUInt32Number CMSEXPORT cmsFormatterForPCSOfProfile(cmsHPROFILE hProfile, cmsU
     cmsColorSpaceSignature ColorSpace = cmsGetPCS(hProfile);
 
     cmsUInt32Number ColorSpaceBits = (cmsUInt32Number) _cmsLCMScolorSpace(ColorSpace);
-    cmsUInt32Number nOutputChans = cmsChannelsOf(ColorSpace);
+    cmsInt32Number  nOutputChans = cmsChannelsOfColorSpace(ColorSpace);
     cmsUInt32Number Float = lIsFloat ? 1U : 0;
 
     // Unsupported color space?
diff --git a/src/java.desktop/share/native/liblcms/cmsplugin.c b/src/java.desktop/share/native/liblcms/cmsplugin.c
index c2808bb9278..f84e0172c81 100644
--- a/src/java.desktop/share/native/liblcms/cmsplugin.c
+++ b/src/java.desktop/share/native/liblcms/cmsplugin.c
@@ -393,12 +393,7 @@ cmsBool CMSEXPORT  _cmsWriteXYZNumber(cmsIOHANDLER* io, const cmsCIEXYZ* XYZ)
 // from Fixed point 8.8 to double
 cmsFloat64Number CMSEXPORT _cms8Fixed8toDouble(cmsUInt16Number fixed8)
 {
-       cmsUInt8Number  msb, lsb;
-
-       lsb = (cmsUInt8Number) (fixed8 & 0xff);
-       msb = (cmsUInt8Number) (((cmsUInt16Number) fixed8 >> 8) & 0xff);
-
-       return (cmsFloat64Number) ((cmsFloat64Number) msb + ((cmsFloat64Number) lsb / 256.0));
+    return fixed8 / 256.0;
 }
 
 cmsUInt16Number CMSEXPORT _cmsDoubleTo8Fixed8(cmsFloat64Number val)
@@ -410,19 +405,7 @@ cmsUInt16Number CMSEXPORT _cmsDoubleTo8Fixed8(cmsFloat64Number val)
 // from Fixed point 15.16 to double
 cmsFloat64Number CMSEXPORT _cms15Fixed16toDouble(cmsS15Fixed16Number fix32)
 {
-    cmsFloat64Number floater, sign, mid;
-    int Whole, FracPart;
-
-    sign  = (fix32 < 0 ? -1 : 1);
-    fix32 = abs(fix32);
-
-    Whole     = (cmsUInt16Number)(fix32 >> 16) & 0xffff;
-    FracPart  = (cmsUInt16Number)(fix32 & 0xffff);
-
-    mid     = (cmsFloat64Number) FracPart / 65536.0;
-    floater = (cmsFloat64Number) Whole + mid;
-
-    return sign * floater;
+    return fix32 / 65536.0;
 }
 
 // from double to Fixed point 15.16
diff --git a/src/java.desktop/share/native/liblcms/cmsps2.c b/src/java.desktop/share/native/liblcms/cmsps2.c
index 537f6854067..9a2ab464f31 100644
--- a/src/java.desktop/share/native/liblcms/cmsps2.c
+++ b/src/java.desktop/share/native/liblcms/cmsps2.c
@@ -460,48 +460,46 @@ void EmitLab2XYZ(cmsIOHANDLER* m)
     _cmsIOPrintf(m, "]\n");
 }
 
-static
-void EmitSafeGuardBegin(cmsIOHANDLER* m, const char* name)
-{
-    _cmsIOPrintf(m, "%%LCMS2: Save previous definition of %s on the operand stack\n", name);
-    _cmsIOPrintf(m, "currentdict /%s known { /%s load } { null } ifelse\n", name, name);
-}
 
-static
-void EmitSafeGuardEnd(cmsIOHANDLER* m, const char* name, int depth)
-{
-    _cmsIOPrintf(m, "%%LCMS2: Restore previous definition of %s\n", name);
-    if (depth > 1) {
-        // cycle topmost items on the stack to bring the previous definition to the front
-        _cmsIOPrintf(m, "%d -1 roll ", depth);
-    }
-    _cmsIOPrintf(m, "dup null eq { pop currentdict /%s undef } { /%s exch def } ifelse\n", name, name);
-}
 
 // Outputs a table of words. It does use 16 bits
 
 static
-void Emit1Gamma(cmsIOHANDLER* m, cmsToneCurve* Table, const char* name)
+void Emit1Gamma(cmsIOHANDLER* m, cmsToneCurve* Table)
 {
     cmsUInt32Number i;
     cmsFloat64Number gamma;
 
-    if (Table == NULL) return; // Error
+    /**
+    * On error, empty tables or lienar assume gamma 1.0
+    */
+    if (Table == NULL ||
+        Table->nEntries <= 0 ||
+        cmsIsToneCurveLinear(Table)) {
 
-    if (Table ->nEntries <= 0) return;  // Empty table
+        _cmsIOPrintf(m, "{ 1 } bind ");
+        return;
+    }
 
-    // Suppress whole if identity
-    if (cmsIsToneCurveLinear(Table)) return;
 
     // Check if is really an exponential. If so, emit "exp"
     gamma = cmsEstimateGamma(Table, 0.001);
      if (gamma > 0) {
-            _cmsIOPrintf(m, "/%s { %g exp } bind def\n", name, gamma);
+            _cmsIOPrintf(m, "{ %g exp } bind ", gamma);
             return;
      }
 
-    EmitSafeGuardBegin(m, "lcms2gammatable");
-    _cmsIOPrintf(m, "/lcms2gammatable [");
+    _cmsIOPrintf(m, "{ ");
+
+    // Bounds check
+    EmitRangeCheck(m);
+
+    // Emit intepolation code
+
+    // PostScript code                      Stack
+    // ===============                      ========================
+                                            // v
+    _cmsIOPrintf(m, " [");
 
     for (i=0; i < Table->nEntries; i++) {
     if (i % 10 == 0)
@@ -509,20 +507,8 @@ void Emit1Gamma(cmsIOHANDLER* m, cmsToneCurve* Table, const char* name)
         _cmsIOPrintf(m, "%d ", Table->Table16[i]);
     }
 
-    _cmsIOPrintf(m, "] def\n");
+    _cmsIOPrintf(m, "] ");                        // v tab
 
-
-    // Emit interpolation code
-
-    // PostScript code                            Stack
-    // ===============                            ========================
-                                                  // v
-    _cmsIOPrintf(m, "/%s {\n  ", name);
-
-    // Bounds check
-    EmitRangeCheck(m);
-
-    _cmsIOPrintf(m, "\n  //lcms2gammatable ");    // v tab
     _cmsIOPrintf(m, "dup ");                      // v tab tab
     _cmsIOPrintf(m, "length 1 sub ");             // v tab dom
     _cmsIOPrintf(m, "3 -1 roll ");                // tab dom v
@@ -549,9 +535,7 @@ void Emit1Gamma(cmsIOHANDLER* m, cmsToneCurve* Table, const char* name)
     _cmsIOPrintf(m, "add ");                      // y
     _cmsIOPrintf(m, "65535 div\n");               // result
 
-    _cmsIOPrintf(m, "} bind def\n");
-
-    EmitSafeGuardEnd(m, "lcms2gammatable", 1);
+    _cmsIOPrintf(m, " } bind ");
 }
 
 
@@ -568,10 +552,10 @@ cmsBool GammaTableEquals(cmsUInt16Number* g1, cmsUInt16Number* g2, cmsUInt32Numb
 // Does write a set of gamma curves
 
 static
-void EmitNGamma(cmsIOHANDLER* m, cmsUInt32Number n, cmsToneCurve* g[], const char* nameprefix)
+void EmitNGamma(cmsIOHANDLER* m, cmsUInt32Number n, cmsToneCurve* g[])
 {
     cmsUInt32Number i;
-    static char buffer[2048];
+
 
     for( i=0; i < n; i++ )
     {
@@ -579,12 +563,10 @@ void EmitNGamma(cmsIOHANDLER* m, cmsUInt32Number n, cmsToneCurve* g[], const cha
 
         if (i > 0 && GammaTableEquals(g[i-1]->Table16, g[i]->Table16, g[i-1]->nEntries, g[i]->nEntries)) {
 
-            _cmsIOPrintf(m, "/%s%d /%s%d load def\n", nameprefix, i, nameprefix, i-1);
+            _cmsIOPrintf(m, "dup ");
         }
         else {
-            snprintf(buffer, sizeof(buffer), "%s%d", nameprefix, (int) i);
-        buffer[sizeof(buffer)-1] = '\0';
-            Emit1Gamma(m, g[i], buffer);
+            Emit1Gamma(m, g[i]);
         }
     }
 
@@ -708,18 +690,21 @@ void WriteCLUT(cmsIOHANDLER* m, cmsStage* mpe, const char* PreMaj,
     sc.FixWhite = FixWhite;
     sc.ColorSpace = ColorSpace;
 
-    _cmsIOPrintf(m, "[");
+    if (sc.Pipeline != NULL && sc.Pipeline->Params != NULL) {
 
-    for (i=0; i < sc.Pipeline->Params->nInputs; i++)
-        _cmsIOPrintf(m, " %d ", sc.Pipeline->Params->nSamples[i]);
+        _cmsIOPrintf(m, "[");
 
-    _cmsIOPrintf(m, " [\n");
+        for (i = 0; i < sc.Pipeline->Params->nInputs; i++)
+            _cmsIOPrintf(m, " %d ", sc.Pipeline->Params->nSamples[i]);
 
-    cmsStageSampleCLut16bit(mpe, OutputValueSampler, (void*) &sc, SAMPLER_INSPECT);
+        _cmsIOPrintf(m, " [\n");
 
-    _cmsIOPrintf(m, PostMin);
-    _cmsIOPrintf(m, PostMaj);
-    _cmsIOPrintf(m, "] ");
+        cmsStageSampleCLut16bit(mpe, OutputValueSampler, (void*)&sc, SAMPLER_INSPECT);
+
+        _cmsIOPrintf(m, PostMin);
+        _cmsIOPrintf(m, PostMaj);
+        _cmsIOPrintf(m, "] ");
+    }
 
 }
 
@@ -733,11 +718,11 @@ int EmitCIEBasedA(cmsIOHANDLER* m, cmsToneCurve* Curve, cmsCIEXYZ* BlackPoint)
     _cmsIOPrintf(m, "[ /CIEBasedA\n");
     _cmsIOPrintf(m, "  <<\n");
 
-    EmitSafeGuardBegin(m, "lcms2gammaproc");
-    Emit1Gamma(m, Curve, "lcms2gammaproc");
+    _cmsIOPrintf(m, "/DecodeA ");
+
+    Emit1Gamma(m, Curve);
 
-    _cmsIOPrintf(m, "/DecodeA /lcms2gammaproc load\n");
-    EmitSafeGuardEnd(m, "lcms2gammaproc", 3);
+    _cmsIOPrintf(m, " \n");
 
     _cmsIOPrintf(m, "/MatrixA [ 0.9642 1.0000 0.8249 ]\n");
     _cmsIOPrintf(m, "/RangeLMN [ 0.0 0.9642 0.0 1.0000 0.0 0.8249 ]\n");
@@ -761,19 +746,11 @@ int EmitCIEBasedABC(cmsIOHANDLER* m, cmsFloat64Number* Matrix, cmsToneCurve** Cu
 
     _cmsIOPrintf(m, "[ /CIEBasedABC\n");
     _cmsIOPrintf(m, "<<\n");
+    _cmsIOPrintf(m, "/DecodeABC [ ");
+
+    EmitNGamma(m, 3, CurveSet);
 
-    EmitSafeGuardBegin(m, "lcms2gammaproc0");
-    EmitSafeGuardBegin(m, "lcms2gammaproc1");
-    EmitSafeGuardBegin(m, "lcms2gammaproc2");
-    EmitNGamma(m, 3, CurveSet, "lcms2gammaproc");
-    _cmsIOPrintf(m, "/DecodeABC [\n");
-    _cmsIOPrintf(m, "   /lcms2gammaproc0 load\n");
-    _cmsIOPrintf(m, "   /lcms2gammaproc1 load\n");
-    _cmsIOPrintf(m, "   /lcms2gammaproc2 load\n");
     _cmsIOPrintf(m, "]\n");
-    EmitSafeGuardEnd(m, "lcms2gammaproc2", 3);
-    EmitSafeGuardEnd(m, "lcms2gammaproc1", 3);
-    EmitSafeGuardEnd(m, "lcms2gammaproc0", 3);
 
     _cmsIOPrintf(m, "/MatrixABC [ " );
 
@@ -805,10 +782,8 @@ int EmitCIEBasedDEF(cmsIOHANDLER* m, cmsPipeline* Pipeline, cmsUInt32Number Inte
 {
     const char* PreMaj;
     const char* PostMaj;
-    const char* PreMin, * PostMin;
+    const char* PreMin, *PostMin;
     cmsStage* mpe;
-    int i, numchans;
-    static char buffer[2048];
 
     mpe = Pipeline->Elements;
 
@@ -837,34 +812,18 @@ int EmitCIEBasedDEF(cmsIOHANDLER* m, cmsPipeline* Pipeline, cmsUInt32Number Inte
 
     if (cmsStageType(mpe) == cmsSigCurveSetElemType) {
 
-        numchans = (int) cmsStageOutputChannels(mpe);
-        for (i = 0; i < numchans; ++i) {
-            snprintf(buffer, sizeof(buffer), "lcms2gammaproc%d", i);
-            buffer[sizeof(buffer) - 1] = '\0';
-            EmitSafeGuardBegin(m, buffer);
-        }
-        EmitNGamma(m, cmsStageOutputChannels(mpe), _cmsStageGetPtrToCurveSet(mpe), "lcms2gammaproc");
-        _cmsIOPrintf(m, "/DecodeDEF [\n");
-        for (i = 0; i < numchans; ++i) {
-            snprintf(buffer, sizeof(buffer), "  /lcms2gammaproc%d load\n", i);
-            buffer[sizeof(buffer) - 1] = '\0';
-            _cmsIOPrintf(m, buffer);
-        }
+        _cmsIOPrintf(m, "/DecodeDEF [ ");
+        EmitNGamma(m, cmsStageOutputChannels(mpe), _cmsStageGetPtrToCurveSet(mpe));
         _cmsIOPrintf(m, "]\n");
-        for (i = numchans - 1; i >= 0; --i) {
-            snprintf(buffer, sizeof(buffer), "lcms2gammaproc%d", i);
-            buffer[sizeof(buffer) - 1] = '\0';
-            EmitSafeGuardEnd(m, buffer, 3);
-        }
 
-        mpe = mpe->Next;
+        mpe = mpe ->Next;
     }
 
     if (cmsStageType(mpe) == cmsSigCLutElemType) {
 
-        _cmsIOPrintf(m, "/Table ");
-        WriteCLUT(m, mpe, PreMaj, PostMaj, PreMin, PostMin, FALSE, (cmsColorSpaceSignature)0);
-        _cmsIOPrintf(m, "]\n");
+            _cmsIOPrintf(m, "/Table ");
+            WriteCLUT(m, mpe, PreMaj, PostMaj, PreMin, PostMin, FALSE, (cmsColorSpaceSignature) 0);
+            _cmsIOPrintf(m, "]\n");
     }
 
     EmitLab2XYZ(m);
@@ -1024,9 +983,9 @@ int WriteInputMatrixShaper(cmsIOHANDLER* m, cmsHPROFILE hProfile, cmsStage* Matr
                 for (j = 0; j < 3; j++)
                     Mat.v[i].n[j] *= MAX_ENCODEABLE_XYZ;
 
-            rc = EmitCIEBasedABC(m, (cmsFloat64Number *)&Mat,
-                _cmsStageGetPtrToCurveSet(Shaper),
-                &BlackPointAdaptedToD50);
+            rc = EmitCIEBasedABC(m,  (cmsFloat64Number *) &Mat,
+                                _cmsStageGetPtrToCurveSet(Shaper),
+                                 &BlackPointAdaptedToD50);
         }
         else {
 
@@ -1053,10 +1012,15 @@ int WriteNamedColorCSA(cmsIOHANDLER* m, cmsHPROFILE hNamedColor, cmsUInt32Number
 
     hLab  = cmsCreateLab4ProfileTHR(m ->ContextID, NULL);
     xform = cmsCreateTransform(hNamedColor, TYPE_NAMED_COLOR_INDEX, hLab, TYPE_Lab_DBL, Intent, 0);
+    cmsCloseProfile(hLab);
+
     if (xform == NULL) return 0;
 
     NamedColorList = cmsGetNamedColorList(xform);
-    if (NamedColorList == NULL) return 0;
+    if (NamedColorList == NULL) {
+        cmsDeleteTransform(xform);
+        return 0;
+    }
 
     _cmsIOPrintf(m, "<<\n");
     _cmsIOPrintf(m, "(colorlistcomment) (%s)\n", "Named color CSA");
@@ -1065,7 +1029,6 @@ int WriteNamedColorCSA(cmsIOHANDLER* m, cmsHPROFILE hNamedColor, cmsUInt32Number
 
     nColors   = cmsNamedColorCount(NamedColorList);
 
-
     for (i=0; i < nColors; i++) {
 
         cmsUInt16Number In[1];
@@ -1080,12 +1043,9 @@ int WriteNamedColorCSA(cmsIOHANDLER* m, cmsHPROFILE hNamedColor, cmsUInt32Number
         _cmsIOPrintf(m, "  (%s) [ %.3f %.3f %.3f ]\n", ColorName, Lab.L, Lab.a, Lab.b);
     }
 
-
-
     _cmsIOPrintf(m, ">>\n");
 
     cmsDeleteTransform(xform);
-    cmsCloseProfile(hLab);
     return 1;
 }
 
@@ -1339,7 +1299,7 @@ int WriteOutputLUT(cmsIOHANDLER* m, cmsHPROFILE hProfile, cmsUInt32Number Intent
     cmsUInt32Number InFrm = TYPE_Lab_16;
     cmsUInt32Number RelativeEncodingIntent;
     cmsColorSpaceSignature ColorSpace;
-
+    cmsStage* first;
 
     hLab = cmsCreateLab4ProfileTHR(m ->ContextID, NULL);
     if (hLab == NULL) return 0;
@@ -1366,7 +1326,6 @@ int WriteOutputLUT(cmsIOHANDLER* m, cmsHPROFILE hProfile, cmsUInt32Number Intent
     cmsCloseProfile(hLab);
 
     if (xform == NULL) {
-
         cmsSignalError(m ->ContextID, cmsERROR_COLORSPACE_CHECK, "Cannot create transform Lab -> Profile in CRD creation");
         return 0;
     }
@@ -1374,10 +1333,12 @@ int WriteOutputLUT(cmsIOHANDLER* m, cmsHPROFILE hProfile, cmsUInt32Number Intent
     // Get a copy of the internal devicelink
     v = (_cmsTRANSFORM*) xform;
     DeviceLink = cmsPipelineDup(v ->Lut);
-    if (DeviceLink == NULL) return 0;
-
+    if (DeviceLink == NULL) {
+        cmsDeleteTransform(xform);
+        return 0;
+    }
 
-    // We need a CLUT
+     // We need a CLUT
     dwFlags |= cmsFLAGS_FORCE_CLUT;
     _cmsOptimizePipeline(m->ContextID, &DeviceLink, RelativeEncodingIntent, &InFrm, &OutputFormat, &dwFlags);
 
@@ -1404,8 +1365,10 @@ int WriteOutputLUT(cmsIOHANDLER* m, cmsHPROFILE hProfile, cmsUInt32Number Intent
 
     _cmsIOPrintf(m, "/RenderTable ");
 
-
-    WriteCLUT(m, cmsPipelineGetPtrToFirstStage(DeviceLink), "<", ">\n", "", "", lFixWhite, ColorSpace);
+    first = cmsPipelineGetPtrToFirstStage(DeviceLink);
+    if (first != NULL) {
+        WriteCLUT(m, first, "<", ">\n", "", "", lFixWhite, ColorSpace);
+    }
 
     _cmsIOPrintf(m, " %d {} bind ", nChannels);
 
@@ -1414,7 +1377,6 @@ int WriteOutputLUT(cmsIOHANDLER* m, cmsHPROFILE hProfile, cmsUInt32Number Intent
 
     _cmsIOPrintf(m, "]\n");
 
-
     EmitIntent(m, Intent);
 
     _cmsIOPrintf(m, ">>\n");
@@ -1477,7 +1439,10 @@ int WriteNamedColorCRD(cmsIOHANDLER* m, cmsHPROFILE hNamedColor, cmsUInt32Number
 
 
     NamedColorList = cmsGetNamedColorList(xform);
-    if (NamedColorList == NULL) return 0;
+    if (NamedColorList == NULL) {
+        cmsDeleteTransform(xform);
+        return 0;
+    }
 
     _cmsIOPrintf(m, "<<\n");
     _cmsIOPrintf(m, "(colorlistcomment) (%s) \n", "Named profile");
diff --git a/src/java.desktop/share/native/liblcms/cmssamp.c b/src/java.desktop/share/native/liblcms/cmssamp.c
index 8a01f7ec685..74f5f4bff29 100644
--- a/src/java.desktop/share/native/liblcms/cmssamp.c
+++ b/src/java.desktop/share/native/liblcms/cmssamp.c
@@ -152,7 +152,7 @@ cmsBool  BlackPointAsDarkerColorant(cmsHPROFILE    hInput,
     // Convert black to Lab
     cmsDoTransform(xform, Black, &Lab, 1);
 
-    // Force it to be neutral, check for inconsistences
+    // Force it to be neutral, check for inconsistencies
     Lab.a = Lab.b = 0;
     if (Lab.L > 50 || Lab.L < 0) Lab.L = 0;
 
diff --git a/src/java.desktop/share/native/liblcms/cmstypes.c b/src/java.desktop/share/native/liblcms/cmstypes.c
index 7b07b6b9cf4..862f393497a 100644
--- a/src/java.desktop/share/native/liblcms/cmstypes.c
+++ b/src/java.desktop/share/native/liblcms/cmstypes.c
@@ -122,7 +122,7 @@ cmsBool RegisterTypesPlugin(cmsContext id, cmsPluginBase* Data, _cmsMemoryClient
     return TRUE;
 }
 
-// Return handler for a given type or NULL if not found. Shared between normal types and MPE. It first tries the additons
+// Return handler for a given type or NULL if not found. Shared between normal types and MPE. It first tries the additions
 // made by plug-ins and then the built-in defaults.
 static
 cmsTagTypeHandler* GetHandler(cmsTagTypeSignature sig, _cmsTagTypeLinkedList* PluginLinkedList, _cmsTagTypeLinkedList* DefaultLinkedList)
@@ -954,6 +954,7 @@ static
 void *Type_Text_Description_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
 {
     char* Text = NULL;
+    wchar_t* UnicodeString = NULL;
     cmsMLU* mlu = NULL;
     cmsUInt32Number  AsciiCount;
     cmsUInt32Number  i, UnicodeCode, UnicodeCount;
@@ -973,7 +974,7 @@ void *Type_Text_Description_Read(struct _cms_typehandler_struct* self, cmsIOHAND
     if (SizeOfTag < AsciiCount) return NULL;
 
     // All seems Ok, allocate the container
-    mlu = cmsMLUalloc(self ->ContextID, 1);
+    mlu = cmsMLUalloc(self ->ContextID, 2);
     if (mlu == NULL) return NULL;
 
     // As many memory as size of tag
@@ -998,15 +999,30 @@ void *Type_Text_Description_Read(struct _cms_typehandler_struct* self, cmsIOHAND
     if (!_cmsReadUInt32Number(io, &UnicodeCount)) goto Done;
     SizeOfTag -= 2* sizeof(cmsUInt32Number);
 
-    if (SizeOfTag < UnicodeCount*sizeof(cmsUInt16Number)) goto Done;
+    if (UnicodeCount == 0 || SizeOfTag < UnicodeCount*sizeof(cmsUInt16Number)) goto Done;
+
+    UnicodeString = (wchar_t*)_cmsMallocZero(self->ContextID, (UnicodeCount + 1) * sizeof(wchar_t));
+    if (UnicodeString == NULL) goto Done;
+
+    if (!_cmsReadWCharArray(io, UnicodeCount, UnicodeString)) {
+        _cmsFree(self->ContextID, (void*)UnicodeString);
+        goto Done;
+    }
+
+    UnicodeString[UnicodeCount] = 0;
 
-    for (i=0; i < UnicodeCount; i++) {
-        if (!io ->Read(io, &Dummy, sizeof(cmsUInt16Number), 1)) goto Done;
+    if (!cmsMLUsetWide(mlu, cmsV2Unicode, cmsV2Unicode, UnicodeString)) {
+        _cmsFree(self->ContextID, (void*)UnicodeString);
+        goto Done;
     }
+
+    _cmsFree(self->ContextID, (void*)UnicodeString);
+    UnicodeString = NULL;
+
     SizeOfTag -= UnicodeCount*sizeof(cmsUInt16Number);
 
     // Skip ScriptCode code if present. Some buggy profiles does have less
-    // data that stricttly required. We need to skip it as this type may come
+    // data that strictly required. We need to skip it as this type may come
     // embedded in other types.
 
     if (SizeOfTag >= sizeof(cmsUInt16Number) + sizeof(cmsUInt8Number) + 67) {
@@ -1026,6 +1042,7 @@ void *Type_Text_Description_Read(struct _cms_typehandler_struct* self, cmsIOHAND
     return mlu;
 
 Error:
+    if (UnicodeString)  _cmsFree(self->ContextID, (void*)UnicodeString);
     if (Text) _cmsFree(self ->ContextID, (void*) Text);
     if (mlu) cmsMLUfree(mlu);
     return NULL;
@@ -1078,7 +1095,7 @@ cmsBool  Type_Text_Description_Write(struct _cms_typehandler_struct* self, cmsIO
 
         // Get both representations.
         cmsMLUgetASCII(mlu, cmsNoLanguage, cmsNoCountry,  Text, len * sizeof(char));
-        cmsMLUgetWide(mlu,  cmsNoLanguage, cmsNoCountry,  Wide, len * sizeof(wchar_t));
+        cmsMLUgetWide(mlu,  cmsV2Unicode,  cmsV2Unicode,  Wide, len * sizeof(wchar_t));
     }
 
     // Tell the real text len including the null terminator and padding
@@ -1577,8 +1594,6 @@ void *Type_MLU_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsU
     if (SizeOfTag == 0)
     {
         Block = NULL;
-        NumOfWchar = 0;
-
     }
     else
     {
@@ -1940,7 +1955,7 @@ void *Type_LUT8_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cms
 
 // We only allow a specific MPE structure: Matrix plus prelin, plus clut, plus post-lin.
 static
-cmsBool  Type_LUT8_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
+cmsBool Type_LUT8_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
 {
     cmsUInt32Number j, nTabSize, i;
     cmsUInt8Number  val;
@@ -1953,6 +1968,12 @@ cmsBool  Type_LUT8_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io,
 
     // Disassemble the LUT into components.
     mpe = NewLUT -> Elements;
+
+    if (mpe == NULL) {  // Should never be empty. Corrupted?
+        cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "empty LUT8 is not supported");
+        return FALSE;
+    }
+
     if (mpe ->Type == cmsSigMatrixElemType) {
 
         if (mpe->InputChannels != 3 || mpe->OutputChannels != 3) return FALSE;
@@ -2694,8 +2715,8 @@ cmsBool WriteSetOfCurves(struct _cms_typehandler_struct* self, cmsIOHANDLER* io,
         // If this is a table-based curve, use curve type even on V4
         CurrentType = Type;
 
-        if ((Curves[i] ->nSegments == 0)||
-            ((Curves[i]->nSegments == 2) && (Curves[i] ->Segments[1].Type == 0)) )
+        if ((Curves[i] ->nSegments == 0) ||                                         // 16 bits tabulated
+            ((Curves[i]->nSegments == 3) && (Curves[i] ->Segments[1].Type == 0)) )  // Floating-point tabulated
             CurrentType = cmsSigCurveType;
         else
         if (Curves[i] ->Segments[0].Type < 0)
@@ -4459,8 +4480,8 @@ void *Type_MPEclut_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io,
     if (!_cmsReadUInt16Number(io, &InputChans)) return NULL;
     if (!_cmsReadUInt16Number(io, &OutputChans)) return NULL;
 
-    if (InputChans == 0) goto Error;
-    if (OutputChans == 0) goto Error;
+    if (InputChans == 0 || InputChans >= cmsMAXCHANNELS) goto Error;
+    if (OutputChans == 0 || OutputChans >= cmsMAXCHANNELS) goto Error;
 
     if (io ->Read(io, Dimensions8, sizeof(cmsUInt8Number), 16) != 16)
         goto Error;
@@ -5250,11 +5271,13 @@ cmsBool WriteOneMLUC(struct _cms_typehandler_struct* self, cmsIOHANDLER* io,  _c
     }
 
     Before = io ->Tell(io);
-    e ->Offsets[i] = Before - BaseOffset;
+    if (e->Offsets != NULL)
+        e ->Offsets[i] = Before - BaseOffset;
 
     if (!Type_MLU_Write(self, io, (void*) mlu, 1)) return FALSE;
 
-    e ->Sizes[i] = io ->Tell(io) - Before;
+    if (e->Sizes != NULL)
+        e ->Sizes[i] = io ->Tell(io) - Before;
     return TRUE;
 }
 
@@ -5499,6 +5522,216 @@ void Type_VideoSignal_Free(struct _cms_typehandler_struct* self, void* Ptr)
     _cmsFree(self->ContextID, Ptr);
 }
 
+
+// ********************************************************************************
+// Microsoft's MHC2 Type support
+// ********************************************************************************
+
+static
+void SetIdentity(cmsFloat64Number XYZ2XYZmatrix[3][4])
+{
+    XYZ2XYZmatrix[0][0] = 1.0; XYZ2XYZmatrix[0][1] = 0.0; XYZ2XYZmatrix[0][2] = 0.0; XYZ2XYZmatrix[0][3] = 0.0;
+    XYZ2XYZmatrix[1][0] = 0.0; XYZ2XYZmatrix[1][1] = 1.0; XYZ2XYZmatrix[1][2] = 0.0; XYZ2XYZmatrix[1][3] = 0.0;
+    XYZ2XYZmatrix[2][0] = 0.0; XYZ2XYZmatrix[2][1] = 0.0; XYZ2XYZmatrix[2][2] = 1.0; XYZ2XYZmatrix[2][3] = 0.0;
+}
+
+static
+cmsBool CloseEnough(cmsFloat64Number a, cmsFloat64Number b)
+{
+    return fabs(b - a) < (1.0 / 65535.0);
+}
+
+cmsBool IsIdentity(cmsFloat64Number XYZ2XYZmatrix[3][4])
+{
+    cmsFloat64Number Identity[3][4];
+    int i, j;
+
+    SetIdentity(Identity);
+
+    for (i = 0; i < 3; i++)
+        for (j = 0; j < 4; j++)
+            if (!CloseEnough(XYZ2XYZmatrix[i][j], Identity[i][j])) return FALSE;
+
+    return TRUE;
+}
+
+static
+void Type_MHC2_Free(struct _cms_typehandler_struct* self, void* Ptr)
+{
+    cmsMHC2Type* mhc2 = (cmsMHC2Type*)Ptr;
+
+    if (mhc2->RedCurve != NULL) _cmsFree(self->ContextID, mhc2->RedCurve);
+    if (mhc2->GreenCurve != NULL) _cmsFree(self->ContextID, mhc2->GreenCurve);
+    if (mhc2->BlueCurve != NULL) _cmsFree(self->ContextID, mhc2->BlueCurve);
+
+    _cmsFree(self->ContextID, Ptr);
+}
+
+void* Type_MHC2_Dup(struct _cms_typehandler_struct* self, const void* Ptr, cmsUInt32Number n)
+{
+    cmsMHC2Type* mhc2 = _cmsDupMem(self->ContextID, Ptr, sizeof(cmsMHC2Type));
+
+    mhc2->RedCurve = _cmsDupMem(self->ContextID,   mhc2->RedCurve, mhc2->CurveEntries*sizeof(cmsFloat64Number));
+    mhc2->GreenCurve = _cmsDupMem(self->ContextID, mhc2->GreenCurve, mhc2->CurveEntries * sizeof(cmsFloat64Number));
+    mhc2->BlueCurve = _cmsDupMem(self->ContextID,  mhc2->BlueCurve, mhc2->CurveEntries * sizeof(cmsFloat64Number));
+
+    if (mhc2->RedCurve == NULL ||
+        mhc2->GreenCurve == NULL ||
+        mhc2->BlueCurve == NULL) {
+
+        Type_MHC2_Free(self, mhc2);
+        return NULL;
+    }
+
+    return mhc2;
+
+    cmsUNUSED_PARAMETER(n);
+}
+
+
+static
+cmsBool WriteDoubles(cmsIOHANDLER* io, cmsUInt32Number n, cmsFloat64Number* Values)
+{
+    cmsUInt32Number i;
+
+    for (i = 0; i < n; i++) {
+
+        if (!_cmsWrite15Fixed16Number(io, *Values++)) return FALSE;
+    }
+
+    return TRUE;
+}
+
+static
+cmsBool Type_MHC2_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
+{
+    cmsMHC2Type* mhc2 = (cmsMHC2Type*)Ptr;
+    cmsUInt32Number BaseOffset = io->Tell(io) - sizeof(_cmsTagBase);
+    cmsUInt32Number TablesOffsetPos;
+    cmsUInt32Number MatrixOffset;
+    cmsUInt32Number OffsetRedTable, OffsetGreenTable, OffsetBlueTable;
+
+    if (!_cmsWriteUInt32Number(io, 0)) return FALSE;
+    if (!_cmsWriteUInt32Number(io, mhc2->CurveEntries)) return FALSE;
+
+    if (!_cmsWrite15Fixed16Number(io, mhc2->MinLuminance)) return FALSE;
+    if (!_cmsWrite15Fixed16Number(io, mhc2->PeakLuminance)) return FALSE;
+
+    TablesOffsetPos = io->Tell(io);
+
+    if (!_cmsWriteUInt32Number(io, 0)) return FALSE;    // Matrix
+    if (!_cmsWriteUInt32Number(io, 0)) return FALSE;    // Curve R
+    if (!_cmsWriteUInt32Number(io, 0)) return FALSE;    // Curve G
+    if (!_cmsWriteUInt32Number(io, 0)) return FALSE;    // Curve B
+
+
+    if (IsIdentity(mhc2->XYZ2XYZmatrix))
+    {
+        MatrixOffset = 0;
+    }
+    else
+    {
+        MatrixOffset = io->Tell(io) - BaseOffset;
+        if (!WriteDoubles(io, 3 * 4, &mhc2->XYZ2XYZmatrix[0][0])) return FALSE;
+    }
+
+    OffsetRedTable = io->Tell(io) - BaseOffset;
+    if (!WriteDoubles(io, mhc2->CurveEntries, mhc2->RedCurve)) return FALSE;
+    OffsetGreenTable = io->Tell(io) - BaseOffset;
+    if (!WriteDoubles(io, mhc2->CurveEntries, mhc2->GreenCurve)) return FALSE;
+    OffsetBlueTable = io->Tell(io) - BaseOffset;
+    if (!WriteDoubles(io, mhc2->CurveEntries, mhc2->BlueCurve)) return FALSE;
+
+    if (!io->Seek(io, TablesOffsetPos)) return FALSE;
+
+    if (!_cmsWriteUInt32Number(io, MatrixOffset)) return FALSE;
+    if (!_cmsWriteUInt32Number(io, OffsetRedTable)) return FALSE;
+    if (!_cmsWriteUInt32Number(io, OffsetGreenTable)) return FALSE;
+    if (!_cmsWriteUInt32Number(io, OffsetBlueTable)) return FALSE;
+
+    return TRUE;
+
+    cmsUNUSED_PARAMETER(self);
+    cmsUNUSED_PARAMETER(nItems);
+}
+
+
+static
+cmsBool ReadDoublesAt(cmsIOHANDLER* io, cmsUInt32Number At, cmsUInt32Number n, cmsFloat64Number* Values)
+{
+    cmsUInt32Number CurrentPos = io->Tell(io);
+    cmsUInt32Number i;
+
+    if (!io->Seek(io, At)) return FALSE;
+
+    for (i = 0; i < n; i++) {
+
+        if (!_cmsRead15Fixed16Number(io, Values++)) return FALSE;
+    }
+
+    if (!io->Seek(io, CurrentPos)) return FALSE;
+
+    return TRUE;
+}
+
+static
+void* Type_MHC2_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
+{
+    cmsMHC2Type* mhc2 = NULL;
+
+    cmsUInt32Number BaseOffset = io->Tell(io) - sizeof(_cmsTagBase);
+    cmsUInt32Number MatrixOffset;
+    cmsUInt32Number OffsetRedTable, OffsetGreenTable, OffsetBlueTable;
+
+    if (!_cmsReadUInt32Number(io, NULL)) return NULL;
+
+    mhc2 = (cmsMHC2Type*)_cmsCalloc(self->ContextID, 1, sizeof(cmsMHC2Type));
+    if (mhc2 == NULL) return NULL;
+
+    if (!_cmsReadUInt32Number(io,    &mhc2->CurveEntries)) goto Error;
+
+    if (mhc2->CurveEntries > 4096) goto Error;
+
+    mhc2->RedCurve = (cmsFloat64Number*)_cmsCalloc(self->ContextID, mhc2->CurveEntries, sizeof(cmsFloat64Number));
+    mhc2->GreenCurve = (cmsFloat64Number*)_cmsCalloc(self->ContextID, mhc2->CurveEntries, sizeof(cmsFloat64Number));
+    mhc2->BlueCurve = (cmsFloat64Number*)_cmsCalloc(self->ContextID, mhc2->CurveEntries, sizeof(cmsFloat64Number));
+
+    if (mhc2->RedCurve == NULL ||
+        mhc2->GreenCurve == NULL ||
+        mhc2->BlueCurve == NULL)  goto Error;
+
+    if (!_cmsRead15Fixed16Number(io, &mhc2->MinLuminance)) goto Error;
+    if (!_cmsRead15Fixed16Number(io, &mhc2->PeakLuminance)) goto Error;
+
+    if (!_cmsReadUInt32Number(io, &MatrixOffset)) goto Error;
+    if (!_cmsReadUInt32Number(io, &OffsetRedTable)) goto Error;
+    if (!_cmsReadUInt32Number(io, &OffsetGreenTable)) goto Error;
+    if (!_cmsReadUInt32Number(io, &OffsetBlueTable)) goto Error;
+
+    if (MatrixOffset == 0)
+        SetIdentity(mhc2->XYZ2XYZmatrix);
+    else
+    {
+        if (!ReadDoublesAt(io, BaseOffset + MatrixOffset, 3*4, &mhc2->XYZ2XYZmatrix[0][0])) goto Error;
+    }
+
+    if (!ReadDoublesAt(io, BaseOffset + OffsetRedTable, mhc2->CurveEntries, mhc2->RedCurve)) goto Error;
+    if (!ReadDoublesAt(io, BaseOffset + OffsetGreenTable, mhc2->CurveEntries, mhc2->GreenCurve)) goto Error;
+    if (!ReadDoublesAt(io, BaseOffset + OffsetBlueTable, mhc2->CurveEntries, mhc2->BlueCurve)) goto Error;
+
+    // Success
+    *nItems = 1;
+    return mhc2;
+
+Error:
+    Type_MHC2_Free(self, mhc2);
+    return NULL;
+
+    cmsUNUSED_PARAMETER(SizeOfTag);
+}
+
+
+
 // ********************************************************************************
 // Type support main routines
 // ********************************************************************************
@@ -5538,7 +5771,8 @@ static const _cmsTagTypeLinkedList SupportedTagTypes[] = {
 {TYPE_HANDLER(cmsSigProfileSequenceIdType,     ProfileSequenceId),  (_cmsTagTypeLinkedList*) &SupportedTagTypes[29] },
 {TYPE_HANDLER(cmsSigDictType,                  Dictionary),         (_cmsTagTypeLinkedList*) &SupportedTagTypes[30] },
 {TYPE_HANDLER(cmsSigcicpType,                  VideoSignal),        (_cmsTagTypeLinkedList*) &SupportedTagTypes[31] },
-{TYPE_HANDLER(cmsSigVcgtType,                  vcgt),                NULL }
+{TYPE_HANDLER(cmsSigVcgtType,                  vcgt),               (_cmsTagTypeLinkedList*) &SupportedTagTypes[32] },
+{TYPE_HANDLER(cmsSigMHC2Type,                  MHC2),                NULL }
 };
 
 
@@ -5734,7 +5968,8 @@ static _cmsTagLinkedList SupportedTags[] = {
     { cmsSigProfileDescriptionMLTag,{ 1, 1, { cmsSigMultiLocalizedUnicodeType}, NULL}, &SupportedTags[63]},
     { cmsSigcicpTag,                { 1, 1, { cmsSigcicpType},               NULL },   &SupportedTags[64]},
 
-    { cmsSigArgyllArtsTag,          { 9, 1, { cmsSigS15Fixed16ArrayType},    NULL}, NULL}
+    { cmsSigArgyllArtsTag,          { 9, 1, { cmsSigS15Fixed16ArrayType},    NULL}, &SupportedTags[65]},
+    { cmsSigMHC2Tag,                { 1, 1, { cmsSigMHC2Type },              NULL}, NULL}
 
 };
 
diff --git a/src/java.desktop/share/native/liblcms/cmsvirt.c b/src/java.desktop/share/native/liblcms/cmsvirt.c
index 6ce04796174..e8d18d4ca9f 100644
--- a/src/java.desktop/share/native/liblcms/cmsvirt.c
+++ b/src/java.desktop/share/native/liblcms/cmsvirt.c
@@ -435,10 +435,9 @@ cmsHPROFILE CMSEXPORT cmsCreateInkLimitingDeviceLinkTHR(cmsContext ContextID,
 
     if (Limit < 0.0 || Limit > 400) {
 
-        cmsSignalError(ContextID, cmsERROR_RANGE, "InkLimiting: Limit should be between 0..400");
-        if (Limit < 0) Limit = 0;
+        cmsSignalError(ContextID, cmsERROR_RANGE, "InkLimiting: Limit should be between 1..400");
+        if (Limit < 1) Limit = 1;
         if (Limit > 400) Limit = 400;
-
     }
 
     hICC = cmsCreateProfilePlaceholder(ContextID);
@@ -701,6 +700,127 @@ cmsHPROFILE CMSEXPORT cmsCreate_sRGBProfile(void)
     return cmsCreate_sRGBProfileTHR(NULL);
 }
 
+/**
+* Oklab colorspace profile (experimental)
+*
+* This virtual profile cannot be saved as an ICC file
+*/
+cmsHPROFILE cmsCreate_OkLabProfile(cmsContext ctx)
+{
+    cmsStage* XYZPCS = _cmsStageNormalizeFromXyzFloat(ctx);
+    cmsStage* PCSXYZ = _cmsStageNormalizeToXyzFloat(ctx);
+
+    const double M_D65_D50[] =
+    {
+       1.047886, 0.022919, -0.050216,
+       0.029582, 0.990484, -0.017079,
+      -0.009252, 0.015073,  0.751678
+    };
+
+    const double M_D50_D65[] =
+    {
+         0.955512609517083, -0.023073214184645,  0.063308961782107,
+        -0.028324949364887,  1.009942432477107,  0.021054814890112,
+         0.012328875695483, -0.020535835374141,  1.330713916450354
+    };
+
+    cmsStage* D65toD50 = cmsStageAllocMatrix(ctx, 3, 3, M_D65_D50, NULL);
+    cmsStage* D50toD65 = cmsStageAllocMatrix(ctx, 3, 3, M_D50_D65, NULL);
+
+    const double M_D65_LMS[] =
+    {
+        0.8189330101, 0.3618667424, -0.1288597137,
+        0.0329845436, 0.9293118715,  0.0361456387,
+        0.0482003018, 0.2643662691,  0.6338517070
+    };
+
+    const double M_LMS_D65[] =
+    {
+        1.227013851103521, -0.557799980651822,  0.281256148966468,
+       -0.040580178423281,  1.112256869616830, -0.071676678665601,
+       -0.076381284505707, -0.421481978418013,  1.586163220440795
+    };
+
+    cmsStage* D65toLMS = cmsStageAllocMatrix(ctx, 3, 3, M_D65_LMS, NULL);
+    cmsStage* LMStoD65 = cmsStageAllocMatrix(ctx, 3, 3, M_LMS_D65, NULL);
+
+    cmsToneCurve* CubeRoot = cmsBuildGamma(ctx, 1.0 / 3.0);
+    cmsToneCurve* Cube     = cmsBuildGamma(ctx,  3.0);
+
+    cmsToneCurve* Roots[3] = { CubeRoot, CubeRoot, CubeRoot };
+    cmsToneCurve* Cubes[3] = { Cube, Cube, Cube };
+
+    cmsStage* NonLinearityFw = cmsStageAllocToneCurves(ctx, 3, Roots);
+    cmsStage* NonLinearityRv = cmsStageAllocToneCurves(ctx, 3, Cubes);
+
+    const double M_LMSprime_OkLab[] =
+    {
+        0.2104542553,  0.7936177850, -0.0040720468,
+        1.9779984951, -2.4285922050,  0.4505937099,
+        0.0259040371,  0.7827717662, -0.8086757660
+    };
+
+    const double M_OkLab_LMSprime[] =
+    {
+        0.999999998450520,  0.396337792173768,  0.215803758060759,
+        1.000000008881761, -0.105561342323656, -0.063854174771706,
+        1.000000054672411, -0.089484182094966, -1.291485537864092
+    };
+
+    cmsStage* LMSprime_OkLab = cmsStageAllocMatrix(ctx, 3, 3, M_LMSprime_OkLab, NULL);
+    cmsStage* OkLab_LMSprime = cmsStageAllocMatrix(ctx, 3, 3, M_OkLab_LMSprime, NULL);
+
+    cmsPipeline* AToB = cmsPipelineAlloc(ctx, 3, 3);
+    cmsPipeline* BToA = cmsPipelineAlloc(ctx, 3, 3);
+
+    cmsHPROFILE hProfile = cmsCreateProfilePlaceholder(ctx);
+
+    cmsSetProfileVersion(hProfile, 4.4);
+
+    cmsSetDeviceClass(hProfile, cmsSigColorSpaceClass);
+    cmsSetColorSpace(hProfile, cmsSig3colorData);
+    cmsSetPCS(hProfile, cmsSigXYZData);
+
+    cmsSetHeaderRenderingIntent(hProfile, INTENT_RELATIVE_COLORIMETRIC);
+
+    /**
+    * Conversion PCS (XYZ/D50) to OkLab
+    */
+    if (!cmsPipelineInsertStage(BToA, cmsAT_END, PCSXYZ)) goto error;
+    if (!cmsPipelineInsertStage(BToA, cmsAT_END, D50toD65)) goto error;
+    if (!cmsPipelineInsertStage(BToA, cmsAT_END, D65toLMS)) goto error;
+    if (!cmsPipelineInsertStage(BToA, cmsAT_END, NonLinearityFw)) goto error;
+    if (!cmsPipelineInsertStage(BToA, cmsAT_END, LMSprime_OkLab)) goto error;
+
+    if (!cmsWriteTag(hProfile, cmsSigBToA0Tag, BToA)) goto error;
+
+    if (!cmsPipelineInsertStage(AToB, cmsAT_END, OkLab_LMSprime)) goto error;
+    if (!cmsPipelineInsertStage(AToB, cmsAT_END, NonLinearityRv)) goto error;
+    if (!cmsPipelineInsertStage(AToB, cmsAT_END, LMStoD65)) goto error;
+    if (!cmsPipelineInsertStage(AToB, cmsAT_END, D65toD50)) goto error;
+    if (!cmsPipelineInsertStage(AToB, cmsAT_END, XYZPCS)) goto error;
+
+    if (!cmsWriteTag(hProfile, cmsSigAToB0Tag, AToB)) goto error;
+
+    cmsPipelineFree(BToA);
+    cmsPipelineFree(AToB);
+
+    cmsFreeToneCurve(CubeRoot);
+    cmsFreeToneCurve(Cube);
+
+    return hProfile;
+
+error:
+    cmsPipelineFree(BToA);
+    cmsPipelineFree(AToB);
+
+    cmsFreeToneCurve(CubeRoot);
+    cmsFreeToneCurve(Cube);
+    cmsCloseProfile(hProfile);
+
+    return NULL;
+
+}
 
 
 typedef struct {
@@ -1060,7 +1180,7 @@ cmsBool CheckOne(const cmsAllowedLUT* Tab, const cmsPipeline* Lut)
 
     for (n=0, mpe = Lut ->Elements; mpe != NULL; mpe = mpe ->Next, n++) {
 
-        if (n > Tab ->nTypes) return FALSE;
+        if (n >= Tab ->nTypes) return FALSE;
         if (cmsStageType(mpe) != Tab ->MpeTypes[n]) return FALSE;
     }
 
@@ -1091,9 +1211,9 @@ const cmsAllowedLUT* FindCombination(const cmsPipeline* Lut, cmsBool IsV4, cmsTa
 cmsHPROFILE CMSEXPORT cmsTransform2DeviceLink(cmsHTRANSFORM hTransform, cmsFloat64Number Version, cmsUInt32Number dwFlags)
 {
     cmsHPROFILE hProfile = NULL;
-        cmsUInt32Number FrmIn, FrmOut;
-        cmsInt32Number ChansIn, ChansOut;
-        int ColorSpaceBitsIn, ColorSpaceBitsOut;
+    cmsUInt32Number FrmIn, FrmOut;
+    cmsInt32Number ChansIn, ChansOut;
+    int ColorSpaceBitsIn, ColorSpaceBitsOut;
     _cmsTRANSFORM* xform = (_cmsTRANSFORM*) hTransform;
     cmsPipeline* LUT = NULL;
     cmsStage* mpe;
@@ -1104,6 +1224,9 @@ cmsHPROFILE CMSEXPORT cmsTransform2DeviceLink(cmsHTRANSFORM hTransform, cmsFloat
 
     _cmsAssert(hTransform != NULL);
 
+    // Check if the pipeline holding is valid
+    if (xform -> Lut == NULL) return NULL;
+
     // Get the first mpe to check for named color
     mpe = cmsPipelineGetPtrToFirstStage(xform ->Lut);
 
diff --git a/src/java.desktop/share/native/liblcms/cmsxform.c b/src/java.desktop/share/native/liblcms/cmsxform.c
index 3f3ad28c6c4..86afd7202fd 100644
--- a/src/java.desktop/share/native/liblcms/cmsxform.c
+++ b/src/java.desktop/share/native/liblcms/cmsxform.c
@@ -943,7 +943,7 @@ _cmsTRANSFORM* AllocEmptyTransform(cmsContext ContextID, cmsPipeline* lut,
        }
 
     // Check whatever this is a true floating point transform
-    if (_cmsFormatterIsFloat(*OutputFormat)) {
+    if (_cmsFormatterIsFloat(*InputFormat) || _cmsFormatterIsFloat(*OutputFormat)) {
 
         // Get formatter function always return a valid union, but the contents of this union may be NULL.
         p ->FromInputFloat = _cmsGetFormatter(ContextID, *InputFormat,  cmsFormatterInput, CMS_PACK_FLAGS_FLOAT).FmtFloat;
@@ -1018,6 +1018,19 @@ _cmsTRANSFORM* AllocEmptyTransform(cmsContext ContextID, cmsPipeline* lut,
         }
     }
 
+    /**
+    * Check consistency for alpha channel copy
+    */
+    if (*dwFlags & cmsFLAGS_COPY_ALPHA)
+    {
+        if (T_EXTRA(*InputFormat) != T_EXTRA(*OutputFormat))
+        {
+            cmsSignalError(ContextID, cmsERROR_NOT_SUITABLE, "Mismatched alpha channels");
+            cmsDeleteTransform(p);
+            return NULL;
+        }
+    }
+
     p ->InputFormat     = *InputFormat;
     p ->OutputFormat    = *OutputFormat;
     p ->dwOriginalFlags = *dwFlags;
diff --git a/src/java.desktop/share/native/liblcms/lcms2.h b/src/java.desktop/share/native/liblcms/lcms2.h
index d5b8c477f23..2d9a8b1248f 100644
--- a/src/java.desktop/share/native/liblcms/lcms2.h
+++ b/src/java.desktop/share/native/liblcms/lcms2.h
@@ -52,7 +52,7 @@
 //
 //---------------------------------------------------------------------------------
 //
-// Version 2.15
+// Version 2.16
 //
 
 #ifndef _lcms2_H
@@ -105,12 +105,15 @@
 
 #ifndef CMS_USE_CPP_API
 #   ifdef __cplusplus
+#       if __cplusplus >= 201703L
+#            define CMS_NO_REGISTER_KEYWORD 1
+#       endif
 extern "C" {
 #   endif
 #endif
 
 // Version/release
-#define LCMS_VERSION        2150
+#define LCMS_VERSION        2160
 
 // I will give the chance of redefining basic types for compilers that are not fully C99 compliant
 #ifndef CMS_BASIC_TYPES_ALREADY_DEFINED
@@ -354,7 +357,8 @@ typedef enum {
     cmsSigUInt8ArrayType                    = 0x75693038,  // 'ui08'
     cmsSigVcgtType                          = 0x76636774,  // 'vcgt'
     cmsSigViewingConditionsType             = 0x76696577,  // 'view'
-    cmsSigXYZType                           = 0x58595A20   // 'XYZ '
+    cmsSigXYZType                           = 0x58595A20,  // 'XYZ '
+    cmsSigMHC2Type                          = 0x4D484332   // 'MHC2'
 
 
 } cmsTagTypeSignature;
@@ -432,7 +436,8 @@ typedef enum {
     cmsSigVcgtTag                           = 0x76636774,  // 'vcgt'
     cmsSigMetaTag                           = 0x6D657461,  // 'meta'
     cmsSigcicpTag                           = 0x63696370,  // 'cicp'
-    cmsSigArgyllArtsTag                     = 0x61727473   // 'arts'
+    cmsSigArgyllArtsTag                     = 0x61727473,  // 'arts'
+    cmsSigMHC2Tag                           = 0x4D484332   // 'MHC2'
 
 } cmsTagSignature;
 
@@ -977,6 +982,7 @@ typedef void* cmsHTRANSFORM;
 #define TYPE_RGB_DBL          (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(0))
 #define TYPE_BGR_DBL          (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(0)|DOSWAP_SH(1))
 #define TYPE_CMYK_DBL         (FLOAT_SH(1)|COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(0))
+#define TYPE_OKLAB_DBL        (FLOAT_SH(1)|COLORSPACE_SH(PT_MCH3)|CHANNELS_SH(3)|BYTES_SH(0))
 
 // IEEE 754-2008 "half"
 #define TYPE_GRAY_HALF_FLT    (FLOAT_SH(1)|COLORSPACE_SH(PT_GRAY)|CHANNELS_SH(1)|BYTES_SH(2))
@@ -1077,6 +1083,19 @@ typedef struct {
 
 } cmsVideoSignalType;
 
+typedef struct {
+    cmsUInt32Number   CurveEntries;
+    cmsFloat64Number* RedCurve;
+    cmsFloat64Number* GreenCurve;
+    cmsFloat64Number* BlueCurve;
+
+    cmsFloat64Number  MinLuminance;         // ST.2086 min luminance in nits
+    cmsFloat64Number  PeakLuminance;        // ST.2086 peak luminance in nits
+
+    cmsFloat64Number XYZ2XYZmatrix[3][4];
+
+} cmsMHC2Type;
+
 
 
 // Get LittleCMS version (for shared objects) -----------------------------------------------------------------------------
@@ -1249,7 +1268,8 @@ CMSAPI cmsBool           CMSEXPORT cmsIsToneCurveMonotonic(const cmsToneCurve* t
 CMSAPI cmsBool           CMSEXPORT cmsIsToneCurveDescending(const cmsToneCurve* t);
 CMSAPI cmsInt32Number    CMSEXPORT cmsGetToneCurveParametricType(const cmsToneCurve* t);
 CMSAPI cmsFloat64Number  CMSEXPORT cmsEstimateGamma(const cmsToneCurve* t, cmsFloat64Number Precision);
-CMSAPI cmsFloat64Number* CMSEXPORT cmsGetToneCurveParams(const cmsToneCurve* t);
+
+CMSAPI const cmsCurveSegment* CMSEXPORT cmsGetToneCurveSegment(cmsInt32Number n, const cmsToneCurve* t);
 
 // Tone curve tabular estimation
 CMSAPI cmsUInt32Number         CMSEXPORT cmsGetToneCurveEstimatedTableEntries(const cmsToneCurve* t);
@@ -1343,8 +1363,11 @@ CMSAPI cmsBool           CMSEXPORT cmsSliceSpaceFloat(cmsUInt32Number nInputs, c
 
 typedef struct _cms_MLU_struct cmsMLU;
 
-#define  cmsNoLanguage "\0\0"
-#define  cmsNoCountry  "\0\0"
+#define  cmsNoLanguage    "\0\0"
+#define  cmsNoCountry     "\0\0"
+
+// Special language/country to retrieve unicode field for description in V2 profiles. Use with care.
+#define  cmsV2Unicode     "\xff\xff"
 
 CMSAPI cmsMLU*           CMSEXPORT cmsMLUalloc(cmsContext ContextID, cmsUInt32Number nItems);
 CMSAPI void              CMSEXPORT cmsMLUfree(cmsMLU* mlu);
@@ -1356,6 +1379,9 @@ CMSAPI cmsBool           CMSEXPORT cmsMLUsetASCII(cmsMLU* mlu,
 CMSAPI cmsBool           CMSEXPORT cmsMLUsetWide(cmsMLU* mlu,
                                                   const char LanguageCode[3], const char CountryCode[3],
                                                   const wchar_t* WideString);
+CMSAPI cmsBool           CMSEXPORT cmsMLUsetUTF8(cmsMLU* mlu,
+                                                  const char LanguageCode[3], const char CountryCode[3],
+                                                  const char* UTF8String);
 
 CMSAPI cmsUInt32Number   CMSEXPORT cmsMLUgetASCII(const cmsMLU* mlu,
                                                   const char LanguageCode[3], const char CountryCode[3],
@@ -1364,6 +1390,10 @@ CMSAPI cmsUInt32Number   CMSEXPORT cmsMLUgetASCII(const cmsMLU* mlu,
 CMSAPI cmsUInt32Number   CMSEXPORT cmsMLUgetWide(const cmsMLU* mlu,
                                                  const char LanguageCode[3], const char CountryCode[3],
                                                  wchar_t* Buffer, cmsUInt32Number BufferSize);
+CMSAPI cmsUInt32Number   CMSEXPORT cmsMLUgetUTF8(const cmsMLU* mlu,
+                                                 const char LanguageCode[3], const char CountryCode[3],
+                                                 char* Buffer, cmsUInt32Number BufferSize);
+
 
 CMSAPI cmsBool           CMSEXPORT cmsMLUgetTranslation(const cmsMLU* mlu,
                                                          const char LanguageCode[3], const char CountryCode[3],
@@ -1588,6 +1618,10 @@ CMSAPI cmsUInt32Number   CMSEXPORT cmsGetProfileInfoASCII(cmsHPROFILE hProfile,
                                                             const char LanguageCode[3], const char CountryCode[3],
                                                             char* Buffer, cmsUInt32Number BufferSize);
 
+CMSAPI cmsUInt32Number  CMSEXPORT cmsGetProfileInfoUTF8(cmsHPROFILE hProfile, cmsInfoType Info,
+                                                            const char LanguageCode[3], const char CountryCode[3],
+                                                            char* Buffer, cmsUInt32Number BufferSize);
+
 // IO handlers ----------------------------------------------------------------------------------------------------------
 
 typedef struct _cms_io_handler cmsIOHANDLER;
@@ -1650,6 +1684,9 @@ CMSAPI cmsHPROFILE      CMSEXPORT cmsCreateInkLimitingDeviceLinkTHR(cmsContext C
 
 CMSAPI cmsHPROFILE      CMSEXPORT cmsCreateInkLimitingDeviceLink(cmsColorSpaceSignature ColorSpace, cmsFloat64Number Limit);
 
+CMSAPI cmsHPROFILE      CMSEXPORT cmsCreateDeviceLinkFromCubeFile(const char* cFileName);
+
+CMSAPI cmsHPROFILE      CMSEXPORT cmsCreateDeviceLinkFromCubeFileTHR(cmsContext ContextID, const char* cFileName);
 
 CMSAPI cmsHPROFILE      CMSEXPORT cmsCreateLab2ProfileTHR(cmsContext ContextID, const cmsCIExyY* WhitePoint);
 CMSAPI cmsHPROFILE      CMSEXPORT cmsCreateLab2Profile(const cmsCIExyY* WhitePoint);
@@ -1662,6 +1699,8 @@ CMSAPI cmsHPROFILE      CMSEXPORT cmsCreateXYZProfile(void);
 CMSAPI cmsHPROFILE      CMSEXPORT cmsCreate_sRGBProfileTHR(cmsContext ContextID);
 CMSAPI cmsHPROFILE      CMSEXPORT cmsCreate_sRGBProfile(void);
 
+CMSAPI cmsHPROFILE      CMSEXPORT cmsCreate_OkLabProfile(cmsContext ctx);
+
 CMSAPI cmsHPROFILE      CMSEXPORT cmsCreateBCHSWabstractProfileTHR(cmsContext ContextID,
                                                              cmsUInt32Number nLUTPoints,
                                                              cmsFloat64Number Bright,
diff --git a/src/java.desktop/share/native/liblcms/lcms2_internal.h b/src/java.desktop/share/native/liblcms/lcms2_internal.h
index 4c29a6c0218..75973edad0d 100644
--- a/src/java.desktop/share/native/liblcms/lcms2_internal.h
+++ b/src/java.desktop/share/native/liblcms/lcms2_internal.h
@@ -288,6 +288,7 @@ typedef CRITICAL_SECTION _cmsMutex;
 #ifdef _MSC_VER
 #    if (_MSC_VER >= 1800)
 #          pragma warning(disable : 26135)
+#          pragma warning(disable : 4127)
 #    endif
 #endif
 
@@ -545,7 +546,7 @@ struct _cmsContext_struct {
     struct _cmsContext_struct* Next;  // Points to next context in the new style
     _cmsSubAllocator* MemPool;        // The memory pool that stores context data
 
-    void* chunks[MemoryClientMax];    // array of pointers to client chunks. Memory itself is hold in the suballocator.
+    void* chunks[MemoryClientMax];    // array of pointers to client chunks. Memory itself is held in the suballocator.
                                       // If NULL, then it reverts to global Context0
 
     _cmsMemPluginChunkType DefaultMemoryManager;  // The allocators used for creating the context itself. Cannot be overridden
@@ -839,6 +840,9 @@ typedef struct _cms_iccprofile_struct {
     // Creation time
     struct tm                Created;
 
+    // Color management module identification
+    cmsUInt32Number          CMM;
+
     // Only most important items found in ICC profiles
     cmsUInt32Number          Version;
     cmsProfileClassSignature DeviceClass;
@@ -846,6 +850,7 @@ typedef struct _cms_iccprofile_struct {
     cmsColorSpaceSignature   PCS;
     cmsUInt32Number          RenderingIntent;
 
+    cmsPlatformSignature     platform;
     cmsUInt32Number          flags;
     cmsUInt32Number          manufacturer, model;
     cmsUInt64Number          attributes;
diff --git a/src/java.desktop/unix/classes/sun/awt/UNIXToolkit.java b/src/java.desktop/unix/classes/sun/awt/UNIXToolkit.java
index 03693e6eb8d..191a12092a1 100644
--- a/src/java.desktop/unix/classes/sun/awt/UNIXToolkit.java
+++ b/src/java.desktop/unix/classes/sun/awt/UNIXToolkit.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2004, 2024, 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,6 +33,7 @@
 import static java.awt.RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_VBGR;
 import static java.awt.RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_VRGB;
 import static java.awt.RenderingHints.VALUE_TEXT_ANTIALIAS_ON;
+import static java.util.concurrent.TimeUnit.SECONDS;
 
 import java.awt.color.ColorSpace;
 
@@ -47,6 +48,9 @@
 import java.awt.image.DataBufferByte;
 import java.awt.image.Raster;
 import java.awt.image.WritableRaster;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
 import java.util.Arrays;
@@ -240,6 +244,72 @@ protected Object lazilyLoadGTKIcon(String longname) {
         return img;
     }
 
+    private static volatile Boolean shouldDisableSystemTray = null;
+
+    /**
+     * There is an issue displaying the xembed icons in appIndicators
+     * area with certain Gnome Shell versions.
+     * To avoid any loss of quality of service, we are disabling
+     * SystemTray support in such cases.
+     *
+     * @return true if system tray should be disabled
+     */
+    public boolean shouldDisableSystemTray() {
+        Boolean result = shouldDisableSystemTray;
+        if (result == null) {
+            synchronized (GTK_LOCK) {
+                result = shouldDisableSystemTray;
+                if (result == null) {
+                    if ("gnome".equals(getDesktop())) {
+                        @SuppressWarnings("removal")
+                        Integer gnomeShellMajorVersion =
+                                AccessController
+                                        .doPrivileged((PrivilegedAction)
+                                                this::getGnomeShellMajorVersion);
+
+                        if (gnomeShellMajorVersion == null
+                                || gnomeShellMajorVersion < 45) {
+
+                            return shouldDisableSystemTray = true;
+                        }
+                    }
+                    shouldDisableSystemTray = result = false;
+                }
+            }
+        }
+        return result;
+    }
+
+    private Integer getGnomeShellMajorVersion() {
+        try {
+            Process process =
+                new ProcessBuilder("/usr/bin/gnome-shell", "--version")
+                        .start();
+            try (InputStreamReader isr = new InputStreamReader(process.getInputStream());
+                 BufferedReader reader = new BufferedReader(isr)) {
+
+                if (process.waitFor(2, SECONDS) &&  process.exitValue() == 0) {
+                    String line = reader.readLine();
+                    if (line != null) {
+                        String[] versionComponents = line
+                                .replaceAll("[^\\d.]", "")
+                                .split("\\.");
+
+                        if (versionComponents.length >= 1) {
+                            return Integer.parseInt(versionComponents[0]);
+                        }
+                    }
+                }
+            }
+        } catch (IOException
+                 | InterruptedException
+                 | IllegalThreadStateException
+                 | NumberFormatException ignored) {
+        }
+
+        return null;
+    }
+
     /**
      * Returns a BufferedImage which contains the Gtk icon requested.  If no
      * such icon exists or an error occurs loading the icon the result will
diff --git a/src/java.desktop/unix/classes/sun/awt/X11/XSystemTrayPeer.java b/src/java.desktop/unix/classes/sun/awt/X11/XSystemTrayPeer.java
index 1a9d040616e..cdbb74ddac1 100644
--- a/src/java.desktop/unix/classes/sun/awt/X11/XSystemTrayPeer.java
+++ b/src/java.desktop/unix/classes/sun/awt/X11/XSystemTrayPeer.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2024, 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 sun.awt.SunToolkit;
 import sun.awt.AppContext;
 import sun.awt.AWTAccessor;
+import sun.awt.UNIXToolkit;
 import sun.util.logging.PlatformLogger;
 
 public class XSystemTrayPeer implements SystemTrayPeer, XMSelectionListener {
@@ -48,22 +49,32 @@ public class XSystemTrayPeer implements SystemTrayPeer, XMSelectionListener {
     private static final XAtom _NET_SYSTEM_TRAY_OPCODE = XAtom.get("_NET_SYSTEM_TRAY_OPCODE");
     private static final XAtom _NET_WM_ICON = XAtom.get("_NET_WM_ICON");
     private static final long SYSTEM_TRAY_REQUEST_DOCK = 0;
+    private final boolean shouldDisableSystemTray;
 
     XSystemTrayPeer(SystemTray target) {
         this.target = target;
         peerInstance = this;
 
-        selection.addSelectionListener(this);
+        UNIXToolkit tk = (UNIXToolkit)Toolkit.getDefaultToolkit();
+        shouldDisableSystemTray = tk.shouldDisableSystemTray();
 
-        long selection_owner = selection.getOwner(SCREEN);
-        available = (selection_owner != XConstants.None);
+        if (!shouldDisableSystemTray) {
+            selection.addSelectionListener(this);
 
-        if (log.isLoggable(PlatformLogger.Level.FINE)) {
-            log.fine(" check if system tray is available. selection owner: " + selection_owner);
+            long selection_owner = selection.getOwner(SCREEN);
+            available = (selection_owner != XConstants.None);
+
+            if (log.isLoggable(PlatformLogger.Level.FINE)) {
+                log.fine(" check if system tray is available. selection owner: " + selection_owner);
+            }
         }
     }
 
     public void ownerChanged(int screen, XMSelection sel, long newOwner, long data, long timestamp) {
+        if (shouldDisableSystemTray) {
+            return;
+        }
+
         if (screen != SCREEN) {
             return;
         }
@@ -77,6 +88,10 @@ public void ownerChanged(int screen, XMSelection sel, long newOwner, long data,
     }
 
     public void ownerDeath(int screen, XMSelection sel, long deadOwner) {
+        if (shouldDisableSystemTray) {
+            return;
+        }
+
         if (screen != SCREEN) {
             return;
         }
diff --git a/src/java.desktop/windows/native/libawt/windows/ThemeReader.cpp b/src/java.desktop/windows/native/libawt/windows/ThemeReader.cpp
index 08e03d00959..12c2677e32a 100644
--- a/src/java.desktop/windows/native/libawt/windows/ThemeReader.cpp
+++ b/src/java.desktop/windows/native/libawt/windows/ThemeReader.cpp
@@ -46,6 +46,7 @@ typedef HRESULT(__stdcall *PFNCLOSETHEMEDATA)(HTHEME hTheme);
 typedef HRESULT(__stdcall *PFNDRAWTHEMEBACKGROUND)(HTHEME hTheme, HDC hdc,
         int iPartId, int iStateId, const RECT *pRect,  const RECT *pClipRect);
 
+typedef HTHEME(__stdcall *PFNOPENTHEMEDATA)(HWND hwnd, LPCWSTR pszClassList);
 typedef HTHEME(__stdcall *PFNOPENTHEMEDATAFORDPI)(HWND hwnd, LPCWSTR pszClassList, UINT dpi);
 
 typedef HRESULT (__stdcall *PFNDRAWTHEMETEXT)(HTHEME hTheme, HDC hdc,
@@ -90,6 +91,7 @@ typedef HRESULT (__stdcall *PFNGETTHEMETRANSITIONDURATION)
                 (HTHEME hTheme, int iPartId, int iStateIdFrom, int iStateIdTo,
                  int iPropId, DWORD *pdwDuration);
 
+static PFNOPENTHEMEDATA OpenThemeDataFunc = NULL;
 static PFNOPENTHEMEDATAFORDPI OpenThemeDataForDpiFunc = NULL;
 static PFNDRAWTHEMEBACKGROUND DrawThemeBackgroundFunc = NULL;
 static PFNCLOSETHEMEDATA CloseThemeDataFunc = NULL;
@@ -109,13 +111,17 @@ static PFNISTHEMEBACKGROUNDPARTIALLYTRANSPARENT
                                IsThemeBackgroundPartiallyTransparentFunc = NULL;
 static PFNGETTHEMETRANSITIONDURATION GetThemeTransitionDurationFunc = NULL;
 
+constexpr unsigned int defaultDPI = 96;
 
-BOOL InitThemes() {
+
+static BOOL InitThemes() {
     static HMODULE hModThemes = NULL;
     hModThemes = JDK_LoadSystemLibrary("UXTHEME.DLL");
     DTRACE_PRINTLN1("InitThemes hModThemes = %x\n", hModThemes);
     if(hModThemes) {
         DTRACE_PRINTLN("Loaded UxTheme.dll\n");
+        OpenThemeDataFunc = (PFNOPENTHEMEDATA)GetProcAddress(hModThemes,
+                                                         "OpenThemeData");
         OpenThemeDataForDpiFunc = (PFNOPENTHEMEDATAFORDPI)GetProcAddress(
                                    hModThemes, "OpenThemeDataForDpi");
         DrawThemeBackgroundFunc = (PFNDRAWTHEMEBACKGROUND)GetProcAddress(
@@ -152,7 +158,7 @@ BOOL InitThemes() {
             (PFNGETTHEMETRANSITIONDURATION)GetProcAddress(hModThemes,
                                         "GetThemeTransitionDuration");
 
-        if(OpenThemeDataForDpiFunc
+        if((OpenThemeDataForDpiFunc || OpenThemeDataFunc)
            && DrawThemeBackgroundFunc
            && CloseThemeDataFunc
            && DrawThemeTextFunc
@@ -173,10 +179,12 @@ BOOL InitThemes() {
               DTRACE_PRINTLN("Loaded function pointers.\n");
               // We need to make sure we can load the Theme.
               // Use the default DPI value of 96 on windows.
-              constexpr unsigned int defaultDPI = 96;
-              HTHEME hTheme = OpenThemeDataForDpiFunc (
-                              AwtToolkit::GetInstance().GetHWnd(),
-                              L"Button", defaultDPI);
+              HTHEME hTheme = OpenThemeDataForDpiFunc
+                              ? OpenThemeDataForDpiFunc(AwtToolkit::GetInstance().GetHWnd(),
+                                                        L"Button", defaultDPI)
+                              : OpenThemeDataFunc(AwtToolkit::GetInstance().GetHWnd(),
+                                                  L"Button");
+
               if(hTheme) {
                   DTRACE_PRINTLN("Loaded Theme data.\n");
                   CloseThemeDataFunc(hTheme);
@@ -246,11 +254,13 @@ JNIEXPORT jlong JNICALL Java_sun_awt_windows_ThemeReader_openTheme
         JNU_ThrowOutOfMemoryError(env, 0);
         return 0;
     }
+
     // We need to open the Theme on a Window that will stick around.
     // The best one for that purpose is the Toolkit window.
-    HTHEME htheme = OpenThemeDataForDpiFunc(
-                    AwtToolkit::GetInstance().GetHWnd(),
-                    str, dpi);
+    HTHEME htheme = OpenThemeDataForDpiFunc
+                    ? OpenThemeDataForDpiFunc(AwtToolkit::GetInstance().GetHWnd(), str, dpi)
+                    : OpenThemeDataFunc(AwtToolkit::GetInstance().GetHWnd(), str);
+
     JNU_ReleaseStringPlatformChars(env, widget, str);
     return (jlong) htheme;
 }
@@ -430,9 +440,14 @@ JNIEXPORT void JNICALL Java_sun_awt_windows_ThemeReader_paintBackground
 
     rect.left = 0;
     rect.top = 0;
-    rect.bottom = rectBottom;
-    rect.right = rectRight;
 
+    if (OpenThemeDataForDpiFunc) {
+        rect.bottom = rectBottom;
+        rect.right = rectRight;
+    } else {
+        rect.bottom = h;
+        rect.right = w;
+    }
     ZeroMemory(pSrcBits,(BITS_PER_PIXEL>>3)*w*h);
 
     HRESULT hres = DrawThemeBackgroundFunc(hTheme, memDC, part, state, &rect, NULL);
@@ -455,6 +470,28 @@ JNIEXPORT void JNICALL Java_sun_awt_windows_ThemeReader_paintBackground
     ReleaseDC(NULL,defaultDC);
 }
 
+static void rescale(SIZE *size) {
+    static int dpiX = -1;
+    static int dpiY = -1;
+
+    if (dpiX == -1 || dpiY == -1) {
+        HWND hWnd = ::GetDesktopWindow();
+        HDC hDC = ::GetDC(hWnd);
+        dpiX = ::GetDeviceCaps(hDC, LOGPIXELSX);
+        dpiY = ::GetDeviceCaps(hDC, LOGPIXELSY);
+        ::ReleaseDC(hWnd, hDC);
+    }
+
+    if (dpiX !=0 && dpiX != defaultDPI) {
+        float invScaleX = (float) defaultDPI / dpiX;
+        size->cx = (int) round(size->cx * invScaleX);
+    }
+    if (dpiY != 0 && dpiY != defaultDPI) {
+        float invScaleY = (float) defaultDPI / dpiY;
+        size->cy = (int) round(size->cy * invScaleY);
+    }
+}
+
 jobject newInsets(JNIEnv *env, jint top, jint left, jint bottom, jint right) {
     if (env->EnsureLocalCapacity(2) < 0) {
         return NULL;
@@ -746,6 +783,10 @@ JNIEXPORT jobject JNICALL Java_sun_awt_windows_ThemeReader_getPartSize
                 CHECK_NULL_RETURN(dimMID, NULL);
             }
 
+            if (!OpenThemeDataForDpiFunc) {
+                rescale(&size);
+            }
+
             jobject dimObj = env->NewObject(dimClassID, dimMID, size.cx, size.cy);
             if (safe_ExceptionOccurred(env)) {
                 env->ExceptionDescribe();
diff --git a/src/java.desktop/windows/native/libawt/windows/awt_Debug.cpp b/src/java.desktop/windows/native/libawt/windows/awt_Debug.cpp
index 88dc0f17abe..148170b5a9a 100644
--- a/src/java.desktop/windows/native/libawt/windows/awt_Debug.cpp
+++ b/src/java.desktop/windows/native/libawt/windows/awt_Debug.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2024, 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
@@ -153,21 +153,20 @@ AwtDebugSupport::~AwtDebugSupport() {
 static jboolean isHeadless() {
     jmethodID headlessFn;
     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
-    jclass graphicsEnvClass = env->FindClass(
-        "java/awt/GraphicsEnvironment");
+    // be on the safe side and avoid JNI warnings by calling ExceptionCheck
+    // an accumulated exception is not cleared
+    env->ExceptionCheck();
+    jclass graphicsEnvClass = env->FindClass("java/awt/GraphicsEnvironment");
 
     if (graphicsEnvClass != NULL) {
-        headlessFn = env->GetStaticMethodID(
-            graphicsEnvClass, "isHeadless", "()Z");
+        headlessFn = env->GetStaticMethodID(graphicsEnvClass, "isHeadless", "()Z");
         if (headlessFn != NULL) {
-            return env->CallStaticBooleanMethod(graphicsEnvClass,
-                                                headlessFn);
+            return env->CallStaticBooleanMethod(graphicsEnvClass, headlessFn);
         }
     }
     return true;
 }
 
-
 void AwtDebugSupport::AssertCallback(const char * expr, const char * file, int line) {
     static const int ASSERT_MSG_SIZE = 1024;
     static const char * AssertFmt =
@@ -177,9 +176,9 @@ void AwtDebugSupport::AssertCallback(const char * expr, const char * file, int l
             "Do you want to break into the debugger?";
 
     static char assertMsg[ASSERT_MSG_SIZE+1];
-    DWORD   lastError = GetLastError();
-    LPSTR       msgBuffer = NULL;
-    int     ret = IDNO;
+    DWORD lastError = GetLastError();
+    LPSTR msgBuffer = NULL;
+    int ret = IDNO;
     static jboolean headless = isHeadless();
 
     DWORD fret= FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/ConnectionPool.java b/src/java.net.http/share/classes/jdk/internal/net/http/ConnectionPool.java
index 0288eb84099..0ad7b9d5992 100644
--- a/src/java.net.http/share/classes/jdk/internal/net/http/ConnectionPool.java
+++ b/src/java.net.http/share/classes/jdk/internal/net/http/ConnectionPool.java
@@ -108,14 +108,10 @@ public boolean equals(Object obj) {
                 return false;
             }
             if (secure && destination != null) {
-                if (destination.getHostName() != null) {
-                    if (!destination.getHostName().equalsIgnoreCase(
-                            other.destination.getHostName())) {
-                        return false;
-                    }
-                } else {
-                    if (other.destination.getHostName() != null)
-                        return false;
+                String hostString = destination.getHostString();
+                if (hostString == null || !hostString.equalsIgnoreCase(
+                        other.destination.getHostString())) {
+                    return false;
                 }
             }
             return true;
diff --git a/src/java.rmi/share/man/rmiregistry.1 b/src/java.rmi/share/man/rmiregistry.1
index 499a5885dd9..1ee99e83e1f 100644
--- a/src/java.rmi/share/man/rmiregistry.1
+++ b/src/java.rmi/share/man/rmiregistry.1
@@ -35,7 +35,7 @@
 . ftr VB CB
 . ftr VBI CBI
 .\}
-.TH "RMIREGISTRY" "1" "2024" "JDK 22-ea" "JDK Commands"
+.TH "RMIREGISTRY" "1" "2024" "JDK 22" "JDK Commands"
 .hy
 .SH NAME
 .PP
diff --git a/src/java.scripting/share/man/jrunscript.1 b/src/java.scripting/share/man/jrunscript.1
index 9e980755b0f..3074714fd56 100644
--- a/src/java.scripting/share/man/jrunscript.1
+++ b/src/java.scripting/share/man/jrunscript.1
@@ -35,7 +35,7 @@
 . ftr VB CB
 . ftr VBI CBI
 .\}
-.TH "JRUNSCRIPT" "1" "2024" "JDK 22-ea" "JDK Commands"
+.TH "JRUNSCRIPT" "1" "2024" "JDK 22" "JDK Commands"
 .hy
 .SH NAME
 .PP
diff --git a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/PropertyManager.java b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/PropertyManager.java
index da21fb4a511..c8d032109a0 100644
--- a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/PropertyManager.java
+++ b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/PropertyManager.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2024, 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
@@ -46,7 +46,7 @@
  * @author K Venugopal
  * @author Sunitha Reddy
  *
- * @LastModified: Nov 2023
+ * @LastModified: Jan 2024
  */
 public class PropertyManager {
 
@@ -184,6 +184,9 @@ public boolean containsProperty(String property) {
      * @return the value of a property
      */
     public Object getProperty(String property) {
+        if (XMLInputFactory.SUPPORT_DTD.equals(property)) {
+            return fSecurityManager.is(XMLSecurityManager.Limit.STAX_SUPPORT_DTD);
+        }
         /**
          * Check to see if the property is managed by the security manager *
          */
diff --git a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLEntityManager.java b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLEntityManager.java
index 6e5663bfa2c..f922849d5fa 100644
--- a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLEntityManager.java
+++ b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/impl/XMLEntityManager.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2024, Oracle and/or its affiliates. All rights reserved.
  */
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
@@ -94,7 +94,7 @@
  * @author K.Venugopal SUN Microsystems
  * @author Neeraj Bajaj SUN Microsystems
  * @author Sunitha Reddy SUN Microsystems
- * @LastModified: Nov 2023
+ * @LastModified: Jan 2024
  */
 public class XMLEntityManager implements XMLComponent, XMLEntityResolver {
 
@@ -1038,8 +1038,9 @@ public StaxXMLInputSource resolveEntityAsPerStax(XMLResourceIdentifier resourceI
         }
 
         // Step 2: custom catalog if specified
-        if ((publicId != null || literalSystemId != null) &&
-                staxInputSource == null && (fUseCatalog && fCatalogFile != null)) {
+        if (staxInputSource == null
+                && (publicId != null || literalSystemId != null)
+                && (fUseCatalog && fCatalogFile != null)) {
             if (fCatalogResolver == null) {
                 fCatalogFeatures = JdkXmlUtils.getCatalogFeatures(fDefer, fCatalogFile, fPrefer, fResolve);
                 fCatalogResolver = CatalogManager.catalogResolver(fCatalogFeatures);
@@ -1049,8 +1050,9 @@ public StaxXMLInputSource resolveEntityAsPerStax(XMLResourceIdentifier resourceI
         }
 
         // Step 3: use the default JDK Catalog Resolver if Step 2's resolve is continue
-        if ((publicId != null || literalSystemId != null) &&
-                staxInputSource == null && JdkXmlUtils.isResolveContinue(fCatalogFeatures)) {
+        if (staxInputSource == null
+                && (publicId != null || literalSystemId != null)
+                && JdkXmlUtils.isResolveContinue(fCatalogFeatures)) {
             initJdkCatalogResolver();
 
             staxInputSource = resolveWithCatalogStAX(fDefCR, JdkCatalog.JDKCATALOG, publicId, literalSystemId);
@@ -1061,9 +1063,9 @@ public StaxXMLInputSource resolveEntityAsPerStax(XMLResourceIdentifier resourceI
         // Note if both publicId and systemId are null, the resolution process continues as usual
         if (staxInputSource != null) {
             fISCreatedByResolver = true;
-        } else if ((publicId == null && literalSystemId == null) ||
-                (JdkXmlUtils.isResolveContinue(fCatalogFeatures) &&
-                fSecurityManager.is(Limit.JDKCATALOG_RESOLVE, JdkConstants.CONTINUE))) {
+        } else if ((publicId == null && literalSystemId == null)
+                || (JdkXmlUtils.isResolveContinue(fCatalogFeatures)
+                && fSecurityManager.is(Limit.JDKCATALOG_RESOLVE, JdkConstants.CONTINUE))) {
             staxInputSource = new StaxXMLInputSource(
                     new XMLInputSource(publicId, literalSystemId, baseSystemId, true), false);
         }
@@ -1206,8 +1208,9 @@ public XMLInputSource resolveEntity(XMLResourceIdentifier resourceIdentifier) th
         }
 
         // Step 2: custom catalog if specified
-        if ((publicId != null || literalSystemId != null || resourceIdentifier.getNamespace() !=null)
-                && xmlInputSource == null && (fUseCatalog && fCatalogFile != null)) {
+        if (xmlInputSource == null
+                && (publicId != null || literalSystemId != null || resourceIdentifier.getNamespace() !=null)
+                && (fUseCatalog && fCatalogFile != null)) {
             if (fCatalogResolver == null) {
                 fCatalogFeatures = JdkXmlUtils.getCatalogFeatures(fDefer, fCatalogFile, fPrefer, fResolve);
                 fCatalogResolver = CatalogManager.catalogResolver(fCatalogFeatures);
@@ -1217,8 +1220,9 @@ public XMLInputSource resolveEntity(XMLResourceIdentifier resourceIdentifier) th
         }
 
         // Step 3: use the default JDK Catalog Resolver if Step 2's resolve is continue
-        if ((publicId != null || literalSystemId != null)
-                && xmlInputSource == null && JdkXmlUtils.isResolveContinue(fCatalogFeatures)) {
+        if (xmlInputSource == null
+                && (publicId != null || literalSystemId != null)
+                && JdkXmlUtils.isResolveContinue(fCatalogFeatures)) {
             initJdkCatalogResolver();
             // unlike a custom catalog, the JDK Catalog only contains entity references
             xmlInputSource = resolveEntity(fDefCR, publicId, literalSystemId, baseSystemId);
@@ -1226,11 +1230,13 @@ public XMLInputSource resolveEntity(XMLResourceIdentifier resourceIdentifier) th
 
         // Step 4: default resolution if not resolved by a resolver and the RESOLVE
         // feature is set to 'continue'
-        // Note if both publicId and systemId are null, the resolution process continues as usual
-        if ((publicId == null && literalSystemId == null) ||
-                ((xmlInputSource == null) && JdkXmlUtils.isResolveContinue(fCatalogFeatures) &&
-                fSecurityManager.is(Limit.JDKCATALOG_RESOLVE, JdkConstants.CONTINUE))) {
-            xmlInputSource = new XMLInputSource(publicId, literalSystemId, baseSystemId, false);
+        if (xmlInputSource == null) {
+            // Note if both publicId and systemId are null, the resolution process continues as usual
+            if ((publicId == null && literalSystemId == null) ||
+                    (JdkXmlUtils.isResolveContinue(fCatalogFeatures) &&
+                    fSecurityManager.is(Limit.JDKCATALOG_RESOLVE, JdkConstants.CONTINUE))) {
+                xmlInputSource = new XMLInputSource(publicId, literalSystemId, baseSystemId, false);
+            }
         }
 
         return xmlInputSource;
diff --git a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/parsers/AbstractSAXParser.java b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/parsers/AbstractSAXParser.java
index ff4e047d4ca..614bd2fdc99 100644
--- a/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/parsers/AbstractSAXParser.java
+++ b/src/java.xml/share/classes/com/sun/org/apache/xerces/internal/parsers/AbstractSAXParser.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved.
  */
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
@@ -79,7 +79,7 @@
  * @author Arnaud Le Hors, IBM
  * @author Andy Clark, IBM
  *
- * @LastModified: July 2023
+ * @LastModified: Jan 2024
  */
 @SuppressWarnings("deprecation")
 public abstract class AbstractSAXParser
@@ -1831,6 +1831,11 @@ else if (featureId.startsWith(XERCES_FEATURES_PREFIX)) {
             }
             */
 
+            // Handle properties managed by XMLSecurityManager
+            if (featureId.equals(XMLSecurityManager.DISALLOW_DTD)) {
+                return securityManager.is(XMLSecurityManager.Limit.XERCES_DISALLOW_DTD);
+            }
+
             return fConfiguration.getFeature(featureId);
         }
         catch (XMLConfigurationException e) {
diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/ThisEscapeAnalyzer.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/ThisEscapeAnalyzer.java
index 0dd32fd8eca..f6ce19fac06 100644
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/ThisEscapeAnalyzer.java
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/ThisEscapeAnalyzer.java
@@ -506,7 +506,7 @@ public void visitMethodDef(JCMethodDecl tree) {
     public void visitApply(JCMethodInvocation invoke) {
 
         // Get method symbol
-        MethodSymbol sym = (MethodSymbol)TreeInfo.symbolFor(invoke.meth);
+        Symbol sym = TreeInfo.symbolFor(invoke.meth);
 
         // Recurse on method expression
         scan(invoke.meth);
@@ -530,7 +530,7 @@ public void visitApply(JCMethodInvocation invoke) {
         invoke(invoke, sym, invoke.args, receiverRefs);
     }
 
-    private void invoke(JCTree site, MethodSymbol sym, List args, RefSet receiverRefs) {
+    private void invoke(JCTree site, Symbol sym, List args, RefSet receiverRefs) {
 
         // Skip if ignoring warnings for a constructor invoked via 'this()'
         if (suppressed.contains(sym))
@@ -810,6 +810,10 @@ public void visitSelect(JCFieldAccess tree) {
 
     @Override
     public void visitReference(JCMemberReference tree) {
+        if (tree.type.isErroneous()) {
+            //error recovery - ignore erroneous member references
+            return ;
+        }
 
         // Scan target expression and extract 'this' references, if any
         scan(tree.expr);
diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java
index 4e5c4e49436..8a546cd3f42 100644
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Gen.java
@@ -1428,6 +1428,11 @@ private void handleSwitch(JCTree swtch, JCExpression selector, List case
                     code.put4(caseidx + 4, offsets[i]);
                 }
             }
+
+            if (swtch instanceof JCSwitchExpression) {
+                 // Emit line position for the end of a switch expression
+                 code.statBegin(TreeInfo.endPos(swtch));
+            }
         }
         code.endScopes(limit);
     }
diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/StringConcat.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/StringConcat.java
index 182efc63dc7..07ee62eb75e 100644
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/StringConcat.java
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/StringConcat.java
@@ -37,6 +37,7 @@
 import static com.sun.tools.javac.code.Kinds.Kind.MTH;
 import static com.sun.tools.javac.code.TypeTag.*;
 import static com.sun.tools.javac.jvm.ByteCodes.*;
+import static com.sun.tools.javac.tree.JCTree.Tag.LITERAL;
 import static com.sun.tools.javac.tree.JCTree.Tag.PLUS;
 import com.sun.tools.javac.jvm.Items.*;
 
@@ -416,7 +417,7 @@ protected void emit(JCDiagnostic.DiagnosticPosition pos, List args, bool
                 for (JCTree arg : t) {
                     Object constVal = arg.type.constValue();
                     if ("".equals(constVal)) continue;
-                    if (arg.type == syms.botType) {
+                    if (arg.type == syms.botType && arg.hasTag(LITERAL)) {
                         // Concat the null into the recipe right away
                         recipe.append((String) null);
                     } else if (constVal != 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 78be89ec1ea..c962862e4bf 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
@@ -967,6 +967,20 @@ public JCExpression parseType(boolean allowVar, List annotations)
         return result;
     }
 
+    protected JCExpression parseIntersectionType(int pos, JCExpression firstType) {
+        JCExpression t = firstType;
+        int pos1 = pos;
+        List targets = List.of(t);
+        while (token.kind == AMP) {
+            accept(AMP);
+            targets = targets.prepend(parseType());
+        }
+        if (targets.length() > 1) {
+            t = toP(F.at(pos1).TypeIntersection(targets.reverse()));
+        }
+        return t;
+    }
+
     public JCExpression unannotatedType(boolean allowVar) {
         return unannotatedType(allowVar, TYPE);
     }
@@ -1337,15 +1351,7 @@ protected JCExpression term3() {
                     case CAST:
                        accept(LPAREN);
                        selectTypeMode();
-                       int pos1 = pos;
-                       List targets = List.of(t = parseType());
-                       while (token.kind == AMP) {
-                           accept(AMP);
-                           targets = targets.prepend(parseType());
-                       }
-                       if (targets.length() > 1) {
-                           t = toP(F.at(pos1).TypeIntersection(targets.reverse()));
-                       }
+                       t = parseIntersectionType(pos, parseType());
                        accept(RPAREN);
                        selectExprMode();
                        JCExpression t1 = term3();
@@ -2853,6 +2859,7 @@ List blockStatement() {
                     case INTLITERAL: case LONGLITERAL: case FLOATLITERAL: case DOUBLELITERAL:
                     case NULL: case IDENTIFIER: case TRUE: case FALSE:
                     case NEW: case SWITCH: case THIS: case SUPER:
+                    case BYTE, CHAR, SHORT, INT, LONG, FLOAT, DOUBLE, VOID, BOOLEAN:
                         isYieldStatement = true;
                         break;
                     case PLUSPLUS: case SUBSUB:
diff --git a/src/jdk.compiler/share/man/javac.1 b/src/jdk.compiler/share/man/javac.1
index b8a7fe60af5..d34e97f05c8 100644
--- a/src/jdk.compiler/share/man/javac.1
+++ b/src/jdk.compiler/share/man/javac.1
@@ -35,7 +35,7 @@
 . ftr VB CB
 . ftr VBI CBI
 .\}
-.TH "JAVAC" "1" "2024" "JDK 22-ea" "JDK Commands"
+.TH "JAVAC" "1" "2024" "JDK 22" "JDK Commands"
 .hy
 .SH NAME
 .PP
diff --git a/src/jdk.compiler/share/man/serialver.1 b/src/jdk.compiler/share/man/serialver.1
index 57148e5f643..7ebb67ebd9a 100644
--- a/src/jdk.compiler/share/man/serialver.1
+++ b/src/jdk.compiler/share/man/serialver.1
@@ -35,7 +35,7 @@
 . ftr VB CB
 . ftr VBI CBI
 .\}
-.TH "SERIALVER" "1" "2024" "JDK 22-ea" "JDK Commands"
+.TH "SERIALVER" "1" "2024" "JDK 22" "JDK Commands"
 .hy
 .SH NAME
 .PP
diff --git a/src/jdk.crypto.mscapi/windows/classes/sun/security/mscapi/CKey.java b/src/jdk.crypto.mscapi/windows/classes/sun/security/mscapi/CKey.java
index e010e971787..9c985f0e483 100644
--- a/src/jdk.crypto.mscapi/windows/classes/sun/security/mscapi/CKey.java
+++ b/src/jdk.crypto.mscapi/windows/classes/sun/security/mscapi/CKey.java
@@ -76,10 +76,14 @@ protected void finalize() throws Throwable {
 
     protected final String algorithm;
 
-    protected CKey(String algorithm, NativeHandles handles, int keyLength) {
+    private final boolean isPublic;
+
+    protected CKey(String algorithm, NativeHandles handles, int keyLength,
+            boolean isPublic) {
         this.algorithm = algorithm;
         this.handles = handles;
         this.keyLength = keyLength;
+        this.isPublic = isPublic;
     }
 
     // Native method to cleanup the key handle.
@@ -102,6 +106,18 @@ public String getAlgorithm() {
         return algorithm;
     }
 
+    public String toString() {
+        String typeStr;
+        if (handles.hCryptKey != 0) {
+            typeStr = getKeyType(handles.hCryptKey) + ", container=" +
+                    getContainerName(handles.hCryptProv);
+        } else {
+            typeStr = "CNG";
+        }
+        return algorithm + " " + (isPublic ? "PublicKey" : "PrivateKey") +
+                " [size=" + keyLength + " bits, type=" + typeStr + "]";
+    }
+
     protected static native String getContainerName(long hCryptProv);
 
     protected static native String getKeyType(long hCryptKey);
diff --git a/src/jdk.crypto.mscapi/windows/classes/sun/security/mscapi/CPrivateKey.java b/src/jdk.crypto.mscapi/windows/classes/sun/security/mscapi/CPrivateKey.java
index 91a7775b8bd..c3882616615 100644
--- a/src/jdk.crypto.mscapi/windows/classes/sun/security/mscapi/CPrivateKey.java
+++ b/src/jdk.crypto.mscapi/windows/classes/sun/security/mscapi/CPrivateKey.java
@@ -42,7 +42,7 @@ class CPrivateKey extends CKey implements PrivateKey {
     private static final long serialVersionUID = 8113152807912338063L;
 
     private CPrivateKey(String alg, NativeHandles handles, int keyLength) {
-        super(alg, handles, keyLength);
+        super(alg, handles, keyLength, false);
     }
 
     // Called by native code inside security.cpp
@@ -65,16 +65,6 @@ public byte[] getEncoded() {
         return null;
     }
 
-    public String toString() {
-        if (handles.hCryptKey != 0) {
-            return algorithm + "PrivateKey [size=" + keyLength + " bits, type=" +
-                    getKeyType(handles.hCryptKey) + ", container=" +
-                    getContainerName(handles.hCryptProv) + "]";
-        } else {
-            return algorithm + "PrivateKey [size=" + keyLength + " bits, type=CNG]";
-        }
-    }
-
     // This class is not serializable
     @java.io.Serial
     private void writeObject(java.io.ObjectOutputStream out)
diff --git a/src/jdk.crypto.mscapi/windows/classes/sun/security/mscapi/CPublicKey.java b/src/jdk.crypto.mscapi/windows/classes/sun/security/mscapi/CPublicKey.java
index 6c3079c3a72..056e85cd036 100644
--- a/src/jdk.crypto.mscapi/windows/classes/sun/security/mscapi/CPublicKey.java
+++ b/src/jdk.crypto.mscapi/windows/classes/sun/security/mscapi/CPublicKey.java
@@ -114,9 +114,8 @@ public ECParameterSpec getParams() {
         }
 
         public String toString() {
-            StringBuffer sb = new StringBuffer();
-            sb.append(algorithm).append("PublicKey [size=").append(keyLength)
-                    .append("]\n  ECPoint: ").append(getW())
+            StringBuffer sb = new StringBuffer(super.toString());
+            sb.append("\n ECPoint: ").append(getW())
                     .append("\n  params: ").append(getParams());
             return sb.toString();
         }
@@ -135,16 +134,8 @@ public static class CRSAPublicKey extends CPublicKey implements RSAPublicKey {
         }
 
         public String toString() {
-            StringBuffer sb = new StringBuffer();
-            sb.append(algorithm).append("PublicKey [size=").append(keyLength)
-                    .append(" bits, type=");
-            if (handles.hCryptKey != 0) {
-                sb.append(getKeyType(handles.hCryptKey))
-                        .append(", container=").append(getContainerName(handles.hCryptProv));
-            } else {
-                sb.append("CNG");
-            }
-            sb.append("]\n  modulus: ").append(getModulus())
+            StringBuffer sb = new StringBuffer(super.toString());
+            sb.append("\n  modulus: ").append(getModulus())
                     .append("\n  public exponent: ").append(getPublicExponent());
             return sb.toString();
         }
@@ -215,7 +206,7 @@ public static CPublicKey of(
 
     protected CPublicKey(
             String alg, NativeHandles handles, int keyLength) {
-        super(alg, handles, keyLength);
+        super(alg, handles, keyLength, true);
     }
 
     @Override
diff --git a/src/jdk.crypto.mscapi/windows/classes/sun/security/mscapi/CRSACipher.java b/src/jdk.crypto.mscapi/windows/classes/sun/security/mscapi/CRSACipher.java
index ef6fa63e0a6..7b2fb631023 100644
--- a/src/jdk.crypto.mscapi/windows/classes/sun/security/mscapi/CRSACipher.java
+++ b/src/jdk.crypto.mscapi/windows/classes/sun/security/mscapi/CRSACipher.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2023, 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.security.Key;
 import java.security.interfaces.*;
 import java.security.spec.*;
+import java.util.Arrays;
 
 import javax.crypto.*;
 import javax.crypto.spec.*;
@@ -61,6 +62,9 @@
  */
 public final class CRSACipher extends CipherSpi {
 
+    private static final int ERROR_INVALID_PARAMETER = 0x57;
+    private static final int NTE_INVALID_PARAMETER = 0x80090027;
+
     // constant for an empty byte array
     private static final byte[] B0 = new byte[0];
 
@@ -101,6 +105,8 @@ public final class CRSACipher extends CipherSpi {
     // cipher parameter for TLS RSA premaster secret
     private AlgorithmParameterSpec spec = null;
 
+    private boolean forTlsPremasterSecret = false;
+
     // the source of randomness
     private SecureRandom random;
 
@@ -171,6 +177,9 @@ protected void engineInit(int opmode, Key key,
             }
             spec = params;
             this.random = random;   // for TLS RSA premaster secret
+            this.forTlsPremasterSecret = true;
+        } else {
+            this.forTlsPremasterSecret = false;
         }
         init(opmode, key);
     }
@@ -278,8 +287,7 @@ private void update(byte[] in, int inOfs, int inLen) {
     }
 
     // internal doFinal() method. Here we perform the actual RSA operation
-    private byte[] doFinal() throws BadPaddingException,
-            IllegalBlockSizeException {
+    private byte[] doFinal() throws IllegalBlockSizeException {
         if (bufOfs > buffer.length) {
             throw new IllegalBlockSizeException("Data must not be longer "
                 + "than " + (buffer.length - paddingLength)  + " bytes");
@@ -308,7 +316,7 @@ private byte[] doFinal() throws BadPaddingException,
                 throw new AssertionError("Internal error");
             }
 
-        } catch (KeyException e) {
+        } catch (KeyException | BadPaddingException e) {
             throw new ProviderException(e);
 
         } finally {
@@ -331,14 +339,14 @@ protected int engineUpdate(byte[] in, int inOfs, int inLen, byte[] out,
 
     // see JCE spec
     protected byte[] engineDoFinal(byte[] in, int inOfs, int inLen)
-            throws BadPaddingException, IllegalBlockSizeException {
+            throws IllegalBlockSizeException {
         update(in, inOfs, inLen);
         return doFinal();
     }
 
     // see JCE spec
     protected int engineDoFinal(byte[] in, int inOfs, int inLen, byte[] out,
-            int outOfs) throws ShortBufferException, BadPaddingException,
+            int outOfs) throws ShortBufferException,
             IllegalBlockSizeException {
         if (outputSize > out.length - outOfs) {
             throw new ShortBufferException
@@ -354,6 +362,7 @@ protected int engineDoFinal(byte[] in, int inOfs, int inLen, byte[] out,
     // see JCE spec
     protected byte[] engineWrap(Key key) throws InvalidKeyException,
             IllegalBlockSizeException {
+
         byte[] encoded = key.getEncoded(); // TODO - unextractable key
         if ((encoded == null) || (encoded.length == 0)) {
             throw new InvalidKeyException("Could not obtain encoded key");
@@ -362,12 +371,7 @@ protected byte[] engineWrap(Key key) throws InvalidKeyException,
             throw new InvalidKeyException("Key is too long for wrapping");
         }
         update(encoded, 0, encoded.length);
-        try {
-            return doFinal();
-        } catch (BadPaddingException e) {
-            // should not occur
-            throw new InvalidKeyException("Wrapping failed", e);
-        }
+        return doFinal();
     }
 
     // see JCE spec
@@ -388,31 +392,31 @@ protected java.security.Key engineUnwrap(byte[] wrappedKey,
         update(wrappedKey, 0, wrappedKey.length);
         try {
             encoded = doFinal();
-        } catch (BadPaddingException e) {
-            if (isTlsRsaPremasterSecret) {
-                failover = e;
-            } else {
-                throw new InvalidKeyException("Unwrapping failed", e);
-            }
         } catch (IllegalBlockSizeException e) {
             // should not occur, handled with length check above
             throw new InvalidKeyException("Unwrapping failed", e);
         }
 
-        if (isTlsRsaPremasterSecret) {
-            if (!(spec instanceof TlsRsaPremasterSecretParameterSpec)) {
-                throw new IllegalStateException(
-                        "No TlsRsaPremasterSecretParameterSpec specified");
+        try {
+            if (isTlsRsaPremasterSecret) {
+                if (!forTlsPremasterSecret) {
+                    throw new IllegalStateException(
+                            "No TlsRsaPremasterSecretParameterSpec specified");
+                }
+
+                // polish the TLS premaster secret
+                encoded = KeyUtil.checkTlsPreMasterSecretKey(
+                        ((TlsRsaPremasterSecretParameterSpec) spec).getClientVersion(),
+                        ((TlsRsaPremasterSecretParameterSpec) spec).getServerVersion(),
+                        random, encoded, encoded == null);
             }
 
-            // polish the TLS premaster secret
-            encoded = KeyUtil.checkTlsPreMasterSecretKey(
-                ((TlsRsaPremasterSecretParameterSpec)spec).getClientVersion(),
-                ((TlsRsaPremasterSecretParameterSpec)spec).getServerVersion(),
-                random, encoded, (failover != null));
+            return constructKey(encoded, algorithm, type);
+        } finally {
+            if (encoded != null) {
+                Arrays.fill(encoded, (byte) 0);
+            }
         }
-
-        return constructKey(encoded, algorithm, type);
     }
 
     // see JCE spec
@@ -496,17 +500,30 @@ private static Key constructKey(byte[] encodedKey,
      * Encrypt/decrypt a data buffer using Microsoft Crypto API or CNG.
      * It expects and returns ciphertext data in big-endian form.
      */
-    private static byte[] encryptDecrypt(byte[] data, int dataSize,
-            CKey key, boolean doEncrypt) throws KeyException {
+    private byte[] encryptDecrypt(byte[] data, int dataSize,
+            CKey key, boolean doEncrypt) throws KeyException, BadPaddingException {
+        int[] returnStatus = new int[1];
+        byte[] result;
         if (key.getHCryptKey() != 0) {
-            return encryptDecrypt(data, dataSize, key.getHCryptKey(), doEncrypt);
+            result = encryptDecrypt(returnStatus, data, dataSize, key.getHCryptKey(), doEncrypt);
         } else {
-            return cngEncryptDecrypt(data, dataSize, key.getHCryptProvider(), doEncrypt);
+            result = cngEncryptDecrypt(returnStatus, data, dataSize, key.getHCryptProvider(), doEncrypt);
         }
+        if ((returnStatus[0] == ERROR_INVALID_PARAMETER) || (returnStatus[0] == NTE_INVALID_PARAMETER)) {
+            if (forTlsPremasterSecret) {
+                result = null;
+            } else {
+                throw new BadPaddingException("Error " + returnStatus[0] + " returned by MSCAPI");
+            }
+        } else if (returnStatus[0] != 0) {
+            throw new KeyException("Error " + returnStatus[0] + " returned by MSCAPI");
+        }
+
+        return result;
     }
 
-    private static native byte[] encryptDecrypt(byte[] data, int dataSize,
+    private static native byte[] encryptDecrypt(int[] returnStatus, byte[] data, int dataSize,
             long key, boolean doEncrypt) throws KeyException;
-    private static native byte[] cngEncryptDecrypt(byte[] data, int dataSize,
+    private static native byte[] cngEncryptDecrypt(int[] returnStatus, byte[] data, int dataSize,
             long key, boolean doEncrypt) throws KeyException;
 }
diff --git a/src/jdk.crypto.mscapi/windows/native/libsunmscapi/security.cpp b/src/jdk.crypto.mscapi/windows/native/libsunmscapi/security.cpp
index f2b6bfd83f6..4787708779d 100644
--- a/src/jdk.crypto.mscapi/windows/native/libsunmscapi/security.cpp
+++ b/src/jdk.crypto.mscapi/windows/native/libsunmscapi/security.cpp
@@ -1905,18 +1905,25 @@ JNIEXPORT void JNICALL Java_sun_security_mscapi_CKeyStore_destroyKeyContainer
 /*
  * Class:     sun_security_mscapi_CRSACipher
  * Method:    encryptDecrypt
- * Signature: ([BIJZ)[B
+ * Signature: ([I[BIJZ)[B
  */
 JNIEXPORT jbyteArray JNICALL Java_sun_security_mscapi_CRSACipher_encryptDecrypt
-  (JNIEnv *env, jclass clazz, jbyteArray jData, jint jDataSize, jlong hKey,
+  (JNIEnv *env, jclass clazz, jintArray jResultStatus, jbyteArray jData, jint jDataSize, jlong hKey,
    jboolean doEncrypt)
 {
     jbyteArray result = NULL;
     jbyte* pData = NULL;
+    jbyte* resultData = NULL;
     DWORD dwDataLen = jDataSize;
     DWORD dwBufLen = env->GetArrayLength(jData);
     DWORD i;
     BYTE tmp;
+    BOOL success;
+    DWORD ss = ERROR_SUCCESS;
+    DWORD lastError = ERROR_SUCCESS;
+    DWORD resultLen = 0;
+    DWORD pmsLen = 48;
+    jbyte pmsArr[48] = {0};
 
     __try
     {
@@ -1943,6 +1950,8 @@ JNIEXPORT jbyteArray JNICALL Java_sun_security_mscapi_CRSACipher_encryptDecrypt
                 pData[i] = pData[dwBufLen - i -1];
                 pData[dwBufLen - i - 1] = tmp;
             }
+            resultData = pData;
+            resultLen = dwBufLen;
         } else {
             // convert to little-endian
             for (i = 0; i < dwBufLen / 2; i++) {
@@ -1952,21 +1961,28 @@ JNIEXPORT jbyteArray JNICALL Java_sun_security_mscapi_CRSACipher_encryptDecrypt
             }
 
             // decrypt
-            if (! ::CryptDecrypt((HCRYPTKEY) hKey, 0, TRUE, 0, (BYTE *)pData, //deprecated
-                &dwBufLen)) {
-
-                ThrowException(env, KEY_EXCEPTION, GetLastError());
-                __leave;
+            success = ::CryptDecrypt((HCRYPTKEY) hKey, 0, TRUE, 0, (BYTE *)pData, //deprecated
+                &dwBufLen);
+            lastError = GetLastError();
+            if (success) {
+                ss = ERROR_SUCCESS;
+                resultData = pData;
+                resultLen = dwBufLen;
+            } else {
+                ss = lastError;
+                resultData = pmsArr;
+                resultLen = pmsLen;
             }
+            env->SetIntArrayRegion(jResultStatus, 0, 1, (jint*) &ss);
         }
 
-        // Create new byte array
-        if ((result = env->NewByteArray(dwBufLen)) == NULL) {
+            // Create new byte array
+        if ((result = env->NewByteArray(resultLen)) == NULL) {
             __leave;
         }
 
         // Copy data from native buffer to Java buffer
-        env->SetByteArrayRegion(result, 0, dwBufLen, (jbyte*) pData);
+        env->SetByteArrayRegion(result, 0, resultLen, (jbyte*) resultData);
     }
     __finally
     {
@@ -1980,17 +1996,22 @@ JNIEXPORT jbyteArray JNICALL Java_sun_security_mscapi_CRSACipher_encryptDecrypt
 /*
  * Class:     sun_security_mscapi_CRSACipher
  * Method:    cngEncryptDecrypt
- * Signature: ([BIJZ)[B
+ * Signature: ([I[BIJZ)[B
  */
 JNIEXPORT jbyteArray JNICALL Java_sun_security_mscapi_CRSACipher_cngEncryptDecrypt
-  (JNIEnv *env, jclass clazz, jbyteArray jData, jint jDataSize, jlong hKey,
+  (JNIEnv *env, jclass clazz, jintArray jResultStatus, jbyteArray jData, jint jDataSize, jlong hKey,
    jboolean doEncrypt)
 {
     SECURITY_STATUS ss;
     jbyteArray result = NULL;
     jbyte* pData = NULL;
+    jbyte* resultData = NULL;
     DWORD dwDataLen = jDataSize;
     DWORD dwBufLen = env->GetArrayLength(jData);
+    DWORD resultLen = 0;
+    DWORD pmsLen = 48;
+    jbyte pmsArr[48] = {0};
+
     __try
     {
         // Copy data from Java buffer to native buffer
@@ -2010,6 +2031,9 @@ JNIEXPORT jbyteArray JNICALL Java_sun_security_mscapi_CRSACipher_cngEncryptDecry
             if (ss != ERROR_SUCCESS) {
                 ThrowException(env, KEY_EXCEPTION, ss);
                 __leave;
+            } else {
+                resultLen = dwBufLen;
+                resultData = pData;
             }
         } else {
             // decrypt
@@ -2018,18 +2042,22 @@ JNIEXPORT jbyteArray JNICALL Java_sun_security_mscapi_CRSACipher_cngEncryptDecry
                     0,
                     (PBYTE)pData, dwBufLen,
                     &dwBufLen, NCRYPT_PAD_PKCS1_FLAG);
-            if (ss != ERROR_SUCCESS) {
-                ThrowException(env, KEY_EXCEPTION, ss);
-                __leave;
+            env->SetIntArrayRegion(jResultStatus, 0, 1, (jint*) &ss);
+            if (ss == ERROR_SUCCESS) {
+                resultLen = dwBufLen;
+                resultData = pData;
+            } else {
+                resultLen = pmsLen;
+                resultData = pmsArr;
             }
-        }
+       }
         // Create new byte array
-        if ((result = env->NewByteArray(dwBufLen)) == NULL) {
+        if ((result = env->NewByteArray(resultLen)) == NULL) {
             __leave;
         }
 
         // Copy data from native buffer to Java buffer
-        env->SetByteArrayRegion(result, 0, dwBufLen, (jbyte*) pData);
+        env->SetByteArrayRegion(result, 0, resultLen, (jbyte*) resultData);
     }
     __finally {
         if (pData) {
diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/CallSiteDescriptor.java b/src/jdk.dynalink/share/classes/jdk/dynalink/CallSiteDescriptor.java
index e1e49f22b4c..e47625fb497 100644
--- a/src/jdk.dynalink/share/classes/jdk/dynalink/CallSiteDescriptor.java
+++ b/src/jdk.dynalink/share/classes/jdk/dynalink/CallSiteDescriptor.java
@@ -88,6 +88,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  * the {@code MethodHandles.Lookup} object it carries. This lookup should be used
  * to find method handles to set as targets of the call site described by this
  * descriptor.
+ * @since 9
  */
 public class CallSiteDescriptor extends SecureLookupSupplier {
     private final Operation operation;
diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/DynamicLinker.java b/src/jdk.dynalink/share/classes/jdk/dynalink/DynamicLinker.java
index eb7de0aba75..23f4f7a8122 100644
--- a/src/jdk.dynalink/share/classes/jdk/dynalink/DynamicLinker.java
+++ b/src/jdk.dynalink/share/classes/jdk/dynalink/DynamicLinker.java
@@ -141,6 +141,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  * in the above example the {@code parseOperation} method is left unimplemented.
  *
  * 
+ * @since 9
  */
 public final class DynamicLinker {
     private static final String CLASS_NAME = DynamicLinker.class.getName();
diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/DynamicLinkerFactory.java b/src/jdk.dynalink/share/classes/jdk/dynalink/DynamicLinkerFactory.java
index a34cff5ba12..ed211008566 100644
--- a/src/jdk.dynalink/share/classes/jdk/dynalink/DynamicLinkerFactory.java
+++ b/src/jdk.dynalink/share/classes/jdk/dynalink/DynamicLinkerFactory.java
@@ -105,6 +105,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  * {@link #setClassLoader(ClassLoader) automatically discovered} ones, and
  * finally the ones configured with {@link #setFallbackLinkers(List)}; this last
  * category usually includes {@link BeansLinker}.
+ * @since 9
  */
 public final class DynamicLinkerFactory {
     @SuppressWarnings("removal")
diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/NamedOperation.java b/src/jdk.dynalink/share/classes/jdk/dynalink/NamedOperation.java
index 7563e3946ad..5fe3e96f43e 100644
--- a/src/jdk.dynalink/share/classes/jdk/dynalink/NamedOperation.java
+++ b/src/jdk.dynalink/share/classes/jdk/dynalink/NamedOperation.java
@@ -106,6 +106,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  * usually containing the textual representation of the source expression that retrieved the
  * callee, e.g. {@code StandardOperation.CALL.named("window.open")}.
  * 

+ * @since 9 */ public final class NamedOperation implements Operation { private final Operation baseOperation; diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/Namespace.java b/src/jdk.dynalink/share/classes/jdk/dynalink/Namespace.java index 69b68d25ffc..8f5e7ede7f6 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/Namespace.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/Namespace.java @@ -66,6 +66,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * set of standard namespaces with the {@link StandardNamespace} enum. Operations * that need to specify a namespace they operate on can be expressed using * {@link NamespaceOperation}. + * @since 9 */ public interface Namespace { } diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/NamespaceOperation.java b/src/jdk.dynalink/share/classes/jdk/dynalink/NamespaceOperation.java index 322767de364..0e047849c2c 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/NamespaceOperation.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/NamespaceOperation.java @@ -134,6 +134,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * StandardNamespace.PROPERTY) * .named("empty"); *
+ * @since 9 */ public final class NamespaceOperation implements Operation { private final Operation baseOperation; diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/NoSuchDynamicMethodException.java b/src/jdk.dynalink/share/classes/jdk/dynalink/NoSuchDynamicMethodException.java index bf20c23b738..8842c32c1be 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/NoSuchDynamicMethodException.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/NoSuchDynamicMethodException.java @@ -64,6 +64,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR /** * Thrown at the invocation if the call site can not be linked by any available {@link GuardingDynamicLinker}. + * @since 9 */ public class NoSuchDynamicMethodException extends RuntimeException { private static final long serialVersionUID = 1L; diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/Operation.java b/src/jdk.dynalink/share/classes/jdk/dynalink/Operation.java index ba22e32c54f..ef0acbc3b57 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/Operation.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/Operation.java @@ -74,6 +74,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * {@code GET:PROPERTY|ELEMENT}), and finally we will refer to named operations * by separating the base operation and the name with the colon character (e.g. * {@code GET:PROPERTY|ELEMENT:color}). + * @since 9 */ public interface Operation { /** diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/RelinkableCallSite.java b/src/jdk.dynalink/share/classes/jdk/dynalink/RelinkableCallSite.java index 5f74edd700c..e14cfdfebd3 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/RelinkableCallSite.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/RelinkableCallSite.java @@ -76,6 +76,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * method handles. A relinkable call site will be managed by a * {@link DynamicLinker} object after being associated with it using its * {@link DynamicLinker#link(RelinkableCallSite)} method. + * @since 9 */ public interface RelinkableCallSite { /** diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/SecureLookupSupplier.java b/src/jdk.dynalink/share/classes/jdk/dynalink/SecureLookupSupplier.java index 73ee39b9002..5ec1f2737fb 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/SecureLookupSupplier.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/SecureLookupSupplier.java @@ -32,6 +32,7 @@ /** * Provides security-checked access to a {@code MethodHandles.Lookup} object. * See {@link #getLookup()} for details. + * @since 9 */ public class SecureLookupSupplier { /** diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/StandardNamespace.java b/src/jdk.dynalink/share/classes/jdk/dynalink/StandardNamespace.java index 55b9acee703..b4c33250d38 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/StandardNamespace.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/StandardNamespace.java @@ -62,6 +62,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR /** * An enumeration of standard namespaces defined by Dynalink. + * @since 9 */ public enum StandardNamespace implements Namespace { /** diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/StandardOperation.java b/src/jdk.dynalink/share/classes/jdk/dynalink/StandardOperation.java index e58bf4e78bf..176a87acd36 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/StandardOperation.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/StandardOperation.java @@ -67,6 +67,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * disappears from their type signature. * {@link NamedOperation} can also be used to decorate {@link #CALL} and {@link #NEW} operations with a * diagnostic name, and as such it does not affect their type signature. + * @since 9 */ public enum StandardOperation implements Operation { /** diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/beans/BeansLinker.java b/src/jdk.dynalink/share/classes/jdk/dynalink/beans/BeansLinker.java index 386f386216c..ca09923292a 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/beans/BeansLinker.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/beans/BeansLinker.java @@ -135,6 +135,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * property and method names on classes and class instances, as well as access * to per-class linkers using the {@link #getLinkerForClass(Class)} * method.

+ * @since 9 */ public class BeansLinker implements GuardingDynamicLinker { private static final ClassValue linkers = new ClassValue<>() { diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/beans/MissingMemberHandlerFactory.java b/src/jdk.dynalink/share/classes/jdk/dynalink/beans/MissingMemberHandlerFactory.java index 1fe50b916d9..c1e2f7eb71d 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/beans/MissingMemberHandlerFactory.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/beans/MissingMemberHandlerFactory.java @@ -67,6 +67,7 @@ * exception itself, as the linkage for the missing member is often conditional. * * @see BeansLinker#BeansLinker(MissingMemberHandlerFactory) + * @since 9 */ @FunctionalInterface public interface MissingMemberHandlerFactory { diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/beans/StaticClass.java b/src/jdk.dynalink/share/classes/jdk/dynalink/beans/StaticClass.java index 62bb74cb29e..ebd6c7e55e2 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/beans/StaticClass.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/beans/StaticClass.java @@ -102,6 +102,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * constructor. You might want to expose a mechanism in your language for * selecting a constructor with an explicit signature through * {@link BeansLinker#getConstructorMethod(Class, String)}. + * @since 9 */ public final class StaticClass implements Serializable { private static final ClassValue staticClasses = new ClassValue<>() { diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/ConversionComparator.java b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/ConversionComparator.java index 6c0dd438bbb..267752b0a23 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/ConversionComparator.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/ConversionComparator.java @@ -70,10 +70,12 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * specific method with unrelated signatures. In these cases, language runtimes * can be asked to resolve the ambiguity by expressing preferences for one * conversion over the other. + * @since 9 */ public interface ConversionComparator { /** * Enumeration of possible outcomes of comparing one conversion to another. + * @since 9 */ enum Comparison { /** The conversions cannot be compared. **/ diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/GuardedInvocation.java b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/GuardedInvocation.java index 1a1e23981c5..174e63bff26 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/GuardedInvocation.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/GuardedInvocation.java @@ -86,6 +86,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * throw an exception of the designated type. The guard, the switch points, and * the exception type are all optional (a guarded invocation having none of them * is unconditionally valid). + * @since 9 */ public class GuardedInvocation { private final MethodHandle invocation; diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/GuardedInvocationTransformer.java b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/GuardedInvocationTransformer.java index 6c775022362..fa4f0cd4545 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/GuardedInvocationTransformer.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/GuardedInvocationTransformer.java @@ -67,6 +67,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * another one. Typical usage is for implementing * {@link DynamicLinkerFactory#setPrelinkTransformer(GuardedInvocationTransformer) * pre-link transformers}. + * @since 9 */ @FunctionalInterface public interface GuardedInvocationTransformer { diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/GuardingDynamicLinker.java b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/GuardingDynamicLinker.java index c604712ae43..e94cb7b9128 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/GuardingDynamicLinker.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/GuardingDynamicLinker.java @@ -87,6 +87,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * Languages can export linkers to other language runtimes for * {@link DynamicLinkerFactory#setClassLoader(ClassLoader) automatic discovery} * using a {@link GuardingDynamicLinkerExporter}. + * @since 9 */ public interface GuardingDynamicLinker { /** diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/GuardingDynamicLinkerExporter.java b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/GuardingDynamicLinkerExporter.java index 03be07cf459..cd670a8fdbe 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/GuardingDynamicLinkerExporter.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/GuardingDynamicLinkerExporter.java @@ -45,6 +45,7 @@ * security manager is present, to ensure that only trusted runtimes can * automatically export their linkers into other runtimes. * @see DynamicLinkerFactory#setClassLoader(ClassLoader) + * @since 9 */ public abstract class GuardingDynamicLinkerExporter implements Supplier> { /** diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/GuardingTypeConverterFactory.java b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/GuardingTypeConverterFactory.java index 981a39059af..bbd327d5bbe 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/GuardingTypeConverterFactory.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/GuardingTypeConverterFactory.java @@ -75,6 +75,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * these conversions, will cause more ambiguity for {@link BeansLinker} in * selecting the correct overload when trying to link to an overloaded Java * method. + * @since 9 */ public interface GuardingTypeConverterFactory { /** diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/LinkRequest.java b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/LinkRequest.java index 209c1920a3f..1feeed03d15 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/LinkRequest.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/LinkRequest.java @@ -69,6 +69,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * site. Instances of these requests will be constructed and passed to all * {@link GuardingDynamicLinker} objects managed by the {@link DynamicLinker} * that is trying to link the call site. + * @since 9 */ public interface LinkRequest { /** diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/LinkerServices.java b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/LinkerServices.java index e66babebf33..5a028205676 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/LinkerServices.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/LinkerServices.java @@ -73,6 +73,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR /** * Interface for services provided to {@link GuardingDynamicLinker} instances by * the {@link DynamicLinker} that owns them. + * @since 9 */ public interface LinkerServices { /** diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/MethodHandleTransformer.java b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/MethodHandleTransformer.java index 2af6294c517..e9ccd30ffed 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/MethodHandleTransformer.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/MethodHandleTransformer.java @@ -68,6 +68,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * Typical usage is for implementing * {@link DynamicLinkerFactory#setInternalObjectsFilter(MethodHandleTransformer) * internal objects filters}. + * @since 9 */ @FunctionalInterface public interface MethodHandleTransformer { diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/MethodTypeConversionStrategy.java b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/MethodTypeConversionStrategy.java index b830e375c12..394f81858ff 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/MethodTypeConversionStrategy.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/MethodTypeConversionStrategy.java @@ -70,6 +70,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * of * {@link DynamicLinkerFactory#setAutoConversionStrategy(MethodTypeConversionStrategy) * method invocation conversions}. + * @since 9 */ @FunctionalInterface public interface MethodTypeConversionStrategy { diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/TypeBasedGuardingDynamicLinker.java b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/TypeBasedGuardingDynamicLinker.java index 53c1a66e862..1565cfee552 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/TypeBasedGuardingDynamicLinker.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/TypeBasedGuardingDynamicLinker.java @@ -68,6 +68,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * linkers will fall into this category, as they recognize their native objects as Java objects of classes implementing * a specific language-native interface or superclass. The linker mechanism can optimize the dispatch for these linkers, * see {@link CompositeTypeBasedGuardingDynamicLinker}. + * @since 9 */ public interface TypeBasedGuardingDynamicLinker extends GuardingDynamicLinker { /** diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/support/CompositeGuardingDynamicLinker.java b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/support/CompositeGuardingDynamicLinker.java index 8ae1f4754cf..c226a9c0b17 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/support/CompositeGuardingDynamicLinker.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/support/CompositeGuardingDynamicLinker.java @@ -72,6 +72,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * A {@link GuardingDynamicLinker} that delegates sequentially to a list of * other guarding dynamic linkers in its * {@link #getGuardedInvocation(LinkRequest, LinkerServices)}. + * @since 9 */ public class CompositeGuardingDynamicLinker implements GuardingDynamicLinker { diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/support/CompositeTypeBasedGuardingDynamicLinker.java b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/support/CompositeTypeBasedGuardingDynamicLinker.java index 184cc8e0ab8..a0805ff57d6 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/support/CompositeTypeBasedGuardingDynamicLinker.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/support/CompositeTypeBasedGuardingDynamicLinker.java @@ -77,6 +77,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * returning true are then bound to the class, and next time a receiver of same * type is encountered, the linking is delegated to those linkers only, speeding * up dispatch. + * @since 9 */ public class CompositeTypeBasedGuardingDynamicLinker implements TypeBasedGuardingDynamicLinker { // Using a separate static class instance so there's no strong reference from the class value back to the composite diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/support/DefaultInternalObjectFilter.java b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/support/DefaultInternalObjectFilter.java index 9929eeb7e50..7a43f7ebbc0 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/support/DefaultInternalObjectFilter.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/support/DefaultInternalObjectFilter.java @@ -80,6 +80,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * the parameter filter as being a wrapping method for exposing internal runtime * objects wrapped into an adapter with some public interface, and the return * value filter as being its inverse unwrapping method. + * @since 9 */ public class DefaultInternalObjectFilter implements MethodHandleTransformer { private static final MethodHandle FILTER_VARARGS = new Lookup(MethodHandles.lookup()).findStatic( diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/support/Guards.java b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/support/Guards.java index 9a456df5ebe..7b0fd0e156b 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/support/Guards.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/support/Guards.java @@ -72,6 +72,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * Utility methods for creating typical guards for * {@link MethodHandles#guardWithTest(MethodHandle, MethodHandle, MethodHandle)} * and for adjusting their method types. + * @since 9 */ public final class Guards { private static final Logger LOG = Logger diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/support/Lookup.java b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/support/Lookup.java index ecf66e7d458..25792f0108b 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/support/Lookup.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/support/Lookup.java @@ -72,6 +72,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * checked exceptions. It is useful in those cases when you're looking up * methods within your own codebase (therefore it is an error if they are not * present). + * @since 9 */ public final class Lookup { private final MethodHandles.Lookup lookup; diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/support/SimpleLinkRequest.java b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/support/SimpleLinkRequest.java index d8cfd8a9d9c..7a00b9fe3ea 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/support/SimpleLinkRequest.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/support/SimpleLinkRequest.java @@ -66,6 +66,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR /** * Default simple implementation of {@link LinkRequest}. + * @since 9 */ public class SimpleLinkRequest implements LinkRequest { diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/support/TypeUtilities.java b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/support/TypeUtilities.java index f5ee9e09093..2a3d667d49a 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/linker/support/TypeUtilities.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/linker/support/TypeUtilities.java @@ -70,6 +70,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR /** * Various static utility methods for working with Java types. + * @since 9 */ public final class TypeUtilities { private TypeUtilities() { diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/package-info.java b/src/jdk.dynalink/share/classes/jdk/dynalink/package-info.java index 03c7b9603f6..1218885ae9a 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/package-info.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/package-info.java @@ -60,5 +60,6 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR /** * Contains interfaces and classes that are used to link an {@code invokedynamic} call site. + * @since 9 */ package jdk.dynalink; diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/support/AbstractRelinkableCallSite.java b/src/jdk.dynalink/share/classes/jdk/dynalink/support/AbstractRelinkableCallSite.java index dbcf3ffd021..84ecfa1db38 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/support/AbstractRelinkableCallSite.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/support/AbstractRelinkableCallSite.java @@ -75,6 +75,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * {@link #relink(GuardedInvocation, MethodHandle)} and * {@link #resetAndRelink(GuardedInvocation, MethodHandle)} * methods. + * @since 9 */ public abstract class AbstractRelinkableCallSite extends MutableCallSite implements RelinkableCallSite { private final CallSiteDescriptor descriptor; diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/support/ChainedCallSite.java b/src/jdk.dynalink/share/classes/jdk/dynalink/support/ChainedCallSite.java index a026512242a..2f75b53fc3d 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/support/ChainedCallSite.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/support/ChainedCallSite.java @@ -84,6 +84,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * Race conditions in linking are resolved by throwing away the * {@link GuardedInvocation} produced on the losing thread without incorporating * it into the chain, so it can lead to repeated linking for the same arguments. + * @since 9 */ public class ChainedCallSite extends AbstractRelinkableCallSite { private static final MethodHandle PRUNE_CATCHES; diff --git a/src/jdk.dynalink/share/classes/jdk/dynalink/support/SimpleRelinkableCallSite.java b/src/jdk.dynalink/share/classes/jdk/dynalink/support/SimpleRelinkableCallSite.java index 06f50b4ff80..022d6088d01 100644 --- a/src/jdk.dynalink/share/classes/jdk/dynalink/support/SimpleRelinkableCallSite.java +++ b/src/jdk.dynalink/share/classes/jdk/dynalink/support/SimpleRelinkableCallSite.java @@ -71,6 +71,7 @@ WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * If the guard of that single invocation fails, or it has an invalidated * switch point, or its invalidating exception triggered, then the call site * will throw it away and ask its associated {@link DynamicLinker} to relink it. + * @since 9 */ public class SimpleRelinkableCallSite extends AbstractRelinkableCallSite { /** diff --git a/src/jdk.hotspot.agent/share/man/jhsdb.1 b/src/jdk.hotspot.agent/share/man/jhsdb.1 index 95d5fca297e..0a0daf889d8 100644 --- a/src/jdk.hotspot.agent/share/man/jhsdb.1 +++ b/src/jdk.hotspot.agent/share/man/jhsdb.1 @@ -35,7 +35,7 @@ . ftr VB CB . ftr VBI CBI .\} -.TH "JHSDB" "1" "2024" "JDK 22-ea" "JDK Commands" +.TH "JHSDB" "1" "2024" "JDK 22" "JDK Commands" .hy .SH NAME .PP diff --git a/src/jdk.httpserver/share/man/jwebserver.1 b/src/jdk.httpserver/share/man/jwebserver.1 index b8d4e9f8417..21400a2d677 100644 --- a/src/jdk.httpserver/share/man/jwebserver.1 +++ b/src/jdk.httpserver/share/man/jwebserver.1 @@ -35,7 +35,7 @@ . ftr VB CB . ftr VBI CBI .\} -.TH "JWEBSERVER" "1" "2024" "JDK 22-ea" "JDK Commands" +.TH "JWEBSERVER" "1" "2024" "JDK 22" "JDK Commands" .hy .SH NAME .PP diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/AbstractSpecies.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/AbstractSpecies.java index fac0012e646..0ff4830ded5 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/AbstractSpecies.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/AbstractSpecies.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, 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 @@ -360,14 +360,6 @@ VectorShuffle iotaShuffle(int start, int step, boolean wrap) { return dummyVector().iotaShuffle(start, step, wrap); } - @ForceInline - @Override - public final Vector fromMemorySegment(MemorySegment ms, long offset, ByteOrder bo) { - return dummyVector() - .fromMemorySegment0(ms, offset) - .maybeSwap(bo); - } - @Override public VectorMask loadMask(boolean[] bits, int offset) { return VectorMask.fromArray(this, bits, offset); diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteVector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteVector.java index ecd162bbdb8..4fc8626754a 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteVector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ByteVector.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, 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 @@ -4194,11 +4194,21 @@ final ByteVector fromIntValues(int[] values) { @ForceInline @Override final public ByteVector fromArray(Object a, int offset) { - // User entry point: Be careful with inputs. + // User entry point + // Defer only to the equivalent method on the vector class, using the same inputs return ByteVector .fromArray(this, (byte[]) a, offset); } + @ForceInline + @Override final + public ByteVector fromMemorySegment(MemorySegment ms, long offset, ByteOrder bo) { + // User entry point + // Defer only to the equivalent method on the vector class, using the same inputs + return ByteVector + .fromMemorySegment(this, ms, offset, bo); + } + @ForceInline @Override final ByteVector dummyVector() { diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleVector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleVector.java index 9b3d683520e..59e67195732 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleVector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/DoubleVector.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, 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 @@ -3797,11 +3797,21 @@ final DoubleVector fromIntValues(int[] values) { @ForceInline @Override final public DoubleVector fromArray(Object a, int offset) { - // User entry point: Be careful with inputs. + // User entry point + // Defer only to the equivalent method on the vector class, using the same inputs return DoubleVector .fromArray(this, (double[]) a, offset); } + @ForceInline + @Override final + public DoubleVector fromMemorySegment(MemorySegment ms, long offset, ByteOrder bo) { + // User entry point + // Defer only to the equivalent method on the vector class, using the same inputs + return DoubleVector + .fromMemorySegment(this, ms, offset, bo); + } + @ForceInline @Override final DoubleVector dummyVector() { diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatVector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatVector.java index f9bb4a9c630..45427817e3d 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatVector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/FloatVector.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, 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 @@ -3747,11 +3747,21 @@ final FloatVector fromIntValues(int[] values) { @ForceInline @Override final public FloatVector fromArray(Object a, int offset) { - // User entry point: Be careful with inputs. + // User entry point + // Defer only to the equivalent method on the vector class, using the same inputs return FloatVector .fromArray(this, (float[]) a, offset); } + @ForceInline + @Override final + public FloatVector fromMemorySegment(MemorySegment ms, long offset, ByteOrder bo) { + // User entry point + // Defer only to the equivalent method on the vector class, using the same inputs + return FloatVector + .fromMemorySegment(this, ms, offset, bo); + } + @ForceInline @Override final FloatVector dummyVector() { diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntVector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntVector.java index b6e9cba0816..3317e25e73e 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntVector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/IntVector.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, 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 @@ -3903,11 +3903,21 @@ final IntVector fromIntValues(int[] values) { @ForceInline @Override final public IntVector fromArray(Object a, int offset) { - // User entry point: Be careful with inputs. + // User entry point + // Defer only to the equivalent method on the vector class, using the same inputs return IntVector .fromArray(this, (int[]) a, offset); } + @ForceInline + @Override final + public IntVector fromMemorySegment(MemorySegment ms, long offset, ByteOrder bo) { + // User entry point + // Defer only to the equivalent method on the vector class, using the same inputs + return IntVector + .fromMemorySegment(this, ms, offset, bo); + } + @ForceInline @Override final IntVector dummyVector() { diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongVector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongVector.java index 98cf154e4a7..9dd3f2eb136 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongVector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/LongVector.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, 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 @@ -3829,11 +3829,21 @@ final LongVector fromIntValues(int[] values) { @ForceInline @Override final public LongVector fromArray(Object a, int offset) { - // User entry point: Be careful with inputs. + // User entry point + // Defer only to the equivalent method on the vector class, using the same inputs return LongVector .fromArray(this, (long[]) a, offset); } + @ForceInline + @Override final + public LongVector fromMemorySegment(MemorySegment ms, long offset, ByteOrder bo) { + // User entry point + // Defer only to the equivalent method on the vector class, using the same inputs + return LongVector + .fromMemorySegment(this, ms, offset, bo); + } + @ForceInline @Override final LongVector dummyVector() { diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortVector.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortVector.java index 0a0f359a40b..84f542f07ff 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortVector.java +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/ShortVector.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, 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 @@ -4188,11 +4188,21 @@ final ShortVector fromIntValues(int[] values) { @ForceInline @Override final public ShortVector fromArray(Object a, int offset) { - // User entry point: Be careful with inputs. + // User entry point + // Defer only to the equivalent method on the vector class, using the same inputs return ShortVector .fromArray(this, (short[]) a, offset); } + @ForceInline + @Override final + public ShortVector fromMemorySegment(MemorySegment ms, long offset, ByteOrder bo) { + // User entry point + // Defer only to the equivalent method on the vector class, using the same inputs + return ShortVector + .fromMemorySegment(this, ms, offset, bo); + } + @ForceInline @Override final ShortVector dummyVector() { diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/X-Vector.java.template b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/X-Vector.java.template index 31441207a9e..ad878268404 100644 --- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/X-Vector.java.template +++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/X-Vector.java.template @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, 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 @@ -5453,11 +5453,21 @@ public abstract class $abstractvectortype$ extends AbstractVector<$Boxtype$> { @ForceInline @Override final public $abstractvectortype$ fromArray(Object a, int offset) { - // User entry point: Be careful with inputs. + // User entry point + // Defer only to the equivalent method on the vector class, using the same inputs return $abstractvectortype$ .fromArray(this, ($type$[]) a, offset); } + @ForceInline + @Override final + public $abstractvectortype$ fromMemorySegment(MemorySegment ms, long offset, ByteOrder bo) { + // User entry point + // Defer only to the equivalent method on the vector class, using the same inputs + return $abstractvectortype$ + .fromMemorySegment(this, ms, offset, bo); + } + @ForceInline @Override final $abstractvectortype$ dummyVector() { diff --git a/src/jdk.jartool/share/classes/sun/tools/jar/Main.java b/src/jdk.jartool/share/classes/sun/tools/jar/Main.java index fce80372b1e..6163ef82647 100644 --- a/src/jdk.jartool/share/classes/sun/tools/jar/Main.java +++ b/src/jdk.jartool/share/classes/sun/tools/jar/Main.java @@ -292,6 +292,9 @@ public synchronized boolean run(String args[]) { } } expand(); + if (!ok) { + return false; + } if (!moduleInfos.isEmpty()) { // All actual file entries (excl manifest and module-info.class) Set jentries = new HashSet<>(); @@ -338,6 +341,9 @@ public synchronized boolean run(String args[]) { tmpFile = createTemporaryFile("tmpjar", ".jar"); } expand(); + if (!ok) { + return false; + } try (FileInputStream in = (fname != null) ? new FileInputStream(inputFile) : new FileInputStream(FileDescriptor.in); FileOutputStream out = new FileOutputStream(tmpFile); diff --git a/src/jdk.jartool/share/man/jar.1 b/src/jdk.jartool/share/man/jar.1 index a1a7f14a55a..1bbcba37d71 100644 --- a/src/jdk.jartool/share/man/jar.1 +++ b/src/jdk.jartool/share/man/jar.1 @@ -35,7 +35,7 @@ . ftr VB CB . ftr VBI CBI .\} -.TH "JAR" "1" "2024" "JDK 22-ea" "JDK Commands" +.TH "JAR" "1" "2024" "JDK 22" "JDK Commands" .hy .SH NAME .PP @@ -186,7 +186,8 @@ created or a non-modular JAR file being updated. Specifies the location of module dependence for generating the hash. .TP \f[V]\[at]\f[R]\f[I]file\f[R] -Reads \f[V]jar\f[R] options and file names from a text file. +Reads \f[V]jar\f[R] options and file names from a text file as if they +were supplied on the command line .SH OPERATION MODIFIERS VALID ONLY IN CREATE, UPDATE, AND GENERATE-INDEX MODES .PP You can use the following options to customize the actions of the create @@ -330,11 +331,14 @@ class files from the file \f[V]classes.list\f[R]. .PP \f[B]Note:\f[R] .PP -To shorten or simplify the \f[V]jar\f[R] command, you can specify -arguments in a separate text file and pass it to the \f[V]jar\f[R] -command with the at sign (\f[V]\[at]\f[R]) as a prefix. +To shorten or simplify the \f[V]jar\f[R] command, you can provide an arg +file that lists the files to include in the JAR file and pass it to the +\f[V]jar\f[R] command with the at sign (\f[V]\[at]\f[R]) as a prefix. .RS .PP \f[V]jar --create --file my.jar \[at]classes.list\f[R] .RE +.PP +If one or more entries in the arg file cannot be found then the jar +command fails without creating the JAR file. .RE diff --git a/src/jdk.jartool/share/man/jarsigner.1 b/src/jdk.jartool/share/man/jarsigner.1 index 2f442ff70ca..c2d44a84246 100644 --- a/src/jdk.jartool/share/man/jarsigner.1 +++ b/src/jdk.jartool/share/man/jarsigner.1 @@ -36,7 +36,7 @@ . ftr VB CB . ftr VBI CBI .\} -.TH "JARSIGNER" "1" "2024" "JDK 22-ea" "JDK Commands" +.TH "JARSIGNER" "1" "2024" "JDK 22" "JDK Commands" .hy .SH NAME .PP @@ -318,7 +318,7 @@ l l l l. T{ keyalg T}@T{ -keysize +key size T}@T{ default sigalg T}@T{ @@ -420,6 +420,9 @@ Otherwise, jarsigner will use parameters that are determined by the size of the key as specified in the table above. For example, an 3072-bit RSASSA-PSS key will use RSASSA-PSS as the signature algorithm and SHA-384 as the hash and MGF1 algorithms. +.IP \[bu] 2 +If a key algorithm is not listed in this table, the \f[V].DSA\f[R] +extension is used when signing a JAR file. .PP These default signature algorithms can be overridden by using the \f[V]-sigalg\f[R] option. @@ -805,8 +808,8 @@ Specifies the name of the message digest algorithm to use when digesting the entries of a JAR file. .RS .PP -For a list of standard message digest algorithm names, see Java Security -Standard Algorithm Names. +For a list of standard message digest algorithm names, see the Java +Security Standard Algorithm Names Specification. .PP If this option isn\[aq]t specified, then \f[V]SHA-384\f[R] is used. There must either be a statically installed provider supplying an @@ -830,8 +833,8 @@ implementation of the specified algorithm or you must specify one with the \f[V]-addprovider\f[R] or \f[V]-providerClass\f[R] option; otherwise, the command doesn\[aq]t succeed. .PP -For a list of standard message digest algorithm names, see Java Security -Standard Algorithm Names. +For a list of standard signature algorithm names, see the Java Security +Standard Algorithm Names Specification. .RE .TP \f[V]-verify\f[R] @@ -946,8 +949,8 @@ If this option isn\[aq]t specified, SHA-384 will be used. .PP See \f[B]Supported Algorithms\f[R]. .PP -For a list of standard message digest algorithm names, see Java Security -Standard Algorithm Names. +For a list of standard message digest algorithm names, see the Java +Security Standard Algorithm Names Specification. .RE .TP \f[V]-internalsf\f[R] diff --git a/src/jdk.javadoc/share/man/javadoc.1 b/src/jdk.javadoc/share/man/javadoc.1 index ad119c1dca3..222397c6826 100644 --- a/src/jdk.javadoc/share/man/javadoc.1 +++ b/src/jdk.javadoc/share/man/javadoc.1 @@ -35,7 +35,7 @@ . ftr VB CB . ftr VBI CBI .\} -.TH "JAVADOC" "1" "2024" "JDK 22-ea" "JDK Commands" +.TH "JAVADOC" "1" "2024" "JDK 22" "JDK Commands" .hy .SH NAME .PP diff --git a/src/jdk.jcmd/share/man/jcmd.1 b/src/jdk.jcmd/share/man/jcmd.1 index 4157cf600e1..3cb0d1e0d0b 100644 --- a/src/jdk.jcmd/share/man/jcmd.1 +++ b/src/jdk.jcmd/share/man/jcmd.1 @@ -1,4 +1,4 @@ -.\" Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved. +.\" Copyright (c) 2012, 2024, 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 @@ -35,7 +35,7 @@ . ftr VB CB . ftr VBI CBI .\} -.TH "JCMD" "1" "2024" "JDK 22-ea" "JDK Commands" +.TH "JCMD" "1" "2024" "JDK 22" "JDK Commands" .hy .SH NAME .PP @@ -164,42 +164,45 @@ The following \f[I]options\f[R] must be specified using either \f[V]-all\f[R]: (Optional) Show help for all commands (BOOLEAN, false) . .RE .TP -\f[V]Compiler.codecache\f[R] -Prints code cache layout and bounds. +\f[V]Compiler.CodeHeap_Analytics\f[R] [\f[I]function\f[R]] [\f[I]granularity\f[R]] +Print CodeHeap analytics .RS .PP -Impact: Low -.RE -.TP -\f[V]Compiler.codelist\f[R] -Prints all compiled methods in code cache that are alive. -.RS +Impact: Low: Depends on code heap size and content. +Holds CodeCache_lock during analysis step, usually sub-second duration. .PP -Impact: Medium +\f[I]arguments\f[R]: +.IP \[bu] 2 +\f[I]function\f[R]: (Optional) Function to be performed (aggregate, +UsedSpace, FreeSpace, MethodCount, MethodSpace, MethodAge, MethodNames, +discard (STRING, all) +.IP \[bu] 2 +\f[I]granularity\f[R]: (Optional) Detail level - smaller value -> more +detail (INT, 4096) .RE .TP -\f[V]Compiler.perfmap\f[R] (Linux only) -Write map file for Linux perf tool. +\f[V]Compiler.codecache\f[R] +Prints code cache layout and bounds. .RS .PP Impact: Low .RE .TP -\f[V]Compiler.queue\f[R] -Prints methods queued for compilation. +\f[V]Compiler.codelist\f[R] +Prints all compiled methods in code cache that are alive. .RS .PP -Impact: Low +Impact: Medium .RE .TP -\f[V]Compiler.directives_add *filename* *arguments*\f[R] +\f[V]Compiler.directives_add\f[R] \f[I]arguments\f[R] Adds compiler directives from a file. .RS .PP Impact: Low .PP \f[I]arguments\f[R]: -.PP +.IP \[bu] 2 \f[I]filename\f[R]: The name of the directives file (STRING, no default value) .RE @@ -225,6 +228,38 @@ Remove latest added compiler directive. Impact: Low .RE .TP +\f[V]Compiler.memory\f[R] [\f[I]options\f[R]] +Print compilation footprint +.RS +.PP +Impact: Medium: Pause time depends on number of compiled methods +.PP +\f[B]Note:\f[R] +.PP +The \f[I]options\f[R] must be specified using either \f[I]key\f[R] or +\f[I]key\f[R]\f[V]=\f[R]\f[I]value\f[R] syntax. +.PP +\f[I]options\f[R]: +.IP \[bu] 2 +\f[V]-H\f[R]: (Optional) Human readable format (BOOLEAN, false) +.IP \[bu] 2 +\f[V]-s\f[R]: (Optional) Minimum memory size (MEMORY SIZE, 0) +.RE +.TP +\f[V]Compiler.perfmap\f[R] (Linux only) +Write map file for Linux perf tool. +.RS +.PP +Impact: Low +.RE +.TP +\f[V]Compiler.queue\f[R] +Prints methods queued for compilation. +.RS +.PP +Impact: Low +.RE +.TP \f[V]GC.class_histogram\f[R] [\f[I]options\f[R]] Provides statistics about the Java heap usage. .RS @@ -281,6 +316,12 @@ gzipped format using the given compression level. .IP \[bu] 2 \f[V]-overwrite\f[R]: (Optional) If specified, the dump file will be overwritten if it exists (BOOLEAN, false) +.IP \[bu] 2 +\f[V]-parallel\f[R]: (Optional) Number of parallel threads to use for +heap dump. +The VM will try to use the specified number of threads, but might use +fewer. +(INT, 1) .PP \f[I]arguments\f[R]: .IP \[bu] 2 @@ -344,6 +385,11 @@ If no parameters are entered, the current settings are displayed. .PP \f[I]options\f[R]: .IP \[bu] 2 +\f[V]dumppath\f[R]: (Optional) Path to the location where a recording +file is written in case the VM runs into a critical error, such as a +system crash. +(STRING, The default location is the current directory) +.IP \[bu] 2 \f[V]globalbuffercount\f[R]: (Optional) Number of global buffers. This option is a legacy option: change the \f[V]memorysize\f[R] parameter to alter the number of global buffers. @@ -641,7 +687,7 @@ Impact: Low .RE .TP \f[V]JVMTI.data_dump\f[R] -Signals the JVM to do a data-dump request for JVMTI. +Signal the JVM to do a data-dump request for JVMTI. .RS .PP Impact: High @@ -757,8 +803,45 @@ Stops the remote management agent. Impact: Low --- no impact .RE .TP +\f[V]System.dump_map\f[R] [\f[I]options\f[R]] (Linux only) +Dumps an annotated process memory map to an output file. +.RS +.PP +Impact: Low +.PP +\f[B]Note:\f[R] +.PP +The following \f[I]options\f[R] must be specified using either +\f[I]key\f[R] or \f[I]key\f[R]\f[V]=\f[R]\f[I]value\f[R] syntax. +.PP +\f[I]options\f[R]: +.IP \[bu] 2 +\f[V]-H\f[R]: (Optional) Human readable format (BOOLEAN, false) +.IP \[bu] 2 +\f[V]-F\f[R]: (Optional) File path (STRING, +\[dq]vm_memory_map_.txt\[dq]) +.RE +.TP +\f[V]System.map\f[R] [\f[I]options\f[R]] (Linux only) +Prints an annotated process memory map of the VM process. +.RS +.PP +Impact: Low +.PP +\f[B]Note:\f[R] +.PP +The following \f[I]options\f[R] must be specified using either +\f[I]key\f[R] or \f[I]key\f[R]\f[V]=\f[R]\f[I]value\f[R] syntax. +.PP +\f[I]options\f[R]: +.IP \[bu] 2 +\f[V]-H\f[R]: (Optional) Human readable format (BOOLEAN, false) +.RE +.TP \f[V]System.native_heap_info\f[R] (Linux only) -Prints information about native heap usage through malloc_info(3). +Attempts to output information regarding native heap usage through +malloc_info(3). +If unsuccessful outputs \[dq]Error: \[dq] and a reason. .RS .PP Impact: Low @@ -771,6 +854,31 @@ Attempts to free up memory by trimming the C-heap. Impact: Low .RE .TP +\f[V]Thread.dump_to_file\f[R] [\f[I]options\f[R]] \f[I]filepath\f[R] +Dump threads, with stack traces, to a file in plain text or JSON format. +.RS +.PP +Impact: Medium: Depends on the number of threads. +.PP +\f[B]Note:\f[R] +.PP +The following \f[I]options\f[R] must be specified using either +\f[I]key\f[R] or \f[I]key\f[R]\f[V]=\f[R]\f[I]value\f[R] syntax. +.PP +\f[I]options\f[R]: +.IP \[bu] 2 +\f[V]-overwrite\f[R]: (Optional) May overwrite existing file (BOOLEAN, +false) +.IP \[bu] 2 +\f[V]-format\f[R]: (Optional) Output format (\[dq]plain\[dq] or +\[dq]json\[dq]) (STRING, plain) +.PP +\f[I]arguments\f[R]: +.IP \[bu] 2 +\f[V]filepath\f[R]: The file path to the output file (STRING, no default +value) +.RE +.TP \f[V]Thread.print\f[R] [\f[I]options\f[R]] Prints all threads with stacktraces. .RS @@ -792,7 +900,7 @@ false) .RE .TP \f[V]VM.cds\f[R] [\f[I]arguments\f[R]] -Dumps a static or dynamic shared archive that includes all currently +Dump a static or dynamic shared archive that includes all currently loaded classes. .RS .PP @@ -818,78 +926,98 @@ If \f[V]dynamic_dump\f[R] is specified, the target JVM must be started with the JVM option \f[V]-XX:+RecordDynamicDumpInfo\f[R]. .RE .TP -\f[V]VM.classloaders\f[R] [\f[I]options\f[R]] -Prints classloader hierarchy. +\f[V]VM.class_hierarchy\f[R] [\f[I]options\f[R]] [\f[I]arguments\f[R]] +Print a list of all loaded classes, indented to show the class +hierarchy. +The name of each class is followed by the ClassLoaderData* of its +ClassLoader, or \[dq]null\[dq] if it is loaded by the bootstrap class +loader. .RS .PP -Impact: Medium --- Depends on number of class loaders and classes -loaded. +Impact: Medium --- depends on the number of loaded classes. +.PP +\f[B]Note:\f[R] .PP The following \f[I]options\f[R] must be specified using either \f[I]key\f[R] or \f[I]key\f[R]\f[V]=\f[R]\f[I]value\f[R] syntax. .PP \f[I]options\f[R]: .IP \[bu] 2 -\f[V]show-classes\f[R]: (Optional) Print loaded classes. +\f[V]-i\f[R]: (Optional) Inherited interfaces should be printed. (BOOLEAN, false) .IP \[bu] 2 -\f[V]verbose\f[R]: (Optional) Print detailed information. +\f[V]-s\f[R]: (Optional) If a classname is specified, print its +subclasses in addition to its superclasses. +Without this option only the superclasses will be printed. (BOOLEAN, false) +.PP +\f[I]arguments\f[R]: .IP \[bu] 2 -\f[V]fold\f[R]: (Optional) Show loaders of the same name and class as -one. -(BOOLEAN, true) +\f[I]classname\f[R]: (Optional) The name of the class whose hierarchy +should be printed. +If not specified, all class hierarchies are printed. +(STRING, no default value) +.RE +.TP +\f[V]VM.classes\f[R] [\f[I]options\f[R]] +Print all loaded classes +.RS +.PP +Impact: Medium: Depends on number of loaded classes. +.PP +The following \f[I]options\f[R] must be specified using either +\f[I]key\f[R] or \f[I]key\f[R]\f[V]=\f[R]\f[I]value\f[R] syntax. +.PP +\f[I]options\f[R]: +.IP \[bu] 2 +\f[V]-verbose\f[R]: (Optional) Dump the detailed content of a Java +class. +Some classes are annotated with flags: \f[V]F\f[R] = has, or inherits, a +non-empty finalize method, \f[V]f\f[R] = has final method, \f[V]W\f[R] = +methods rewritten, \f[V]C\f[R] = marked with \f[V]\[at]Contended\f[R] +annotation, \f[V]R\f[R] = has been redefined, \f[V]S\f[R] = is shared +class (BOOLEAN, false) .RE .TP \f[V]VM.classloader_stats\f[R] -Prints statistics about all ClassLoaders. +Print statistics about all ClassLoaders. .RS .PP Impact: Low .RE .TP -\f[V]VM.class_hierarchy\f[R] [\f[I]options\f[R]] [\f[I]arguments\f[R]] -Prints a list of all loaded classes, indented to show the class -hierarchy. -The name of each class is followed by the ClassLoaderData* of its -ClassLoader, or \[dq]null\[dq] if it is loaded by the bootstrap class -loader. +\f[V]VM.classloaders\f[R] [\f[I]options\f[R]] +Prints classloader hierarchy. .RS .PP -Impact: Medium --- depends on the number of loaded classes. -.PP -\f[B]Note:\f[R] +Impact: Medium --- Depends on number of class loaders and classes +loaded. .PP The following \f[I]options\f[R] must be specified using either \f[I]key\f[R] or \f[I]key\f[R]\f[V]=\f[R]\f[I]value\f[R] syntax. .PP \f[I]options\f[R]: .IP \[bu] 2 -\f[V]-i\f[R]: (Optional) Inherited interfaces should be printed. +\f[V]show-classes\f[R]: (Optional) Print loaded classes. (BOOLEAN, false) .IP \[bu] 2 -\f[V]-s\f[R]: (Optional) If a classname is specified, print its -subclasses in addition to its superclasses. -Without this option only the superclasses will be printed. +\f[V]verbose\f[R]: (Optional) Print detailed information. (BOOLEAN, false) -.PP -\f[I]arguments\f[R]: .IP \[bu] 2 -\f[I]classname\f[R]: (Optional) The name of the class whose hierarchy -should be printed. -If not specified, all class hierarchies are printed. -(STRING, no default value) +\f[V]fold\f[R]: (Optional) Show loaders of the same name and class as +one. +(BOOLEAN, true) .RE .TP \f[V]VM.command_line\f[R] -Prints the command line used to start this VM instance. +Print the command line used to start this VM instance. .RS .PP Impact: Low .RE .TP \f[V]VM.dynlibs\f[R] -Prints the loaded dynamic libraries. +Print loaded dynamic libraries. .RS .PP Impact: Low @@ -918,8 +1046,25 @@ If omitted, all events are printed. (STRING, no default value) .RE .TP +\f[V]VM.flags\f[R] [\f[I]options\f[R]] +Print the VM flag options and their current values. +.RS +.PP +Impact: Low +.PP +\f[B]Note:\f[R] +.PP +The following \f[I]options\f[R] must be specified using either +\f[I]key\f[R] or \f[I]key\f[R]\f[V]=\f[R]\f[I]value\f[R] syntax. +.PP +\f[I]options\f[R]: +.IP \[bu] 2 +\f[V]-all\f[R]: (Optional) Prints all flags supported by the VM +(BOOLEAN, false). +.RE +.TP \f[V]VM.info\f[R] -Prints information about the JVM environment and status. +Print information about the JVM environment and status. .RS .PP Impact: Low @@ -964,23 +1109,6 @@ configuration. (BOOLEAN, no default value) .RE .TP -\f[V]VM.flags\f[R] [\f[I]options\f[R]] -Prints the VM flag options and their current values. -.RS -.PP -Impact: Low -.PP -\f[B]Note:\f[R] -.PP -The following \f[I]options\f[R] must be specified using either -\f[I]key\f[R] or \f[I]key\f[R]\f[V]=\f[R]\f[I]value\f[R] syntax. -.PP -\f[I]options\f[R]: -.IP \[bu] 2 -\f[V]-all\f[R]: (Optional) Prints all flags supported by the VM -(BOOLEAN, false). -.RE -.TP \f[V]VM.metaspace\f[R] [\f[I]options\f[R]] Prints the statistics for the metaspace .RS @@ -1015,6 +1143,10 @@ classes for each loader. space. (BOOLEAN, false) .IP \[bu] 2 +\f[V]chunkfreelist\f[R]: (Optional) Shows details about global chunk +free lists (ChunkManager). +(BOOLEAN, false) +.IP \[bu] 2 \f[V]scale\f[R]: (Optional) Memory usage in which to scale. Valid values are: 1, KB, MB or GB (fixed scale) or \[dq]dynamic\[dq] for a dynamically chosen scale. @@ -1022,7 +1154,7 @@ a dynamically chosen scale. .RE .TP \f[V]VM.native_memory\f[R] [\f[I]options\f[R]] -Prints native memory usage +Print native memory usage .RS .PP Impact: Medium @@ -1064,16 +1196,8 @@ purpose. (STRING, KB) .RE .TP -\f[V]VM.print_touched_methods\f[R] -Prints all methods that have ever been touched during the lifetime of -this JVM. -.RS -.PP -Impact: Medium --- depends on Java content. -.RE -.TP \f[V]VM.set_flag\f[R] [\f[I]arguments\f[R]] -Sets the VM flag option by using the provided value. +Sets VM flag option using the provided value. .RS .PP Impact: Low @@ -1088,7 +1212,7 @@ no default value) .RE .TP \f[V]VM.stringtable\f[R] [\f[I]options\f[R]] -Dumps the string table. +Dump string table. .RS .PP Impact: Medium --- depends on the Java content. @@ -1105,7 +1229,7 @@ table (BOOLEAN, false) .RE .TP \f[V]VM.symboltable\f[R] [\f[I]options\f[R]] -Dumps the symbol table. +Dump symbol table. .RS .PP Impact: Medium --- depends on the Java content. @@ -1121,6 +1245,13 @@ The following \f[I]options\f[R] must be specified using either table (BOOLEAN, false) .RE .TP +\f[V]VM.system_properties\f[R] +Print system properties. +.RS +.PP +Impact: Low +.RE +.TP \f[V]VM.systemdictionary\f[R] Prints the statistics for dictionary hashtable sizes and bucket length. .RS @@ -1138,15 +1269,8 @@ The following \f[I]options\f[R] must be specified using either for all class loaders (BOOLEAN, false) . .RE .TP -\f[V]VM.system_properties\f[R] -Prints the system properties. -.RS -.PP -Impact: Low -.RE -.TP \f[V]VM.uptime\f[R] [\f[I]options\f[R]] -Prints the VM uptime. +Print VM uptime. .RS .PP Impact: Low @@ -1163,7 +1287,7 @@ The following \f[I]options\f[R] must be specified using either .RE .TP \f[V]VM.version\f[R] -Prints JVM version information. +Print JVM version information. .RS .PP Impact: Low diff --git a/src/jdk.jcmd/share/man/jinfo.1 b/src/jdk.jcmd/share/man/jinfo.1 index ab87b21ab25..2c01b0201ca 100644 --- a/src/jdk.jcmd/share/man/jinfo.1 +++ b/src/jdk.jcmd/share/man/jinfo.1 @@ -35,7 +35,7 @@ . ftr VB CB . ftr VBI CBI .\} -.TH "JINFO" "1" "2024" "JDK 22-ea" "JDK Commands" +.TH "JINFO" "1" "2024" "JDK 22" "JDK Commands" .hy .SH NAME .PP diff --git a/src/jdk.jcmd/share/man/jmap.1 b/src/jdk.jcmd/share/man/jmap.1 index 84e8abd7f0b..365f88b6582 100644 --- a/src/jdk.jcmd/share/man/jmap.1 +++ b/src/jdk.jcmd/share/man/jmap.1 @@ -35,7 +35,7 @@ . ftr VB CB . ftr VBI CBI .\} -.TH "JMAP" "1" "2024" "JDK 22-ea" "JDK Commands" +.TH "JMAP" "1" "2024" "JDK 22" "JDK Commands" .hy .SH NAME .PP diff --git a/src/jdk.jcmd/share/man/jps.1 b/src/jdk.jcmd/share/man/jps.1 index 65284dd8efc..5ab0ba8fbe0 100644 --- a/src/jdk.jcmd/share/man/jps.1 +++ b/src/jdk.jcmd/share/man/jps.1 @@ -35,7 +35,7 @@ . ftr VB CB . ftr VBI CBI .\} -.TH "JPS" "1" "2024" "JDK 22-ea" "JDK Commands" +.TH "JPS" "1" "2024" "JDK 22" "JDK Commands" .hy .SH NAME .PP diff --git a/src/jdk.jcmd/share/man/jstack.1 b/src/jdk.jcmd/share/man/jstack.1 index d865d38138d..916ddadcfa7 100644 --- a/src/jdk.jcmd/share/man/jstack.1 +++ b/src/jdk.jcmd/share/man/jstack.1 @@ -35,7 +35,7 @@ . ftr VB CB . ftr VBI CBI .\} -.TH "JSTACK" "1" "2024" "JDK 22-ea" "JDK Commands" +.TH "JSTACK" "1" "2024" "JDK 22" "JDK Commands" .hy .SH NAME .PP diff --git a/src/jdk.jcmd/share/man/jstat.1 b/src/jdk.jcmd/share/man/jstat.1 index d62916c5c04..65d35c77a77 100644 --- a/src/jdk.jcmd/share/man/jstat.1 +++ b/src/jdk.jcmd/share/man/jstat.1 @@ -35,7 +35,7 @@ . ftr VB CB . ftr VBI CBI .\} -.TH "JSTAT" "1" "2024" "JDK 22-ea" "JDK Commands" +.TH "JSTAT" "1" "2024" "JDK 22" "JDK Commands" .hy .SH NAME .PP diff --git a/src/jdk.jconsole/share/man/jconsole.1 b/src/jdk.jconsole/share/man/jconsole.1 index 5b61f92e6fa..7086f8fd168 100644 --- a/src/jdk.jconsole/share/man/jconsole.1 +++ b/src/jdk.jconsole/share/man/jconsole.1 @@ -35,7 +35,7 @@ . ftr VB CB . ftr VBI CBI .\} -.TH "JCONSOLE" "1" "2024" "JDK 22-ea" "JDK Commands" +.TH "JCONSOLE" "1" "2024" "JDK 22" "JDK Commands" .hy .SH NAME .PP diff --git a/src/jdk.jdeps/share/man/javap.1 b/src/jdk.jdeps/share/man/javap.1 index 46d83c90f45..ebc6089f51a 100644 --- a/src/jdk.jdeps/share/man/javap.1 +++ b/src/jdk.jdeps/share/man/javap.1 @@ -35,7 +35,7 @@ . ftr VB CB . ftr VBI CBI .\} -.TH "JAVAP" "1" "2024" "JDK 22-ea" "JDK Commands" +.TH "JAVAP" "1" "2024" "JDK 22" "JDK Commands" .hy .SH NAME .PP diff --git a/src/jdk.jdeps/share/man/jdeprscan.1 b/src/jdk.jdeps/share/man/jdeprscan.1 index c252198d432..62a995aca53 100644 --- a/src/jdk.jdeps/share/man/jdeprscan.1 +++ b/src/jdk.jdeps/share/man/jdeprscan.1 @@ -35,7 +35,7 @@ . ftr VB CB . ftr VBI CBI .\} -.TH "JDEPRSCAN" "1" "2024" "JDK 22-ea" "JDK Commands" +.TH "JDEPRSCAN" "1" "2024" "JDK 22" "JDK Commands" .hy .SH NAME .PP diff --git a/src/jdk.jdeps/share/man/jdeps.1 b/src/jdk.jdeps/share/man/jdeps.1 index 32eb438b520..41189da8362 100644 --- a/src/jdk.jdeps/share/man/jdeps.1 +++ b/src/jdk.jdeps/share/man/jdeps.1 @@ -35,7 +35,7 @@ . ftr VB CB . ftr VBI CBI .\} -.TH "JDEPS" "1" "2024" "JDK 22-ea" "JDK Commands" +.TH "JDEPS" "1" "2024" "JDK 22" "JDK Commands" .hy .SH NAME .PP diff --git a/src/jdk.jdi/share/man/jdb.1 b/src/jdk.jdi/share/man/jdb.1 index d53d8b7ac6e..f4a130e4dc0 100644 --- a/src/jdk.jdi/share/man/jdb.1 +++ b/src/jdk.jdi/share/man/jdb.1 @@ -35,7 +35,7 @@ . ftr VB CB . ftr VBI CBI .\} -.TH "JDB" "1" "2024" "JDK 22-ea" "JDK Commands" +.TH "JDB" "1" "2024" "JDK 22" "JDK Commands" .hy .SH NAME .PP diff --git a/src/jdk.jdwp.agent/share/native/libdt_socket/socketTransport.c b/src/jdk.jdwp.agent/share/native/libdt_socket/socketTransport.c index d494a7ecb2c..e85c5d4e0e5 100644 --- a/src/jdk.jdwp.agent/share/native/libdt_socket/socketTransport.c +++ b/src/jdk.jdwp.agent/share/native/libdt_socket/socketTransport.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2024, 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 @@ -395,18 +395,14 @@ parseAddress(const char *address, struct addrinfo **result) { return getAddrInfo(address, hostnameLen, port, &hints, result); } -/* - * Input is sockaddr just because all clients have it. - */ -static void convertIPv4ToIPv6(const struct sockaddr *addr4, struct in6_addr *addr6) { +static void convertIPv4ToIPv6(const struct in_addr *addr4, struct in6_addr *addr6) { // Implement in a platform-independent way. // Spec requires in_addr has s_addr member, in6_addr has s6_addr[16] member. - struct in_addr *a4 = &(((struct sockaddr_in*)addr4)->sin_addr); memset(addr6, 0, sizeof(*addr6)); // for safety // Mapped address contains 80 zero bits, then 16 "1" bits, then IPv4 address (4 bytes). addr6->s6_addr[10] = addr6->s6_addr[11] = 0xFF; - memcpy(&(addr6->s6_addr[12]), &(a4->s_addr), 4); + memcpy(&(addr6->s6_addr[12]), &(addr4->s_addr), 4); } /* @@ -415,37 +411,19 @@ static void convertIPv4ToIPv6(const struct sockaddr *addr4, struct in6_addr *add */ static jdwpTransportError parseAllowedAddr(const char *buffer, struct in6_addr *result, int *isIPv4) { - struct addrinfo hints; - struct addrinfo *addrInfo = NULL; - jdwpTransportError err; - - /* - * To parse both IPv4 and IPv6 need to specify AF_UNSPEC family - * (with AF_INET6 IPv4 addresses are not parsed even with AI_V4MAPPED and AI_ALL flags). - */ - memset (&hints, 0, sizeof(hints)); - hints.ai_family = AF_UNSPEC; // IPv6 or mapped IPv4 - hints.ai_socktype = SOCK_STREAM; - hints.ai_protocol = IPPROTO_TCP; - hints.ai_flags = AI_NUMERICHOST; // only numeric addresses, no resolution - - err = getAddrInfo(buffer, strlen(buffer), NULL, &hints, &addrInfo); - - if (err != JDWPTRANSPORT_ERROR_NONE) { - return err; - } - - if (addrInfo->ai_family == AF_INET6) { - memcpy(result, &(((struct sockaddr_in6 *)(addrInfo->ai_addr))->sin6_addr), sizeof(*result)); + struct in_addr addr; + struct in6_addr addr6; + if (inet_pton(AF_INET6, buffer, &addr6) == 1) { *isIPv4 = 0; - } else { // IPv4 address - convert to mapped IPv6 - struct in6_addr addr6; - convertIPv4ToIPv6(addrInfo->ai_addr, &addr6); - memcpy(result, &addr6, sizeof(*result)); + } else if (inet_pton(AF_INET, buffer, &addr) == 1) { + // IPv4 address - convert to mapped IPv6 + convertIPv4ToIPv6(&addr, &addr6); *isIPv4 = 1; + } else { + return JDWPTRANSPORT_ERROR_IO_ERROR; } - dbgsysFreeAddrInfo(addrInfo); + memcpy(result, &addr6, sizeof(*result)); return JDWPTRANSPORT_ERROR_NONE; } @@ -603,7 +581,8 @@ isPeerAllowed(struct sockaddr_storage *peer) { int i; // _peers contains IPv6 subnet and mask (IPv4 is converted to mapped IPv6) if (peer->ss_family == AF_INET) { - convertIPv4ToIPv6((struct sockaddr *)peer, &tmp); + struct in_addr *addr4 = &(((struct sockaddr_in*)peer)->sin_addr); + convertIPv4ToIPv6(addr4, &tmp); addr6 = &tmp; } else { addr6 = &(((struct sockaddr_in6 *)peer)->sin6_addr); @@ -752,7 +731,7 @@ socketTransport_startListening(jdwpTransportEnv* env, const char* address, if (isEqualIPv6Addr(listenAddr, mappedAny)) { for (ai = addrInfo; ai != NULL; ai = ai->ai_next) { - if (isEqualIPv6Addr(listenAddr, in6addr_any)) { + if (isEqualIPv6Addr(ai, in6addr_any)) { listenAddr = ai; break; } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/periodic/BatchManager.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/periodic/BatchManager.java index 141cf1a932b..8d51cb1de6f 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/periodic/BatchManager.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/periodic/BatchManager.java @@ -63,11 +63,7 @@ private void groupTasksIntoBatches(List tasks) { } for (PeriodicTask task : activeSortedTasks(tasks)) { if (task.isSchedulable()) { - Batch batch = task.getBatch(); - // If new task, or period has changed, find new batch - if (batch == null) { - batch = findBatch(task.getPeriod()); - } + Batch batch = findBatch(task.getPeriod(), task.getBatch()); batch.add(task); } } @@ -89,7 +85,7 @@ private List activeSortedTasks(List unsorted) { return tasks; } - private Batch findBatch(long period) { + private Batch findBatch(long period, Batch oldBatch) { // All events with a period less than 1000 ms // get their own unique batch. The rationale for // this is to avoid a scenario where a user (mistakenly) specifies @@ -102,7 +98,7 @@ private Batch findBatch(long period) { return batch; } } - Batch batch = new Batch(period); + Batch batch = oldBatch != null ? oldBatch : new Batch(period); batches.add(batch); return batch; } diff --git a/src/jdk.jfr/share/man/jfr.1 b/src/jdk.jfr/share/man/jfr.1 index 576721fe21a..1f2461534ce 100644 --- a/src/jdk.jfr/share/man/jfr.1 +++ b/src/jdk.jfr/share/man/jfr.1 @@ -35,7 +35,7 @@ . ftr VB CB . ftr VBI CBI .\} -.TH "JFR" "1" "2024" "JDK 22-ea" "JDK Commands" +.TH "JFR" "1" "2024" "JDK 22" "JDK Commands" .hy .SH NAME .PP diff --git a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/SystemModulesPlugin.java b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/SystemModulesPlugin.java index 735c969a886..40693b33d6d 100644 --- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/SystemModulesPlugin.java +++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/SystemModulesPlugin.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, 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 @@ -1827,6 +1827,9 @@ private String genSystemModulesMapClass(ClassDesc allSystemModules, // write the class file to the pool as a resource String rn = "/java.base/" + SYSTEM_MODULES_MAP_CLASSNAME + ".class"; + // sort the map of module name to the class name of the generated SystemModules class + List> systemModulesMap = map.entrySet() + .stream().sorted(Map.Entry.comparingByKey()).toList(); ResourcePoolEntry e = ResourcePoolEntry.create(rn, ClassFile.of().build( CD_SYSTEM_MODULES_MAP, clb -> clb.withFlags(ACC_FINAL + ACC_SUPER) @@ -1877,10 +1880,10 @@ private String genSystemModulesMapClass(ClassDesc allSystemModules, cob.anewarray(CD_String); int index = 0; - for (String moduleName : sorted(map.keySet())) { + for (Map.Entry entry : systemModulesMap) { cob.dup() // arrayref .constantInstruction(index) - .constantInstruction(moduleName) + .constantInstruction(entry.getKey()) .aastore(); index++; } @@ -1898,10 +1901,10 @@ private String genSystemModulesMapClass(ClassDesc allSystemModules, .anewarray(CD_String); int index = 0; - for (String className : sorted(map.values())) { + for (Map.Entry entry : systemModulesMap) { cob.dup() // arrayref .constantInstruction(index) - .constantInstruction(className.replace('/', '.')) + .constantInstruction(entry.getValue().replace('/', '.')) .aastore(); index++; } diff --git a/src/jdk.jlink/share/man/jlink.1 b/src/jdk.jlink/share/man/jlink.1 index a8aaf2982fe..05b63fabd64 100644 --- a/src/jdk.jlink/share/man/jlink.1 +++ b/src/jdk.jlink/share/man/jlink.1 @@ -35,7 +35,7 @@ . ftr VB CB . ftr VBI CBI .\} -.TH "JLINK" "1" "2024" "JDK 22-ea" "JDK Commands" +.TH "JLINK" "1" "2024" "JDK 22" "JDK Commands" .hy .SH NAME .PP diff --git a/src/jdk.jlink/share/man/jmod.1 b/src/jdk.jlink/share/man/jmod.1 index 74b73cd9d92..ccaedbc5332 100644 --- a/src/jdk.jlink/share/man/jmod.1 +++ b/src/jdk.jlink/share/man/jmod.1 @@ -35,7 +35,7 @@ . ftr VB CB . ftr VBI CBI .\} -.TH "JMOD" "1" "2024" "JDK 22-ea" "JDK Commands" +.TH "JMOD" "1" "2024" "JDK 22" "JDK Commands" .hy .SH NAME .PP diff --git a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/resources/services_utils.sh b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/resources/services_utils.sh index 730137104cf..27a71ab6161 100644 --- a/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/resources/services_utils.sh +++ b/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/resources/services_utils.sh @@ -4,7 +4,8 @@ register_services () { for unit in "$@"; do - systemctl enable --now "$unit" + local unit_name=`basename "$unit"` + systemctl enable --now "$unit_name" done } diff --git a/src/jdk.jpackage/share/man/jpackage.1 b/src/jdk.jpackage/share/man/jpackage.1 index ec26b28e852..4da59198c1e 100644 --- a/src/jdk.jpackage/share/man/jpackage.1 +++ b/src/jdk.jpackage/share/man/jpackage.1 @@ -35,7 +35,7 @@ . ftr VB CB . ftr VBI CBI .\} -.TH "JPACKAGE" "1" "2024" "JDK 22-ea" "JDK Commands" +.TH "JPACKAGE" "1" "2024" "JDK 22" "JDK Commands" .hy .SH NAME .PP diff --git a/src/jdk.jpackage/windows/native/applauncher/WinLauncher.cpp b/src/jdk.jpackage/windows/native/applauncher/WinLauncher.cpp index d9757bd0819..119cbbd79c5 100644 --- a/src/jdk.jpackage/windows/native/applauncher/WinLauncher.cpp +++ b/src/jdk.jpackage/windows/native/applauncher/WinLauncher.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, 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 @@ -264,7 +264,7 @@ void launchApp() { } JOBOBJECT_EXTENDED_LIMIT_INFORMATION jobInfo = { }; jobInfo.BasicLimitInformation.LimitFlags = - JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; + JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE | JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK; if (!SetInformationJobObject(jobHandle.get(), JobObjectExtendedLimitInformation, &jobInfo, sizeof(jobInfo))) { JP_THROW(SysError(tstrings::any() << diff --git a/src/jdk.jshell/share/classes/jdk/jshell/CompletenessAnalyzer.java b/src/jdk.jshell/share/classes/jdk/jshell/CompletenessAnalyzer.java index 1579a48786c..663ca164a3d 100644 --- a/src/jdk.jshell/share/classes/jdk/jshell/CompletenessAnalyzer.java +++ b/src/jdk.jshell/share/classes/jdk/jshell/CompletenessAnalyzer.java @@ -190,7 +190,7 @@ static enum TK { EOF(TokenKind.EOF, 0), // ERROR(TokenKind.ERROR, XERRO), // IDENTIFIER(TokenKind.IDENTIFIER, XEXPR1|XDECL1|XTERM), // - UNDERSCORE(TokenKind.UNDERSCORE, XDECL1), // _ + UNDERSCORE(TokenKind.UNDERSCORE, XDECL1|XEXPR), // _ CLASS(TokenKind.CLASS, XEXPR|XDECL1|XBRACESNEEDED), // class decl (MAPPED: DOTCLASS) MONKEYS_AT(TokenKind.MONKEYS_AT, XEXPR|XDECL1), // @ IMPORT(TokenKind.IMPORT, XDECL1|XSTART), // import -- consider declaration diff --git a/src/jdk.jshell/share/classes/jdk/jshell/TaskFactory.java b/src/jdk.jshell/share/classes/jdk/jshell/TaskFactory.java index ac777435102..5360e0d517f 100644 --- a/src/jdk.jshell/share/classes/jdk/jshell/TaskFactory.java +++ b/src/jdk.jshell/share/classes/jdk/jshell/TaskFactory.java @@ -80,8 +80,13 @@ import com.sun.tools.javac.comp.Enter; import com.sun.tools.javac.comp.Env; import com.sun.tools.javac.comp.Resolve; +import com.sun.tools.javac.parser.JavacParser; +import com.sun.tools.javac.parser.Lexer; import com.sun.tools.javac.parser.Parser; import com.sun.tools.javac.parser.ParserFactory; +import com.sun.tools.javac.parser.ScannerFactory; +import static com.sun.tools.javac.parser.Tokens.TokenKind.AMP; +import com.sun.tools.javac.tree.JCTree; import com.sun.tools.javac.tree.JCTree.JCExpression; import com.sun.tools.javac.tree.JCTree.JCTypeCast; import com.sun.tools.javac.tree.JCTree.JCVariableDecl; @@ -363,7 +368,7 @@ private ParseTask(SourceHandler sh, JavacTaskImpl task, DiagnosticCollector diagnostics, boolean forceExpression) { - super(sh, task, diagnostics); + super(sh, task, diagnostics, false); ReplParserFactory.preRegister(context, forceExpression); cuts = parse(); units = Util.stream(cuts) @@ -402,7 +407,7 @@ class AnalyzeTask extends BaseTask { private AnalyzeTask(SourceHandler sh, JavacTaskImpl task, DiagnosticCollector diagnostics) { - super(sh, task, diagnostics); + super(sh, task, diagnostics, true); cuts = analyze(); } @@ -440,7 +445,7 @@ class CompileTask extends BaseTask { CompileTask(SourceHandlersh, JavacTaskImpl jti, DiagnosticCollector diagnostics) { - super(sh, jti, diagnostics); + super(sh, jti, diagnostics, true); } boolean compile() { @@ -504,11 +509,15 @@ abstract class BaseTask { private BaseTask(SourceHandler sh, JavacTaskImpl task, - DiagnosticCollector diagnostics) { + DiagnosticCollector diagnostics, + boolean analyzeParserFactory) { this.sourceHandler = sh; this.task = task; context = task.getContext(); this.diagnostics = diagnostics; + if (analyzeParserFactory) { + JShellAnalyzeParserFactory.preRegister(context); + } } abstract Iterable cuTrees(); @@ -693,7 +702,7 @@ private void setVariableType(VarSnippet s) { Symtab syms = Symtab.instance(context); Names names = Names.instance(context); Log log = Log.instance(context); - ParserFactory parserFactory = ParserFactory.instance(context); + JShellAnalyzeParserFactory parserFactory = (JShellAnalyzeParserFactory) ParserFactory.instance(context); Attr attr = Attr.instance(context); Enter enter = Enter.instance(context); DisableAccessibilityResolve rs = (DisableAccessibilityResolve) Resolve.instance(context); @@ -709,26 +718,28 @@ private void setVariableType(VarSnippet s) { //ignore any errors: JavaFileObject prev = log.useSource(null); DiscardDiagnosticHandler h = new DiscardDiagnosticHandler(log); - try { - //parse the type as a cast, i.e. "() x". This is to support - //intersection types: - CharBuffer buf = CharBuffer.wrap(("(" + typeName +")x\u0000").toCharArray(), 0, typeName.length() + 3); - Parser parser = parserFactory.newParser(buf, false, false, false); - JCExpression expr = parser.parseExpression(); - if (expr.hasTag(Tag.TYPECAST)) { - //if parsed OK, attribute and set the type: - var2OriginalType.put(field, field.type); - - JCTypeCast tree = (JCTypeCast) expr; - rs.runWithoutAccessChecks(() -> { - field.type = attr.attribType(tree.clazz, - enter.getEnvs().iterator().next().enclClass.sym); - }); + parserFactory.runPermitIntersectionTypes(() -> { + try { + //parse the type as a cast, i.e. "() x". This is to support + //intersection types: + CharBuffer buf = CharBuffer.wrap(("(" + typeName +")x\u0000").toCharArray(), 0, typeName.length() + 3); + Parser parser = parserFactory.newParser(buf, false, false, false); + JCExpression expr = parser.parseExpression(); + if (expr.hasTag(Tag.TYPECAST)) { + //if parsed OK, attribute and set the type: + var2OriginalType.put(field, field.type); + + JCTypeCast tree = (JCTypeCast) expr; + rs.runWithoutAccessChecks(() -> { + field.type = attr.attribType(tree.clazz, + enter.getEnvs().iterator().next().enclClass.sym); + }); + } + } finally { + log.popDiagnosticHandler(h); + log.useSource(prev); } - } finally { - log.popDiagnosticHandler(h); - log.useSource(prev); - } + }); } } } @@ -777,4 +788,52 @@ public boolean isAccessible(Env env, Type site, Symbol sym, boolean private static final class Marker {} } + private static final class JShellAnalyzeParserFactory extends ParserFactory { + public static void preRegister(Context context) { + if (context.get(Marker.class) == null) { + context.put(parserFactoryKey, ((Factory) c -> new JShellAnalyzeParserFactory(c))); + context.put(Marker.class, new Marker()); + } + } + + private final ScannerFactory scannerFactory; + private boolean permitIntersectionTypes; + + public JShellAnalyzeParserFactory(Context context) { + super(context); + this.scannerFactory = ScannerFactory.instance(context); + } + + /**Run the given Runnable with intersection type permitted. + * + * @param r Runnnable to run + */ + public void runPermitIntersectionTypes(Runnable r) { + boolean prevPermitIntersectionTypes = permitIntersectionTypes; + try { + permitIntersectionTypes = true; + r.run(); + } finally { + permitIntersectionTypes = prevPermitIntersectionTypes; + } + } + + @Override + public JavacParser newParser(CharSequence input, boolean keepDocComments, boolean keepEndPos, boolean keepLineMap, boolean parseModuleInfo) { + com.sun.tools.javac.parser.Lexer lexer = scannerFactory.newScanner(input, keepDocComments); + return new JavacParser(this, lexer, keepDocComments, keepLineMap, keepEndPos, parseModuleInfo) { + @Override + public JCExpression parseType(boolean allowVar, com.sun.tools.javac.util.List annotations) { + int pos = token.pos; + JCExpression t = super.parseType(allowVar, annotations); + if (permitIntersectionTypes) { + t = parseIntersectionType(pos, t); + } + return t; + } + }; + } + + private static final class Marker {} + } } diff --git a/src/jdk.jshell/share/man/jshell.1 b/src/jdk.jshell/share/man/jshell.1 index 8651b703214..f77df0b4c6a 100644 --- a/src/jdk.jshell/share/man/jshell.1 +++ b/src/jdk.jshell/share/man/jshell.1 @@ -36,7 +36,7 @@ . ftr VB CB . ftr VBI CBI .\} -.TH "JSHELL" "1" "2024" "JDK 22-ea" "JDK Commands" +.TH "JSHELL" "1" "2024" "JDK 22" "JDK Commands" .hy .SH NAME .PP diff --git a/src/jdk.jstatd/share/man/jstatd.1 b/src/jdk.jstatd/share/man/jstatd.1 index 81e433bced5..de4162a7787 100644 --- a/src/jdk.jstatd/share/man/jstatd.1 +++ b/src/jdk.jstatd/share/man/jstatd.1 @@ -35,7 +35,7 @@ . ftr VB CB . ftr VBI CBI .\} -.TH "JSTATD" "1" "2024" "JDK 22-ea" "JDK Commands" +.TH "JSTATD" "1" "2024" "JDK 22" "JDK Commands" .hy .SH NAME .PP diff --git a/src/jdk.management/unix/native/libmanagement_ext/OperatingSystemImpl.c b/src/jdk.management/unix/native/libmanagement_ext/OperatingSystemImpl.c index 3183d8ef9a1..5b978ba38e1 100644 --- a/src/jdk.management/unix/native/libmanagement_ext/OperatingSystemImpl.c +++ b/src/jdk.management/unix/native/libmanagement_ext/OperatingSystemImpl.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, 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 @@ -105,6 +105,12 @@ static jlong get_total_or_available_swap_space_size(JNIEnv* env, jboolean availa throw_internal_error(env, "sysctlbyname failed"); } return available ? (jlong)vmusage.xsu_avail : (jlong)vmusage.xsu_total; +#elif defined(_AIX) + perfstat_memory_total_t memory_info; + if (perfstat_memory_total(NULL, &memory_info, sizeof(perfstat_memory_total_t), 1) == -1) { + throw_internal_error(env, "perfstat_memory_total failed"); + } + return available ? (jlong)(memory_info.pgsp_free * 4L * 1024L) : (jlong)(memory_info.pgsp_total * 4L * 1024L); #else /* _ALLBSD_SOURCE */ /* * XXXBSD: there's no way available to get swap info in diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index 01634e28062..7c6e4e7cff4 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -1,5 +1,5 @@ # -# Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2016, 2024, 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 @@ -64,6 +64,7 @@ compiler/rtm/locking/TestUseRTMXendForLockBusy.java 8183263 generic-x64,generic- compiler/rtm/print/TestPrintPreciseRTMLockingStatistics.java 8183263 generic-x64,generic-i586 compiler/c2/Test8004741.java 8235801 generic-all +compiler/c2/irTests/TestDuplicateBackedge.java 8318904 generic-all compiler/codecache/jmx/PoolsIndependenceTest.java 8264632 macosx-all @@ -85,10 +86,12 @@ gc/epsilon/TestMemoryMXBeans.java 8206434 generic-all gc/g1/humongousObjects/objectGraphTest/TestObjectGraphAfterGC.java 8156755 generic-all gc/g1/logging/TestG1LoggingFailure.java 8169634 generic-all gc/g1/humongousObjects/TestHeapCounters.java 8178918 generic-all +gc/TestAllocHumongousFragment.java#adaptive 8298781 generic-all +gc/TestAllocHumongousFragment.java#aggressive 8298781 generic-all +gc/TestAllocHumongousFragment.java#iu-aggressive 8298781 generic-all +gc/TestAllocHumongousFragment.java#g1 8298781 generic-all +gc/TestAllocHumongousFragment.java#static 8298781 generic-all gc/stress/gclocker/TestExcessGCLockerCollections.java 8229120 generic-all -gc/stress/gclocker/TestGCLockerWithParallel.java 8180622 generic-all -gc/stress/gclocker/TestGCLockerWithSerial.java 8180622 generic-all -gc/stress/gclocker/TestGCLockerWithShenandoah.java 8180622 generic-all gc/stress/TestStressG1Humongous.java 8286554 windows-x64 ############################################################################# @@ -104,6 +107,7 @@ runtime/os/TestTracePageSizes.java#G1 8267460 linux-aarch64 runtime/os/TestTracePageSizes.java#Parallel 8267460 linux-aarch64 runtime/os/TestTracePageSizes.java#Serial 8267460 linux-aarch64 runtime/ErrorHandling/CreateCoredumpOnCrash.java 8267433 macosx-x64 +runtime/CompressedOops/CompressedClassPointers.java 8322943 aix-ppc64 runtime/StackGuardPages/TestStackGuardPagesNative.java 8303612 linux-all runtime/ErrorHandling/TestDwarf.java#checkDecoder 8305489 linux-all runtime/ErrorHandling/MachCodeFramesInErrorFile.java 8313315 linux-ppc64le diff --git a/test/hotspot/jtreg/TEST.groups b/test/hotspot/jtreg/TEST.groups index 4573c0ebb9b..814141f81a4 100644 --- a/test/hotspot/jtreg/TEST.groups +++ b/test/hotspot/jtreg/TEST.groups @@ -21,6 +21,11 @@ # questions. # +# All tests + +all = \ + :hotspot_all + hotspot_all = \ / @@ -28,6 +33,8 @@ hotspot_all_no_apps = \ / \ -applications +# Component test groups + hotspot_compiler = \ compiler @@ -356,7 +363,6 @@ tier2_gc_shenandoah = \ tier3_gc_shenandoah = \ gc/stress/gcold/TestGCOldWithShenandoah.java \ gc/stress/gcbasher/TestGCBasherWithShenandoah.java \ - gc/stress/gclocker/TestGCLockerWithShenandoah.java \ gc/stress/systemgc/TestSystemGCWithShenandoah.java \ gc/shenandoah/TestStringDedupStress.java \ -:tier2_gc_shenandoah diff --git a/test/hotspot/jtreg/compiler/c1/TestLargeMonitorOffset.java b/test/hotspot/jtreg/compiler/c1/TestLargeMonitorOffset.java new file mode 100644 index 00000000000..d5cdb6bee52 --- /dev/null +++ b/test/hotspot/jtreg/compiler/c1/TestLargeMonitorOffset.java @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2024, 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 8310844 + * @summary Verify that monitors with large offset in the OSR buffer are handled properly. + * @run main/othervm -Xbatch -XX:CompileCommand=compileonly,TestLargeMonitorOffset::* TestLargeMonitorOffset + */ + +public class TestLargeMonitorOffset { + + public static void test() { + long l1, l2, l3, l4, l5, l6, l7, l8, l9, l10, + l11, l12, l13, l14, l15, l16, l17, l18, l19, l20, + l21, l22, l23, l24, l25, l26, l27, l28, l29, l30, + l31, l32, l33, l34, l35, l36, l37, l38, l39, l40, + l41, l42, l43, l44, l45, l46, l47, l48, l49, l50, + l51, l52, l53, l54, l55, l56, l57, l58, l59, l60, + l61, l62, l63, l64, l65, l66, l67, l68, l69, l70, + l71, l72, l73, l74, l75, l76, l77, l78, l79, l80, + l81, l82, l83, l84, l85, l86, l87, l88, l89, l90, + l91, l92, l93, l94, l95, l96, l97, l98, l99, l100, + l101, l102, l103, l104, l105, l106, l107, l108, l109, l110, + l111, l112, l113, l114, l115, l116, l117, l118, l119, l120, + l121, l122, l123, l124, l125, l126, l127, l128, l129, l130, + l131, l132, l133, l134, l135, l136, l137, l138, l139, l140, + l141, l142, l143, l144, l145, l146, l147, l148, l149, l150, + l151, l152, l153, l154, l155, l156, l157, l158, l159, l160, + l161, l162, l163, l164, l165, l166, l167, l168, l169, l170, + l171, l172, l173, l174, l175, l176, l177, l178, l179, l180, + l181, l182, l183, l184, l185, l186, l187, l188, l189, l190, + l191, l192, l193, l194, l195, l196, l197, l198, l199, l200, + l201, l202, l203, l204, l205, l206, l207, l208, l209, l210, + l211, l212, l213, l214, l215, l216, l217, l218, l219, l220, + l221, l222, l223, l224, l225, l226, l227, l228, l229, l230, + l231, l232, l233, l234, l235, l236, l237, l238, l239, l240, + l241, l242, l243, l244, l245, l246, l247, l248, l249, l250, + l251, l252, l253, l254, l255, l256, l257, l258, l259, l260, + l261, l262, l263, l264, l265, l266, l267, l268, l269, l270, + l271, l272, l273, l274, l275, l276, l277, l278, l279, l280, + l281, l282, l283, l284, l285, l286, l287, l288, l289, l290, + l291, l292, l293, l294, l295, l296, l297, l298, l299, l300, + l301, l302, l303, l304, l305, l306, l307, l308, l309, l310, + l311, l312, l313, l314, l315, l316, l317, l318, l319, l320, + l321, l322, l323, l324, l325, l326, l327, l328, l329, l330, + l331, l332, l333, l334, l335, l336, l337, l338, l339, l340, + l341, l342, l343, l344, l345, l346, l347, l348, l349, l350, + l351, l352, l353, l354, l355, l356, l357, l358, l359, l360, + l361, l362, l363, l364, l365, l366, l367, l368, l369, l370, + l371, l372, l373, l374, l375, l376, l377, l378, l379, l380, + l381, l382, l383, l384, l385, l386, l387, l388, l389, l390, + l391, l392, l393, l394, l395, l396, l397, l398, l399, l400, + l401, l402, l403, l404, l405, l406, l407, l408, l409, l410, + l411, l412, l413, l414, l415, l416, l417, l418, l419, l420, + l421, l422, l423, l424, l425, l426, l427, l428, l429, l430, + l431, l432, l433, l434, l435, l436, l437, l438, l439, l440, + l441, l442, l443, l444, l445, l446, l447, l448, l449, l450, + l451, l452, l453, l454, l455, l456, l457, l458, l459, l460, + l461, l462, l463, l464, l465, l466, l467, l468, l469, l470, + l471, l472, l473, l474, l475, l476, l477, l478, l479, l480, + l481, l482, l483, l484, l485, l486, l487, l488, l489, l490, + l491, l492, l493, l494, l495, l496, l497, l498, l499, l500, + l501, l502, l503, l504, l505, l506, l507, l508, l509, l510, + l511, l512, l513, l514, l515, l516, l517, l518, l519, l520, + l521, l522, l523, l524, l525, l526, l527, l528, l529, l530, + l531, l532, l533, l534, l535, l536, l537, l538, l539, l540, + l541, l542, l543, l544, l545, l546, l547, l548, l549, l550, + l551, l552, l553, l554, l555, l556, l557, l558, l559, l560, + l561, l562, l563, l564, l565, l566, l567, l568, l569, l570, + l571, l572, l573, l574, l575, l576, l577, l578, l579, l580, + l581, l582, l583, l584, l585, l586, l587, l588, l589, l590, + l591, l592, l593, l594, l595, l596, l597, l598, l599, l600, + l601, l602, l603, l604, l605, l606, l607, l608, l609, l610, + l611, l612, l613, l614, l615, l616, l617, l618, l619, l620, + l621, l622, l623, l624, l625, l626, l627, l628, l629, l630, + l631, l632, l633, l634, l635, l636, l637, l638, l639, l640, + l641, l642, l643, l644, l645, l646, l647, l648, l649, l650, + l651, l652, l653, l654, l655, l656, l657, l658, l659, l660, + l661, l662, l663, l664, l665, l666, l667, l668, l669, l670, + l671, l672, l673, l674, l675, l676, l677, l678, l679, l680, + l681, l682, l683, l684, l685, l686, l687, l688, l689, l690, + l691, l692, l693, l694, l695, l696, l697, l698, l699, l700, + l701, l702, l703, l704, l705, l706, l707, l708, l709, l710, + l711, l712, l713, l714, l715, l716, l717, l718, l719, l720, + l721, l722, l723, l724, l725, l726, l727, l728, l729, l730, + l731, l732, l733, l734, l735, l736, l737, l738, l739, l740, + l741, l742, l743, l744, l745, l746, l747, l748, l749, l750, + l751, l752, l753, l754, l755, l756, l757, l758, l759, l760, + l761, l762, l763, l764, l765, l766, l767, l768, l769, l770, + l771, l772, l773, l774, l775, l776, l777, l778, l779, l780, + l781, l782, l783, l784, l785, l786, l787, l788, l789, l790, + l791, l792, l793, l794, l795, l796, l797, l798, l799, l800, + l801, l802, l803, l804, l805, l806, l807, l808, l809, l810, + l811, l812, l813, l814, l815, l816, l817, l818, l819, l820, + l821, l822, l823, l824, l825, l826, l827, l828, l829, l830, + l831, l832, l833, l834, l835, l836, l837, l838, l839, l840, + l841, l842, l843, l844, l845, l846, l847, l848, l849, l850, + l851, l852, l853, l854, l855, l856, l857, l858, l859, l860, + l861, l862, l863, l864, l865, l866, l867, l868, l869, l870, + l871, l872, l873, l874, l875, l876, l877, l878, l879, l880, + l881, l882, l883, l884, l885, l886, l887, l888, l889, l890, + l891, l892, l893, l894, l895, l896, l897, l898, l899, l900, + l901, l902, l903, l904, l905, l906, l907, l908, l909, l910, + l911, l912, l913, l914, l915, l916, l917, l918, l919, l920, + l921, l922, l923, l924, l925, l926, l927, l928, l929, l930, + l931, l932, l933, l934, l935, l936, l937, l938, l939, l940, + l941, l942, l943, l944, l945, l946, l947, l948, l949, l950, + l951, l952, l953, l954, l955, l956, l957, l958, l959, l960, + l961, l962, l963, l964, l965, l966, l967, l968, l969, l970, + l971, l972, l973, l974, l975, l976, l977, l978, l979, l980, + l981, l982, l983, l984, l985, l986, l987, l988, l989, l990, + l991, l992, l993, l994, l995, l996, l997, l998, l999, l1000; + + synchronized (TestLargeMonitorOffset.class) { + // Trigger OSR compilation with monitor in the OSR buffer + for (int i = 0; i < 1_000_000; ++i) { + + } + } + } + + public static void main(String[] args) { + test(); + } +} diff --git a/test/hotspot/jtreg/compiler/c2/TestMinValueStrideLongCountedLoop.java b/test/hotspot/jtreg/compiler/c2/TestMinValueStrideLongCountedLoop.java new file mode 100644 index 00000000000..5fb9885dac1 --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/TestMinValueStrideLongCountedLoop.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2024, 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 compiler.c2; + +/* + * @test + * @bug 8323154 + * @summary Long counted loop exit check should not be transformed into an unsigned check + * + * @run main/othervm -Xbatch -XX:CompileCommand=compileonly,compiler.c2.TestMinValueStrideLongCountedLoop::test + * compiler.c2.TestMinValueStrideLongCountedLoop + */ + +public class TestMinValueStrideLongCountedLoop { + static long limit = 0; + static long res = 0; + + public static void main(String[] args) { + for (int i = 0; i < 10000; i++) { + test(); + } + } + + static void test() { + for (long i = 0; i >= limit + (Long.MIN_VALUE + 1); i += Long.MIN_VALUE) { + res += 42; + } + } +} diff --git a/test/hotspot/jtreg/compiler/c2/irTests/TestPrunedExHandler.java b/test/hotspot/jtreg/compiler/c2/irTests/TestPrunedExHandler.java index eacaa9fca85..9b91375acb7 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/TestPrunedExHandler.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/TestPrunedExHandler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, 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 @@ * @bug 8267532 * @summary check that uncommon trap is generated for unhandled catch block * @library /test/lib / + * @requires vm.opt.DeoptimizeALot != true * @run driver compiler.c2.irTests.TestPrunedExHandler */ diff --git a/test/hotspot/jtreg/compiler/escapeAnalysis/TestInvalidLocation.java b/test/hotspot/jtreg/compiler/escapeAnalysis/TestInvalidLocation.java new file mode 100644 index 00000000000..f97532abfb1 --- /dev/null +++ b/test/hotspot/jtreg/compiler/escapeAnalysis/TestInvalidLocation.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2024, 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 8323190 + * @summary C2 Segfaults during code generation because of unhandled SafePointScalarMerge monitor debug info. + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -Xcomp -XX:+ReduceAllocationMerges TestInvalidLocation + */ + +public class TestInvalidLocation { + static boolean var2 = true; + static double[] var4 = new double[1]; + + public static void main(String[] args) { + for (int i = 0; i < 10; i++) { + System.out.println(test()); + } + } + + static Class0 test() { + double[] var14; + double var3; + StringBuilder var1 = new StringBuilder(); + Class0 var0 = Class1.Class1_sfield0; + synchronized (var2 ? new StringBuilder() : var1) { + var14 = var4; + for (int i0 = 0; i0 < var0.Class0_field0.length && i0 < var14.length; i0 = 1) { + var3 = var14[i0]; + } + } + return var0; + } + + static class Class0 { + double[] Class0_field0; + Class0() { + Class0_field0 = new double[] { 85.42200639495138 }; + } + } + + class Class1 { + static Class0 Class1_sfield0 = new Class0(); + } +} diff --git a/test/hotspot/jtreg/compiler/intrinsics/base64/TestBase64.java b/test/hotspot/jtreg/compiler/intrinsics/base64/TestBase64.java index 5d2651c3285..0d3c9569c33 100644 --- a/test/hotspot/jtreg/compiler/intrinsics/base64/TestBase64.java +++ b/test/hotspot/jtreg/compiler/intrinsics/base64/TestBase64.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, 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 @@ -46,10 +46,13 @@ import java.util.Base64; import java.util.Base64.Decoder; import java.util.Base64.Encoder; +import java.util.HexFormat; import java.util.Objects; import java.util.Random; import java.util.Arrays; +import static java.lang.String.format; + import compiler.whitebox.CompilerWhiteBoxTest; import jdk.test.whitebox.code.Compiler; import jtreg.SkippedException; @@ -69,6 +72,8 @@ public static void main(String[] args) throws Exception { warmup(); + length_checks(); + test0(FileType.ASCII, Base64Type.BASIC, Base64.getEncoder(), Base64.getDecoder(),"plain.txt", "baseEncode.txt", iters); test0(FileType.ASCII, Base64Type.URLSAFE, Base64.getUrlEncoder(), Base64.getUrlDecoder(),"plain.txt", "urlEncode.txt", iters); test0(FileType.ASCII, Base64Type.MIME, Base64.getMimeEncoder(), Base64.getMimeDecoder(),"plain.txt", "mimeEncode.txt", iters); @@ -302,4 +307,118 @@ private static final byte getBadBase64Char(Base64Type b64Type) { throw new InternalError("Internal test error: getBadBase64Char called with unknown Base64Type value"); } } + + static final int POSITIONS = 30_000; + static final int BASE_LENGTH = 256; + static final HexFormat HEX_FORMAT = HexFormat.of().withUpperCase().withDelimiter(" "); + + static int[] plainOffsets = new int[POSITIONS + 1]; + static byte[] plainBytes; + static int[] base64Offsets = new int[POSITIONS + 1]; + static byte[] base64Bytes; + + static { + // Set up ByteBuffer with characters to be encoded + int plainLength = 0; + for (int i = 0; i < plainOffsets.length; i++) { + plainOffsets[i] = plainLength; + int positionLength = (BASE_LENGTH + i) % 2048; + plainLength += positionLength; + } + // Put one of each possible byte value into ByteBuffer + plainBytes = new byte[plainLength]; + for (int i = 0; i < plainBytes.length; i++) { + plainBytes[i] = (byte) i; + } + + // Grab various slices of the ByteBuffer and encode them + ByteBuffer plainBuffer = ByteBuffer.wrap(plainBytes); + int base64Length = 0; + for (int i = 0; i < POSITIONS; i++) { + base64Offsets[i] = base64Length; + int offset = plainOffsets[i]; + int length = plainOffsets[i + 1] - offset; + ByteBuffer plainSlice = plainBuffer.slice(offset, length); + base64Length += Base64.getEncoder().encode(plainSlice).remaining(); + } + + // Decode the slices created above and ensure lengths match + base64Offsets[base64Offsets.length - 1] = base64Length; + base64Bytes = new byte[base64Length]; + for (int i = 0; i < POSITIONS; i++) { + int plainOffset = plainOffsets[i]; + ByteBuffer plainSlice = plainBuffer.slice(plainOffset, plainOffsets[i + 1] - plainOffset); + ByteBuffer encodedBytes = Base64.getEncoder().encode(plainSlice); + int base64Offset = base64Offsets[i]; + int expectedLength = base64Offsets[i + 1] - base64Offset; + if (expectedLength != encodedBytes.remaining()) { + throw new IllegalStateException(format("Unexpected length: %s <> %s", encodedBytes.remaining(), expectedLength)); + } + encodedBytes.get(base64Bytes, base64Offset, expectedLength); + } + } + + public static void length_checks() { + decodeAndCheck(); + encodeDecode(); + System.out.println("Test complete, no invalid decodes detected"); + } + + // Use ByteBuffer to cause decode() to use the base + offset form of decode + // Checks for bug reported in JDK-8321599 where padding characters appear + // within the beginning of the ByteBuffer *before* the offset. This caused + // the decoded string length to be off by 1 or 2 bytes. + static void decodeAndCheck() { + for (int i = 0; i < POSITIONS; i++) { + ByteBuffer encodedBytes = base64BytesAtPosition(i); + ByteBuffer decodedBytes = Base64.getDecoder().decode(encodedBytes); + + if (!decodedBytes.equals(plainBytesAtPosition(i))) { + String base64String = base64StringAtPosition(i); + String plainHexString = plainHexStringAtPosition(i); + String decodedHexString = HEX_FORMAT.formatHex(decodedBytes.array(), decodedBytes.arrayOffset() + decodedBytes.position(), decodedBytes.arrayOffset() + decodedBytes.limit()); + throw new IllegalStateException(format("Mismatch for %s\n\nExpected:\n%s\n\nActual:\n%s", base64String, plainHexString, decodedHexString)); + } + } + } + + // Encode strings of lengths 1-1K, decode, and ensure length and contents correct. + // This checks that padding characters are properly handled by decode. + static void encodeDecode() { + String allAs = "A(=)".repeat(128); + for (int i = 1; i <= 512; i++) { + String encStr = Base64.getEncoder().encodeToString(allAs.substring(0, i).getBytes()); + String decStr = new String(Base64.getDecoder().decode(encStr)); + + if ((decStr.length() != allAs.substring(0, i).length()) || + (!Objects.equals(decStr, allAs.substring(0, i))) + ) { + throw new IllegalStateException(format("Mismatch: Expected: %s\n Actual: %s\n", allAs.substring(0, i), decStr)); + } + } + } + + static ByteBuffer plainBytesAtPosition(int position) { + int offset = plainOffsets[position]; + int length = plainOffsets[position + 1] - offset; + return ByteBuffer.wrap(plainBytes, offset, length); + } + + static String plainHexStringAtPosition(int position) { + int offset = plainOffsets[position]; + int length = plainOffsets[position + 1] - offset; + return HEX_FORMAT.formatHex(plainBytes, offset, offset + length); + } + + static String base64StringAtPosition(int position) { + int offset = base64Offsets[position]; + int length = base64Offsets[position + 1] - offset; + return new String(base64Bytes, offset, length, StandardCharsets.UTF_8); + } + + static ByteBuffer base64BytesAtPosition(int position) { + int offset = base64Offsets[position]; + int length = base64Offsets[position + 1] - offset; + return ByteBuffer.wrap(base64Bytes, offset, length); + } } diff --git a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java index 634f3397bbb..d12148b1983 100644 --- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java +++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestResolvedJavaMethod.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2024, 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,7 +41,7 @@ * java.base/jdk.internal.misc * java.base/jdk.internal.vm * java.base/sun.reflect.annotation - * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI -XX:-UseJVMCICompiler jdk.vm.ci.runtime.test.TestResolvedJavaMethod + * @run junit/othervm/timeout=240 -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI -XX:-UseJVMCICompiler jdk.vm.ci.runtime.test.TestResolvedJavaMethod */ package jdk.vm.ci.runtime.test; diff --git a/test/hotspot/jtreg/compiler/loopopts/TestRemixAddressExpressionsWithIrreducibleLoop.java b/test/hotspot/jtreg/compiler/loopopts/TestRemixAddressExpressionsWithIrreducibleLoop.java new file mode 100644 index 00000000000..ff7be96007d --- /dev/null +++ b/test/hotspot/jtreg/compiler/loopopts/TestRemixAddressExpressionsWithIrreducibleLoop.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2024, 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 8326638 + * @summary Test handling of irreducible loops in PhaseIdealLoop::remix_address_expressions. + * @run main/othervm -XX:-TieredCompilation -Xbatch + * -XX:CompileCommand=compileonly,TestRemixAddressExpressionsWithIrreducibleLoop::test + * TestRemixAddressExpressionsWithIrreducibleLoop + */ + +public class TestRemixAddressExpressionsWithIrreducibleLoop { + + public static void main(String[] args) { + test("4"); + } + + public static void test(String arg) { + for (int i = 0; i < 100_000; ++i) { + int j = 0; + while (true) { + boolean tmp = "1\ufff0".startsWith(arg, 2 - arg.length()); + if (j++ > 100) + break; + } + loop: + while (i >= 100) { + for (int i2 = 0; i2 < 1; i2 = 1) + if (j > 300) + break loop; + j++; + } + } + } +} diff --git a/test/hotspot/jtreg/compiler/splitif/TestSplitDivThroughPhiWithControl.java b/test/hotspot/jtreg/compiler/splitif/TestSplitDivThroughPhiWithControl.java new file mode 100644 index 00000000000..28e4db334f5 --- /dev/null +++ b/test/hotspot/jtreg/compiler/splitif/TestSplitDivThroughPhiWithControl.java @@ -0,0 +1,210 @@ +/* + * Copyright (c) 2024, 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 id=normal + * @bug 8323101 + * @summary Test split_thru_phi with pinned divisions/modulo that have phi as inputs. + * @run main/othervm -Xbatch + * -XX:CompileCommand=compileonly,compiler.splitif.TestSplitDivThroughPhiWithControl::* + * compiler.splitif.TestSplitDivThroughPhiWithControl + */ + +/* + * @test id=fuzzer + * @bug 8323101 + * @summary Test split_thru_phi with pinned divisions/modulo that have phi as inputs. + * @run main/othervm -Xbatch -XX:PerMethodTrapLimit=0 + * -XX:CompileCommand=compileonly,compiler.splitif.TestSplitDivThroughPhiWithControl::* + * compiler.splitif.TestSplitDivThroughPhiWithControl + */ + +package compiler.splitif; + +public class TestSplitDivThroughPhiWithControl { + static int divisorInt = 34; + static int iFld; + static int x; + static int y; + static long divisorLong = 34L; + static long lFld; + static long lFld2; + static long lFld3; + static boolean flag; + + static int[] iArr = new int[400]; + + public static void main(String[] strArr) { + iArr[0] = 52329; + for (int i = 0; i < 10000; i++) { + flag = i % 3 == 0; // Avoid unstable if trap + divisorInt = i % 2 == 0 ? 0 : 23; // Avoid div by zero trap + divisorLong = divisorInt; // Avoid div by zero trap + try { + testIntDiv(); + } catch (ArithmeticException e) { + // Expected. + } + + try { + testIntMod(); + } catch (ArithmeticException e) { + // Expected. + } + + try { + testLongDiv(); // Currently does not trigger due to JDK-8323652 + } catch (ArithmeticException e) { + // Expected. + } + + try { + testLongMod(); // Currently does not trigger due to JDK-8323652 + } catch (ArithmeticException e) { + // Expected. + } + + testFuzzer(); + } + } + + static void testIntDiv() { + int a; + + for (int j = 0; j < 100; j++) { + y += 5; + int sub = j - 3; // AddI + int div = (sub / divisorInt); // DivI with AddI input + + if (flag) { + a = y; + } else { + a = 2; + } + // Region + + // Use StoreI with AddI input. Store needs to be split through Region in Split-If which is done together + // with AddI. + iFld = sub; + + if (a < 3) { // If that's split in Split-If + // Use of DivI -> after Split-If, DivI gets a Phi input that merges the split AddI nodes. + // -> triggers assert that we should not find pinned div nodes in cannot_split_division(). + x = div; + } + } + } + + // Same as testIntDiv() but with ModI + static void testIntMod() { + int a; + + for (int j = 0; j < 100; j++) { + y += 5; + int sub = j - 3; + int mod = (sub % divisorInt); + + if (flag) { + a = y; + } else { + a = 2; + } + + iFld = sub; + + if (a < 3) { + x = mod; // Only StoreI visited first but not mod since it's an input + } + } + } + + // Same as testIntDiv() but with DivL + static void testLongDiv() { + long a; + + for (int j = 0; j < 100; j++) { + y += 5; + long sub = j - 3; + long div = (sub / divisorLong); + + if (flag) { + a = lFld2; + } else { + a = 2; + } + + lFld = sub; + + if (a < 3) { + lFld3 = div; + } + } + } + + + // Same as testIntDiv() but with ModL + static void testLongMod() { + long a; + + for (long j = 0; j < 100; j++) { + lFld2 += 5; + long sub = j - 3; + long mod = (sub % divisorLong); + + if (flag) { + a = lFld2; + } else { + a = 2; + } + + lFld = sub; + + if (a < 3) { + lFld3 = mod; // Only StoreI visited first but not mod since it's an input + } + } + } + + // Original fuzzer crash + static void testFuzzer() { + int i19, i21 = 4928, i23 = 14; + for (int i = 5; i < 100; i++) { + i19 = i23; + int j = 1; + while (true) { + try { + i21 = (iArr[0] / 34); + i23 = (j % i21); + } catch (ArithmeticException a_e) { + } + iArr = iArr; + iFld = i21; + iArr[1] += 5; + if (j == 1000) { + break; + } + j++; + } + } + } +} diff --git a/test/hotspot/jtreg/compiler/types/TestSubTypeOfAbstractClass.java b/test/hotspot/jtreg/compiler/types/TestSubTypeOfAbstractClass.java deleted file mode 100644 index 63274b86e72..00000000000 --- a/test/hotspot/jtreg/compiler/types/TestSubTypeOfAbstractClass.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (c) 2023, 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. - */ - -/** - * @test - * @bug 8316533 - * @summary Oop of abstract class A with no subclass is subtype checked after null-check - * @run driver compiler.types.TestSubTypeOfAbstractClass - */ - -/** - * @test - * @bug 8316533 - * @summary Oop of abstract class A is subtype checked after null-check - * @requires vm.compiler2.enabled - * @run main/othervm -XX:CompileCommand=compileonly,*A::test - * -Xcomp -XX:+IgnoreUnrecognizedVMOptions -XX:+StressReflectiveCode - * compiler.types.TestSubTypeOfAbstractClass - */ - -package compiler.types; - -public class TestSubTypeOfAbstractClass { - - abstract class A { - public static A get_null() { - return null; - } - - public static boolean test() { - // NullCheck -> CastPP with type A:NotNull - // But A is abstract with no subclass, hence this type is impossible - return get_null() instanceof A; - } - } - - public static void main(String[] args) { - for (int i = 0; i < 10_000; i++ ) { - A.test(); - } - } -} diff --git a/test/hotspot/jtreg/compiler/unsafe/UnsafeArrayCopy.java b/test/hotspot/jtreg/compiler/unsafe/UnsafeArrayCopy.java new file mode 100644 index 00000000000..ac94609be34 --- /dev/null +++ b/test/hotspot/jtreg/compiler/unsafe/UnsafeArrayCopy.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2024, 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 8316756 + * @summary Test UNSAFE.copyMemory in combination with Escape Analysis + * @library /test/lib + * + * @modules java.base/jdk.internal.misc + * + * @run main/othervm -XX:-TieredCompilation -Xbatch -XX:CompileCommand=quiet -XX:CompileCommand=compileonly,compiler.unsafe.UnsafeArrayCopy::test* + * compiler.unsafe.UnsafeArrayCopy + */ + +package compiler.unsafe; + +import java.lang.reflect.*; +import java.util.*; + +import jdk.internal.misc.Unsafe; + + +public class UnsafeArrayCopy { + + private static Unsafe UNSAFE = Unsafe.getUnsafe(); + + static long SRC_BASE = UNSAFE.allocateMemory(4); + static long DST_BASE = UNSAFE.allocateMemory(4); + + static class MyClass { + int x; + } + + static int test() { + MyClass obj = new MyClass(); // Non-escaping to trigger Escape Analysis + UNSAFE.copyMemory(null, SRC_BASE, null, DST_BASE, 4); + obj.x = 42; + return obj.x; + } + + static int[] test2() { + int[] src = new int[4]; + int[] dst = new int[4]; + MyClass obj = new MyClass(); + UNSAFE.copyMemory(src, 0, dst, 0, 4); + obj.x = 42; + dst[1] = obj.x; + return dst; + } + + public static void main(String[] args) { + for (int i = 0; i < 50_000; ++i) { + test(); + test2(); + } + } +} diff --git a/test/hotspot/jtreg/compiler/vectorapi/TestIntrinsicBailOut.java b/test/hotspot/jtreg/compiler/vectorapi/TestIntrinsicBailOut.java index 49548bd7244..72e1c3aa30f 100644 --- a/test/hotspot/jtreg/compiler/vectorapi/TestIntrinsicBailOut.java +++ b/test/hotspot/jtreg/compiler/vectorapi/TestIntrinsicBailOut.java @@ -1,5 +1,6 @@ /* * Copyright (C) 2021, 2022, THL A29 Limited, a Tencent company. All rights reserved. + * Copyright (c) 2024, 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,6 +37,17 @@ * -XX:-TieredCompilation compiler.vectorapi.TestIntrinsicBailOut */ +/* + * @test + * @bug 8317299 + * @summary Vector API intrinsincs should handle JVM state correctly whith late inlining when compiling with -InlineUnsafeOps + * @modules jdk.incubator.vector + * @requires vm.cpu.features ~= ".*avx512.*" + * @run main/othervm -Xcomp -XX:+UnlockDiagnosticVMOptions -XX:-InlineUnsafeOps -XX:+IgnoreUnrecognizedVMOptions -XX:UseAVX=3 + * -XX:CompileCommand=compileonly,compiler.vectorapi.TestIntrinsicBailOut::test -XX:CompileCommand=quiet + * -XX:-TieredCompilation compiler.vectorapi.TestIntrinsicBailOut + */ + public class TestIntrinsicBailOut { static final VectorSpecies SPECIES256 = DoubleVector.SPECIES_256; diff --git a/test/hotspot/jtreg/compiler/vectorization/runner/BasicDoubleOpTest.java b/test/hotspot/jtreg/compiler/vectorization/runner/BasicDoubleOpTest.java index 0f758be4ed0..a3fcdbaa9b0 100644 --- a/test/hotspot/jtreg/compiler/vectorization/runner/BasicDoubleOpTest.java +++ b/test/hotspot/jtreg/compiler/vectorization/runner/BasicDoubleOpTest.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2022, 2023, Arm Limited. All rights reserved. + * Copyright (c) 2024, 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 @@ -237,6 +238,17 @@ public double[] vectorMax() { return res; } + @Test + @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx", "true"}, + counts = {IRNode.MAX_VD, ">0"}) + public double[] vectorMax_8322090() { + double[] res = new double[SIZE]; + for (int i = 0; i < SIZE; i++) { + res[i] = Math.max(d[i], d[i]); + } + return res; + } + @Test @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx", "true"}, counts = {IRNode.MIN_VD, ">0"}) diff --git a/test/hotspot/jtreg/gc/g1/TestSkipRebuildRemsetPhase.java b/test/hotspot/jtreg/gc/g1/TestSkipRebuildRemsetPhase.java index 4c7190ada02..c2448416efa 100644 --- a/test/hotspot/jtreg/gc/g1/TestSkipRebuildRemsetPhase.java +++ b/test/hotspot/jtreg/gc/g1/TestSkipRebuildRemsetPhase.java @@ -45,7 +45,7 @@ public static void main(String[] args) throws Exception { "-XX:+UnlockExperimentalVMOptions", "-XX:+UnlockDiagnosticVMOptions", "-XX:+WhiteBoxAPI", - "-XX:G1MixedGCLiveThresholdPercent=20", + "-XX:G1MixedGCLiveThresholdPercent=0", "-Xlog:gc+marking=debug,gc+phases=debug,gc+remset+tracking=trace", "-Xms10M", "-Xmx10M", diff --git a/test/hotspot/jtreg/gc/stress/gclocker/TestGCLocker.java b/test/hotspot/jtreg/gc/stress/gclocker/TestGCLocker.java deleted file mode 100644 index 36b9a59fde6..00000000000 --- a/test/hotspot/jtreg/gc/stress/gclocker/TestGCLocker.java +++ /dev/null @@ -1,228 +0,0 @@ -/* - * Copyright (c) 2017, 2023, 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.stress.gclocker; - -// Stress the GC locker by calling GetPrimitiveArrayCritical while -// concurrently filling up old gen. - -import java.lang.management.MemoryPoolMXBean; -import java.lang.management.ManagementFactory; -import java.lang.management.MemoryUsage; -import java.util.ArrayDeque; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Queue; - -final class ThreadUtils { - public static void sleep(long durationMS) { - try { - Thread.sleep(durationMS); - } catch (Exception e) { - } - } -} - -class Filler { - private static final int SIZE = 250000; - - private int[] i1 = new int[SIZE]; - private int[] i2 = new int[SIZE]; - private short[] s1 = new short[SIZE]; - private short[] s2 = new short[SIZE]; - - private Map map = new HashMap<>(); - - public Filler() { - for (int i = 0; i < 10000; i++) { - map.put(new Object(), new Object()); - } - } -} - -class Exitable { - private volatile boolean shouldExit = false; - - protected boolean shouldExit() { - return shouldExit; - } - - public void exit() { - shouldExit = true; - } -} - -class MemoryWatcher { - private MemoryPoolMXBean bean; - private final int thresholdPromille = 750; - private final int criticalThresholdPromille = 800; - private final long minGCWaitNanos = 1_000_000_000L; - private final long minFreeWaitElapsedNanos = 30L * 1_000_000_000L; - private final long minFreeCriticalWaitNanos; - - private int lastUsage = 0; - private long lastGCDetectedNanos = System.nanoTime(); - private long lastFreeNanos = System.nanoTime(); - - public MemoryWatcher(String mxBeanName, long minFreeCriticalWaitNanos) { - this.minFreeCriticalWaitNanos = minFreeCriticalWaitNanos; - List memoryBeans = ManagementFactory.getMemoryPoolMXBeans(); - for (MemoryPoolMXBean bean : memoryBeans) { - if (bean.getName().equals(mxBeanName)) { - this.bean = bean; - break; - } - } - } - - private int getMemoryUsage() { - if (bean == null) { - Runtime r = Runtime.getRuntime(); - float free = (float) r.freeMemory() / r.maxMemory(); - return Math.round((1 - free) * 1000); - } else { - MemoryUsage usage = bean.getUsage(); - float used = (float) usage.getUsed() / usage.getCommitted(); - return Math.round(used * 1000); - } - } - - public synchronized boolean shouldFreeUpSpace() { - int usage = getMemoryUsage(); - long nowNanos = System.nanoTime(); - - boolean detectedGC = false; - if (usage < lastUsage) { - lastGCDetectedNanos = nowNanos; - detectedGC = true; - } - - lastUsage = usage; - - long elapsedNanos = nowNanos - lastFreeNanos; - long timeSinceLastGCNanos = nowNanos - lastGCDetectedNanos; - - if (usage > criticalThresholdPromille && elapsedNanos > minFreeCriticalWaitNanos) { - lastFreeNanos = nowNanos; - return true; - } else if (usage > thresholdPromille && !detectedGC) { - if (elapsedNanos > minFreeWaitElapsedNanos || timeSinceLastGCNanos > minGCWaitNanos) { - lastFreeNanos = nowNanos; - return true; - } - } - - return false; - } -} - -class MemoryUser extends Exitable implements Runnable { - private final Queue cache = new ArrayDeque(); - private final MemoryWatcher watcher; - - private void load() { - if (watcher.shouldFreeUpSpace()) { - int toRemove = cache.size() / 5; - for (int i = 0; i < toRemove; i++) { - cache.remove(); - } - } - cache.add(new Filler()); - } - - public MemoryUser(String mxBeanName, long minFreeCriticalWaitNanos) { - watcher = new MemoryWatcher(mxBeanName, minFreeCriticalWaitNanos); - } - - @Override - public void run() { - for (int i = 0; i < 200; i++) { - load(); - } - - while (!shouldExit()) { - load(); - } - } -} - -class GCLockerStresser extends Exitable implements Runnable { - static native void fillWithRandomValues(byte[] array); - - @Override - public void run() { - byte[] array = new byte[1024 * 1024]; - while (!shouldExit()) { - fillWithRandomValues(array); - } - } -} - -public class TestGCLocker { - private static Exitable startGCLockerStresser(String name) { - GCLockerStresser task = new GCLockerStresser(); - - Thread thread = new Thread(task); - thread.setName(name); - thread.setPriority(Thread.MIN_PRIORITY); - thread.start(); - - return task; - } - - private static Exitable startMemoryUser(String mxBeanName, long minFreeCriticalWaitNanos) { - MemoryUser task = new MemoryUser(mxBeanName, minFreeCriticalWaitNanos); - - Thread thread = new Thread(task); - thread.setName("Memory User"); - thread.start(); - - return task; - } - - public static void main(String[] args) { - System.loadLibrary("TestGCLocker"); - - long durationMinutes = args.length > 0 ? Long.parseLong(args[0]) : 5; - String mxBeanName = args.length > 1 ? args[1] : null; - long minFreeCriticalWaitNanos = args.length > 2 - ? Integer.parseInt(args[2]) * 1_000_000L - : 500_000_000L; - - Exitable stresser1 = startGCLockerStresser("GCLockerStresser1"); - Exitable stresser2 = startGCLockerStresser("GCLockerStresser2"); - Exitable memoryUser = startMemoryUser(mxBeanName, minFreeCriticalWaitNanos); - - try { - Thread.sleep(durationMinutes * 60_000L); - } catch (InterruptedException e) { - throw new RuntimeException("Test Failure, did not except an InterruptedException", e); - } - - stresser1.exit(); - stresser2.exit(); - memoryUser.exit(); - } -} diff --git a/test/hotspot/jtreg/gc/stress/gclocker/TestGCLockerWithShenandoah.java b/test/hotspot/jtreg/gc/stress/gclocker/TestGCLockerWithShenandoah.java deleted file mode 100644 index 586fdc79881..00000000000 --- a/test/hotspot/jtreg/gc/stress/gclocker/TestGCLockerWithShenandoah.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (c) 2017, 2018, 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. - * - */ - -package gc.stress.gclocker; - -/* - * @test id=default - * @library / - * @requires vm.gc.Shenandoah - * @summary Stress Shenandoah's JNI handling by calling GetPrimitiveArrayCritical while concurrently filling up old gen. - * - * @run main/native/othervm/timeout=200 -Xlog:gc*=info -Xms1500m -Xmx1500m -XX:+UnlockExperimentalVMOptions -XX:+UnlockDiagnosticVMOptions - * -XX:+UseShenandoahGC - * -XX:+ShenandoahVerify - * gc.stress.gclocker.TestGCLockerWithShenandoah - * - * @run main/native/othervm/timeout=200 -Xlog:gc*=info -Xms1500m -Xmx1500m -XX:+UnlockExperimentalVMOptions -XX:+UnlockDiagnosticVMOptions - * -XX:+UseShenandoahGC - * gc.stress.gclocker.TestGCLockerWithShenandoah - */ - -/* - * @test id=aggressive - * @library / - * @requires vm.gc.Shenandoah - * @summary Stress Shenandoah's JNI handling by calling GetPrimitiveArrayCritical while concurrently filling up old gen. - * - * @run main/native/othervm/timeout=200 -Xlog:gc*=info -Xms1500m -Xmx1500m -XX:+UnlockExperimentalVMOptions -XX:+UnlockDiagnosticVMOptions - * -XX:+UseShenandoahGC -XX:ShenandoahGCHeuristics=aggressive - * -XX:+ShenandoahOOMDuringEvacALot - * gc.stress.gclocker.TestGCLockerWithShenandoah - * - * @run main/native/othervm/timeout=200 -Xlog:gc*=info -Xms1500m -Xmx1500m -XX:+UnlockExperimentalVMOptions -XX:+UnlockDiagnosticVMOptions - * -XX:+UseShenandoahGC -XX:ShenandoahGCHeuristics=aggressive - * -XX:+ShenandoahAllocFailureALot - * gc.stress.gclocker.TestGCLockerWithShenandoah - */ -public class TestGCLockerWithShenandoah { - public static void main(String[] args) { - String[] testArgs = {"2", "Shenandoah", "0"}; - TestGCLocker.main(testArgs); - } -} diff --git a/test/hotspot/jtreg/gtest/NativeHeapTrimmerGtest.java b/test/hotspot/jtreg/gtest/NativeHeapTrimmerGtest.java index 60a93e748f6..82ee888f653 100644 --- a/test/hotspot/jtreg/gtest/NativeHeapTrimmerGtest.java +++ b/test/hotspot/jtreg/gtest/NativeHeapTrimmerGtest.java @@ -1,6 +1,6 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2023 Red Hat, Inc. All rights reserved. + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, 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 @@ -29,5 +29,5 @@ * @modules java.base/jdk.internal.misc * java.xml * @requires vm.flagless - * @run main/native GTestWrapper --gtest_filter=os.trim* -Xlog:trimnative -XX:+UnlockExperimentalVMOptions -XX:TrimNativeHeapInterval=100 + * @run main/native GTestWrapper --gtest_filter=os.trim* -Xlog:trimnative -XX:TrimNativeHeapInterval=100 */ diff --git a/test/hotspot/jtreg/runtime/CommandLine/UnrecognizedProperty.java b/test/hotspot/jtreg/runtime/CommandLine/UnrecognizedProperty.java new file mode 100644 index 00000000000..4b1d4fa3867 --- /dev/null +++ b/test/hotspot/jtreg/runtime/CommandLine/UnrecognizedProperty.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2023, 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 8321479 + * @summary VM should not crash with property "-D-D" + * @requires vm.flagless + * @library /test/lib + * @run driver UnrecognizedProperty + */ + +import jdk.test.lib.process.ProcessTools; +import jdk.test.lib.process.OutputAnalyzer; + +public class UnrecognizedProperty { + public static void main(String[] args) throws Exception { + ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder( + "-D-D"); + + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldContain("Usage: java"); + output.shouldHaveExitValue(1); + } +} diff --git a/test/hotspot/jtreg/runtime/Thread/ThreadCountLimit.java b/test/hotspot/jtreg/runtime/Thread/ThreadCountLimit.java index 418d05197b5..1afd6c1898f 100644 --- a/test/hotspot/jtreg/runtime/Thread/ThreadCountLimit.java +++ b/test/hotspot/jtreg/runtime/Thread/ThreadCountLimit.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, 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,10 +24,19 @@ /** * @test * @summary Stress test that reaches the process limit for thread count, or time limit. + * @requires os.family != "aix" * @key stress * @run main/othervm -Xmx1g ThreadCountLimit */ +/** + * @test + * @summary Stress test that reaches the process limit for thread count, or time limit. + * @requires os.family == "aix" + * @key stress + * @run main/othervm -Xmx1g -XX:MaxExpectedDataSegmentSize=16g ThreadCountLimit + */ + import java.util.concurrent.CountDownLatch; import java.util.ArrayList; diff --git a/test/hotspot/jtreg/runtime/cds/appcds/JarBuilder.java b/test/hotspot/jtreg/runtime/cds/appcds/JarBuilder.java index b9c2063f3e7..ef13a0a9414 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/JarBuilder.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/JarBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2024, 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 @@ -199,6 +199,23 @@ public static void createModularJar(String jarPath, createJar(argList); } + public static void createModularJarWithManifest(String jarPath, + String classesDir, + String mainClass, + String manifest) throws Exception { + ArrayList argList = new ArrayList(); + argList.add("--create"); + argList.add("--file=" + jarPath); + if (mainClass != null) { + argList.add("--main-class=" + mainClass); + } + argList.add("--manifest=" + manifest); + argList.add("-C"); + argList.add(classesDir); + argList.add("."); + createJar(argList); + } + private static void createJar(ArrayList args) { if (DEBUG) printIterable("createJar args: ", args); diff --git a/test/hotspot/jtreg/runtime/cds/appcds/TransformInterfaceOfLambda.java b/test/hotspot/jtreg/runtime/cds/appcds/TransformInterfaceOfLambda.java new file mode 100644 index 00000000000..8bbc713fa6f --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/TransformInterfaceOfLambda.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2024, 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 8323950 + * @summary Transforming an interface of an archived lambda proxy class should not + * crash the VM. The lambda proxy class should be regenerated during runtime. + * @requires vm.cds + * @requires vm.jvmti + * @requires vm.flagless + * @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds/test-classes + * @compile test-classes/SimpleTest.java + * @compile test-classes/TransformBootClass.java + * @run driver TransformInterfaceOfLambda + */ + +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; +import jdk.test.lib.helpers.ClassFileInstaller; + +public class TransformInterfaceOfLambda { + + public static String agentClasses[] = { + TransformBootClass.class.getName(), + }; + + public static void main(String[] args) throws Exception { + String mainClass = SimpleTest.class.getName(); + String namePrefix = "transform-interface-of-lambda"; + JarBuilder.build(namePrefix, mainClass); + + String appJar = TestCommon.getTestJar(namePrefix + ".jar"); + + String agentJar = + ClassFileInstaller.writeJar("TransformBootClass.jar", + ClassFileInstaller.Manifest.fromSourceFile("test-classes/TransformBootClass.mf"), + agentClasses); + String useJavaAgent = "-javaagent:" + agentJar + "=java/util/function/IntFunction"; + + ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder( + "-cp", appJar, "-Xlog:class+load,cds=debug", + "-XX:+UnlockDiagnosticVMOptions", + "-XX:+AllowArchivingWithJavaAgent", + useJavaAgent, + mainClass); + OutputAnalyzer out = new OutputAnalyzer(pb.start()); + System.out.println(out.getStdout()); + out.shouldHaveExitValue(0) + // the class loaded by the SimpleTest should be from the archive + .shouldContain("[class,load] java.text.SimpleDateFormat source: shared objects file") + // the IntFunction is the interface which is being transformed. The + // interface is a super type of the following lambda proxy class. + .shouldContain("Transforming class java/util/function/IntFunction") + // the lambda proxy class should be regenerated + .shouldMatch(".class.load.*sun.util.locale.provider.LocaleProviderAdapter[$][$]Lambda/0x.*source:.*sun.util.locale.provider.LocaleProviderAdapter"); + } +} diff --git a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/ModularJarWithNonExistentJar.java b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/ModularJarWithNonExistentJar.java new file mode 100644 index 00000000000..9e7579a34fd --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/ModularJarWithNonExistentJar.java @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2024, 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 8322657 + * @summary This test defines an application module using the DefineModuleApp. + * When performing dynamic dump, the modular jar containing the module + * is in the -cp. The jar listed in the "Class-Path" attribute of the modular + * jar doesn't exist. VM should not crash during dynamic dump under this scenario. + * @requires vm.cds + * @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds + * /test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/test-classes + * @build jdk.test.whitebox.WhiteBox DefineModuleApp + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar define_module_app.jar DefineModuleApp + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. ModularJarWithNonExistentJar + */ + +import java.io.File; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +import jdk.test.lib.cds.CDSTestUtils; +import jdk.test.lib.helpers.ClassFileInstaller; + +public class ModularJarWithNonExistentJar extends DynamicArchiveTestBase { + private static final Path USER_DIR = Paths.get(CDSTestUtils.getOutputDir()); + + private static final String TEST_SRC = System.getProperty("test.src"); + + private static final Path SRC_DIR = Paths.get(TEST_SRC, "../jigsaw/modulepath/src"); + private static final Path MODS_DIR = Paths.get("mods"); + private static final Path MANIFEST_PATH = Paths.get(TEST_SRC, "test-classes/manifest-with-non-existent-jar.txt"); + + // the module name of the test module + private static final String TEST_MODULE = "com.simple"; + + // the module main class + private static final String MAIN_CLASS = "com.simple.Main"; + + private static Path moduleDir = null; + private static Path modularJar = null; + + public static void buildTestModule() throws Exception { + + // javac -d mods/$TESTMODULE --module-path MOD_DIR src/$TESTMODULE/** + JarBuilder.compileModule(SRC_DIR.resolve(TEST_MODULE), + MODS_DIR.resolve(TEST_MODULE), + MODS_DIR.toString()); + + + moduleDir = Files.createTempDirectory(USER_DIR, "mlib"); + + modularJar = moduleDir.resolve(TEST_MODULE + ".jar"); + String classes = MODS_DIR.resolve(TEST_MODULE).toString(); + JarBuilder.createModularJarWithManifest(modularJar.toString(), classes, + MAIN_CLASS, MANIFEST_PATH.toString()); + } + + public static void main(String... args) throws Exception { + runTest(ModularJarWithNonExistentJar::testDefaultBase); + } + + static void testDefaultBase() throws Exception { + String topArchiveName = getNewArchiveName("top"); + doTest(topArchiveName); + } + + private static void doTest(String topArchiveName) throws Exception { + // compile the module and create the modular jar file + buildTestModule(); + String appJar = ClassFileInstaller.getJarPath("define_module_app.jar"); + dump(topArchiveName, + "-Xlog:cds,class+path=info", + "-Xlog:cds+dynamic=debug", + "-cp", appJar + File.pathSeparator + modularJar.toString(), + "DefineModuleApp", moduleDir.toString(), TEST_MODULE) + .assertNormalExit(output -> { + output.shouldContain("Written dynamic archive 0x"); + }); + } +} diff --git a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/test-classes/DefineModuleApp.java b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/test-classes/DefineModuleApp.java new file mode 100644 index 00000000000..fad62598cc7 --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/test-classes/DefineModuleApp.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2024, 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. + * + */ + +/** + * This app defines a module using the ModuleLayer.defineModulesWithOneLoader API + * which calls the JVM_DefineModule. + **/ + +import java.nio.file.Path; +import java.lang.ModuleLayer.Controller; +import java.lang.module.*; +import java.util.List; +import java.util.Set; + +public class DefineModuleApp { + public static void main(String[] args) throws Throwable { + if (args.length != 2) { + throw new RuntimeException("DefineModuleApp expects 2 args but saw " + args.length); + } + final Path MODS = Path.of(args[0]); + final String MODULE_NAME = args[1]; + Configuration cf = ModuleLayer.boot() + .configuration() + .resolve(ModuleFinder.of(), ModuleFinder.of(MODS), Set.of(MODULE_NAME)); + ResolvedModule m = cf.findModule(MODULE_NAME).orElseThrow(); + ModuleLayer bootLayer = ModuleLayer.boot(); + ClassLoader scl = ClassLoader.getSystemClassLoader(); + Controller controller = ModuleLayer.defineModulesWithOneLoader(cf, List.of(bootLayer), scl); + } +} diff --git a/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/test-classes/manifest-with-non-existent-jar.txt b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/test-classes/manifest-with-non-existent-jar.txt new file mode 100644 index 00000000000..7558b8b2c82 --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/dynamicArchive/test-classes/manifest-with-non-existent-jar.txt @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +Class-Path: NonExistent.jar +Created-By: 23-internal (Oracle Corporation) diff --git a/test/hotspot/jtreg/runtime/cds/appcds/jigsaw/module/ModuleOption.java b/test/hotspot/jtreg/runtime/cds/appcds/jigsaw/module/ModuleOption.java index b7b0e8778c8..fa4fa5321ee 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/jigsaw/module/ModuleOption.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/jigsaw/module/ModuleOption.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, 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 @@ -38,7 +38,10 @@ public static void main(String[] args) throws Exception { final String moduleOption = "jdk.httpserver/sun.net.httpserver.simpleserver.Main"; final String incubatorModule = "jdk.incubator.vector"; final String loggingOption = "-Xlog:cds=debug,cds+module=debug,cds+heap=info,module=trace"; - final String versionPattern = "java.[0-9][0-9][-].*"; + // Pattern of a module version string. + // e.g. JDK 22: "java 22" + // JDK 22.0.1: "java 22.0.1" + final String versionPattern = "java.[0-9][0-9].*"; final String subgraphCannotBeUsed = "subgraph jdk.internal.module.ArchivedBootLayer cannot be used because full module graph is disabled"; String archiveName = TestCommon.getNewArchiveName("module-option"); TestCommon.setCurrentArchiveName(archiveName); diff --git a/test/hotspot/jtreg/gc/stress/gclocker/TestGCLockerWithParallel.java b/test/hotspot/jtreg/runtime/cds/appcds/test-classes/SimpleTest.java similarity index 62% rename from test/hotspot/jtreg/gc/stress/gclocker/TestGCLockerWithParallel.java rename to test/hotspot/jtreg/runtime/cds/appcds/test-classes/SimpleTest.java index eeee969a252..7d6ecb73047 100644 --- a/test/hotspot/jtreg/gc/stress/gclocker/TestGCLockerWithParallel.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/test-classes/SimpleTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 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,18 +22,14 @@ * */ -package gc.stress.gclocker; - /* - * @test TestGCLockerWithParallel - * @library / - * @requires vm.gc.Parallel - * @summary Stress Parallel's GC locker by calling GetPrimitiveArrayCritical while concurrently filling up old gen. - * @run main/native/othervm/timeout=200 -Xlog:gc*=info -Xms1500m -Xmx1500m -XX:+UseParallelGC gc.stress.gclocker.TestGCLockerWithParallel + * Loading the java.text.SimpleDateFormat class will in turn load the + * sun.util.locale.provider.LocaleProviderAdapter$$Lambda/0x... lambda proxy class + * which will also load its interface java.util.function.IntFunction. + * By default, all of the above classes should be in the default CDS archive. */ -public class TestGCLockerWithParallel { - public static void main(String[] args) { - String[] testArgs = {"2", "PS Old Gen"}; - TestGCLocker.main(testArgs); +public class SimpleTest { + public static void main(String[] args) throws Exception { + new java.text.SimpleDateFormat(); } } diff --git a/test/hotspot/jtreg/gc/stress/gclocker/TestGCLockerWithG1.java b/test/hotspot/jtreg/runtime/jni/abstractMethod/AbstractMethodClass.jasm similarity index 63% rename from test/hotspot/jtreg/gc/stress/gclocker/TestGCLockerWithG1.java rename to test/hotspot/jtreg/runtime/jni/abstractMethod/AbstractMethodClass.jasm index a70a35daa63..24c53f2032d 100644 --- a/test/hotspot/jtreg/gc/stress/gclocker/TestGCLockerWithG1.java +++ b/test/hotspot/jtreg/runtime/jni/abstractMethod/AbstractMethodClass.jasm @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 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,19 +21,23 @@ * questions. * */ - -package gc.stress.gclocker; - /* - * @test TestGCLockerWithG1 - * @library / - * @requires vm.gc.G1 - * @summary Stress G1's GC locker by calling GetPrimitiveArrayCritical while concurrently filling up old gen. - * @run main/native/othervm/timeout=200 -Xlog:gc*=info -Xms1500m -Xmx1500m -XX:+UseG1GC gc.stress.gclocker.TestGCLockerWithG1 + * This is a non-abstract class with an abstract method. + * */ -public class TestGCLockerWithG1 { - public static void main(String[] args) { - String[] testArgs = {"2", "G1 Old Gen"}; - TestGCLocker.main(testArgs); +super public class AbstractMethodClass + extends java/lang/Object + version 51:0 // Java 7 version +{ + + public Method "":"()V" + stack 1 locals 1 + { + aload_0; + invokespecial Method java/lang/Object."":"()V"; + return; } + + public abstract Method "abstractM":"()V"; + } diff --git a/test/hotspot/jtreg/runtime/jni/abstractMethod/TestJNIAbstractMethod.java b/test/hotspot/jtreg/runtime/jni/abstractMethod/TestJNIAbstractMethod.java new file mode 100644 index 00000000000..2384f6d5aef --- /dev/null +++ b/test/hotspot/jtreg/runtime/jni/abstractMethod/TestJNIAbstractMethod.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2024, 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 8323243 + * @summary Test that invocation of an abstract method from JNI works correctly + * @compile AbstractMethodClass.jasm + * @run main/othervm/native TestJNIAbstractMethod + */ + +/** + * We are testing invocation of an abstract method from JNI - which should + * simply result in throwning AbstractMethodError. To invoke an abstract method + * we must have an instance method (as abstract static methods are illegal), + * but instantiating an abstract class is also illegal at the Java language + * level, so we have to use a custom jasm class that contains an abstract method + * declaration, but which is not itself declared as an abstract class. + */ +public class TestJNIAbstractMethod { + + // Invokes an abstract method from JNI and throws AbstractMethodError. + private static native void invokeAbstractM(Class AMclass, + AbstractMethodClass receiver); + + static { + System.loadLibrary("JNIAbstractMethod"); + } + + public static void main(String[] args) { + AbstractMethodClass obj = new AbstractMethodClass(); + try { + System.out.println("Attempting direct invocation via Java"); + obj.abstractM(); + throw new RuntimeException("Did not get AbstractMethodError from Java!"); + } catch (AbstractMethodError expected) { + System.out.println("ok - got expected exception: " + expected); + } + try { + System.out.println("Attempting direct invocation via JNI"); + invokeAbstractM(obj.getClass(), obj); + throw new RuntimeException("Did not get AbstractMethodError from JNI!"); + } catch (AbstractMethodError expected) { + System.out.println("ok - got expected exception: " + expected); + } + } +} diff --git a/test/hotspot/jtreg/runtime/jni/abstractMethod/libJNIAbstractMethod.c b/test/hotspot/jtreg/runtime/jni/abstractMethod/libJNIAbstractMethod.c new file mode 100644 index 00000000000..35a28f7029a --- /dev/null +++ b/test/hotspot/jtreg/runtime/jni/abstractMethod/libJNIAbstractMethod.c @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2024, 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 +#include +#include + +JNIEXPORT void JNICALL Java_TestJNIAbstractMethod_invokeAbstractM(JNIEnv* env, + jclass this_cls, + jclass target_cls, + jobject receiver) { + + jmethodID mid = (*env)->GetMethodID(env, target_cls, "abstractM", "()V"); + if (mid == NULL) { + fprintf(stderr, "Error looking up method abstractM\n"); + (*env)->ExceptionDescribe(env); + exit(1); + } + + printf("Invoking abstract method ...\n"); + (*env)->CallVoidMethod(env, receiver, mid); // Should raise exception + +} diff --git a/test/hotspot/jtreg/runtime/os/TestTracePageSizes.java b/test/hotspot/jtreg/runtime/os/TestTracePageSizes.java index e4ad27b46e5..a94d9af4c27 100644 --- a/test/hotspot/jtreg/runtime/os/TestTracePageSizes.java +++ b/test/hotspot/jtreg/runtime/os/TestTracePageSizes.java @@ -350,7 +350,7 @@ public RangeWithPageSize(String start, String end, String pageSize, String thpEl this.start = Long.parseUnsignedLong(start, 16); this.end = Long.parseUnsignedLong(end, 16); this.pageSize = Long.parseLong(pageSize); - this.thpEligible = Integer.parseInt(thpEligible) == 1; + this.thpEligible = thpEligible == null ? false : (Integer.parseInt(thpEligible) == 1); vmFlagHG = false; vmFlagHT = false; @@ -365,12 +365,11 @@ public RangeWithPageSize(String start, String end, String pageSize, String thpEl } } - // When the THP policy is 'always' instead of 'madvise, the vmFlagHG property is false. - // Check the THPeligible property instead. - isTHP = !vmFlagHT && this.thpEligible; + // When the THP policy is 'always' instead of 'madvise, the vmFlagHG property is false, + // therefore also check thpEligible. If this is still causing problems in the future, + // we might have to check the AnonHugePages field. - // vmFlagHG should imply isTHP - assert !vmFlagHG || isTHP; + isTHP = vmFlagHG || this.thpEligible; } public long getPageSize() { diff --git a/test/hotspot/jtreg/runtime/os/TestTrimNative.java b/test/hotspot/jtreg/runtime/os/TestTrimNative.java index 84d8d41de1b..e8645a91479 100644 --- a/test/hotspot/jtreg/runtime/os/TestTrimNative.java +++ b/test/hotspot/jtreg/runtime/os/TestTrimNative.java @@ -1,7 +1,7 @@ /* * Copyright (c) 2023 SAP SE. All rights reserved. - * Copyright (c) 2023 Red Hat, Inc. All rights reserved. - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, Red Hat, Inc. All rights reserved. + * Copyright (c) 2023, 2024, 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 @@ -278,7 +278,7 @@ public static void main(String[] args) throws Exception { long trimInterval = 500; // twice per second long ms1 = System.currentTimeMillis(); OutputAnalyzer output = runTestWithOptions( - new String[] { "-XX:+UnlockExperimentalVMOptions", "-XX:TrimNativeHeapInterval=" + trimInterval }, + new String[] { "-XX:TrimNativeHeapInterval=" + trimInterval }, new String[] { TestTrimNative.Tester.class.getName(), "5000" } ); long ms2 = System.currentTimeMillis(); @@ -293,7 +293,7 @@ public static void main(String[] args) throws Exception { case "trimNativeHighInterval": { OutputAnalyzer output = runTestWithOptions( - new String[] { "-XX:+UnlockExperimentalVMOptions", "-XX:TrimNativeHeapInterval=" + Integer.MAX_VALUE }, + new String[] { "-XX:TrimNativeHeapInterval=" + Integer.MAX_VALUE }, new String[] { TestTrimNative.Tester.class.getName(), "5000" } ); checkExpectedLogMessages(output, true, Integer.MAX_VALUE); @@ -305,7 +305,7 @@ public static void main(String[] args) throws Exception { case "trimNativeLowIntervalStrict": { long ms1 = System.currentTimeMillis(); OutputAnalyzer output = runTestWithOptions( - new String[] { "-XX:+UnlockExperimentalVMOptions", "-XX:TrimNativeHeapInterval=1" }, + new String[] { "-XX:TrimNativeHeapInterval=1" }, new String[] { TestTrimNative.Tester.class.getName(), "0" } ); long ms2 = System.currentTimeMillis(); @@ -316,7 +316,7 @@ public static void main(String[] args) throws Exception { case "testOffOnNonCompliantPlatforms": { OutputAnalyzer output = runTestWithOptions( - new String[] { "-XX:+UnlockExperimentalVMOptions", "-XX:TrimNativeHeapInterval=1" }, + new String[] { "-XX:TrimNativeHeapInterval=1" }, new String[] { "-version" } ); checkExpectedLogMessages(output, false, 0); @@ -327,7 +327,7 @@ public static void main(String[] args) throws Exception { case "testOffExplicit": { OutputAnalyzer output = runTestWithOptions( - new String[] { "-XX:+UnlockExperimentalVMOptions", "-XX:TrimNativeHeapInterval=0" }, + new String[] { "-XX:TrimNativeHeapInterval=0" }, new String[] { "-version" } ); checkExpectedLogMessages(output, false, 0); diff --git a/test/hotspot/jtreg/serviceability/jvmti/vthread/HeapDump/VThreadInHeapDump.java b/test/hotspot/jtreg/serviceability/jvmti/vthread/HeapDump/VThreadInHeapDump.java index 7fe5abb800f..2243a1d37b6 100644 --- a/test/hotspot/jtreg/serviceability/jvmti/vthread/HeapDump/VThreadInHeapDump.java +++ b/test/hotspot/jtreg/serviceability/jvmti/vthread/HeapDump/VThreadInHeapDump.java @@ -26,7 +26,9 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.HashSet; import java.util.List; +import java.util.Set; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -223,11 +225,22 @@ private static void verifyDump(File dumpFile) throws Exception { // Log all threads with stack traces and stack references. List threads = snapshot.getThreads(); List roots = Collections.list(snapshot.getRoots()); + // And detect thread object duplicates. + Set uniqueThreads = new HashSet<>(); + log("Threads:"); for (ThreadObject thread: threads) { + JavaHeapObject threadObj = snapshot.findThing(thread.getId()); + JavaClass threadClass = threadObj.getClazz(); StackTrace st = thread.getStackTrace(); StackFrame[] frames = st.getFrames(); - log("thread " + thread.getIdString() + ", " + frames.length + " frames"); + log("thread " + thread.getIdString() + " (" + threadClass.getName() + "), " + frames.length + " frames"); + + if (uniqueThreads.contains(thread.getId())) { + log(" - ERROR: duplicate"); + } else { + uniqueThreads.add(thread.getId()); + } List stackRoots = findStackRoot(roots, thread); for (int i = 0; i < frames.length; i++) { @@ -250,6 +263,10 @@ private static void verifyDump(File dumpFile) throws Exception { } } + if (threads.size() != uniqueThreads.size()) { + throw new RuntimeException("Thread duplicates detected (" + (threads.size() - uniqueThreads.size()) + ")"); + } + // Verify objects from thread stacks are dumped. test(snapshot, VThreadInHeapDumpTarg.VThreadMountedReferenced.class); test(snapshot, VThreadInHeapDumpTarg.PThreadReferenced.class); diff --git a/test/hotspot/jtreg/serviceability/jvmti/vthread/SuspendWithInterruptLock/SuspendWithInterruptLock.java b/test/hotspot/jtreg/serviceability/jvmti/vthread/SuspendWithInterruptLock/SuspendWithInterruptLock.java new file mode 100644 index 00000000000..d679f382d93 --- /dev/null +++ b/test/hotspot/jtreg/serviceability/jvmti/vthread/SuspendWithInterruptLock/SuspendWithInterruptLock.java @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2023, 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 id=default + * @summary Do not suspend virtual threads in a critical section. + * @bug 8311218 + * @requires vm.continuations + * @library /testlibrary + * @run main/othervm SuspendWithInterruptLock + */ + +/** + * @test id=xint + * @summary Do not suspend virtual threads in a critical section. + * @bug 8311218 + * @requires vm.continuations + * @library /testlibrary + * @run main/othervm -Xint SuspendWithInterruptLock + */ + +import jvmti.JVMTIUtils; + +public class SuspendWithInterruptLock { + static volatile boolean done; + + public static void main(String[] args) throws Exception { + Thread yielder = Thread.ofVirtual().name("yielder").start(() -> yielder()); + Thread stateReader = Thread.ofVirtual().name("stateReader").start(() -> stateReader(yielder)); + Thread suspender = new Thread(() -> suspender(stateReader)); + suspender.start(); + + yielder.join(); + stateReader.join(); + suspender.join(); + } + + static private void yielder() { + int iterations = 100_000; + while (iterations-- > 0) { + Thread.yield(); + } + done = true; + } + + static private void stateReader(Thread target) { + while (!done) { + target.getState(); + } + } + + static private void suspender(Thread target) { + while (!done) { + suspendThread(target); + sleep(1); + resumeThread(target); + // Allow progress + sleep(5); + } + } + + static void suspendThread(Thread t) { + try { + JVMTIUtils.suspendThread(t); + } catch (JVMTIUtils.JvmtiException e) { + if (e.getCode() != JVMTIUtils.JVMTI_ERROR_THREAD_NOT_ALIVE) { + throw e; + } + } + } + + static void resumeThread(Thread t) { + try { + JVMTIUtils.resumeThread(t); + } catch (JVMTIUtils.JvmtiException e) { + if (e.getCode() != JVMTIUtils.JVMTI_ERROR_THREAD_NOT_ALIVE) { + throw e; + } + } + } + + static private void sleep(long millis) { + try { + Thread.sleep(millis); + } catch (InterruptedException e) {} + } +} + diff --git a/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large001/large001.java b/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large001/large001.java index f325231c660..4d93785e5c6 100644 --- a/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large001/large001.java +++ b/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large001/large001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -59,7 +59,7 @@ * @comment generate and compile nsk.share.gc.newclass.* classes * @run driver nsk.share.gc.GenClassesBuilder * - * @run main/othervm + * @run main/othervm/timeout=300 * -XX:-UseGCOverheadLimit * -Xlog:gc* * gc.gctests.LargeObjects.large001.large001 diff --git a/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large002/TestDescription.java b/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large002/TestDescription.java index 17841794d9f..c96b47cf1cd 100644 --- a/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large002/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large002/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, 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 @@ -60,7 +60,7 @@ * @comment generate and compile nsk.share.gc.newclass.* classes * @run driver nsk.share.gc.GenClassesBuilder * - * @run main/othervm + * @run main/othervm/timeout=300 * -XX:-UseGCOverheadLimit * gc.gctests.LargeObjects.large001.large001 * -largeClassesPath classes diff --git a/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large003/TestDescription.java b/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large003/TestDescription.java index f4eaac14956..adfa8879153 100644 --- a/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large003/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large003/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, 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 @@ -64,7 +64,7 @@ * @comment generate and compile nsk.share.gc.newclass.* classes * @run driver nsk.share.gc.GenClassesBuilder * - * @run main/othervm + * @run main/othervm/timeout=300 * -XX:-UseGCOverheadLimit * gc.gctests.LargeObjects.large001.large001 * -largeClassesPath classes diff --git a/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large004/TestDescription.java b/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large004/TestDescription.java index 0eb20405d1d..7b09a18d798 100644 --- a/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large004/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large004/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, 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 @@ -64,7 +64,7 @@ * @comment generate and compile nsk.share.gc.newclass.* classes * @run driver nsk.share.gc.GenClassesBuilder * - * @run main/othervm + * @run main/othervm/timeout=300 * -XX:-UseGCOverheadLimit * gc.gctests.LargeObjects.large001.large001 * -largeClassesPath classes diff --git a/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large005/TestDescription.java b/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large005/TestDescription.java index 9df5a7a3afb..d2943ff90ab 100644 --- a/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large005/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/gc/gctests/LargeObjects/large005/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, 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 @@ -64,7 +64,7 @@ * @comment generate and compile nsk.share.gc.newclass.* classes * @run driver nsk.share.gc.GenClassesBuilder * - * @run main/othervm + * @run main/othervm/timeout=300 * -XX:-UseGCOverheadLimit * gc.gctests.LargeObjects.large001.large001 * -largeClassesPath classes diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load002/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load002/TestDescription.java index 5f22015b8d1..563eb7500a0 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load002/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load002/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -47,7 +47,7 @@ * /test/lib * @comment generate and compile LoadableClassXXX classes * @run driver nsk.monitoring.stress.classload.GenClassesBuilder - * @run main/othervm + * @run main/othervm/timeout=180 * -XX:-UseGCOverheadLimit * nsk.monitoring.stress.classload.load001 * classes diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load003/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load003/TestDescription.java index d1663931559..d972a74492c 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load003/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load003/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -47,7 +47,7 @@ * /test/lib * @comment generate and compile LoadableClassXXX classes * @run driver nsk.monitoring.stress.classload.GenClassesBuilder - * @run main/othervm + * @run main/othervm/timeout=180 * -XX:-UseGCOverheadLimit * nsk.monitoring.stress.classload.load001 * classes diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load007/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load007/TestDescription.java index 93bfe9f2c27..f8674cdbd21 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load007/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load007/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -47,7 +47,7 @@ * /test/lib * @comment generate and compile LoadableClassXXX classes * @run driver nsk.monitoring.stress.classload.GenClassesBuilder - * @run main/othervm/timeout=180 + * @run main/othervm/timeout=360 * -XX:-UseGCOverheadLimit * nsk.monitoring.stress.classload.load001 * classes diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load008/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load008/TestDescription.java index 08d7a9f1634..f306fda9e02 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load008/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load008/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, 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 @@ -45,7 +45,7 @@ * /test/lib * @comment generate and compile LoadableClassXXX classes * @run driver nsk.monitoring.stress.classload.GenClassesBuilder - * @run main/othervm/timeout=180 + * @run main/othervm/timeout=420 * -XX:-UseGCOverheadLimit * nsk.monitoring.stress.classload.load001 * classes diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load009/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load009/TestDescription.java index 3ab4ffeca7c..50f8116f7c9 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load009/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load009/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, 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 @@ -45,7 +45,7 @@ * /test/lib * @comment generate and compile LoadableClassXXX classes * @run driver nsk.monitoring.stress.classload.GenClassesBuilder - * @run main/othervm/timeout=180 + * @run main/othervm/timeout=420 * -XX:-UseGCOverheadLimit * nsk.monitoring.stress.classload.load001 * classes diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load010/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load010/TestDescription.java index 130f620faef..4f477035cd2 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load010/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load010/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -47,7 +47,7 @@ * /test/lib * @comment generate and compile LoadableClassXXX classes * @run driver nsk.monitoring.stress.classload.GenClassesBuilder - * @run main/othervm + * @run main/othervm/timeout=300 * -XX:-UseGCOverheadLimit * nsk.monitoring.stress.classload.load001 * classes diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load011/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load011/TestDescription.java index 97615b68290..110f270daff 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load011/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load011/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, 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 @@ -45,7 +45,7 @@ * /test/lib * @comment generate and compile LoadableClassXXX classes * @run driver nsk.monitoring.stress.classload.GenClassesBuilder - * @run main/othervm/timeout=180 + * @run main/othervm/timeout=360 * -XX:-UseGCOverheadLimit * nsk.monitoring.stress.classload.load001 * classes diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load012/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load012/TestDescription.java index e56cfe387e2..52c9d3e8ae7 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load012/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/load012/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, 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 @@ -45,7 +45,7 @@ * /test/lib * @comment generate and compile LoadableClassXXX classes * @run driver nsk.monitoring.stress.classload.GenClassesBuilder - * @run main/othervm/timeout=180 + * @run main/othervm/timeout=300 * -XX:-UseGCOverheadLimit * nsk.monitoring.stress.classload.load001 * classes diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload003/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload003/TestDescription.java index 7c0a01a6f9b..6c8d9f61e36 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload003/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload003/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -47,7 +47,7 @@ * /test/lib * @comment generate and compile LoadableClassXXX classes * @run driver nsk.monitoring.stress.classload.GenClassesBuilder - * @run main/othervm + * @run main/othervm/timeout=180 * -XX:-UseGCOverheadLimit * nsk.monitoring.stress.classload.unload001 * classes diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload007/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload007/TestDescription.java index b0a7526afce..62eaaa6c40a 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload007/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload007/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, 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 @@ -49,7 +49,7 @@ * /test/lib * @comment generate and compile LoadableClassXXX classes * @run driver nsk.monitoring.stress.classload.GenClassesBuilder - * @run main/othervm + * @run main/othervm/timeout=180 * -XX:-UseGCOverheadLimit * nsk.monitoring.stress.classload.unload001 * classes diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload009/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload009/TestDescription.java index b02f88e9f20..27c19980411 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload009/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/classload/unload009/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -47,7 +47,7 @@ * /test/lib * @comment generate and compile LoadableClassXXX classes * @run driver nsk.monitoring.stress.classload.GenClassesBuilder - * @run main/othervm + * @run main/othervm/timeout=180 * -XX:-UseGCOverheadLimit * nsk.monitoring.stress.classload.unload001 * classes diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/cmon001/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/cmon001/TestDescription.java index 25ea2963e3c..b2c9bf5f6f7 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/cmon001/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/cmon001/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, 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,6 +62,6 @@ * * @library /vmTestbase * /test/lib - * @run main/othervm nsk.monitoring.stress.thread.cmon001 -threadCount=400 + * @run main/othervm/timeout=240 nsk.monitoring.stress.thread.cmon001 -threadCount=400 */ diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/cmon002/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/cmon002/TestDescription.java index 50e5d7356ad..126277038eb 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/cmon002/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/cmon002/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, 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 @@ -63,6 +63,6 @@ * * @library /vmTestbase * /test/lib - * @run main/othervm nsk.monitoring.stress.thread.cmon001 -testMode=server -threadCount=400 + * @run main/othervm/timeout=240 nsk.monitoring.stress.thread.cmon001 -testMode=server -threadCount=400 */ diff --git a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/cmon003/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/cmon003/TestDescription.java index aef8902aec9..dd0cad5b708 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/cmon003/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/monitoring/stress/thread/cmon003/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, 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 @@ -63,7 +63,7 @@ * * @library /vmTestbase * /test/lib - * @run main/othervm + * @run main/othervm/timeout=240 * nsk.monitoring.stress.thread.cmon001 * -testMode=server * -MBeanServer=custom diff --git a/test/jaxp/TEST.groups b/test/jaxp/TEST.groups index 0b67ed428b9..f8cb73c4393 100644 --- a/test/jaxp/TEST.groups +++ b/test/jaxp/TEST.groups @@ -20,6 +20,14 @@ # questions. # +# All tests + +all = \ + :jaxp_all + +jaxp_all = \ + / + # Tiered testing definitions # No jaxp tests are tier 1. @@ -34,6 +42,3 @@ tier3 = # No tier 4 tests. tier4 = - -jaxp_all = \ - javax/xml/jaxp diff --git a/test/jaxp/javax/xml/jaxp/unittest/common/catalog/NullIdTest.java b/test/jaxp/javax/xml/jaxp/unittest/common/catalog/NullIdTest.java new file mode 100644 index 00000000000..442f13f4927 --- /dev/null +++ b/test/jaxp/javax/xml/jaxp/unittest/common/catalog/NullIdTest.java @@ -0,0 +1,201 @@ +/* + * Copyright (c) 2024, 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 common.catalog; + +import org.w3c.dom.ls.LSInput; +import org.w3c.dom.ls.LSResourceResolver; +import org.xml.sax.SAXException; + +import javax.xml.catalog.CatalogFeatures; +import javax.xml.transform.Source; +import javax.xml.transform.stream.StreamSource; +import javax.xml.validation.SchemaFactory; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.io.StringReader; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import static java.util.Objects.requireNonNull; +import static javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URI; +import static javax.xml.catalog.CatalogManager.catalogResolver; +import javax.xml.catalog.CatalogResolver; +import javax.xml.validation.Validator; +import org.testng.annotations.Test; + +/* + * @test + * @bug 8323571 + * @library /javax/xml/jaxp/libs /javax/xml/jaxp/unittest + * @run testng common.catalog.NullIdTest + * @summary Verifies null values are handled properly in the source resolution + * process. + */ +public class NullIdTest { + private static final Map SCHEMAS; + // Source Level JDK 8 + static { + Map map = new HashMap<>(); + map.put("https://schemas.opentest4j.org/reporting/events/0.1.0", "events.xsd"); + map.put("https://schemas.opentest4j.org/reporting/core/0.1.0", "core.xsd"); + SCHEMAS = Collections.unmodifiableMap(map); + } + + /* + * Verifies that the source resolution process recognizes the custom InputSource + * correctly even though the public and system IDs are null. + */ + @Test + public void test() throws Exception { + String xml = ""; + validate(new StreamSource(new StringReader(xml))); + System.out.println("Successfully validated"); + } + + private static void validate(Source source) throws SAXException, IOException { + SchemaFactory schemaFactory = SchemaFactory.newInstance(W3C_XML_SCHEMA_NS_URI); + Validator validator = schemaFactory.newSchema().newValidator(); + validator.setResourceResolver(createResourceResolver()); + validator.validate(source); + } + + private static LSResourceResolver createResourceResolver() { + return (type, namespaceURI, publicId, systemId, baseURI) -> { + if (namespaceURI != null) { + if (SCHEMAS.containsKey(namespaceURI)) { + CustomLSInputImpl input = new CustomLSInputImpl(); + input.setPublicId(publicId); + String schema = SCHEMAS.get(namespaceURI); + input.setSystemId(requireNonNull(NullIdTest.class.getResource(schema)).toExternalForm()); + input.setBaseURI(baseURI); + InputStream stream = NullIdTest.class.getResourceAsStream(schema); + input.setCharacterStream(new InputStreamReader(requireNonNull(stream))); + return input; + } + } + if (systemId != null) { + CatalogFeatures features = CatalogFeatures.builder() + .with(CatalogFeatures.Feature.RESOLVE, "continue") + .build(); + CatalogResolver catalogResolver = catalogResolver(features); + return catalogResolver.resolveResource(type, namespaceURI, publicId, systemId, baseURI); + } + return null; + }; + } + + static class CustomLSInputImpl implements LSInput { + + private Reader characterStream; + private InputStream byteStream; + private String stringData; + private String systemId; + private String publicId; + private String baseURI; + private String encoding; + private boolean certifiedText; + + @Override + public Reader getCharacterStream() { + return characterStream; + } + + @Override + public void setCharacterStream(Reader characterStream) { + this.characterStream = characterStream; + } + + @Override + public InputStream getByteStream() { + return byteStream; + } + + @Override + public void setByteStream(InputStream byteStream) { + this.byteStream = byteStream; + } + + @Override + public String getStringData() { + return stringData; + } + + @Override + public void setStringData(String stringData) { + this.stringData = stringData; + } + + @Override + public String getSystemId() { + return systemId; + } + + @Override + public void setSystemId(String systemId) { + this.systemId = systemId; + } + + @Override + public String getPublicId() { + return publicId; + } + + @Override + public void setPublicId(String publicId) { + this.publicId = publicId; + } + + @Override + public String getBaseURI() { + return baseURI; + } + + @Override + public void setBaseURI(String baseURI) { + this.baseURI = baseURI; + } + + @Override + public String getEncoding() { + return encoding; + } + + @Override + public void setEncoding(String encoding) { + this.encoding = encoding; + } + + @Override + public boolean getCertifiedText() { + return certifiedText; + } + + @Override + public void setCertifiedText(boolean certifiedText) { + this.certifiedText = certifiedText; + } + } +} diff --git a/test/jaxp/javax/xml/jaxp/unittest/common/catalog/core.xsd b/test/jaxp/javax/xml/jaxp/unittest/common/catalog/core.xsd new file mode 100644 index 00000000000..41b0de3425b --- /dev/null +++ b/test/jaxp/javax/xml/jaxp/unittest/common/catalog/core.xsd @@ -0,0 +1,97 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/jaxp/javax/xml/jaxp/unittest/common/catalog/events.xsd b/test/jaxp/javax/xml/jaxp/unittest/common/catalog/events.xsd new file mode 100644 index 00000000000..56d5a431211 --- /dev/null +++ b/test/jaxp/javax/xml/jaxp/unittest/common/catalog/events.xsd @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/jaxp/javax/xml/jaxp/unittest/common/dtd/DTDPropertiesTest.java b/test/jaxp/javax/xml/jaxp/unittest/common/dtd/DTDPropertiesTest.java new file mode 100644 index 00000000000..14215004937 --- /dev/null +++ b/test/jaxp/javax/xml/jaxp/unittest/common/dtd/DTDPropertiesTest.java @@ -0,0 +1,132 @@ +/* + * Copyright (c) 2024, 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 common.dtd; + +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; +import javax.xml.stream.XMLInputFactory; +import org.testng.Assert; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; +import org.xml.sax.XMLReader; + +/* + * @test + * @bug 8322214 + * @library /javax/xml/jaxp/libs /javax/xml/jaxp/unittest + * @run testng common.dtd.DTDPropertiesTest + * @summary Verifies the getProperty function on DTD properties works the same + * as before the property 'jdk.xml.dtd.support' was introduced. + */ +public class DTDPropertiesTest { + // Xerces Property + public static final String DISALLOW_DTD = "http://apache.org/xml/features/disallow-doctype-decl"; + + /* + * DataProvider for verifying Xerces' disallow-DTD feature + * Fields: property name, setting (null indicates not specified), expected + */ + @DataProvider(name = "XercesProperty") + public Object[][] getXercesProperty() throws Exception { + return new Object[][] { + { DISALLOW_DTD, null, false}, + { DISALLOW_DTD, true, true}, + { DISALLOW_DTD, false, false}, + }; + } + + /* + * DataProvider for verifying StAX's supportDTD feature + * Fields: property name, setting (null indicates not specified), expected + */ + @DataProvider(name = "StAXProperty") + public Object[][] getStAXProperty() throws Exception { + return new Object[][] { + { XMLInputFactory.SUPPORT_DTD, null, true}, + { XMLInputFactory.SUPPORT_DTD, true, true}, + { XMLInputFactory.SUPPORT_DTD, false, false}, + }; + } + + /** + * Verifies the disallow DTD feature with SAX. + * + * @param name the name of the property + * @param setting the setting of the property, null means not specified + * @param expected the expected value + * @throws Exception if the test fails + */ + @Test(dataProvider = "XercesProperty") + public void testSAX(String name, Boolean setting, Boolean expected) throws Exception { + SAXParserFactory spf = SAXParserFactory.newDefaultInstance(); + if (setting != null) { + spf.setFeature(name, setting); + } + Assert.assertEquals((Boolean)spf.getFeature(name), expected); + System.out.println(spf.getFeature(name)); + + + SAXParser saxParser = spf.newSAXParser(); + XMLReader reader = saxParser.getXMLReader(); + Assert.assertEquals((Boolean)reader.getFeature(name), expected); + System.out.println(reader.getFeature(name)); + } + + /** + * Verifies the disallow DTD feature with DOM. + * + * @param name the name of the property + * @param setting the setting of the property, null means not specified + * @param expected the expected value + * @throws Exception if the test fails + */ + @Test(dataProvider = "XercesProperty") + public void testDOM(String name, Boolean setting, Boolean expected) throws Exception { + DocumentBuilderFactory dbf = DocumentBuilderFactory.newDefaultInstance(); + if (setting != null) { + dbf.setFeature(name, setting); + } + Assert.assertEquals((Boolean)dbf.getFeature(name), expected); + System.out.println(dbf.getFeature(name)); + } + + /** + * Verifies the StAX's supportDTD feature. + * + * @param name the name of the property + * @param setting the setting of the property, null means not specified + * @param expected the expected value + * @throws Exception if the test fails + */ + @Test(dataProvider = "StAXProperty") + public void testStAX(String name, Boolean setting, Boolean expected) throws Exception { + XMLInputFactory xif = XMLInputFactory.newInstance(); + if (setting != null) { + xif.setProperty(name, setting); + } + Assert.assertEquals((Boolean)xif.getProperty(name), expected); + System.out.println((Boolean)xif.getProperty(name)); + } +} diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 94a020585e4..372ece4abac 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -624,7 +624,6 @@ sun/security/provider/PolicyFile/GrantAllPermToExtWhenNoPolicy.java 8039280 gene sun/security/provider/PolicyParser/PrincipalExpansionError.java 8039280 generic-all sun/security/pkcs11/sslecc/ClientJSSEServerJSSE.java 8316183 linux-ppc64le -sun/security/pkcs11/Provider/MultipleLogins.sh 8319128 linux-aarch64 ############################################################################ diff --git a/test/jdk/TEST.groups b/test/jdk/TEST.groups index d15b79ea91c..fa033bff12e 100644 --- a/test/jdk/TEST.groups +++ b/test/jdk/TEST.groups @@ -20,6 +20,17 @@ # questions. # +############################################################################### +# +# All tests +# + +all = \ + :jdk_all + +jdk_all = \ + / + ############################################################################### # # Tiered testing definitions diff --git a/test/jdk/com/sun/crypto/provider/Cipher/AEAD/AEADBufferTest.java b/test/jdk/com/sun/crypto/provider/Cipher/AEAD/AEADBufferTest.java index 4bf5a6263a9..a3b9064cb8a 100644 --- a/test/jdk/com/sun/crypto/provider/Cipher/AEAD/AEADBufferTest.java +++ b/test/jdk/com/sun/crypto/provider/Cipher/AEAD/AEADBufferTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, 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 @@ -873,6 +873,76 @@ static void initTest() { "3c819d9a9bed087615030b65", new byte[0], null, null, "250327c674aaf477aef2675748cf6971"), + // Random test data + new Data(AES, 4, "272f16edb81a7abbea887357a58c1917", + "794ec588176c703d3d2a7a07", + new byte[2075], null, + "15b461672153270e8ba1e6789f7641c5411f3e642abda731b6086f535c216457" + + "e87305bc59a1ff1f7e1e0bbdf302b75549b136606c67d7e5f71277aeca4bc670" + + "07a98f78e0cfa002ed183e62f07893ad31fe67aad1bb37e15b957a14d145f14f" + + "7483d041f2c3612ad5033155984470bdfc64d18df73c2745d92f28461bb09832" + + "33524811321ba87d213692825815dd13f528dba601a3c319cac6be9b48686c23" + + "a0ce23d5062916ea8827bbb243f585e446131489e951354c8ab24661f625c02e" + + "15536c5bb602244e98993ff745f3e523399b2059f0e062d8933fad2366e7e147" + + "510a931282bb0e3f635efe7bf05b1dd715f95f5858261b00735224256b6b3e80" + + "7364cb53ff6d4e88f928cf67ac70da127718a8a35542efbae9dd7567c818a074" + + "9a0c74bd69014639f59768bc55056d1166ea5523e8c66f9d78d980beb8f0d83b" + + "a9e2c5544b94dc3a1a4b6f0f95f897b010150e89ebcacf0daee3c2793d6501a0" + + "b58b411de273dee987e8e8cf8bb29ef2e7f655b46b55fabf64c6a4295e0d080b" + + "6a570ace90eb0fe0f5b5d878bdd90eddaa1150e4d5a6505b350aac814fe99615" + + "317ecd0516a464c7904011ef5922409c0d65b1e43b69d7c3293a8f7d3e9fbee9" + + "eb91ec0007a7d6f72e64deb675d459c5ba07dcfd58d08e6820b100465e6e04f0" + + "663e310584a00d36d23699c1bffc6afa094c75184fc7cde7ad35909c0f49f2f3" + + "fe1e6d745ab628d74ea56b757047de57ce18b4b3c71e8af31a6fac16189cb0a3" + + "a97a1bea447042ce382fcf726560476d759c24d5c735525ea26a332c2094408e" + + "671c7deb81d5505bbfd178f866a6f3a011b3cfdbe089b4957a790688028dfdf7" + + "9a096b3853f9d0d6d3feef230c7f5f46ffbf7486ebdaca5804dc5bf9d202415e" + + "e0d67b365c2f92a17ea740807e4f0b198b42b54f15faa9dff2c7c35d2cf8d72e" + + "b8f8b18875a2e7b5c43d1e0aa5139c461e8153c7f632895aa46ffe2b134e6a0d" + + "dfbf6a336e709adfe951bd52c4dfc7b07a15fb3888fc35b7e758922f87a104c4" + + "563c5c7839cfe5a7edbdb97264a7c4ebc90367b10cbe09dbf2390767ad7afaa8" + + "8fb46b39d3f55f216d2104e5cf040bf3d39b758bea28e2dbce576c808d17a8eb" + + "e2fd183ef42a774e39119dff1f539efeb6ad15d889dfcb0d54d0d4d4cc03c8d9" + + "aa6c9ebd157f5e7170183298d6a30ada8792dcf793d931e2a1eafccbc63c11c0" + + "c5c5ed60837f30017d693ccb294df392a8066a0594a56954aea7b78a16e9a11f" + + "4a8bc2104070a7319f5fab0d2c4ccad8ec5cd8f47c839179bfd54a7bf225d502" + + "cd0a318752fe763e8c09eb88fa57fc5399ad1f797d0595c7b8afdd23f13603e9" + + "6802192bb51433b7723f4e512bd4f799feb94b458e7f9792f5f9bd6733828f70" + + "a6b7ffbbc0bb7575021f081ec2a0d37fecd7cda2daec9a3a9d9dfe1c8034cead" + + "e4b56b581cc82bd5b74b2b30817967d9da33850336f171a4c68e2438e03f4b11" + + "96da92f01b3b7aeab795180ccf40a4b090b1175a1fc0b67c95f93105c3aef00e" + + "13d76cc402539192274fee703730cd0d1c5635257719cc96cacdbad00c6255e2" + + "bd40c775b43ad09599e84f2c3205d75a6661ca3f151183be284b354ce21457d1" + + "3ba65b9b2cdb81874bd14469c2008b3ddec78f7225ecc710cc70de7912ca6a6d" + + "348168322ab59fdafcf5c833bfa0ad4046f4b6da90e9f263db7079af592eda07" + + "5bf16c6b1a8346da9c292a48bf660860a4fc89eaef40bc132779938eca294569" + + "787c740af2b5a8de7f5e10ac750d1e3d0ef3ed168ba408a676e10b8a20bd4be8" + + "3e8336b45e54481726d73e1bd19f165a98e242aca0d8387f2dd22d02d74e23db" + + "4cef9a523587413e0a44d7e3260019a34d3a6b38426ae9fa4655be338d721970" + + "cb9fe76c073f26f9303093a033022cd2c62b2790bce633ba9026a1c93b6535f1" + + "1882bf5880e511b9e1b0b7d8f23a993aae5fd275faac3a5b4ccaf7c06b0b266a" + + "ee970a1e3a4cd7a41094f516960630534e692545b25a347c30e3f328bba4825f" + + "ed754e5525d846131ecba7ca120a6aeabc7bab9f59c890c80b7e31f9bc741591" + + "55d292433ce9558e104102f2cc63ee267c1c8333e841522707ea6d595cb802b9" + + "61697da77bbc4cb404ea62570ab335ebffa2023730732ac5ddba1c3dbb5be408" + + "3c50aea462c1ffa166d7cc3db4b742b747e81b452db2363e91374dee8c6b40f0" + + "e7fbf50e60eaf5cc5649f6bb553aae772c185026ceb052af088c545330a1ffbf" + + "50615b8c7247c6cd386afd7440654f4e15bcfae0c45442ec814fe88433a9d616" + + "ee6cc3f163f0d3d325526d05f25d3b37ad5eeb3ca77248ad86c9042b16c65554" + + "aebb6ad3e17b981492b13f42c5a5dc088e991da303e5a273fdbb8601aece4267" + + "47b01f6cb972e6da1743a0d7866cf206e95f23c6f8e337c901b9cd34a9a1fbbe" + + "1694f2c26b00dfa4d02c0d54540163e798fbdc9c25f30d6406f5b4c13f7ed619" + + "34e350f4059c13aa5e973307a9e3058917cda96fdd082e9c629ccfb2a9f98d12" + + "5c6e4703a7b0f348f5cdeb63cef2133d1c6c1a087591e0a2bca29d09c6565e66" + + "e91042f83b0e74e60a5d57562c23e2fbcd6599c29d7c19e47cf625c2ce24bb8a" + + "13f8e54041498437eec2cedd1e3d8e57a051baa962c0a62d70264d99c5ee716d" + + "5c8b9078db08c8b2c5613f464198a7aff43f76c5b4612b46a4f1cd2a494386c5" + + "7fd28f3d199f0ba8d8e39116cc7db16ce6188205ee49a9dce3d4fa32ea394919" + + "f6e91ef58b84d00b99596b4306c2d9f432d917bb4ac73384c42ae12adb4920d8" + + "c33a816febcb299dcddf3ec7a8eb6e04cdc90891c6e145bd9fc5f41dc4061a46" + + "9feba38545b64ec8203f386ceef52785619e991d274ae80af7e54af535e0b011" + + "5effdf847472992875e09398457604d04e0bb965db692c0cdcf11a", + "687cc09c89298491deb51061d709af"), // Randomly generated data at the time of execution. new Data(AES, 5, "11754cd72aec309bf52f7687212e8957", 16, 12345))); diff --git a/test/jdk/com/sun/crypto/provider/Cipher/AEAD/GCMIncrementByte4.java b/test/jdk/com/sun/crypto/provider/Cipher/AEAD/GCMIncrementByte4.java index 1a92e0f4249..a4d1fa47456 100644 --- a/test/jdk/com/sun/crypto/provider/Cipher/AEAD/GCMIncrementByte4.java +++ b/test/jdk/com/sun/crypto/provider/Cipher/AEAD/GCMIncrementByte4.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, 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,18 +25,18 @@ /* * @test - * @summary Uses GCMBufferTest to run a long test with incrementing through - * each byte in each byte array + * @summary Uses AEADBufferTest to run a long test with incrementing through + * each byte in each byte array using AES GCM * @run main/manual GCMIncrementByte4 */ public class GCMIncrementByte4 { public static void main(String args[]) throws Exception { - GCMBufferTest.initTest(); - new GCMBufferTest("AES/GCM/NoPadding", - List.of(GCMBufferTest.dtype.BYTE, GCMBufferTest.dtype.BYTE, - GCMBufferTest.dtype.BYTE)).incrementalSegments().dataSet(4). + AEADBufferTest.initTest(); + new AEADBufferTest("AES/GCM/NoPadding", + List.of(AEADBufferTest.dtype.BYTE, AEADBufferTest.dtype.BYTE, + AEADBufferTest.dtype.BYTE)).incrementalSegments().dataSet(4). test(); } diff --git a/test/jdk/com/sun/crypto/provider/Cipher/AEAD/GCMIncrementDirect4.java b/test/jdk/com/sun/crypto/provider/Cipher/AEAD/GCMIncrementDirect4.java index 1aac884bfb7..32481c72154 100644 --- a/test/jdk/com/sun/crypto/provider/Cipher/AEAD/GCMIncrementDirect4.java +++ b/test/jdk/com/sun/crypto/provider/Cipher/AEAD/GCMIncrementDirect4.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, 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,18 +25,18 @@ /* * @test - * @summary Uses GCMBufferTest to run a long test with incrementing through - * each byte in each direct bytebuffer + * @summary Uses AEADBufferTest to run a long test with incrementing through + * each byte in each direct bytebuffer using AES GCM * @run main/manual GCMIncrementDirect4 */ public class GCMIncrementDirect4 { public static void main(String args[]) throws Exception { - GCMBufferTest.initTest(); - new GCMBufferTest("AES/GCM/NoPadding", - List.of(GCMBufferTest.dtype.DIRECT, GCMBufferTest.dtype.DIRECT, - GCMBufferTest.dtype.DIRECT)).incrementalSegments().dataSet(4). + AEADBufferTest.initTest(); + new AEADBufferTest("AES/GCM/NoPadding", + List.of(AEADBufferTest.dtype.DIRECT, AEADBufferTest.dtype.DIRECT, + AEADBufferTest.dtype.DIRECT)).incrementalSegments().dataSet(4). test(); } } diff --git a/test/jdk/com/sun/crypto/provider/Cipher/AEAD/OverlapByteBuffer.java b/test/jdk/com/sun/crypto/provider/Cipher/AEAD/OverlapByteBuffer.java index c8af2d2fbd5..9c62556d88b 100644 --- a/test/jdk/com/sun/crypto/provider/Cipher/AEAD/OverlapByteBuffer.java +++ b/test/jdk/com/sun/crypto/provider/Cipher/AEAD/OverlapByteBuffer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, 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,14 +23,18 @@ import javax.crypto.Cipher; import javax.crypto.spec.GCMParameterSpec; +import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; import java.nio.ByteBuffer; +import java.security.spec.AlgorithmParameterSpec; /* * @test * @summary This tests overlapping buffers using ByteBuffer.slice() with * array-backed ByteBuffer, read only array-backed, ByteBuffer, and direct * ByteBuffer. + * @run main OverlapByteBuffer AES/GCM/NoPadding + * @run main OverlapByteBuffer ChaCha20-Poly1305 */ /* @@ -45,19 +49,38 @@ public class OverlapByteBuffer { + byte[] baseBuf = new byte[8192]; + ByteBuffer output, input, in; + int outOfs; + String algorithm; + SecretKeySpec key; + AlgorithmParameterSpec params; + public static void main(String[] args) throws Exception { - byte[] baseBuf = new byte[8192]; - ByteBuffer output, input, in; - // Output offset from the baseBuf - int outOfs; + new OverlapByteBuffer(args[0]).test(); + } + + OverlapByteBuffer(String algorithm) throws Exception { + this.algorithm = algorithm; + switch (algorithm) { + case "AES/GCM/NoPadding" -> { + params = new GCMParameterSpec(128, new byte[12]); + key = new SecretKeySpec(new byte[16], "AES"); + } + case "ChaCha20-Poly1305" -> { + params = new IvParameterSpec(new byte[12]); + key = new SecretKeySpec(new byte[32], ""); + } + default -> throw new Exception("unknown algorithm: " + algorithm); + } + } + void test() throws Exception { + // Output offset from the baseBuf for (int i = 0; i < 3; i++) { for (outOfs = -1; outOfs <= 1; outOfs++) { - SecretKeySpec key = new SecretKeySpec(new byte[16], "AES"); - GCMParameterSpec params = - new GCMParameterSpec(128, new byte[12]); - Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding"); + Cipher cipher = Cipher.getInstance(algorithm); cipher.init(Cipher.ENCRYPT_MODE, key, params); // Offset on the particular ByteBuffer (aka position()) @@ -84,7 +107,8 @@ public static void main(String[] args) throws Exception { input = ByteBuffer.wrap(buffer, inOfsInBuf, sliceLen). slice(); - System.out.println("Using read-only array-backed " + "ByteBuffer"); + System.out.println("Using read-only array-backed " + + "ByteBuffer"); in = input.asReadOnlyBuffer(); } case 2 -> { @@ -102,9 +126,7 @@ public static void main(String[] args) throws Exception { in = input.duplicate(); } - default -> { - throw new Exception("Unknown index " + i); - } + default -> throw new Exception("Unknown index " + i); } System.out.println("inOfsInBuf = " + inOfsInBuf); diff --git a/test/jdk/com/sun/crypto/provider/DHKEM/Compliance.java b/test/jdk/com/sun/crypto/provider/DHKEM/Compliance.java index 27b72b5cf7c..22c5c89b57b 100644 --- a/test/jdk/com/sun/crypto/provider/DHKEM/Compliance.java +++ b/test/jdk/com/sun/crypto/provider/DHKEM/Compliance.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,7 +26,9 @@ * @bug 8297878 * @summary Key Encapsulation Mechanism API * @library /test/lib + * @build java.base/com.sun.crypto.provider.EvenKEMImpl * @modules java.base/com.sun.crypto.provider + * @run main/othervm Compliance */ import jdk.test.lib.Asserts; import jdk.test.lib.Utils; @@ -45,18 +47,19 @@ import com.sun.crypto.provider.DHKEM; +import static com.sun.crypto.provider.EvenKEMImpl.isEven; + public class Compliance { public static void main(String[] args) throws Exception { basic(); conform(); determined(); - try { - Security.insertProviderAt(new ProviderImpl(), 1); - delayed(); - } finally { - Security.removeProvider("XP"); - } + // Patch an alternate DHKEM in SunEC which is ahead of SunJCE + // in security provider listing. + Security.getProvider("SunEC") + .put("KEM.DHKEM", "com.sun.crypto.provider.EvenKEMImpl"); + delayed(); } // Encapsulated conformance checks @@ -220,34 +223,6 @@ static byte[] calcDetermined(long seed) throws Exception { return enc2; } - public static class ProviderImpl extends Provider { - ProviderImpl() { - super("XP", "1", "XP"); - put("KEM.DHKEM", "Compliance$KEMImpl"); - } - } - - static boolean isEven(Key k) { - return Arrays.hashCode(k.getEncoded()) % 2 == 0; - } - - public static class KEMImpl extends DHKEM { - - @Override - public EncapsulatorSpi engineNewEncapsulator(PublicKey pk, AlgorithmParameterSpec spec, SecureRandom secureRandom) - throws InvalidAlgorithmParameterException, InvalidKeyException { - if (!isEven(pk)) throw new InvalidKeyException("Only accept even keys"); - return super.engineNewEncapsulator(pk, spec, secureRandom); - } - - @Override - public DecapsulatorSpi engineNewDecapsulator(PrivateKey sk, AlgorithmParameterSpec spec) - throws InvalidAlgorithmParameterException, InvalidKeyException { - if (!isEven(sk)) throw new InvalidKeyException("Only accept even keys"); - return super.engineNewDecapsulator(sk, spec); - } - } - // Ensure delayed provider selection static void delayed() throws Exception { KeyPairGenerator g = KeyPairGenerator.getInstance("X25519"); @@ -266,7 +241,7 @@ static void delayed() throws Exception { KEM.Encapsulator eodd = kem.newEncapsulator(odd); KEM.Encapsulator eeven = kem.newEncapsulator(even); Asserts.assertEQ(eodd.providerName(), "SunJCE"); - Asserts.assertEQ(eeven.providerName(), "XP"); + Asserts.assertEQ(eeven.providerName(), "SunEC"); } static ECPublicKey badECKey() { diff --git a/test/jdk/com/sun/crypto/provider/DHKEM/java.base/com/sun/crypto/provider/EvenKEMImpl.java b/test/jdk/com/sun/crypto/provider/DHKEM/java.base/com/sun/crypto/provider/EvenKEMImpl.java new file mode 100644 index 00000000000..dc478c25954 --- /dev/null +++ b/test/jdk/com/sun/crypto/provider/DHKEM/java.base/com/sun/crypto/provider/EvenKEMImpl.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2024, 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 com.sun.crypto.provider; + +import java.security.*; +import java.security.spec.*; +import java.util.Arrays; + +// The alternate DHKEM implementation used by the Compliance.java test. +public class EvenKEMImpl extends DHKEM { + + public static boolean isEven(Key k) { + return Arrays.hashCode(k.getEncoded()) % 2 == 0; + } + + @Override + public EncapsulatorSpi engineNewEncapsulator( + PublicKey pk, AlgorithmParameterSpec spec, SecureRandom secureRandom) + throws InvalidAlgorithmParameterException, InvalidKeyException { + if (!isEven(pk)) throw new InvalidKeyException("Only accept even keys"); + return super.engineNewEncapsulator(pk, spec, secureRandom); + } + + @Override + public DecapsulatorSpi engineNewDecapsulator( + PrivateKey sk, AlgorithmParameterSpec spec) + throws InvalidAlgorithmParameterException, InvalidKeyException { + if (!isEven(sk)) throw new InvalidKeyException("Only accept even keys"); + return super.engineNewDecapsulator(sk, spec); + } +} diff --git a/test/jdk/java/awt/font/JNICheck/FreeTypeScalerJNICheck.java b/test/jdk/java/awt/font/JNICheck/FreeTypeScalerJNICheck.java index 73c2770fba5..942416ff781 100644 --- a/test/jdk/java/awt/font/JNICheck/FreeTypeScalerJNICheck.java +++ b/test/jdk/java/awt/font/JNICheck/FreeTypeScalerJNICheck.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2021, JetBrains s.r.o.. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -45,7 +45,10 @@ public static void main(String[] args) throws Exception { } else { ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder("-Xcheck:jni", FreeTypeScalerJNICheck.class.getName(), "runtest"); OutputAnalyzer oa = ProcessTools.executeProcess(pb); - oa.shouldContain("Done").shouldNotContain("WARNING").shouldHaveExitValue(0); + oa.shouldContain("Done") + .shouldNotContain("WARNING") + .shouldNotContain("AWT Assertion") + .shouldHaveExitValue(0); } } @@ -54,8 +57,7 @@ public static void runTest() { BufferedImage bi = new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB); Graphics2D g2d = bi.createGraphics(); - for (String ff : families) - { + for (String ff : families) { Font font = new Font(ff, Font.PLAIN, 12); Rectangle2D bounds = font.getStringBounds("test", g2d.getFontRenderContext()); g2d.setFont(font); @@ -66,4 +68,3 @@ public static void runTest() { System.out.println("Done"); } } - diff --git a/test/jdk/java/foreign/TestLayouts.java b/test/jdk/java/foreign/TestLayouts.java index f4048aaa68a..2aa398468cc 100644 --- a/test/jdk/java/foreign/TestLayouts.java +++ b/test/jdk/java/foreign/TestLayouts.java @@ -371,13 +371,13 @@ public void testVarHandleCaching() { } @Test(expectedExceptions=IllegalArgumentException.class, - expectedExceptionsMessageRegExp=".*Negative offset.*") + expectedExceptionsMessageRegExp=".*offset is negative.*") public void testScaleNegativeOffset() { JAVA_INT.scale(-1, 0); } @Test(expectedExceptions=IllegalArgumentException.class, - expectedExceptionsMessageRegExp=".*Negative index.*") + expectedExceptionsMessageRegExp=".*index is negative.*") public void testScaleNegativeIndex() { JAVA_INT.scale(0, -1); } diff --git a/test/jdk/java/foreign/TestMemoryAccessInstance.java b/test/jdk/java/foreign/TestMemoryAccessInstance.java index d56f44388a4..b749c96ac54 100644 --- a/test/jdk/java/foreign/TestMemoryAccessInstance.java +++ b/test/jdk/java/foreign/TestMemoryAccessInstance.java @@ -164,6 +164,13 @@ public void badAccessOverflowInIndexedAccess(String t } } + @Test(dataProvider = "segmentAccessors") + public void negativeOffset(String testName, Accessor accessor) { + MemorySegment segment = MemorySegment.ofArray(new byte[100]); + assertThrows(IndexOutOfBoundsException.class, () -> accessor.get(segment, -ValueLayout.JAVA_LONG.byteSize())); + assertThrows(IndexOutOfBoundsException.class, () -> accessor.set(segment, -ValueLayout.JAVA_LONG.byteSize(), accessor.value)); + } + static final ByteOrder NE = ByteOrder.nativeOrder(); @DataProvider(name = "segmentAccessors") diff --git a/test/jdk/java/foreign/TestScope.java b/test/jdk/java/foreign/TestScope.java index 337dce7d0ca..b7bcc4d373c 100644 --- a/test/jdk/java/foreign/TestScope.java +++ b/test/jdk/java/foreign/TestScope.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, 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,11 @@ import java.lang.foreign.Arena; import java.lang.foreign.MemorySegment; import java.lang.foreign.SymbolLookup; +import java.lang.foreign.ValueLayout; import java.nio.ByteBuffer; import java.nio.IntBuffer; +import java.util.HexFormat; +import java.util.stream.LongStream; import static org.testng.Assert.*; @@ -108,6 +111,30 @@ public void testSameLookupScope() { testDerivedBufferScope(segment1.reinterpret(10)); } + @Test + public void testZeroedOfAuto() { + testZeroed(Arena.ofAuto()); + } + + @Test + public void testZeroedGlobal() { + testZeroed(Arena.global()); + } + + @Test + public void testZeroedOfConfined() { + try (Arena arena = Arena.ofConfined()) { + testZeroed(arena); + } + } + + @Test + public void testZeroedOfShared() { + try (Arena arena = Arena.ofShared()) { + testZeroed(arena); + } + } + void testDerivedBufferScope(MemorySegment segment) { ByteBuffer buffer = segment.asByteBuffer(); MemorySegment.Scope expectedScope = segment.scope(); @@ -119,4 +146,14 @@ void testDerivedBufferScope(MemorySegment segment) { IntBuffer view = buffer.asIntBuffer(); assertEquals(expectedScope, MemorySegment.ofBuffer(view).scope()); } + + private static final MemorySegment ZEROED_MEMORY = MemorySegment.ofArray(new byte[8102]); + + void testZeroed(Arena arena) { + long byteSize = ZEROED_MEMORY.byteSize(); + var segment = arena.allocate(byteSize, Long.BYTES); + long mismatch = ZEROED_MEMORY.mismatch(segment); + assertEquals(mismatch, -1); + } + } diff --git a/test/jdk/java/foreign/TestScopedOperations.java b/test/jdk/java/foreign/TestScopedOperations.java index 70223c00c00..d680d234145 100644 --- a/test/jdk/java/foreign/TestScopedOperations.java +++ b/test/jdk/java/foreign/TestScopedOperations.java @@ -27,6 +27,7 @@ */ import java.lang.foreign.Arena; +import java.lang.foreign.MemoryLayout; import java.lang.foreign.MemorySegment; import java.lang.foreign.ValueLayout; @@ -135,6 +136,8 @@ public void testOpOutsideConfinement(String name, ScopedOperation scopedO ScopedOperation.ofScope(a -> a.allocateFrom(ValueLayout.JAVA_FLOAT, new float[]{0}), "Arena::allocateFrom/float"); ScopedOperation.ofScope(a -> a.allocateFrom(ValueLayout.JAVA_LONG, new long[]{0}), "Arena::allocateFrom/long"); ScopedOperation.ofScope(a -> a.allocateFrom(ValueLayout.JAVA_DOUBLE, new double[]{0}), "Arena::allocateFrom/double"); + var source = MemorySegment.ofArray(new byte[]{}); + ScopedOperation.ofScope(a -> a.allocateFrom(ValueLayout.JAVA_INT, source, JAVA_BYTE, 0, 1), "Arena::allocateFrom/5arg"); }; @DataProvider(name = "scopedOperations") diff --git a/test/jdk/java/foreign/TestSegmentAllocators.java b/test/jdk/java/foreign/TestSegmentAllocators.java index 0e0c49320da..87418f39d90 100644 --- a/test/jdk/java/foreign/TestSegmentAllocators.java +++ b/test/jdk/java/foreign/TestSegmentAllocators.java @@ -44,6 +44,8 @@ import java.nio.ShortBuffer; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.BiFunction; import java.util.function.Function; @@ -189,6 +191,81 @@ public void testAllocatorAllocateFromHeapSegment() { } } + // Invariant checking tests for the SegmentAllocator method: + // MemorySegment allocateFrom(ValueLayout elementLayout, + // MemorySegment source, + // ValueLayout sourceElementLayout, + // long sourceOffset, + // long elementCount) { + @Test + public void testAllocatorAllocateFromArguments() { + try (Arena arena = Arena.ofConfined()) { + var sourceElements = 2; + var source = arena.allocate(ValueLayout.JAVA_LONG, sourceElements); + var elementLayout = ValueLayout.JAVA_INT; + var sourceElementLayout = ValueLayout.JAVA_INT; + + // IllegalArgumentException if {@code elementLayout.byteSize() != sourceElementLayout.byteSize()} + assertThrows(IllegalArgumentException.class, () -> + arena.allocateFrom(elementLayout, source, ValueLayout.JAVA_BYTE, 0, 1) + ); + + // IllegalArgumentException if source segment/offset + // are incompatible with the alignment constraint + // in the source element layout + assertThrows(IllegalArgumentException.class, () -> + arena.allocateFrom(elementLayout, source.asSlice(1), sourceElementLayout, 0, 1) + ); + assertThrows(IllegalArgumentException.class, () -> + arena.allocateFrom(elementLayout, source, sourceElementLayout, 1, 1) + ); + + // IllegalArgumentException if {@code elementLayout.byteAlignment() > elementLayout.byteSize()} + assertThrows(IllegalArgumentException.class, () -> + arena.allocateFrom(elementLayout.withByteAlignment(elementLayout.byteAlignment() * 2), source, sourceElementLayout, 1, 1) + ); + + // IllegalStateException if the {@linkplain MemorySegment#scope() scope} associated + // with {@code source} is not {@linkplain MemorySegment.Scope#isAlive() alive} + // This is tested in TestScopedOperations + + // WrongThreadException if this method is called from a thread {@code T}, + // such that {@code source.isAccessibleBy(T) == false} + CompletableFuture future = CompletableFuture.supplyAsync(Arena::ofConfined); + try { + Arena otherThreadArena = future.get(); + assertThrows(WrongThreadException.class, () -> + otherThreadArena.allocateFrom(elementLayout, source, sourceElementLayout, 0, 1) + ); + } catch (ExecutionException | InterruptedException e) { + fail("Unable to create arena", e); + } + + // IllegalArgumentException if {@code elementCount * sourceElementLayout.byteSize()} overflows + assertThrows(IllegalArgumentException.class, () -> + arena.allocateFrom(elementLayout, source, sourceElementLayout, 0, Long.MAX_VALUE) + ); + + // IndexOutOfBoundsException if {@code sourceOffset > source.byteSize() - (elementCount * sourceElementLayout.byteSize())} + assertThrows(IndexOutOfBoundsException.class, () -> + arena.allocateFrom(elementLayout, source, sourceElementLayout, source.byteSize() - (1 * sourceElementLayout.byteAlignment()) + elementLayout.byteSize(), 1) + ); + + // IndexOutOfBoundsException if {@code sourceOffset < 0} + assertThrows(IndexOutOfBoundsException.class, () -> + arena.allocateFrom(elementLayout, source, sourceElementLayout, -elementLayout.byteSize(), 1) + ); + + // IllegalArgumentException if {@code elementCount < 0} + assertThrows(IllegalArgumentException.class, () -> + arena.allocateFrom(elementLayout, source, sourceElementLayout, 0, -1) + ); + + + } + } + + @Test public void testArrayAllocateDelegation() { AtomicInteger calls = new AtomicInteger(); diff --git a/test/jdk/java/foreign/TestSegmentCopy.java b/test/jdk/java/foreign/TestSegmentCopy.java index 414cd0a8451..88636bf5420 100644 --- a/test/jdk/java/foreign/TestSegmentCopy.java +++ b/test/jdk/java/foreign/TestSegmentCopy.java @@ -145,6 +145,66 @@ public void testHyperAlignedDst() { MemorySegment.copy(segment, JAVA_BYTE.withByteAlignment(2), 0, segment, 0, 4); } + @Test + public void testCopy5ArgWithNegativeValues() { + MemorySegment src = MemorySegment.ofArray(new byte[] {1, 2, 3, 4}); + MemorySegment dst = MemorySegment.ofArray(new byte[] {1, 2, 3, 4}); + assertThrows(IndexOutOfBoundsException.class, () -> + MemorySegment.copy(src, -1, dst, 0, 4) + ); + assertThrows(IndexOutOfBoundsException.class, () -> + MemorySegment.copy(src, 0, dst, -1, 4) + ); + assertThrows(IndexOutOfBoundsException.class, () -> + MemorySegment.copy(src, 0, dst, 0, -1) + ); + } + + @Test + public void testCopy7ArgWithNegativeValues() { + MemorySegment src = MemorySegment.ofArray(new byte[] {1, 2, 3, 4}); + MemorySegment dst = MemorySegment.ofArray(new byte[] {1, 2, 3, 4}); + assertThrows(IndexOutOfBoundsException.class, () -> + MemorySegment.copy(src, JAVA_BYTE, -1, dst, JAVA_BYTE, 0, 4) + ); + assertThrows(IndexOutOfBoundsException.class, () -> + MemorySegment.copy(src, JAVA_BYTE, 0, dst, JAVA_BYTE, -1, 4) + ); + assertThrows(IndexOutOfBoundsException.class, () -> + MemorySegment.copy(src, JAVA_BYTE, 0, dst, JAVA_BYTE, 0, -1) + ); + } + + @Test + public void testCopyFromArrayWithNegativeValues() { + MemorySegment src = MemorySegment.ofArray(new byte[] {1, 2, 3, 4}); + byte[] dst = new byte[] {1, 2, 3, 4}; + assertThrows(IndexOutOfBoundsException.class, () -> + MemorySegment.copy(src, JAVA_BYTE, -1, dst, 0, 4) + ); + assertThrows(IndexOutOfBoundsException.class, () -> + MemorySegment.copy(src, JAVA_BYTE, 0, dst, -1, 4) + ); + assertThrows(IndexOutOfBoundsException.class, () -> + MemorySegment.copy(src, JAVA_BYTE, 0, dst, 0, -1) + ); + } + + @Test + public void testCopyToArrayWithNegativeValues() { + byte[] src = new byte[] {1, 2, 3, 4}; + MemorySegment dst = MemorySegment.ofArray(new byte[] {1, 2, 3, 4}); + assertThrows(IndexOutOfBoundsException.class, () -> + MemorySegment.copy(src, -1, dst, JAVA_BYTE, 0, 4) + ); + assertThrows(IndexOutOfBoundsException.class, () -> + MemorySegment.copy(src, 0, dst, JAVA_BYTE, -1, 4) + ); + assertThrows(IndexOutOfBoundsException.class, () -> + MemorySegment.copy(src, 0, dst, JAVA_BYTE, 0, -1) + ); + } + enum Type { // Byte BYTE(byte.class, JAVA_BYTE, i -> (byte)i), diff --git a/test/jdk/java/foreign/TestSegments.java b/test/jdk/java/foreign/TestSegments.java index 94b49eb7e59..44ecd12ba5e 100644 --- a/test/jdk/java/foreign/TestSegments.java +++ b/test/jdk/java/foreign/TestSegments.java @@ -43,6 +43,7 @@ import java.util.function.Supplier; import static java.lang.foreign.ValueLayout.JAVA_INT; +import static java.lang.foreign.ValueLayout.JAVA_LONG; import static org.testng.Assert.*; public class TestSegments { @@ -55,14 +56,13 @@ public void testBadAllocateAlign(long size, long align) { @Test public void testZeroLengthNativeSegment() { try (Arena arena = Arena.ofConfined()) { - Arena session = arena; - var segment = session.allocate(0, 1); + var segment = arena.allocate(0, 1); assertEquals(segment.byteSize(), 0); MemoryLayout seq = MemoryLayout.sequenceLayout(0, JAVA_INT); - segment = session.allocate(seq); + segment = arena.allocate(seq); assertEquals(segment.byteSize(), 0); assertEquals(segment.address() % seq.byteAlignment(), 0); - segment = session.allocate(0, 4); + segment = arena.allocate(0, 4); assertEquals(segment.byteSize(), 0); assertEquals(segment.address() % 4, 0); MemorySegment rawAddress = MemorySegment.ofAddress(segment.address()); @@ -133,8 +133,7 @@ public void testDerivedScopes(Supplier segmentSupplier) { @Test public void testEqualsOffHeap() { try (Arena arena = Arena.ofConfined()) { - Arena scope1 = arena; - MemorySegment segment = scope1.allocate(100, 1); + MemorySegment segment = arena.allocate(100, 1); assertEquals(segment, segment.asReadOnly()); assertEquals(segment, segment.asSlice(0, 100)); assertNotEquals(segment, segment.asSlice(10, 90)); diff --git a/test/jdk/java/foreign/UpcallTestHelper.java b/test/jdk/java/foreign/UpcallTestHelper.java index bbc01959ccd..8adf5580f51 100644 --- a/test/jdk/java/foreign/UpcallTestHelper.java +++ b/test/jdk/java/foreign/UpcallTestHelper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, 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,9 @@ import java.util.ArrayList; import java.util.List; import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; -import static org.testng.Assert.assertTrue; +import static org.testng.Assert.fail; public class UpcallTestHelper extends NativeTestHelper { @@ -50,16 +51,18 @@ public OutputAnalyzer runInNewProcess(Class target, boolean useSpec, List invokePark()); + assertContains(output, "reason:NATIVE"); assertContains(output, "(Native Method)"); - assertDoesNotContain(output, "<== monitors"); + } + + /** + * Test parking in class initializer. + */ + @Test + void testPinnedCausedByClassInitializer() throws Exception { + class C { + static { + park(); + } + } + String output = run(C::new); + assertContains(output, "reason:NATIVE"); + assertContains(output, ""); + } + + /** + * Test contention writing to System.out when pinned. The test creates four threads + * that write to System.out when pinned, this is enough to potentially deadlock + * without the changes in JDK-8322846. + */ + @Test + void testContention() throws Exception { + // use several classes to avoid duplicate stack traces + class C1 { + synchronized void print() { + System.out.println("hello"); + } + } + class C2 { + synchronized void print() { + System.out.println("hello"); + } + } + class C3 { + synchronized void print() { + System.out.println("hello"); + } + } + class C4 { + synchronized void print() { + System.out.println("hello"); + } + } + + try (var executor = Executors.newVirtualThreadPerTaskExecutor()) { + executor.submit(() -> { + new C1().print(); + }); + executor.submit(() -> { + new C2().print(); + }); + executor.submit(() -> { + new C3().print(); + }); + executor.submit(() -> { + new C4().print(); + }); + } } /** diff --git a/test/jdk/java/lang/Thread/virtual/stress/GetStackTraceALotWhenPinned.java b/test/jdk/java/lang/Thread/virtual/stress/GetStackTraceALotWhenPinned.java new file mode 100644 index 00000000000..e00cf89fb8c --- /dev/null +++ b/test/jdk/java/lang/Thread/virtual/stress/GetStackTraceALotWhenPinned.java @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2023, 2024, 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 8322818 + * @summary Stress test Thread.getStackTrace on a virtual thread that is pinned + * @requires vm.debug != true + * @modules java.base/java.lang:+open + * @library /test/lib + * @run main/othervm GetStackTraceALotWhenPinned 500000 + */ + +/* + * @test + * @requires vm.debug == true + * @modules java.base/java.lang:+open + * @library /test/lib + * @run main/othervm/timeout=300 GetStackTraceALotWhenPinned 200000 + */ + +import java.time.Instant; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.locks.LockSupport; +import jdk.test.lib.thread.VThreadRunner; + +public class GetStackTraceALotWhenPinned { + + public static void main(String[] args) throws Exception { + // need at least two carrier threads when main thread is a virtual thread + if (Thread.currentThread().isVirtual()) { + VThreadRunner.ensureParallelism(2); + } + + int iterations = Integer.parseInt(args[0]); + var barrier = new Barrier(2); + + // Start a virtual thread that loops doing Thread.yield and parking while pinned. + // This loop creates the conditions for the main thread to sample the stack trace + // as it transitions from being unmounted to parking while pinned. + var thread = Thread.startVirtualThread(() -> { + boolean timed = false; + for (int i = 0; i < iterations; i++) { + // wait for main thread to arrive + barrier.await(); + + Thread.yield(); + synchronized (GetStackTraceALotWhenPinned.class) { + if (timed) { + LockSupport.parkNanos(Long.MAX_VALUE); + } else { + LockSupport.park(); + } + } + timed = !timed; + } + }); + + long lastTimestamp = System.currentTimeMillis(); + for (int i = 0; i < iterations; i++) { + // wait for virtual thread to arrive + barrier.await(); + + thread.getStackTrace(); + LockSupport.unpark(thread); + + long currentTime = System.currentTimeMillis(); + if ((currentTime - lastTimestamp) > 500) { + System.out.format("%s %d remaining ...%n", Instant.now(), (iterations - i)); + lastTimestamp = currentTime; + } + } + } + + /** + * Alow threads wait for each other to reach a common barrier point. This class does + * not park threads that are waiting for the barrier to trip, instead it spins. This + * makes it suitable for tests that use LockSupport.park or Thread.yield. + */ + private static class Barrier { + private final int parties; + private final AtomicInteger count; + private volatile int generation; + + Barrier(int parties) { + this.parties = parties; + this.count = new AtomicInteger(parties); + } + + void await() { + int g = generation; + if (count.decrementAndGet() == 0) { + count.set(parties); + generation = g + 1; + } else { + while (generation == g) { + Thread.onSpinWait(); + } + } + } + + } +} diff --git a/test/jdk/java/net/HttpURLConnection/HttpURLConnectionExpectContinueTest.java b/test/jdk/java/net/HttpURLConnection/HttpURLConnectionExpectContinueTest.java index b21a47ed1be..c9b8bc85b70 100644 --- a/test/jdk/java/net/HttpURLConnection/HttpURLConnectionExpectContinueTest.java +++ b/test/jdk/java/net/HttpURLConnection/HttpURLConnectionExpectContinueTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, 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 @@ -431,7 +431,6 @@ private HttpURLConnection createConnection() throws Exception { HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setDoOutput(true); - connection.setConnectTimeout(1000); connection.setReadTimeout(5000); connection.setUseCaches(false); connection.setInstanceFollowRedirects(false); diff --git a/test/jdk/java/nio/channels/DatagramChannel/InterruptibleOrNot.java b/test/jdk/java/nio/channels/DatagramChannel/InterruptibleOrNot.java index 7d369d7ddd9..794ede84a92 100644 --- a/test/jdk/java/nio/channels/DatagramChannel/InterruptibleOrNot.java +++ b/test/jdk/java/nio/channels/DatagramChannel/InterruptibleOrNot.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,7 @@ * @test * @bug 8236246 * @modules java.base/sun.nio.ch - * @run testng InterruptibleOrNot + * @run junit InterruptibleOrNot * @summary Test SelectorProviderImpl.openDatagramChannel(boolean) to create * DatagramChannel objects that optionally support interrupt */ @@ -40,152 +40,178 @@ import java.nio.channels.ClosedByInterruptException; import java.nio.channels.DatagramChannel; import java.time.Duration; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; +import java.util.Arrays; import sun.nio.ch.DefaultSelectorProvider; -import org.testng.annotations.Test; -import static org.testng.Assert.*; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.function.Executable; +import static org.junit.jupiter.api.Assertions.*; -@Test public class InterruptibleOrNot { + // DatagramChannel implementation class + private static String dcImplClassName; - public void testInterruptBeforeInterruptibleReceive() throws Exception { - testInterruptBeforeReceive(true); - } - - public void testInterruptDuringInterruptibleReceive() throws Exception { - testInterruptDuringReceive(true); - } - - public void testInterruptBeforeUninterruptibleReceive() throws Exception { - testInterruptBeforeReceive(false); - } - - public void testInterruptDuringUninterruptibleReceive() throws Exception { - testInterruptDuringReceive(false); - } - - public void testInterruptBeforeInterruptibleSend() throws Exception { - testInterruptBeforeSend(true); + @BeforeAll + static void setup() throws Exception { + try (DatagramChannel dc = boundDatagramChannel(true)) { + dcImplClassName = dc.getClass().getName(); + } } - public void testInterruptBeforeUninterruptibleSend() throws Exception { - testInterruptBeforeSend(false); + /** + * Call DatagramChannel.receive with the interrupt status set, the DatagramChannel + * is interruptible. + */ + @Test + public void testInterruptBeforeInterruptibleReceive() throws Exception { + try (DatagramChannel dc = boundDatagramChannel(true)) { + ByteBuffer buf = ByteBuffer.allocate(100); + Thread.currentThread().interrupt(); + assertThrows(ClosedByInterruptException.class, () -> dc.receive(buf)); + assertFalse(dc.isOpen()); + } finally { + Thread.interrupted(); // clear interrupt status + } } /** - * Test invoking DatagramChannel receive with interrupt status set + * Test interrupting a thread blocked in DatagramChannel.receive, the DatagramChannel + * is interruptible. */ - static void testInterruptBeforeReceive(boolean interruptible) - throws Exception - { - try (DatagramChannel dc = openDatagramChannel(interruptible)) { - dc.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0)); - Future timeout = scheduleClose(dc, Duration.ofSeconds(2)); - try { - ByteBuffer buf = ByteBuffer.allocate(100); - Thread.currentThread().interrupt(); - assertThrows(expectedException(interruptible), () -> dc.receive(buf)); - } finally { - timeout.cancel(false); - } + @Test + public void testInterruptDuringInterruptibleReceive() throws Exception { + try (DatagramChannel dc = boundDatagramChannel(true)) { + ByteBuffer buf = ByteBuffer.allocate(100); + Thread thread = Thread.currentThread(); + onReceive(thread::interrupt); + assertThrows(ClosedByInterruptException.class, () -> dc.receive(buf)); + assertFalse(dc.isOpen()); } finally { - Thread.interrupted(); // clear interrupt + Thread.interrupted(); // clear interrupt status } } /** - * Test Thread.interrupt when target thread is blocked in DatagramChannel receive + * Call DatagramChannel.receive with the interrupt status set, the DatagramChannel + * is not interruptible. */ - static void testInterruptDuringReceive(boolean interruptible) - throws Exception - { - try (DatagramChannel dc = openDatagramChannel(interruptible)) { - dc.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0)); - Future timerTask = scheduleClose(dc, Duration.ofSeconds(5)); - Future interruptTask = scheduleInterrupt(Thread.currentThread(), Duration.ofSeconds(1)); - try { - ByteBuffer buf = ByteBuffer.allocate(100); - assertThrows(expectedException(interruptible), () -> dc.receive(buf)); - } finally { - timerTask.cancel(false); - interruptTask.cancel(false); - } + @Test + public void testInterruptBeforeUninterruptibleReceive() throws Exception { + try (DatagramChannel dc = boundDatagramChannel(false)) { + ByteBuffer buf = ByteBuffer.allocate(100); + onReceive(() -> { + // close the channel after a delay to ensure receive wakes up + Thread.sleep(1000); + dc.close(); + }); + Thread.currentThread().interrupt(); + assertThrows(AsynchronousCloseException.class, () -> dc.receive(buf)); + assertFalse(dc.isOpen()); } finally { - Thread.interrupted(); // clear interrupt + Thread.interrupted(); // clear interrupt status } } /** - * Test invoking DatagramChannel send with interrupt status set + * Test interrupting a thread blocked in DatagramChannel.receive, the DatagramChannel + * is not interruptible. */ - static void testInterruptBeforeSend(boolean interruptible) - throws Exception - { - try (DatagramChannel dc = openDatagramChannel(interruptible)) { - dc.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0)); - Future timeout = scheduleClose(dc, Duration.ofSeconds(2)); - try { - ByteBuffer buf = ByteBuffer.allocate(100); - SocketAddress target = dc.getLocalAddress(); - Thread.currentThread().interrupt(); - if (interruptible) { - assertThrows(ClosedByInterruptException.class, () -> dc.send(buf, target)); - } else { - int n = dc.send(buf, target); - assertTrue(n == 100); - } - } finally { - timeout.cancel(false); - } + @Test + public void testInterruptDuringUninterruptibleReceive() throws Exception { + try (DatagramChannel dc = boundDatagramChannel(true)) { + ByteBuffer buf = ByteBuffer.allocate(100); + + Thread thread = Thread.currentThread(); + onReceive(() -> { + // interrupt should not cause the receive to wakeup + thread.interrupt(); + + // close the channel after a delay to ensure receive wakes up + Thread.sleep(1000); + dc.close(); + }); + assertThrows(AsynchronousCloseException.class, () -> dc.receive(buf)); + assertFalse(dc.isOpen()); } finally { - Thread.interrupted(); // clear interrupt + Thread.interrupted(); // clear interrupt status } } /** - * Creates a DatagramChannel that is interruptible or not. + * Call DatagramChannel.send with the interrupt status set, the DatagramChannel + * is interruptible. */ - static DatagramChannel openDatagramChannel(boolean interruptible) throws IOException { - if (interruptible) { - return DatagramChannel.open(); - } else { - return DefaultSelectorProvider.get().openUninterruptibleDatagramChannel(); + @Test + public void testInterruptBeforeInterruptibleSend() throws Exception { + try (DatagramChannel dc = boundDatagramChannel(true)) { + ByteBuffer buf = ByteBuffer.allocate(100); + SocketAddress target = dc.getLocalAddress(); + Thread.currentThread().interrupt(); + assertThrows(ClosedByInterruptException.class, () -> dc.send(buf, target)); + assertFalse(dc.isOpen()); + } finally { + Thread.interrupted(); // clear interrupt } } /** - * Expect ClosedByInterruptException if interruptible. + * Call DatagramChannel.send with the interrupt status set, the DatagramChannel + * is not interruptible. */ - static Class expectedException(boolean expectInterrupt) { - if (expectInterrupt) { - return ClosedByInterruptException.class; - } else { - return AsynchronousCloseException.class; + @Test + public void testInterruptBeforeUninterruptibleSend() throws Exception { + try (DatagramChannel dc = boundDatagramChannel(false)) { + ByteBuffer buf = ByteBuffer.allocate(100); + SocketAddress target = dc.getLocalAddress(); + Thread.currentThread().interrupt(); + int n = dc.send(buf, target); + assertEquals(100, n); + assertTrue(dc.isOpen()); + } finally { + Thread.interrupted(); // clear interrupt status } } /** - * Schedule the given object to be closed. + * Creates a DatagramChannel that is interruptible or not, and bound to the loopback + * address. */ - static Future scheduleClose(Closeable c, Duration timeout) { - long nanos = TimeUnit.NANOSECONDS.convert(timeout); - return STPE.schedule(() -> { - c.close(); - return null; - }, nanos, TimeUnit.NANOSECONDS); + static DatagramChannel boundDatagramChannel(boolean interruptible) throws IOException { + DatagramChannel dc; + if (interruptible) { + dc = DatagramChannel.open(); + } else { + dc = DefaultSelectorProvider.get().openUninterruptibleDatagramChannel(); + } + try { + dc.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0)); + } catch (IOException ioe) { + dc.close(); + throw ioe; + } + return dc; } /** - * Schedule the given thread to be interrupted. + * Runs the given action when the current thread is sampled in DatagramChannel.receive. */ - static Future scheduleInterrupt(Thread t, Duration timeout) { - long nanos = TimeUnit.NANOSECONDS.convert(timeout); - return STPE.schedule(t::interrupt, nanos, TimeUnit.NANOSECONDS); + static void onReceive(Executable action) { + Thread target = Thread.currentThread(); + Thread.ofPlatform().daemon().start(() -> { + try { + boolean found = false; + while (!found) { + Thread.sleep(20); + StackTraceElement[] stack = target.getStackTrace(); + found = Arrays.stream(stack) + .anyMatch(e -> dcImplClassName.equals(e.getClassName()) + && "receive".equals(e.getMethodName())); + } + action.execute(); + } catch (Throwable ex) { + ex.printStackTrace(); + } + }); } - - static final ScheduledExecutorService STPE = Executors.newScheduledThreadPool(0); } diff --git a/test/jdk/java/nio/file/Files/ReadWriteString.java b/test/jdk/java/nio/file/Files/ReadWriteString.java index 885cbb771dc..8b5241fa1cf 100644 --- a/test/jdk/java/nio/file/Files/ReadWriteString.java +++ b/test/jdk/java/nio/file/Files/ReadWriteString.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,8 +29,13 @@ import java.nio.charset.UnmappableCharacterException; import static java.nio.charset.StandardCharsets.ISO_8859_1; import static java.nio.charset.StandardCharsets.US_ASCII; -import static java.nio.charset.StandardCharsets.UTF_16; import static java.nio.charset.StandardCharsets.UTF_8; +import static java.nio.charset.StandardCharsets.UTF_16; +import static java.nio.charset.StandardCharsets.UTF_16BE; +import static java.nio.charset.StandardCharsets.UTF_16LE; +import static java.nio.charset.StandardCharsets.UTF_32; +import static java.nio.charset.StandardCharsets.UTF_32BE; +import static java.nio.charset.StandardCharsets.UTF_32LE; import java.nio.file.Files; import java.nio.file.OpenOption; import java.nio.file.Path; @@ -40,15 +45,15 @@ import java.util.Arrays; import java.util.Random; import java.util.concurrent.Callable; +import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertTrue; import static org.testng.Assert.fail; -import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; /* @test - * @bug 8201276 8205058 8209576 8287541 8288589 + * @bug 8201276 8205058 8209576 8287541 8288589 8325590 * @build ReadWriteString PassThroughFileSystem * @run testng ReadWriteString * @summary Unit test for methods for Files readString and write methods. @@ -61,6 +66,7 @@ public class ReadWriteString { // data for text files final String TEXT_UNICODE = "\u201CHello\u201D"; final String TEXT_ASCII = "ABCDEFGHIJKLMNOPQRSTUVWXYZ\n abcdefghijklmnopqrstuvwxyz\n 1234567890\n"; + final static String TEXT_PERSON_CART_WHEELING = "\ud83e\udd38"; private static final String JA_STRING = "\u65e5\u672c\u8a9e\u6587\u5b57\u5217"; private static final Charset WINDOWS_1252 = Charset.forName("windows-1252"); private static final Charset WINDOWS_31J = Charset.forName("windows-31j"); @@ -154,7 +160,16 @@ public Object[][] getReadString() { {testFiles[1], TEXT_ASCII, US_ASCII, US_ASCII}, {testFiles[1], TEXT_ASCII, US_ASCII, UTF_8}, {testFiles[1], TEXT_UNICODE, UTF_8, null}, - {testFiles[1], TEXT_UNICODE, UTF_8, UTF_8} + {testFiles[1], TEXT_UNICODE, UTF_8, UTF_8}, + {testFiles[1], TEXT_ASCII, US_ASCII, ISO_8859_1}, + {testFiles[1], TEXT_PERSON_CART_WHEELING, UTF_16, UTF_16}, + {testFiles[1], TEXT_PERSON_CART_WHEELING, UTF_16BE, UTF_16BE}, + {testFiles[1], TEXT_PERSON_CART_WHEELING, UTF_16LE, UTF_16LE}, + {testFiles[1], TEXT_PERSON_CART_WHEELING, UTF_32, UTF_32}, + {testFiles[1], TEXT_PERSON_CART_WHEELING, UTF_32BE, UTF_32BE}, + {testFiles[1], TEXT_PERSON_CART_WHEELING, UTF_32LE, UTF_32LE}, + {testFiles[1], TEXT_PERSON_CART_WHEELING, WINDOWS_1252, WINDOWS_1252}, + {testFiles[1], TEXT_PERSON_CART_WHEELING, WINDOWS_31J, WINDOWS_31J} }; } @@ -304,6 +319,21 @@ public void testMalformedReadBytes(byte[] data, Charset csRead, Class c) { try { c.call(); diff --git a/test/jdk/java/security/cert/CertPathBuilder/akiExt/AKISerialNumber.java b/test/jdk/java/security/cert/CertPathBuilder/akiExt/AKISerialNumber.java index e8ab65d78dd..53db87cfe63 100644 --- a/test/jdk/java/security/cert/CertPathBuilder/akiExt/AKISerialNumber.java +++ b/test/jdk/java/security/cert/CertPathBuilder/akiExt/AKISerialNumber.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2024, 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 @@ -118,6 +118,8 @@ public static void main(String[] args) throws Exception { PKIXBuilderParameters params = new PKIXBuilderParameters (Collections.singleton(anchor), sel); params.setRevocationEnabled(false); + // Set date to 2024-01-01 to satisfy cert constraints + params.setDate(new java.util.Date(1704067200000l)); ArrayList certs = new ArrayList<>(); certs.add(intCert); diff --git a/test/jdk/java/time/test/java/time/format/TestUTCParse.java b/test/jdk/java/time/test/java/time/format/TestUTCParse.java index 6da94f04f04..c1766b47030 100644 --- a/test/jdk/java/time/test/java/time/format/TestUTCParse.java +++ b/test/jdk/java/time/test/java/time/format/TestUTCParse.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, 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 * @modules jdk.localedata - * @bug 8303440 8317979 + * @bug 8303440 8317979 8322647 * @summary Test parsing "UTC-XX:XX" text works correctly */ package test.java.time.format; @@ -43,8 +43,8 @@ public class TestUTCParse { static { - // Assuming CLDR's SHORT name for "America/Juneau" - // produces "UTC\u212209:00" + // Assuming CLDR's SHORT name for "America/Manaus" + // produces "UTC\u221204:00" System.setProperty("java.locale.providers", "CLDR"); } @@ -60,9 +60,9 @@ public Object[][] utcZoneIdStrings() { @Test public void testUTCShortNameRoundTrip() { var fmt = DateTimeFormatter.ofPattern("z", Locale.FRANCE); - var zdt = ZonedDateTime.of(2023, 3, 3, 0, 0, 0, 0, ZoneId.of("America/Juneau")); + var zdt = ZonedDateTime.of(2023, 3, 3, 0, 0, 0, 0, ZoneId.of("America/Manaus")); var formatted = fmt.format(zdt); - assertEquals(formatted, "UTC\u221209:00"); + assertEquals(formatted, "UTC\u221204:00"); assertEquals(fmt.parse(formatted).query(TemporalQueries.zoneId()), zdt.getZone()); } diff --git a/test/jdk/java/util/Currency/ValidateISO4217.java b/test/jdk/java/util/Currency/ValidateISO4217.java index c4fdc5ca2e0..53788c899b3 100644 --- a/test/jdk/java/util/Currency/ValidateISO4217.java +++ b/test/jdk/java/util/Currency/ValidateISO4217.java @@ -25,7 +25,7 @@ * @test * @bug 4691089 4819436 4942982 5104960 6544471 6627549 7066203 7195759 * 8039317 8074350 8074351 8145952 8187946 8193552 8202026 8204269 - * 8208746 8209775 8264792 8274658 8283277 8296239 + * 8208746 8209775 8264792 8274658 8283277 8296239 8321480 * @summary Validate ISO 4217 data for Currency class. * @modules java.base/java.util:open * jdk.localedata @@ -86,7 +86,7 @@ public class ValidateISO4217 { // Codes that are obsolete, do not have related country, extra currency private static final String otherCodes = "ADP-AFA-ATS-AYM-AZM-BEF-BGL-BOV-BYB-BYR-CHE-CHW-CLF-COU-CUC-CYP-" - + "DEM-EEK-ESP-FIM-FRF-GHC-GRD-GWP-IEP-ITL-LTL-LUF-LVL-MGF-MRO-MTL-MXV-MZM-NLG-" + + "DEM-EEK-ESP-FIM-FRF-GHC-GRD-GWP-HRK-IEP-ITL-LTL-LUF-LVL-MGF-MRO-MTL-MXV-MZM-NLG-" + "PTE-ROL-RUR-SDD-SIT-SLL-SKK-SRG-STD-TMM-TPE-TRL-VEF-UYI-USN-USS-VEB-VED-" + "XAG-XAU-XBA-XBB-XBC-XBD-XDR-XFO-XFU-XPD-XPT-XSU-XTS-XUA-XXX-" + "YUM-ZMK-ZWD-ZWN-ZWR"; @@ -168,7 +168,7 @@ private static void processColumns(StringTokenizer tokens, String country) throw if (format == null) { createDateFormat(); } - // If the cut-over already passed, test the changed data too + // If the cut-over already passed, use the new curency for ISO4217Codes if (format.parse(tokens.nextToken()).getTime() < System.currentTimeMillis()) { currency = tokens.nextToken(); numeric = tokens.nextToken(); @@ -267,20 +267,21 @@ private static List additionalCodesProvider() { * throws an IllegalArgumentException or returns null. The test data * supplied is every possible combination of AA -> ZZ. */ - @ParameterizedTest - @MethodSource("codeCombos") - public void twoLetterCodesTest(String country) { - if (codes[toIndex(country)] == UNDEFINED) { - // if a code is undefined / 0, creating a Currency from it - // should throw an IllegalArgumentException - assertThrows(IllegalArgumentException.class, - ()-> Currency.getInstance(Locale.of("", country)), - "Error: This should be an undefined code and throw IllegalArgumentException: " + country); - } else if (codes[toIndex(country)] == SKIPPED) { - // if a code is marked as skipped / 2, creating a Currency from it - // should return null - assertNull(Currency.getInstance(Locale.of("", country)), - "Error: Currency.getInstance() for this locale should return null: " + country); + @Test + public void twoLetterCodesTest() { + for (String country : codeCombos()) { + if (codes[toIndex(country)] == UNDEFINED) { + // if a code is undefined / 0, creating a Currency from it + // should throw an IllegalArgumentException + assertThrows(IllegalArgumentException.class, + () -> Currency.getInstance(Locale.of("", country)), + "Error: This should be an undefined code and throw IllegalArgumentException: " + country); + } else if (codes[toIndex(country)] == SKIPPED) { + // if a code is marked as skipped / 2, creating a Currency from it + // should return null + assertNull(Currency.getInstance(Locale.of("", country)), + "Error: Currency.getInstance() for this locale should return null: " + country); + } } } diff --git a/test/jdk/java/util/Currency/tablea1.txt b/test/jdk/java/util/Currency/tablea1.txt index 4e33a62c05e..6e85de5e6d2 100644 --- a/test/jdk/java/util/Currency/tablea1.txt +++ b/test/jdk/java/util/Currency/tablea1.txt @@ -1,12 +1,12 @@ # # -# Amendments up until ISO 4217 AMENDMENT NUMBER 175 -# (As of 31 March 2023) +# Amendments up until ISO 4217 AMENDMENT NUMBER 176 +# (As of 06 December 2023) # # Version FILEVERSION=3 -DATAVERSION=175 +DATAVERSION=176 # ISO 4217 currency data AF AFN 971 2 @@ -67,9 +67,9 @@ CD CDF 976 2 CK NZD 554 2 CR CRC 188 2 CI XOF 952 0 -HR HRK 191 2 2022-12-31-23-00-00 EUR 978 2 +HR EUR 978 2 CU CUP 192 2 -CW ANG 532 2 +CW ANG 532 2 2025-04-01-04-00-00 XCG 532 2 CY EUR 978 2 CZ CZK 203 2 DK DKK 208 2 @@ -233,7 +233,7 @@ LK LKR 144 2 SD SDG 938 2 SR SRD 968 2 SJ NOK 578 2 -SX ANG 532 2 +SX ANG 532 2 2025-04-01-04-00-00 XCG 532 2 SZ SZL 748 2 SE SEK 752 2 CH CHF 756 2 diff --git a/test/jdk/java/util/Locale/LocaleProviders.java b/test/jdk/java/util/Locale/LocaleProviders.java index c4acb0689b1..556409fb650 100644 --- a/test/jdk/java/util/Locale/LocaleProviders.java +++ b/test/jdk/java/util/Locale/LocaleProviders.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2024, 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 @@ -35,6 +35,10 @@ import java.util.logging.StreamHandler; import java.util.spi.*; import java.util.stream.IntStream; +import java.util.stream.Stream; + +import jdk.test.lib.Utils; +import jdk.test.lib.process.ProcessTools; import sun.util.locale.provider.LocaleProviderAdapter; import static java.util.logging.LogManager.*; @@ -447,7 +451,8 @@ static void bug8248695Test() { } } - // Run only if the platform locale is en-GB + // Run only if the underlying platform locale is en-GB + // (Setting the java locale via command line properties does not substitute this) static void bug8257964Test() { var defLoc = Locale.getDefault(Locale.Category.FORMAT); var type = LocaleProviderAdapter.getAdapter(CalendarNameProvider.class, Locale.UK) @@ -476,4 +481,30 @@ static void bug8257964Test() { "provider is not HOST: " + type); } } + + /* Method is used by the LocaleProviders* related tests to launch a + * LocaleProviders test method with the appropriate LocaleProvider (e.g. CLDR, + * COMPAT, ETC.) + */ + static void test(String prefList, String methodName, String... params) throws Throwable { + + List command = List.of( + "-ea", "-esa", + "-cp", Utils.TEST_CLASS_PATH, + // Required for LocaleProvidersLogger + "-Djava.util.logging.config.class=LocaleProviders$LogConfig", + "-Djava.locale.providers=" + prefList, + "--add-exports=java.base/sun.util.locale.provider=ALL-UNNAMED", + "LocaleProviders", methodName); + + // Build process with arguments, if required by the method + ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder( + Stream.concat(command.stream(), Stream.of(params)).toList()); + + // Evaluate process status + int exitCode = ProcessTools.executeCommand(pb).getExitValue(); + if (exitCode != 0) { + throw new RuntimeException("Unexpected exit code: " + exitCode); + } + } } diff --git a/test/jdk/java/util/Locale/LocaleProvidersCalendar.java b/test/jdk/java/util/Locale/LocaleProvidersCalendar.java new file mode 100644 index 00000000000..93d11da772b --- /dev/null +++ b/test/jdk/java/util/Locale/LocaleProvidersCalendar.java @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2012, 2024, 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 8228465 8232871 8257964 + * @summary Test any Calendar Locale provider related issues + * @library /test/lib + * @build LocaleProviders + * @modules java.base/sun.util.locale.provider + * @run junit/othervm LocaleProvidersCalendar + */ + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.EnabledOnOs; +import org.junit.jupiter.api.condition.EnabledIfSystemProperty; + +import static org.junit.jupiter.api.condition.OS.MAC; +import static org.junit.jupiter.api.condition.OS.WINDOWS; + +public class LocaleProvidersCalendar { + + /* + * 8228465 (Windows only): Ensure correct ERA display name under HOST Windows + */ + @Test + @EnabledOnOs(WINDOWS) + public void gregCalEraHost() throws Throwable { + LocaleProviders.test("HOST", "bug8228465Test"); + } + + /* + * 8232871 (macOS only): Ensure correct Japanese calendar values under + * HOST Mac. + */ + @Test + @EnabledOnOs(MAC) + public void japaneseCalValuesHost() throws Throwable { + LocaleProviders.test("HOST", "bug8232871Test"); + } + + /* + * 8257964 (macOS/Windows only): Ensure correct Calendar::getMinimalDaysInFirstWeek + * value under HOST Windows / Mac. Only run against machine with underlying + * OS locale of en-GB. + */ + @Test + @EnabledOnOs({WINDOWS, MAC}) + @EnabledIfSystemProperty(named = "user.language", matches = "en") + @EnabledIfSystemProperty(named = "user.country", matches = "GB") + public void minDaysFirstWeekHost() throws Throwable { + LocaleProviders.test("HOST", "bug8257964Test"); + } +} diff --git a/test/jdk/java/util/Locale/LocaleProvidersDateTimeFormatter.java b/test/jdk/java/util/Locale/LocaleProvidersDateTimeFormatter.java new file mode 100644 index 00000000000..e304dc73fac --- /dev/null +++ b/test/jdk/java/util/Locale/LocaleProvidersDateTimeFormatter.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2012, 2024, 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 8248695 + * @summary Test any java.time.DateTimeFormatter Locale provider related issues + * @library /test/lib + * @build LocaleProviders + * @modules java.base/sun.util.locale.provider + * @run junit/othervm LocaleProvidersDateTimeFormatter + */ + +import org.junit.jupiter.api.Test; + +public class LocaleProvidersDateTimeFormatter { + + /* + * 8248695: Ensure DateTimeFormatter::ofLocalizedDate does not throw exception + * under HOST (date only pattern leaks time field) + */ + @Test + public void dateOnlyJavaTimePattern() throws Throwable { + LocaleProviders.test("HOST", "bug8248695Test"); + } +} diff --git a/test/jdk/java/util/Locale/LocaleProvidersFormat.java b/test/jdk/java/util/Locale/LocaleProvidersFormat.java new file mode 100644 index 00000000000..0584b82b318 --- /dev/null +++ b/test/jdk/java/util/Locale/LocaleProvidersFormat.java @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2012, 2024, 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 7198834 8001440 8013086 8013903 8027289 8232860 + * @summary Test any java.text.Format Locale provider related issues + * @library /test/lib + * @build LocaleProviders + * providersrc.spi.src.tznp + * providersrc.spi.src.tznp8013086 + * @modules java.base/sun.util.locale.provider + * @run junit/othervm LocaleProvidersFormat + */ + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.EnabledIfSystemProperty; +import org.junit.jupiter.api.condition.EnabledOnOs; + +import static org.junit.jupiter.api.condition.OS.MAC; +import static org.junit.jupiter.api.condition.OS.WINDOWS; + +public class LocaleProvidersFormat { + + /* + * 7198834: Ensure under Windows/HOST, adapter does not append an extra space for date patterns. + */ + @Test + @EnabledOnOs(WINDOWS) + public void dateFormatExtraSpace() throws Throwable { + LocaleProviders.test("HOST", "bug7198834Test"); + } + + /* + * 8001440: Ensure under CLDR, when number extension of the language + * tag is invalid, test program does not throw exception when calling + * NumberFormat::format. + */ + @Test + public void formatWithInvalidLocaleExtension() throws Throwable { + LocaleProviders.test("CLDR", "bug8001440Test"); + } + + /* + * 8013086: Ensure a custom TimeZoneNameProvider does not cause an NPE + * in simpleDateFormat, as SimpleDateFormat::matchZoneString expects the + * name array is fully filled with non-null names. + */ + @Test + public void simpleDateFormatWithTZNProvider() throws Throwable { + LocaleProviders.test("JRE,SPI", "bug8013086Test", "ja", "JP"); + LocaleProviders.test("COMPAT,SPI", "bug8013086Test", "ja", "JP"); + } + + /* + * 8013903 (Windows only): Ensure HOST adapter with Japanese locale produces + * the correct Japanese era, month, day names. + */ + @Test + @EnabledOnOs(WINDOWS) + public void windowsJapaneseDateFields() throws Throwable { + LocaleProviders.test("HOST,JRE", "bug8013903Test"); + LocaleProviders.test("HOST", "bug8013903Test"); + LocaleProviders.test("HOST,COMPAT", "bug8013903Test"); + } + + /* + * 8027289: Ensure if underlying system format locale is zh_CN, the Window's currency + * symbol under HOST provider is \u00A5, the yen (yuan) sign. + */ + @Test + @EnabledOnOs(WINDOWS) + @EnabledIfSystemProperty(named = "user.language", matches = "zh") + @EnabledIfSystemProperty(named = "user.country", matches = "CN") + public void windowsChineseCurrencySymbol() throws Throwable { + LocaleProviders.test("JRE,HOST", "bug8027289Test", "FFE5"); + LocaleProviders.test("COMPAT,HOST", "bug8027289Test", "FFE5"); + LocaleProviders.test("HOST", "bug8027289Test", "00A5"); + } + + /* + * 8232860 (macOS/Windows only): Ensure the Host adapter returns the number + * pattern for number/integer instances, which require optional fraction digits. + */ + @Test + @EnabledOnOs({WINDOWS, MAC}) + public void hostOptionalFracDigits() throws Throwable { + LocaleProviders.test("HOST", "bug8232860Test"); + } +} diff --git a/test/jdk/java/util/Locale/LocaleProvidersLogger.java b/test/jdk/java/util/Locale/LocaleProvidersLogger.java new file mode 100644 index 00000000000..a6e15914c3b --- /dev/null +++ b/test/jdk/java/util/Locale/LocaleProvidersLogger.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2012, 2024, 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 8245241 8246721 8261919 + * @summary Test the Locale provider preference is logged + * @library /test/lib + * @build LocaleProviders + * @modules java.base/sun.util.locale.provider + * @run junit/othervm -Djdk.lang.Process.allowAmbiguousCommands=false LocaleProvidersLogger + */ + +import org.junit.jupiter.api.Test; + +public class LocaleProvidersLogger { + + /* + * 8245241 8246721 8261919: Ensure if an incorrect system property for locale providers is set, + * it should be logged and presented to the user. The option + * jdk.lang.Process.allowAmbiguousCommands=false is needed for properly escaping + * double quotes in the string argument. + */ + @Test + public void logIncorrectLocaleProvider() throws Throwable { + LocaleProviders.test("FOO", "bug8245241Test", + "Invalid locale provider adapter \"FOO\" ignored."); + } +} diff --git a/test/jdk/java/util/Locale/LocaleProvidersRun.java b/test/jdk/java/util/Locale/LocaleProvidersRun.java index 947633a8e21..7b6e87247a0 100644 --- a/test/jdk/java/util/Locale/LocaleProvidersRun.java +++ b/test/jdk/java/util/Locale/LocaleProvidersRun.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2024, 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,175 +23,151 @@ /* * @test - * @bug 6336885 7196799 7197573 7198834 8000245 8000615 8001440 8008577 - * 8010666 8013086 8013233 8013903 8015960 8028771 8054482 8062006 - * 8150432 8215913 8220227 8228465 8232871 8232860 8236495 8245241 - * 8246721 8248695 8257964 8261919 - * @summary tests for "java.locale.providers" system property - * @requires vm.flagless + * @bug 6336885 7196799 7197573 8008577 8010666 8013233 8015960 8028771 + * 8054482 8062006 8150432 8215913 8220227 8236495 + * @summary General Locale provider test (ex: adapter loading). See the + * other LocaleProviders* test classes for more specific tests (ex: + * java.text.Format related bugs). * @library /test/lib * @build LocaleProviders - * providersrc.spi.src.tznp - * providersrc.spi.src.tznp8013086 - * @modules java.base/sun.util.locale - * java.base/sun.util.locale.provider - * @run main/othervm -Djdk.lang.Process.allowAmbiguousCommands=false LocaleProvidersRun + * @modules java.base/sun.util.locale.provider + * @run junit/othervm LocaleProvidersRun */ import java.util.Locale; +import java.util.stream.Stream; -import jdk.test.lib.process.ProcessTools; -import jdk.test.lib.Utils; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.DisabledIfSystemProperty; +import org.junit.jupiter.api.condition.EnabledIfSystemProperty; +import org.junit.jupiter.api.condition.EnabledOnOs; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import static org.junit.jupiter.api.condition.OS.WINDOWS; + +/* + * Note: If this test launches too many JVMs, consider increasing timeout. + * As the LocaleProvider is set during java startup time, this test and the subclasses + * will always have to launch a separate JVM for testing of different providers. + */ public class LocaleProvidersRun { - public static void main(String[] args) throws Throwable { - //get the platform default locales - Locale platDefLoc = Locale.getDefault(Locale.Category.DISPLAY); - String defLang = platDefLoc.getLanguage(); - String defCtry = platDefLoc.getCountry(); - System.out.println("DEFLANG = " + defLang); - System.out.println("DEFCTRY = " + defCtry); + private static String defLang; + private static String defCtry; + private static String defFmtLang; + private static String defFmtCtry; + + // Get the system default locale values. Used to decide param values for tests. + @BeforeAll + static void setUp() { + Locale platDefLoc = Locale.getDefault(Locale.Category.DISPLAY); Locale platDefFormat = Locale.getDefault(Locale.Category.FORMAT); - String defFmtLang = platDefFormat.getLanguage(); - String defFmtCtry = platDefFormat.getCountry(); - System.out.println("DEFFMTLANG = " + defFmtLang); - System.out.println("DEFFMTCTRY = " + defFmtCtry); - - //Run Test - //testing HOST is selected for the default locale, - // if specified on Windows or MacOSX + defLang = platDefLoc.getLanguage(); + defCtry = platDefLoc.getCountry(); + defFmtLang = platDefFormat.getLanguage(); + defFmtCtry = platDefFormat.getCountry(); + + // Print out system defaults for diagnostic purposes + System.out.printf("DEFLANG = %s, DEFCTRY = %s, DEFFMTLANG = %s, DEFFMTCTRY = %s", + defLang, defCtry, defFmtLang, defFmtCtry); + } + + /* + * Test the adapter loading logic in LocaleProviderAdapter. + * Ensures that correct fallbacks are implemented. + */ + @ParameterizedTest + @MethodSource + public void adapterTest(String prefList, String param1, + String param2, String param3) throws Throwable { + LocaleProviders.test(prefList, "adapterTest", param1, param2, param3); + } + + /* + * Data provider which only launches against the LocaleProvider::adapterTest + * method. The arguments are dictated based off the operating system/platform + * Locale. Tests against variety of provider orders. + */ + private static Stream adapterTest() { + // Testing HOST is selected for the default locale if specified on Windows or MacOSX String osName = System.getProperty("os.name"); String param1 = "JRE"; - if(osName.startsWith("Windows") || osName.startsWith("Mac")) { + if (osName.startsWith("Windows") || osName.startsWith("Mac")) { param1 = "HOST"; } - testRun("HOST,JRE", "adapterTest", param1, defLang, defCtry); - //testing HOST is NOT selected for the non-default locale, if specified - //Try to find the locale JRE supports which is not the platform default + // Testing HOST is NOT selected for the non-default locale, if specified + // try to find the locale JRE supports which is not the platform default // (HOST supports that one) String param2; String param3; - if (!defLang.equals("en") && !defFmtLang.equals("en")){ + if (!defLang.equals("en") && !defFmtLang.equals("en")) { param2 = "en"; param3 = "US"; - } else if(!defLang.equals("ja") && !defFmtLang.equals("ja")){ + } else if (!defLang.equals("ja") && !defFmtLang.equals("ja")) { param2 = "ja"; param3 = "JP"; } else { param2 = "zh"; param3 = "CN"; } - testRun("HOST,JRE", "adapterTest", "JRE", param2, param3); - - //testing SPI is NOT selected, as there is none. - testRun("SPI,JRE", "adapterTest", "JRE", "en", "US"); - testRun("SPI,COMPAT", "adapterTest", "JRE", "en", "US"); - - //testing the order, variant #1. This assumes en_GB DateFormat data are - // available both in JRE & CLDR - testRun("CLDR,JRE", "adapterTest", "CLDR", "en", "GB"); - testRun("CLDR,COMPAT", "adapterTest", "CLDR", "en", "GB"); - - //testing the order, variant #2. This assumes en_GB DateFormat data are - // available both in JRE & CLDR - testRun("JRE,CLDR", "adapterTest", "JRE", "en", "GB"); - testRun("COMPAT,CLDR", "adapterTest", "JRE", "en", "GB"); - - //testing the order, variant #3 for non-existent locale in JRE - // assuming "haw" is not in JRE. - testRun("JRE,CLDR", "adapterTest", "CLDR", "haw", ""); - testRun("COMPAT,CLDR", "adapterTest", "CLDR", "haw", ""); - - //testing the order, variant #4 for the bug 7196799. CLDR's "zh" data - // should be used in "zh_CN" - testRun("CLDR", "adapterTest", "CLDR", "zh", "CN"); - - //testing FALLBACK provider. SPI and invalid one cases. - testRun("SPI", "adapterTest", "FALLBACK", "en", "US"); - testRun("FOO", "adapterTest", "CLDR", "en", "US"); - testRun("BAR,SPI", "adapterTest", "FALLBACK", "en", "US"); - - //testing 7198834 fix. - testRun("HOST", "bug7198834Test", "", "", ""); - - //testing 8000245 fix. - testRun("JRE", "tzNameTest", "Europe/Moscow", "", ""); - testRun("COMPAT", "tzNameTest", "Europe/Moscow", "", ""); - - //testing 8000615 fix. - testRun("JRE", "tzNameTest", "America/Los_Angeles", "", ""); - testRun("COMPAT", "tzNameTest", "America/Los_Angeles", "", ""); - - //testing 8001440 fix. - testRun("CLDR", "bug8001440Test", "", "", ""); - - //testing 8010666 fix. - if (defLang.equals("en")) { - testRun("HOST", "bug8010666Test", "", "", ""); - } - - //testing 8013086 fix. - testRun("JRE,SPI", "bug8013086Test", "ja", "JP", ""); - testRun("COMPAT,SPI", "bug8013086Test", "ja", "JP", ""); - - //testing 8013903 fix. (Windows only) - testRun("HOST,JRE", "bug8013903Test", "", "", ""); - testRun("HOST", "bug8013903Test", "", "", ""); - testRun("HOST,COMPAT", "bug8013903Test", "", "", ""); - - //testing 8027289 fix, if the platform format default is zh_CN - // this assumes Windows' currency symbol for zh_CN is \u00A5, the yen - // (yuan) sign. - if (defFmtLang.equals("zh") && defFmtCtry.equals("CN")) { - testRun("JRE,HOST", "bug8027289Test", "FFE5", "", ""); - testRun("COMPAT,HOST", "bug8027289Test", "FFE5", "", ""); - testRun("HOST", "bug8027289Test", "00A5", "", ""); - } - //testing 8220227 fix. (Windows only) - if (!defLang.equals("en")) { - testRun("HOST", "bug8220227Test", "", "", ""); - } - - //testing 8228465 fix. (Windows only) - testRun("HOST", "bug8228465Test", "", "", ""); - - //testing 8232871 fix. (macOS only) - testRun("HOST", "bug8232871Test", "", "", ""); - - //testing 8232860 fix. (macOS/Windows only) - testRun("HOST", "bug8232860Test", "", "", ""); - - //testing 8245241 fix. - //jdk.lang.Process.allowAmbiguousCommands=false is needed for properly escaping - //double quotes in the string argument. - testRun("FOO", "bug8245241Test", - "Invalid locale provider adapter \"FOO\" ignored.", "", ""); - - //testing 8248695 fix. - testRun("HOST", "bug8248695Test", "", "", ""); + return Stream.of( + Arguments.of("HOST,JRE", param1, defLang, defCtry), + Arguments.of("HOST,JRE", "JRE", param2, param3), + + // Testing SPI is NOT selected, as there is none. + Arguments.of("SPI,JRE", "JRE", "en", "US"), + Arguments.of("SPI,COMPAT", "JRE", "en", "US"), + + // Testing the order, variant #1. This assumes en_GB DateFormat data are + // available both in JRE & CLDR + Arguments.of("CLDR,JRE", "CLDR", "en", "GB"), + Arguments.of("CLDR,COMPAT", "CLDR", "en", "GB"), + + // Testing the order, variant #2. This assumes en_GB DateFormat data are + // available both in JRE & CLDR + Arguments.of("JRE,CLDR", "JRE", "en", "GB"), + Arguments.of("COMPAT,CLDR", "JRE", "en", "GB"), + + // Testing the order, variant #3 for non-existent locale in JRE + // assuming "haw" is not in JRE. + Arguments.of("JRE,CLDR", "CLDR", "haw", ""), + Arguments.of("COMPAT,CLDR", "CLDR", "haw", ""), + + // Testing the order, variant #4 for the bug 7196799. CLDR's "zh" data + // should be used in "zh_CN" + Arguments.of("CLDR", "CLDR", "zh", "CN"), + + // Testing FALLBACK provider. SPI and invalid one cases. + Arguments.of("SPI", "FALLBACK", "en", "US"), + Arguments.of("FOO", "CLDR", "en", "US"), + Arguments.of("BAR,SPI", "FALLBACK", "en", "US") + ); + } - //testing 8257964 fix. (macOS/Windows only) - testRun("HOST", "bug8257964Test", "", "", ""); + /* + * 8010666: Test to ensure correct implementation of Currency/LocaleNameProvider + * in HOST Windows provider (English locale) + */ + @Test + @EnabledOnOs(WINDOWS) + @EnabledIfSystemProperty(named = "user.language", matches = "en") + public void currencyNameProviderWindowsHost() throws Throwable { + LocaleProviders.test("HOST", "bug8010666Test"); } - private static void testRun(String prefList, String methodName, - String param1, String param2, String param3) throws Throwable { - - // Build process (without VM flags) - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder( - "-ea", "-esa", - "-cp", Utils.TEST_CLASS_PATH, - "-Djava.util.logging.config.class=LocaleProviders$LogConfig", - "-Djava.locale.providers=" + prefList, - "--add-exports=java.base/sun.util.locale.provider=ALL-UNNAMED", - "LocaleProviders", methodName, param1, param2, param3); - // Evaluate process status - int exitCode = ProcessTools.executeCommand(pb).getExitValue(); - if (exitCode != 0) { - throw new RuntimeException("Unexpected exit code: " + exitCode); - } + /* + * 8220227: Ensure Locale::getDisplayCountry does not display error message + * under HOST Windows (non-english locale) + */ + @Test + @EnabledOnOs(WINDOWS) + @DisabledIfSystemProperty(named = "user.language", matches = "en") + public void nonEnglishDisplayCountryHost() throws Throwable { + LocaleProviders.test("HOST", "bug8220227Test"); } } diff --git a/test/jdk/java/util/Locale/LocaleProvidersTimeZone.java b/test/jdk/java/util/Locale/LocaleProvidersTimeZone.java new file mode 100644 index 00000000000..46ab5054306 --- /dev/null +++ b/test/jdk/java/util/Locale/LocaleProvidersTimeZone.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2012, 2024, 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 8000245 8000615 + * @summary Test any TimeZone Locale provider related issues + * @library /test/lib + * @build LocaleProviders + * providersrc.spi.src.tznp + * providersrc.spi.src.tznp8013086 + * @modules java.base/sun.util.locale.provider + * @run junit/othervm LocaleProvidersTimeZone + */ + +import org.junit.jupiter.api.Test; + +public class LocaleProvidersTimeZone { + + /* + * 8000245 and 8000615: Ensure preference is followed, even with a custom + * SPI defined. + */ + @Test + public void timeZoneWithCustomProvider() throws Throwable { + LocaleProviders.test("JRE", "tzNameTest", "Europe/Moscow"); + LocaleProviders.test("COMPAT", "tzNameTest", "Europe/Moscow"); + LocaleProviders.test("JRE", "tzNameTest", "America/Los_Angeles"); + LocaleProviders.test("COMPAT", "tzNameTest", "America/Los_Angeles"); + } +} diff --git a/test/jdk/java/util/TimeZone/TimeZoneData/VERSION b/test/jdk/java/util/TimeZone/TimeZoneData/VERSION index c5483b48512..bf027918ce7 100644 --- a/test/jdk/java/util/TimeZone/TimeZoneData/VERSION +++ b/test/jdk/java/util/TimeZone/TimeZoneData/VERSION @@ -1 +1 @@ -tzdata2023c +tzdata2024a diff --git a/test/jdk/java/util/TimeZone/TimeZoneData/aliases.txt b/test/jdk/java/util/TimeZone/TimeZoneData/aliases.txt index 07c5edbafee..82bad17c553 100644 --- a/test/jdk/java/util/TimeZone/TimeZoneData/aliases.txt +++ b/test/jdk/java/util/TimeZone/TimeZoneData/aliases.txt @@ -148,7 +148,6 @@ Link America/Puerto_Rico America/Tortola Link Pacific/Port_Moresby Antarctica/DumontDUrville Link Pacific/Auckland Antarctica/McMurdo Link Asia/Riyadh Antarctica/Syowa -Link Asia/Urumqi Antarctica/Vostok Link Europe/Berlin Arctic/Longyearbyen Link Asia/Riyadh Asia/Aden Link Asia/Qatar Asia/Bahrain diff --git a/test/jdk/java/util/concurrent/LinkedTransferQueue/SubclassTest.java b/test/jdk/java/util/concurrent/LinkedTransferQueue/SubclassTest.java new file mode 100644 index 00000000000..ed9897f6291 --- /dev/null +++ b/test/jdk/java/util/concurrent/LinkedTransferQueue/SubclassTest.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2024, 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 8323659 + * @summary Ensures that the implementation of LTQ add and put methods does + * not call overridable offer. This test specifically asserts implementation + * details of LTQ. It's not that such impl details cannot change, just that + * such a change should be deliberately done with suitable consideration + * to compatibility. + * @run testng SubclassTest + */ + +import java.util.concurrent.LinkedTransferQueue; +import java.util.concurrent.TimeUnit; +import org.testng.annotations.Test; +import static org.testng.Assert.assertEquals; + +@Test +public class SubclassTest { + + public void testPut() { + var queue = new TestLinkedTransferQueue(); + queue.put(new Object()); + assertEquals(queue.size(), 1); + } + + public void testAdd() { + var queue = new TestLinkedTransferQueue(); + queue.add(new Object()); + assertEquals(queue.size(), 1); + } + + public void testTimedOffer() { + var queue = new TestLinkedTransferQueue(); + queue.offer(new Object(), 60, TimeUnit.SECONDS); + assertEquals(queue.size(), 1); + } + + static class TestLinkedTransferQueue extends LinkedTransferQueue { + @Override + public boolean offer(Object obj) { + return false; // simulate fails to add the given obj + } + } +} diff --git a/test/jdk/javax/crypto/KEM/RSA_KEM.java b/test/jdk/javax/crypto/KEM/RSA_KEM.java index c46ded77623..e666df432a6 100644 --- a/test/jdk/javax/crypto/KEM/RSA_KEM.java +++ b/test/jdk/javax/crypto/KEM/RSA_KEM.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, 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 @@ * @modules java.base/sun.security.jca * java.base/sun.security.rsa * java.base/sun.security.util + * java.base/javax.crypto:+open */ import sun.security.jca.JCAUtil; import sun.security.rsa.RSACore; @@ -88,7 +89,7 @@ public static void main(String[] args) throws Exception { KeyPair kp = g.generateKeyPair(); for (RSAKEMParameterSpec kspec : kspecs) { SecretKey cek = KeyGenerator.getInstance("AES").generateKey(); - KEM kem1 = KEM.getInstance("RSA-KEM", p); + KEM kem1 = getKemImpl(p); Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding"); c.init(Cipher.ENCRYPT_MODE, cek, new IvParameterSpec(iv)); byte[] ciphertext = c.doFinal(msg); @@ -101,7 +102,7 @@ public static void main(String[] args) throws Exception { AlgorithmParameters a = AlgorithmParameters.getInstance("RSA-KEM", p); a.init(enc.params()); - KEM kem2 = KEM.getInstance("RSA-KEM", p); + KEM kem2 = getKemImpl(p); KEM.Decapsulator d = kem2.newDecapsulator(kp.getPrivate(), a.getParameterSpec(AlgorithmParameterSpec.class)); SecretKey k = d.decapsulate(enc.encapsulation(), 0, d.secretSize(), "AES"); Cipher c3 = Cipher.getInstance(kspec.encAlg); @@ -122,6 +123,14 @@ public static void main(String[] args) throws Exception { } } + // To bypass the JCE security provider signature check + private static KEM getKemImpl(Provider p) throws Exception { + var ctor = KEM.class.getDeclaredConstructor( + String.class, KEMSpi.class, Provider.class); + ctor.setAccessible(true); + return ctor.newInstance("RSA-KEM", new KEMImpl(), p); + } + static final String RSA_KEM = "1.2.840.113549.1.9.16.3.14"; static final String KEM_RSA = "1.0.18033.2.2.4"; diff --git a/test/jdk/jdk/incubator/vector/Byte128VectorLoadStoreTests.java b/test/jdk/jdk/incubator/vector/Byte128VectorLoadStoreTests.java index 029c0ad5b0c..b95119678fb 100644 --- a/test/jdk/jdk/incubator/vector/Byte128VectorLoadStoreTests.java +++ b/test/jdk/jdk/incubator/vector/Byte128VectorLoadStoreTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, 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 @@ -248,7 +248,8 @@ static byte[] fill(byte[] a, ToByteF f) { @DontInline static ByteVector fromArray(byte[] a, int i) { - return ByteVector.fromArray(SPECIES, a, i); + // Tests the species method and the equivalent vector method it defers to + return (ByteVector) SPECIES.fromArray(a, i); } @DontInline @@ -268,7 +269,8 @@ static void intoArray(ByteVector v, byte[] a, int i, VectorMask m) { @DontInline static ByteVector fromMemorySegment(MemorySegment a, int i, ByteOrder bo) { - return ByteVector.fromMemorySegment(SPECIES, a, i, bo); + // Tests the species method and the equivalent vector method it defers to + return (ByteVector) SPECIES.fromMemorySegment(a, i, bo); } @DontInline diff --git a/test/jdk/jdk/incubator/vector/Byte256VectorLoadStoreTests.java b/test/jdk/jdk/incubator/vector/Byte256VectorLoadStoreTests.java index f6368b4972e..fac54c8450c 100644 --- a/test/jdk/jdk/incubator/vector/Byte256VectorLoadStoreTests.java +++ b/test/jdk/jdk/incubator/vector/Byte256VectorLoadStoreTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, 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 @@ -248,7 +248,8 @@ static byte[] fill(byte[] a, ToByteF f) { @DontInline static ByteVector fromArray(byte[] a, int i) { - return ByteVector.fromArray(SPECIES, a, i); + // Tests the species method and the equivalent vector method it defers to + return (ByteVector) SPECIES.fromArray(a, i); } @DontInline @@ -268,7 +269,8 @@ static void intoArray(ByteVector v, byte[] a, int i, VectorMask m) { @DontInline static ByteVector fromMemorySegment(MemorySegment a, int i, ByteOrder bo) { - return ByteVector.fromMemorySegment(SPECIES, a, i, bo); + // Tests the species method and the equivalent vector method it defers to + return (ByteVector) SPECIES.fromMemorySegment(a, i, bo); } @DontInline diff --git a/test/jdk/jdk/incubator/vector/Byte512VectorLoadStoreTests.java b/test/jdk/jdk/incubator/vector/Byte512VectorLoadStoreTests.java index 31cab63e85f..208f543855a 100644 --- a/test/jdk/jdk/incubator/vector/Byte512VectorLoadStoreTests.java +++ b/test/jdk/jdk/incubator/vector/Byte512VectorLoadStoreTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, 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 @@ -248,7 +248,8 @@ static byte[] fill(byte[] a, ToByteF f) { @DontInline static ByteVector fromArray(byte[] a, int i) { - return ByteVector.fromArray(SPECIES, a, i); + // Tests the species method and the equivalent vector method it defers to + return (ByteVector) SPECIES.fromArray(a, i); } @DontInline @@ -268,7 +269,8 @@ static void intoArray(ByteVector v, byte[] a, int i, VectorMask m) { @DontInline static ByteVector fromMemorySegment(MemorySegment a, int i, ByteOrder bo) { - return ByteVector.fromMemorySegment(SPECIES, a, i, bo); + // Tests the species method and the equivalent vector method it defers to + return (ByteVector) SPECIES.fromMemorySegment(a, i, bo); } @DontInline diff --git a/test/jdk/jdk/incubator/vector/Byte64VectorLoadStoreTests.java b/test/jdk/jdk/incubator/vector/Byte64VectorLoadStoreTests.java index 69bdc215b8c..d486fae103c 100644 --- a/test/jdk/jdk/incubator/vector/Byte64VectorLoadStoreTests.java +++ b/test/jdk/jdk/incubator/vector/Byte64VectorLoadStoreTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, 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 @@ -248,7 +248,8 @@ static byte[] fill(byte[] a, ToByteF f) { @DontInline static ByteVector fromArray(byte[] a, int i) { - return ByteVector.fromArray(SPECIES, a, i); + // Tests the species method and the equivalent vector method it defers to + return (ByteVector) SPECIES.fromArray(a, i); } @DontInline @@ -268,7 +269,8 @@ static void intoArray(ByteVector v, byte[] a, int i, VectorMask m) { @DontInline static ByteVector fromMemorySegment(MemorySegment a, int i, ByteOrder bo) { - return ByteVector.fromMemorySegment(SPECIES, a, i, bo); + // Tests the species method and the equivalent vector method it defers to + return (ByteVector) SPECIES.fromMemorySegment(a, i, bo); } @DontInline diff --git a/test/jdk/jdk/incubator/vector/ByteMaxVectorLoadStoreTests.java b/test/jdk/jdk/incubator/vector/ByteMaxVectorLoadStoreTests.java index 3d4272f1803..64e9b8d09dd 100644 --- a/test/jdk/jdk/incubator/vector/ByteMaxVectorLoadStoreTests.java +++ b/test/jdk/jdk/incubator/vector/ByteMaxVectorLoadStoreTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, 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 @@ -255,7 +255,8 @@ static byte[] fill(byte[] a, ToByteF f) { @DontInline static ByteVector fromArray(byte[] a, int i) { - return ByteVector.fromArray(SPECIES, a, i); + // Tests the species method and the equivalent vector method it defers to + return (ByteVector) SPECIES.fromArray(a, i); } @DontInline @@ -275,7 +276,8 @@ static void intoArray(ByteVector v, byte[] a, int i, VectorMask m) { @DontInline static ByteVector fromMemorySegment(MemorySegment a, int i, ByteOrder bo) { - return ByteVector.fromMemorySegment(SPECIES, a, i, bo); + // Tests the species method and the equivalent vector method it defers to + return (ByteVector) SPECIES.fromMemorySegment(a, i, bo); } @DontInline diff --git a/test/jdk/jdk/incubator/vector/Double128VectorLoadStoreTests.java b/test/jdk/jdk/incubator/vector/Double128VectorLoadStoreTests.java index f803bd85b4a..e2a18853b31 100644 --- a/test/jdk/jdk/incubator/vector/Double128VectorLoadStoreTests.java +++ b/test/jdk/jdk/incubator/vector/Double128VectorLoadStoreTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, 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 @@ -248,7 +248,8 @@ static double[] fill(double[] a, ToDoubleF f) { @DontInline static DoubleVector fromArray(double[] a, int i) { - return DoubleVector.fromArray(SPECIES, a, i); + // Tests the species method and the equivalent vector method it defers to + return (DoubleVector) SPECIES.fromArray(a, i); } @DontInline @@ -268,7 +269,8 @@ static void intoArray(DoubleVector v, double[] a, int i, VectorMask m) { @DontInline static DoubleVector fromMemorySegment(MemorySegment a, int i, ByteOrder bo) { - return DoubleVector.fromMemorySegment(SPECIES, a, i, bo); + // Tests the species method and the equivalent vector method it defers to + return (DoubleVector) SPECIES.fromMemorySegment(a, i, bo); } @DontInline diff --git a/test/jdk/jdk/incubator/vector/Double256VectorLoadStoreTests.java b/test/jdk/jdk/incubator/vector/Double256VectorLoadStoreTests.java index 5b040a4fa41..9ceb01569b4 100644 --- a/test/jdk/jdk/incubator/vector/Double256VectorLoadStoreTests.java +++ b/test/jdk/jdk/incubator/vector/Double256VectorLoadStoreTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, 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 @@ -248,7 +248,8 @@ static double[] fill(double[] a, ToDoubleF f) { @DontInline static DoubleVector fromArray(double[] a, int i) { - return DoubleVector.fromArray(SPECIES, a, i); + // Tests the species method and the equivalent vector method it defers to + return (DoubleVector) SPECIES.fromArray(a, i); } @DontInline @@ -268,7 +269,8 @@ static void intoArray(DoubleVector v, double[] a, int i, VectorMask m) { @DontInline static DoubleVector fromMemorySegment(MemorySegment a, int i, ByteOrder bo) { - return DoubleVector.fromMemorySegment(SPECIES, a, i, bo); + // Tests the species method and the equivalent vector method it defers to + return (DoubleVector) SPECIES.fromMemorySegment(a, i, bo); } @DontInline diff --git a/test/jdk/jdk/incubator/vector/Double512VectorLoadStoreTests.java b/test/jdk/jdk/incubator/vector/Double512VectorLoadStoreTests.java index c5a77fb5c9b..d997f19340e 100644 --- a/test/jdk/jdk/incubator/vector/Double512VectorLoadStoreTests.java +++ b/test/jdk/jdk/incubator/vector/Double512VectorLoadStoreTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, 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 @@ -248,7 +248,8 @@ static double[] fill(double[] a, ToDoubleF f) { @DontInline static DoubleVector fromArray(double[] a, int i) { - return DoubleVector.fromArray(SPECIES, a, i); + // Tests the species method and the equivalent vector method it defers to + return (DoubleVector) SPECIES.fromArray(a, i); } @DontInline @@ -268,7 +269,8 @@ static void intoArray(DoubleVector v, double[] a, int i, VectorMask m) { @DontInline static DoubleVector fromMemorySegment(MemorySegment a, int i, ByteOrder bo) { - return DoubleVector.fromMemorySegment(SPECIES, a, i, bo); + // Tests the species method and the equivalent vector method it defers to + return (DoubleVector) SPECIES.fromMemorySegment(a, i, bo); } @DontInline diff --git a/test/jdk/jdk/incubator/vector/Double64VectorLoadStoreTests.java b/test/jdk/jdk/incubator/vector/Double64VectorLoadStoreTests.java index db495f703ea..056fdebafcf 100644 --- a/test/jdk/jdk/incubator/vector/Double64VectorLoadStoreTests.java +++ b/test/jdk/jdk/incubator/vector/Double64VectorLoadStoreTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, 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 @@ -248,7 +248,8 @@ static double[] fill(double[] a, ToDoubleF f) { @DontInline static DoubleVector fromArray(double[] a, int i) { - return DoubleVector.fromArray(SPECIES, a, i); + // Tests the species method and the equivalent vector method it defers to + return (DoubleVector) SPECIES.fromArray(a, i); } @DontInline @@ -268,7 +269,8 @@ static void intoArray(DoubleVector v, double[] a, int i, VectorMask m) { @DontInline static DoubleVector fromMemorySegment(MemorySegment a, int i, ByteOrder bo) { - return DoubleVector.fromMemorySegment(SPECIES, a, i, bo); + // Tests the species method and the equivalent vector method it defers to + return (DoubleVector) SPECIES.fromMemorySegment(a, i, bo); } @DontInline diff --git a/test/jdk/jdk/incubator/vector/DoubleMaxVectorLoadStoreTests.java b/test/jdk/jdk/incubator/vector/DoubleMaxVectorLoadStoreTests.java index 6f5efbd89b1..69a6525ff99 100644 --- a/test/jdk/jdk/incubator/vector/DoubleMaxVectorLoadStoreTests.java +++ b/test/jdk/jdk/incubator/vector/DoubleMaxVectorLoadStoreTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, 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 @@ -255,7 +255,8 @@ static double[] fill(double[] a, ToDoubleF f) { @DontInline static DoubleVector fromArray(double[] a, int i) { - return DoubleVector.fromArray(SPECIES, a, i); + // Tests the species method and the equivalent vector method it defers to + return (DoubleVector) SPECIES.fromArray(a, i); } @DontInline @@ -275,7 +276,8 @@ static void intoArray(DoubleVector v, double[] a, int i, VectorMask m) { @DontInline static DoubleVector fromMemorySegment(MemorySegment a, int i, ByteOrder bo) { - return DoubleVector.fromMemorySegment(SPECIES, a, i, bo); + // Tests the species method and the equivalent vector method it defers to + return (DoubleVector) SPECIES.fromMemorySegment(a, i, bo); } @DontInline diff --git a/test/jdk/jdk/incubator/vector/Float128VectorLoadStoreTests.java b/test/jdk/jdk/incubator/vector/Float128VectorLoadStoreTests.java index 79886797761..6c583c39195 100644 --- a/test/jdk/jdk/incubator/vector/Float128VectorLoadStoreTests.java +++ b/test/jdk/jdk/incubator/vector/Float128VectorLoadStoreTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, 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 @@ -248,7 +248,8 @@ static float[] fill(float[] a, ToFloatF f) { @DontInline static FloatVector fromArray(float[] a, int i) { - return FloatVector.fromArray(SPECIES, a, i); + // Tests the species method and the equivalent vector method it defers to + return (FloatVector) SPECIES.fromArray(a, i); } @DontInline @@ -268,7 +269,8 @@ static void intoArray(FloatVector v, float[] a, int i, VectorMask m) { @DontInline static FloatVector fromMemorySegment(MemorySegment a, int i, ByteOrder bo) { - return FloatVector.fromMemorySegment(SPECIES, a, i, bo); + // Tests the species method and the equivalent vector method it defers to + return (FloatVector) SPECIES.fromMemorySegment(a, i, bo); } @DontInline diff --git a/test/jdk/jdk/incubator/vector/Float256VectorLoadStoreTests.java b/test/jdk/jdk/incubator/vector/Float256VectorLoadStoreTests.java index 794e21ef648..fbb2496bd6e 100644 --- a/test/jdk/jdk/incubator/vector/Float256VectorLoadStoreTests.java +++ b/test/jdk/jdk/incubator/vector/Float256VectorLoadStoreTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, 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 @@ -248,7 +248,8 @@ static float[] fill(float[] a, ToFloatF f) { @DontInline static FloatVector fromArray(float[] a, int i) { - return FloatVector.fromArray(SPECIES, a, i); + // Tests the species method and the equivalent vector method it defers to + return (FloatVector) SPECIES.fromArray(a, i); } @DontInline @@ -268,7 +269,8 @@ static void intoArray(FloatVector v, float[] a, int i, VectorMask m) { @DontInline static FloatVector fromMemorySegment(MemorySegment a, int i, ByteOrder bo) { - return FloatVector.fromMemorySegment(SPECIES, a, i, bo); + // Tests the species method and the equivalent vector method it defers to + return (FloatVector) SPECIES.fromMemorySegment(a, i, bo); } @DontInline diff --git a/test/jdk/jdk/incubator/vector/Float512VectorLoadStoreTests.java b/test/jdk/jdk/incubator/vector/Float512VectorLoadStoreTests.java index 70e9863064b..adc9b7a89c5 100644 --- a/test/jdk/jdk/incubator/vector/Float512VectorLoadStoreTests.java +++ b/test/jdk/jdk/incubator/vector/Float512VectorLoadStoreTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, 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 @@ -248,7 +248,8 @@ static float[] fill(float[] a, ToFloatF f) { @DontInline static FloatVector fromArray(float[] a, int i) { - return FloatVector.fromArray(SPECIES, a, i); + // Tests the species method and the equivalent vector method it defers to + return (FloatVector) SPECIES.fromArray(a, i); } @DontInline @@ -268,7 +269,8 @@ static void intoArray(FloatVector v, float[] a, int i, VectorMask m) { @DontInline static FloatVector fromMemorySegment(MemorySegment a, int i, ByteOrder bo) { - return FloatVector.fromMemorySegment(SPECIES, a, i, bo); + // Tests the species method and the equivalent vector method it defers to + return (FloatVector) SPECIES.fromMemorySegment(a, i, bo); } @DontInline diff --git a/test/jdk/jdk/incubator/vector/Float64VectorLoadStoreTests.java b/test/jdk/jdk/incubator/vector/Float64VectorLoadStoreTests.java index f8ebeab7db2..e9d042c53c5 100644 --- a/test/jdk/jdk/incubator/vector/Float64VectorLoadStoreTests.java +++ b/test/jdk/jdk/incubator/vector/Float64VectorLoadStoreTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, 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 @@ -248,7 +248,8 @@ static float[] fill(float[] a, ToFloatF f) { @DontInline static FloatVector fromArray(float[] a, int i) { - return FloatVector.fromArray(SPECIES, a, i); + // Tests the species method and the equivalent vector method it defers to + return (FloatVector) SPECIES.fromArray(a, i); } @DontInline @@ -268,7 +269,8 @@ static void intoArray(FloatVector v, float[] a, int i, VectorMask m) { @DontInline static FloatVector fromMemorySegment(MemorySegment a, int i, ByteOrder bo) { - return FloatVector.fromMemorySegment(SPECIES, a, i, bo); + // Tests the species method and the equivalent vector method it defers to + return (FloatVector) SPECIES.fromMemorySegment(a, i, bo); } @DontInline diff --git a/test/jdk/jdk/incubator/vector/FloatMaxVectorLoadStoreTests.java b/test/jdk/jdk/incubator/vector/FloatMaxVectorLoadStoreTests.java index 61c9db74289..844942e2010 100644 --- a/test/jdk/jdk/incubator/vector/FloatMaxVectorLoadStoreTests.java +++ b/test/jdk/jdk/incubator/vector/FloatMaxVectorLoadStoreTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, 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 @@ -255,7 +255,8 @@ static float[] fill(float[] a, ToFloatF f) { @DontInline static FloatVector fromArray(float[] a, int i) { - return FloatVector.fromArray(SPECIES, a, i); + // Tests the species method and the equivalent vector method it defers to + return (FloatVector) SPECIES.fromArray(a, i); } @DontInline @@ -275,7 +276,8 @@ static void intoArray(FloatVector v, float[] a, int i, VectorMask m) { @DontInline static FloatVector fromMemorySegment(MemorySegment a, int i, ByteOrder bo) { - return FloatVector.fromMemorySegment(SPECIES, a, i, bo); + // Tests the species method and the equivalent vector method it defers to + return (FloatVector) SPECIES.fromMemorySegment(a, i, bo); } @DontInline diff --git a/test/jdk/jdk/incubator/vector/Int128VectorLoadStoreTests.java b/test/jdk/jdk/incubator/vector/Int128VectorLoadStoreTests.java index 6bac67a5775..9e6d82510e1 100644 --- a/test/jdk/jdk/incubator/vector/Int128VectorLoadStoreTests.java +++ b/test/jdk/jdk/incubator/vector/Int128VectorLoadStoreTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, 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 @@ -248,7 +248,8 @@ static int[] fill(int[] a, ToIntF f) { @DontInline static IntVector fromArray(int[] a, int i) { - return IntVector.fromArray(SPECIES, a, i); + // Tests the species method and the equivalent vector method it defers to + return (IntVector) SPECIES.fromArray(a, i); } @DontInline @@ -268,7 +269,8 @@ static void intoArray(IntVector v, int[] a, int i, VectorMask m) { @DontInline static IntVector fromMemorySegment(MemorySegment a, int i, ByteOrder bo) { - return IntVector.fromMemorySegment(SPECIES, a, i, bo); + // Tests the species method and the equivalent vector method it defers to + return (IntVector) SPECIES.fromMemorySegment(a, i, bo); } @DontInline diff --git a/test/jdk/jdk/incubator/vector/Int256VectorLoadStoreTests.java b/test/jdk/jdk/incubator/vector/Int256VectorLoadStoreTests.java index 6d5212d0268..b90b0a42d10 100644 --- a/test/jdk/jdk/incubator/vector/Int256VectorLoadStoreTests.java +++ b/test/jdk/jdk/incubator/vector/Int256VectorLoadStoreTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, 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 @@ -248,7 +248,8 @@ static int[] fill(int[] a, ToIntF f) { @DontInline static IntVector fromArray(int[] a, int i) { - return IntVector.fromArray(SPECIES, a, i); + // Tests the species method and the equivalent vector method it defers to + return (IntVector) SPECIES.fromArray(a, i); } @DontInline @@ -268,7 +269,8 @@ static void intoArray(IntVector v, int[] a, int i, VectorMask m) { @DontInline static IntVector fromMemorySegment(MemorySegment a, int i, ByteOrder bo) { - return IntVector.fromMemorySegment(SPECIES, a, i, bo); + // Tests the species method and the equivalent vector method it defers to + return (IntVector) SPECIES.fromMemorySegment(a, i, bo); } @DontInline diff --git a/test/jdk/jdk/incubator/vector/Int512VectorLoadStoreTests.java b/test/jdk/jdk/incubator/vector/Int512VectorLoadStoreTests.java index fe3f55d65e5..424d4b63fcb 100644 --- a/test/jdk/jdk/incubator/vector/Int512VectorLoadStoreTests.java +++ b/test/jdk/jdk/incubator/vector/Int512VectorLoadStoreTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, 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 @@ -248,7 +248,8 @@ static int[] fill(int[] a, ToIntF f) { @DontInline static IntVector fromArray(int[] a, int i) { - return IntVector.fromArray(SPECIES, a, i); + // Tests the species method and the equivalent vector method it defers to + return (IntVector) SPECIES.fromArray(a, i); } @DontInline @@ -268,7 +269,8 @@ static void intoArray(IntVector v, int[] a, int i, VectorMask m) { @DontInline static IntVector fromMemorySegment(MemorySegment a, int i, ByteOrder bo) { - return IntVector.fromMemorySegment(SPECIES, a, i, bo); + // Tests the species method and the equivalent vector method it defers to + return (IntVector) SPECIES.fromMemorySegment(a, i, bo); } @DontInline diff --git a/test/jdk/jdk/incubator/vector/Int64VectorLoadStoreTests.java b/test/jdk/jdk/incubator/vector/Int64VectorLoadStoreTests.java index ce64e0fcd3c..e1abfdcccd9 100644 --- a/test/jdk/jdk/incubator/vector/Int64VectorLoadStoreTests.java +++ b/test/jdk/jdk/incubator/vector/Int64VectorLoadStoreTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, 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 @@ -248,7 +248,8 @@ static int[] fill(int[] a, ToIntF f) { @DontInline static IntVector fromArray(int[] a, int i) { - return IntVector.fromArray(SPECIES, a, i); + // Tests the species method and the equivalent vector method it defers to + return (IntVector) SPECIES.fromArray(a, i); } @DontInline @@ -268,7 +269,8 @@ static void intoArray(IntVector v, int[] a, int i, VectorMask m) { @DontInline static IntVector fromMemorySegment(MemorySegment a, int i, ByteOrder bo) { - return IntVector.fromMemorySegment(SPECIES, a, i, bo); + // Tests the species method and the equivalent vector method it defers to + return (IntVector) SPECIES.fromMemorySegment(a, i, bo); } @DontInline diff --git a/test/jdk/jdk/incubator/vector/IntMaxVectorLoadStoreTests.java b/test/jdk/jdk/incubator/vector/IntMaxVectorLoadStoreTests.java index f61bb34f813..3e11b366a77 100644 --- a/test/jdk/jdk/incubator/vector/IntMaxVectorLoadStoreTests.java +++ b/test/jdk/jdk/incubator/vector/IntMaxVectorLoadStoreTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, 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 @@ -255,7 +255,8 @@ static int[] fill(int[] a, ToIntF f) { @DontInline static IntVector fromArray(int[] a, int i) { - return IntVector.fromArray(SPECIES, a, i); + // Tests the species method and the equivalent vector method it defers to + return (IntVector) SPECIES.fromArray(a, i); } @DontInline @@ -275,7 +276,8 @@ static void intoArray(IntVector v, int[] a, int i, VectorMask m) { @DontInline static IntVector fromMemorySegment(MemorySegment a, int i, ByteOrder bo) { - return IntVector.fromMemorySegment(SPECIES, a, i, bo); + // Tests the species method and the equivalent vector method it defers to + return (IntVector) SPECIES.fromMemorySegment(a, i, bo); } @DontInline diff --git a/test/jdk/jdk/incubator/vector/Long128VectorLoadStoreTests.java b/test/jdk/jdk/incubator/vector/Long128VectorLoadStoreTests.java index 5c36d67d0d6..7425e8e11e8 100644 --- a/test/jdk/jdk/incubator/vector/Long128VectorLoadStoreTests.java +++ b/test/jdk/jdk/incubator/vector/Long128VectorLoadStoreTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, 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 @@ -248,7 +248,8 @@ static long[] fill(long[] a, ToLongF f) { @DontInline static LongVector fromArray(long[] a, int i) { - return LongVector.fromArray(SPECIES, a, i); + // Tests the species method and the equivalent vector method it defers to + return (LongVector) SPECIES.fromArray(a, i); } @DontInline @@ -268,7 +269,8 @@ static void intoArray(LongVector v, long[] a, int i, VectorMask m) { @DontInline static LongVector fromMemorySegment(MemorySegment a, int i, ByteOrder bo) { - return LongVector.fromMemorySegment(SPECIES, a, i, bo); + // Tests the species method and the equivalent vector method it defers to + return (LongVector) SPECIES.fromMemorySegment(a, i, bo); } @DontInline diff --git a/test/jdk/jdk/incubator/vector/Long256VectorLoadStoreTests.java b/test/jdk/jdk/incubator/vector/Long256VectorLoadStoreTests.java index c8f932fda56..78e16570eb8 100644 --- a/test/jdk/jdk/incubator/vector/Long256VectorLoadStoreTests.java +++ b/test/jdk/jdk/incubator/vector/Long256VectorLoadStoreTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, 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 @@ -248,7 +248,8 @@ static long[] fill(long[] a, ToLongF f) { @DontInline static LongVector fromArray(long[] a, int i) { - return LongVector.fromArray(SPECIES, a, i); + // Tests the species method and the equivalent vector method it defers to + return (LongVector) SPECIES.fromArray(a, i); } @DontInline @@ -268,7 +269,8 @@ static void intoArray(LongVector v, long[] a, int i, VectorMask m) { @DontInline static LongVector fromMemorySegment(MemorySegment a, int i, ByteOrder bo) { - return LongVector.fromMemorySegment(SPECIES, a, i, bo); + // Tests the species method and the equivalent vector method it defers to + return (LongVector) SPECIES.fromMemorySegment(a, i, bo); } @DontInline diff --git a/test/jdk/jdk/incubator/vector/Long512VectorLoadStoreTests.java b/test/jdk/jdk/incubator/vector/Long512VectorLoadStoreTests.java index 825706ced04..cf41e488c44 100644 --- a/test/jdk/jdk/incubator/vector/Long512VectorLoadStoreTests.java +++ b/test/jdk/jdk/incubator/vector/Long512VectorLoadStoreTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, 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 @@ -248,7 +248,8 @@ static long[] fill(long[] a, ToLongF f) { @DontInline static LongVector fromArray(long[] a, int i) { - return LongVector.fromArray(SPECIES, a, i); + // Tests the species method and the equivalent vector method it defers to + return (LongVector) SPECIES.fromArray(a, i); } @DontInline @@ -268,7 +269,8 @@ static void intoArray(LongVector v, long[] a, int i, VectorMask m) { @DontInline static LongVector fromMemorySegment(MemorySegment a, int i, ByteOrder bo) { - return LongVector.fromMemorySegment(SPECIES, a, i, bo); + // Tests the species method and the equivalent vector method it defers to + return (LongVector) SPECIES.fromMemorySegment(a, i, bo); } @DontInline diff --git a/test/jdk/jdk/incubator/vector/Long64VectorLoadStoreTests.java b/test/jdk/jdk/incubator/vector/Long64VectorLoadStoreTests.java index ecbd349b279..532074f9d62 100644 --- a/test/jdk/jdk/incubator/vector/Long64VectorLoadStoreTests.java +++ b/test/jdk/jdk/incubator/vector/Long64VectorLoadStoreTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, 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 @@ -248,7 +248,8 @@ static long[] fill(long[] a, ToLongF f) { @DontInline static LongVector fromArray(long[] a, int i) { - return LongVector.fromArray(SPECIES, a, i); + // Tests the species method and the equivalent vector method it defers to + return (LongVector) SPECIES.fromArray(a, i); } @DontInline @@ -268,7 +269,8 @@ static void intoArray(LongVector v, long[] a, int i, VectorMask m) { @DontInline static LongVector fromMemorySegment(MemorySegment a, int i, ByteOrder bo) { - return LongVector.fromMemorySegment(SPECIES, a, i, bo); + // Tests the species method and the equivalent vector method it defers to + return (LongVector) SPECIES.fromMemorySegment(a, i, bo); } @DontInline diff --git a/test/jdk/jdk/incubator/vector/LongMaxVectorLoadStoreTests.java b/test/jdk/jdk/incubator/vector/LongMaxVectorLoadStoreTests.java index e601af509a5..462fe0dcd8c 100644 --- a/test/jdk/jdk/incubator/vector/LongMaxVectorLoadStoreTests.java +++ b/test/jdk/jdk/incubator/vector/LongMaxVectorLoadStoreTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, 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 @@ -255,7 +255,8 @@ static long[] fill(long[] a, ToLongF f) { @DontInline static LongVector fromArray(long[] a, int i) { - return LongVector.fromArray(SPECIES, a, i); + // Tests the species method and the equivalent vector method it defers to + return (LongVector) SPECIES.fromArray(a, i); } @DontInline @@ -275,7 +276,8 @@ static void intoArray(LongVector v, long[] a, int i, VectorMask m) { @DontInline static LongVector fromMemorySegment(MemorySegment a, int i, ByteOrder bo) { - return LongVector.fromMemorySegment(SPECIES, a, i, bo); + // Tests the species method and the equivalent vector method it defers to + return (LongVector) SPECIES.fromMemorySegment(a, i, bo); } @DontInline diff --git a/test/jdk/jdk/incubator/vector/Short128VectorLoadStoreTests.java b/test/jdk/jdk/incubator/vector/Short128VectorLoadStoreTests.java index e51ccfeec19..6898bdea621 100644 --- a/test/jdk/jdk/incubator/vector/Short128VectorLoadStoreTests.java +++ b/test/jdk/jdk/incubator/vector/Short128VectorLoadStoreTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, 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 @@ -248,7 +248,8 @@ static short[] fill(short[] a, ToShortF f) { @DontInline static ShortVector fromArray(short[] a, int i) { - return ShortVector.fromArray(SPECIES, a, i); + // Tests the species method and the equivalent vector method it defers to + return (ShortVector) SPECIES.fromArray(a, i); } @DontInline @@ -268,7 +269,8 @@ static void intoArray(ShortVector v, short[] a, int i, VectorMask m) { @DontInline static ShortVector fromMemorySegment(MemorySegment a, int i, ByteOrder bo) { - return ShortVector.fromMemorySegment(SPECIES, a, i, bo); + // Tests the species method and the equivalent vector method it defers to + return (ShortVector) SPECIES.fromMemorySegment(a, i, bo); } @DontInline diff --git a/test/jdk/jdk/incubator/vector/Short256VectorLoadStoreTests.java b/test/jdk/jdk/incubator/vector/Short256VectorLoadStoreTests.java index cbe0063168a..45044570a1a 100644 --- a/test/jdk/jdk/incubator/vector/Short256VectorLoadStoreTests.java +++ b/test/jdk/jdk/incubator/vector/Short256VectorLoadStoreTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, 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 @@ -248,7 +248,8 @@ static short[] fill(short[] a, ToShortF f) { @DontInline static ShortVector fromArray(short[] a, int i) { - return ShortVector.fromArray(SPECIES, a, i); + // Tests the species method and the equivalent vector method it defers to + return (ShortVector) SPECIES.fromArray(a, i); } @DontInline @@ -268,7 +269,8 @@ static void intoArray(ShortVector v, short[] a, int i, VectorMask m) { @DontInline static ShortVector fromMemorySegment(MemorySegment a, int i, ByteOrder bo) { - return ShortVector.fromMemorySegment(SPECIES, a, i, bo); + // Tests the species method and the equivalent vector method it defers to + return (ShortVector) SPECIES.fromMemorySegment(a, i, bo); } @DontInline diff --git a/test/jdk/jdk/incubator/vector/Short512VectorLoadStoreTests.java b/test/jdk/jdk/incubator/vector/Short512VectorLoadStoreTests.java index eb847075ea4..fb467b6ed78 100644 --- a/test/jdk/jdk/incubator/vector/Short512VectorLoadStoreTests.java +++ b/test/jdk/jdk/incubator/vector/Short512VectorLoadStoreTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, 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 @@ -248,7 +248,8 @@ static short[] fill(short[] a, ToShortF f) { @DontInline static ShortVector fromArray(short[] a, int i) { - return ShortVector.fromArray(SPECIES, a, i); + // Tests the species method and the equivalent vector method it defers to + return (ShortVector) SPECIES.fromArray(a, i); } @DontInline @@ -268,7 +269,8 @@ static void intoArray(ShortVector v, short[] a, int i, VectorMask m) { @DontInline static ShortVector fromMemorySegment(MemorySegment a, int i, ByteOrder bo) { - return ShortVector.fromMemorySegment(SPECIES, a, i, bo); + // Tests the species method and the equivalent vector method it defers to + return (ShortVector) SPECIES.fromMemorySegment(a, i, bo); } @DontInline diff --git a/test/jdk/jdk/incubator/vector/Short64VectorLoadStoreTests.java b/test/jdk/jdk/incubator/vector/Short64VectorLoadStoreTests.java index ad73af04b53..1b7e59bc9f9 100644 --- a/test/jdk/jdk/incubator/vector/Short64VectorLoadStoreTests.java +++ b/test/jdk/jdk/incubator/vector/Short64VectorLoadStoreTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, 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 @@ -248,7 +248,8 @@ static short[] fill(short[] a, ToShortF f) { @DontInline static ShortVector fromArray(short[] a, int i) { - return ShortVector.fromArray(SPECIES, a, i); + // Tests the species method and the equivalent vector method it defers to + return (ShortVector) SPECIES.fromArray(a, i); } @DontInline @@ -268,7 +269,8 @@ static void intoArray(ShortVector v, short[] a, int i, VectorMask m) { @DontInline static ShortVector fromMemorySegment(MemorySegment a, int i, ByteOrder bo) { - return ShortVector.fromMemorySegment(SPECIES, a, i, bo); + // Tests the species method and the equivalent vector method it defers to + return (ShortVector) SPECIES.fromMemorySegment(a, i, bo); } @DontInline diff --git a/test/jdk/jdk/incubator/vector/ShortMaxVectorLoadStoreTests.java b/test/jdk/jdk/incubator/vector/ShortMaxVectorLoadStoreTests.java index 6412897c2c7..10621a68b6b 100644 --- a/test/jdk/jdk/incubator/vector/ShortMaxVectorLoadStoreTests.java +++ b/test/jdk/jdk/incubator/vector/ShortMaxVectorLoadStoreTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, 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 @@ -255,7 +255,8 @@ static short[] fill(short[] a, ToShortF f) { @DontInline static ShortVector fromArray(short[] a, int i) { - return ShortVector.fromArray(SPECIES, a, i); + // Tests the species method and the equivalent vector method it defers to + return (ShortVector) SPECIES.fromArray(a, i); } @DontInline @@ -275,7 +276,8 @@ static void intoArray(ShortVector v, short[] a, int i, VectorMask m) { @DontInline static ShortVector fromMemorySegment(MemorySegment a, int i, ByteOrder bo) { - return ShortVector.fromMemorySegment(SPECIES, a, i, bo); + // Tests the species method and the equivalent vector method it defers to + return (ShortVector) SPECIES.fromMemorySegment(a, i, bo); } @DontInline diff --git a/test/jdk/jdk/incubator/vector/templates/X-LoadStoreTest.java.template b/test/jdk/jdk/incubator/vector/templates/X-LoadStoreTest.java.template index f9226d073b5..a2c642b7a86 100644 --- a/test/jdk/jdk/incubator/vector/templates/X-LoadStoreTest.java.template +++ b/test/jdk/jdk/incubator/vector/templates/X-LoadStoreTest.java.template @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, 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 @@ -268,7 +268,8 @@ public class $vectorteststype$ extends AbstractVectorLoadStoreTest { @DontInline static $abstractvectortype$ fromArray($type$[] a, int i) { - return $abstractvectortype$.fromArray(SPECIES, a, i); + // Tests the species method and the equivalent vector method it defers to + return ($abstractvectortype$) SPECIES.fromArray(a, i); } @DontInline @@ -288,7 +289,8 @@ public class $vectorteststype$ extends AbstractVectorLoadStoreTest { @DontInline static $abstractvectortype$ fromMemorySegment(MemorySegment a, int i, ByteOrder bo) { - return $abstractvectortype$.fromMemorySegment(SPECIES, a, i, bo); + // Tests the species method and the equivalent vector method it defers to + return ($abstractvectortype$) SPECIES.fromMemorySegment(a, i, bo); } @DontInline diff --git a/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/CAInterop.java b/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/CAInterop.java index b5bb698e458..0ef37377b1e 100644 --- a/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/CAInterop.java +++ b/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/CAInterop.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, 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 @@ -451,6 +451,24 @@ * @run main/othervm -Djava.security.debug=certpath CAInterop emsigneccrootcag3 CRL */ +/* + * @test id=certainlyrootr1 + * @bug 8321408 + * @summary Interoperability tests with Certainly Root R1 + * @library /test/lib + * @build jtreg.SkippedException ValidatePathWithURL CAInterop + * @run main/othervm -Djava.security.debug=certpath,ocsp CAInterop certainlyrootr1 DEFAULT + */ + +/* + * @test id=certainlyroote1 + * @bug 8321408 + * @summary Interoperability tests with Certainly Root E1 + * @library /test/lib + * @build jtreg.SkippedException ValidatePathWithURL CAInterop + * @run main/othervm -Djava.security.debug=certpath,ocsp CAInterop certainlyroote1 DEFAULT + */ + /** * Collection of certificate validation tests for interoperability with external CAs */ @@ -613,6 +631,13 @@ private CATestURLs getTestURLs(String alias) { new CATestURLs("https://testovg3.emsign.com/RootOVG3.html", "https://testovg3r.emsign.com/RootOVG3MR.html"); + case "certainlyrootr1" -> + new CATestURLs("https://valid.root-r1.certainly.com", + "https://revoked.root-r1.certainly.com"); + case "certainlyroote1" -> + new CATestURLs("https://valid.root-e1.certainly.com", + "https://revoked.root-e1.certainly.com"); + default -> throw new RuntimeException("No test setup found for: " + alias); }; } diff --git a/test/jdk/sun/java2d/cmm/ColorConvertOp/ColCvtAlphaDifferentSrcDst.java b/test/jdk/sun/java2d/cmm/ColorConvertOp/ColCvtAlphaDifferentSrcDst.java index 31db9d1a380..22868ffaf3c 100644 --- a/test/jdk/sun/java2d/cmm/ColorConvertOp/ColCvtAlphaDifferentSrcDst.java +++ b/test/jdk/sun/java2d/cmm/ColorConvertOp/ColCvtAlphaDifferentSrcDst.java @@ -52,7 +52,7 @@ /* * @test - * @bug 8012229 8300725 8279216 + * @bug 8012229 8300725 8279216 8323210 * @summary one more test to check the alpha channel */ public final class ColCvtAlphaDifferentSrcDst { diff --git a/test/jdk/sun/java2d/marlin/ClipShapeTest.java b/test/jdk/sun/java2d/marlin/ClipShapeTest.java index 65de6e750c9..3bdbd416e63 100644 --- a/test/jdk/sun/java2d/marlin/ClipShapeTest.java +++ b/test/jdk/sun/java2d/marlin/ClipShapeTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, 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 @@ -52,20 +52,43 @@ import javax.imageio.ImageWriter; import javax.imageio.stream.ImageOutputStream; -/** - * @test +/* + * @test id=Poly * @bug 8191814 - * @summary Verifies that Marlin rendering generates the same - * images with and without clipping optimization with all possible - * stroke (cap/join) and/or dashes or fill modes (EO rules) - * for paths made of either 9 lines, 4 quads, 2 cubics (random) - * Note: Use the argument -slow to run more intensive tests (too much time) - * + * @summary Runs the test with "-poly" option * @run main/othervm/timeout=300 -Dsun.java2d.renderer=sun.java2d.marlin.DMarlinRenderingEngine ClipShapeTest -poly + */ + +/* + * @test id=PolyDoDash + * @bug 8191814 + * @summary Runs the test with "-poly -doDash" options * @run main/othervm/timeout=300 -Dsun.java2d.renderer=sun.java2d.marlin.DMarlinRenderingEngine ClipShapeTest -poly -doDash + */ + +/* + * @test id=Cubic + * @bug 8191814 + * @summary Runs the test with "-cubic" option * @run main/othervm/timeout=300 -Dsun.java2d.renderer=sun.java2d.marlin.DMarlinRenderingEngine ClipShapeTest -cubic + */ + +/* + * @test id=CubicDoDash + * @bug 8191814 + * @summary Runs the test with "-cubic -doDash" options * @run main/othervm/timeout=300 -Dsun.java2d.renderer=sun.java2d.marlin.DMarlinRenderingEngine ClipShapeTest -cubic -doDash -*/ + */ + +/** + * Verifies that Marlin rendering generates the same images with and without + * clipping optimization with all possible stroke (cap/join) and/or dashes or + * fill modes (EO rules) for paths made of either 9 lines, 4 quads, 2 cubics + * (random). + *

+ * Note: Use the argument {@code -slow} to run more intensive tests (too much + * time). + */ public final class ClipShapeTest { // test options: diff --git a/test/jdk/sun/security/lib/cacerts/VerifyCACerts.java b/test/jdk/sun/security/lib/cacerts/VerifyCACerts.java index 595cce5d2b7..548024efc6c 100644 --- a/test/jdk/sun/security/lib/cacerts/VerifyCACerts.java +++ b/test/jdk/sun/security/lib/cacerts/VerifyCACerts.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2024, 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,6 +29,7 @@ * 8223499 8225392 8232019 8234245 8233223 8225068 8225069 8243321 8243320 * 8243559 8225072 8258630 8259312 8256421 8225081 8225082 8225083 8245654 * 8305975 8304760 8307134 8295894 8314960 8317373 8317374 8318759 8319187 + * 8321408 * @summary Check root CA entries in cacerts file */ import java.io.ByteArrayInputStream; @@ -47,12 +48,12 @@ public class VerifyCACerts { + File.separator + "security" + File.separator + "cacerts"; // The numbers of certs now. - private static final int COUNT = 106; + private static final int COUNT = 108; // SHA-256 of cacerts, can be generated with // shasum -a 256 cacerts | sed -e 's/../&:/g' | tr '[:lower:]' '[:upper:]' | cut -c1-95 private static final String CHECKSUM - = "C6:81:90:32:46:65:82:69:6B:BF:EE:C2:BE:AB:48:59:CB:2F:B6:7B:93:F2:B3:7E:A0:07:17:0C:79:F6:D9:AC"; + = "C4:A2:41:9E:B6:4D:77:26:AA:21:02:83:51:C7:88:21:66:1E:D8:88:4A:AC:84:D5:B0:15:0C:7C:C6:45:85:AF"; // Hex formatter to upper case with ":" delimiter private static final HexFormat HEX = HexFormat.ofDelimiter(":").withUpperCase(); @@ -273,6 +274,10 @@ public class VerifyCACerts { "86:A1:EC:BA:08:9C:4A:8D:3B:BE:27:34:C6:12:BA:34:1D:81:3E:04:3C:F9:E8:A8:62:CD:5C:57:A3:6B:BE:6B"); put("emsignrootcag2 [jdk]", "1A:A0:C2:70:9E:83:1B:D6:E3:B5:12:9A:00:BA:41:F7:EE:EF:02:08:72:F1:E6:50:4B:F0:F6:C3:F2:4F:3A:F3"); + put("certainlyrootr1 [jdk]", + "77:B8:2C:D8:64:4C:43:05:F7:AC:C5:CB:15:6B:45:67:50:04:03:3D:51:C6:0C:62:02:A8:E0:C3:34:67:D3:A0"); + put("certainlyroote1 [jdk]", + "B4:58:5F:22:E4:AC:75:6A:4E:86:12:A1:36:1C:5D:9D:03:1A:93:FD:84:FE:BB:77:8F:A3:06:8B:0F:C4:2D:C2"); } }; diff --git a/test/jdk/sun/security/pkcs11/PKCS11Test.java b/test/jdk/sun/security/pkcs11/PKCS11Test.java index ccdbd2d8e49..82c25d2a436 100644 --- a/test/jdk/sun/security/pkcs11/PKCS11Test.java +++ b/test/jdk/sun/security/pkcs11/PKCS11Test.java @@ -54,10 +54,14 @@ import java.util.ServiceConfigurationError; import java.util.ServiceLoader; import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; import javax.crypto.SecretKey; import javax.crypto.spec.SecretKeySpec; +import jdk.test.lib.Platform; import jdk.test.lib.artifacts.Artifact; import jdk.test.lib.artifacts.ArtifactResolver; import jdk.test.lib.artifacts.ArtifactResolverException; @@ -231,7 +235,17 @@ public static String getBase() throws Exception { throw new RuntimeException("Test root directory not found"); } } - PKCS11_BASE = new File(cwd, PKCS11_REL_PATH.replace('/', SEP)).getAbsolutePath(); + File pkcs11 = new File(cwd, PKCS11_REL_PATH.replace('/', SEP)); + if (!new File(pkcs11, "nss/p11-nss.txt").exists()) { + // this test might be in the closed + pkcs11 = new File(new File(cwd, "../../../open/test/jdk"), + PKCS11_REL_PATH.replace('/', SEP)); + if (!new File(pkcs11, "nss/p11-nss.txt").exists()) { + throw new RuntimeException("Not a PKCS11 directory" + + pkcs11.getAbsolutePath()); + } + } + PKCS11_BASE = pkcs11.getAbsolutePath(); return PKCS11_BASE; } @@ -743,10 +757,18 @@ private static String fetchNssLib(String osId) { return fetchNssLib(MACOSX_AARCH64.class); case "Linux-amd64-64": - return fetchNssLib(LINUX_X64.class); + if (Platform.isOracleLinux7()) { + throw new SkippedException("Skipping Oracle Linux prior to v8"); + } else { + return fetchNssLib(LINUX_X64.class); + } case "Linux-aarch64-64": - throw new SkippedException("Per JDK-8319128, skipping Linux aarch64 platforms."); + if (Platform.isOracleLinux7()) { + throw new SkippedException("Skipping Oracle Linux prior to v8"); + } else { + return fetchNssLib(LINUX_AARCH64.class); + } default: return null; } diff --git a/test/jdk/sun/security/pkcs11/Provider/MultipleLogins.java b/test/jdk/sun/security/pkcs11/Provider/MultipleLogins.java index 5d6fb68aceb..ddce6e8733d 100644 --- a/test/jdk/sun/security/pkcs11/Provider/MultipleLogins.java +++ b/test/jdk/sun/security/pkcs11/Provider/MultipleLogins.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2023, 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,6 +21,7 @@ * questions. */ + import sun.security.pkcs11.SunPKCS11; import javax.security.auth.Subject; @@ -32,12 +33,10 @@ import java.io.IOException; import java.lang.ref.WeakReference; import java.security.*; -import java.util.Iterator; import java.util.PropertyPermission; -import java.util.ServiceConfigurationError; -import java.util.ServiceLoader; import jdk.test.lib.util.ForceGC; +import jtreg.SkippedException; public class MultipleLogins { private static final String KS_TYPE = "PKCS11"; @@ -46,7 +45,13 @@ public class MultipleLogins { static final Policy DEFAULT_POLICY = Policy.getPolicy(); public static void main(String[] args) throws Exception { - String nssConfig = PKCS11Test.getNssConfig(); + String nssConfig = null; + try { + nssConfig = PKCS11Test.getNssConfig(); + } catch (SkippedException exc) { + System.out.println("Skipping test: " + exc.getMessage()); + } + if (nssConfig == null) { // No test framework support yet. Ignore System.out.println("No NSS config found. Skipping."); diff --git a/test/jdk/sun/security/pkcs11/Provider/MultipleLogins.sh b/test/jdk/sun/security/pkcs11/Provider/MultipleLogins.sh index 5ad75ca1363..56a4fd6b806 100644 --- a/test/jdk/sun/security/pkcs11/Provider/MultipleLogins.sh +++ b/test/jdk/sun/security/pkcs11/Provider/MultipleLogins.sh @@ -26,6 +26,7 @@ # @summary # @library /test/lib/ # @build jdk.test.lib.util.ForceGC +# jdk.test.lib.Platform # @run shell MultipleLogins.sh # set a few environment variables so that the shell-script can run stand-alone diff --git a/test/jdk/sun/util/resources/cldr/TimeZoneNamesTest.java b/test/jdk/sun/util/resources/cldr/TimeZoneNamesTest.java index eb56c087ad6..a468f6b1f1b 100644 --- a/test/jdk/sun/util/resources/cldr/TimeZoneNamesTest.java +++ b/test/jdk/sun/util/resources/cldr/TimeZoneNamesTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2024, 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,10 @@ /* * @test - * @bug 8181157 8202537 8234347 8236548 8261279 + * @bug 8181157 8202537 8234347 8236548 8261279 8322647 * @modules jdk.localedata - * @summary Checks CLDR time zone names are generated correctly at runtime + * @summary Checks CLDR time zone names are generated correctly at + * either build or runtime * @run testng/othervm -Djava.locale.providers=CLDR TimeZoneNamesTest */ @@ -45,8 +46,8 @@ @Test public class TimeZoneNamesTest { - @DataProvider(name="noResourceTZs") - Object[][] data() { + @DataProvider + Object[][] sampleTZs() { return new Object[][] { // tzid, locale, style, expected @@ -174,11 +175,49 @@ Object[][] data() { "UTC+03:00", "heure : Istanbul", "UTC+03:00"}, + + // Short names derived from TZDB at build time + {"Europe/Lisbon", Locale.US, "Western European Standard Time", + "WET", + "Western European Summer Time", + "WEST", + "Western European Time", + "WET"}, + {"Atlantic/Azores", Locale.US, "Azores Standard Time", + "GMT-01:00", + "Azores Summer Time", + "GMT", + "Azores Time", + "GMT-01:00"}, + {"Australia/Perth", Locale.US, "Australian Western Standard Time", + "AWST", + "Australian Western Daylight Time", + "AWDT", + "Western Australia Time", + "AWT"}, + {"Africa/Harare", Locale.US, "Central Africa Time", + "CAT", + "Harare Daylight Time", + "CAT", + "Harare Time", + "CAT"}, + {"Europe/Dublin", Locale.US, "Greenwich Mean Time", + "GMT", + "Irish Standard Time", + "IST", + "Dublin Time", + "GMT"}, + {"Pacific/Gambier", Locale.US, "Gambier Time", + "GMT-09:00", + "Gambier Daylight Time", + "GMT-09:00", + "Gambier Time", + "GMT-09:00"}, }; } - @Test(dataProvider="noResourceTZs") + @Test(dataProvider="sampleTZs") public void test_tzNames(String tzid, Locale locale, String lstd, String sstd, String ldst, String sdst, String lgen, String sgen) { // Standard time assertEquals(TimeZone.getTimeZone(tzid).getDisplayName(false, TimeZone.LONG, locale), lstd); @@ -197,16 +236,14 @@ public void test_tzNames(String tzid, Locale locale, String lstd, String sstd, S @Test public void test_getZoneStrings() { assertFalse( - Arrays.stream(Locale.getAvailableLocales()) + Locale.availableLocales() .limit(30) .peek(l -> System.out.println("Locale: " + l)) .map(l -> DateFormatSymbols.getInstance(l).getZoneStrings()) - .flatMap(zs -> Arrays.stream(zs)) + .flatMap(Arrays::stream) .peek(names -> System.out.println(" tz: " + names[0])) - .flatMap(names -> Arrays.stream(names)) - .filter(name -> Objects.isNull(name) || name.isEmpty()) - .findAny() - .isPresent(), + .flatMap(Arrays::stream) + .anyMatch(name -> Objects.isNull(name) || name.isEmpty()), "getZoneStrings() returned array containing non-empty string element(s)"); } } diff --git a/test/jdk/tools/jar/InputFilesTest.java b/test/jdk/tools/jar/InputFilesTest.java index 3dc08293a76..6a0a7e29021 100644 --- a/test/jdk/tools/jar/InputFilesTest.java +++ b/test/jdk/tools/jar/InputFilesTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2023, 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 8165944 + * @bug 8165944 8318971 * @summary test several jar tool input file scenarios with variations on -C * options with/without a --release option. Some input files are * duplicates that sometimes cause exceptions and other times do not, @@ -153,6 +153,84 @@ public void test6() throws IOException { jar("cf test.jar --release 9 -C test1 a -C test2 a"); } + /** + * Containing non-existent file in the file list + * The final jar should not be created and correct error message should be caught. + * IOException is triggered as expected. + */ + @Test + public void testNonExistentFileInput() throws IOException { + touch("existingTestFile.txt"); + onCompletion = () -> rm("existingTestFile.txt"); + try { + jar("cf test.jar existingTestFile.txt nonExistentTestFile.txt"); + Assert.fail("jar tool unexpectedly completed successfully"); + } catch (IOException e) { + Assert.assertEquals(e.getMessage().trim(), "nonExistentTestFile.txt : no such file or directory"); + Assert.assertTrue(Files.notExists(Path.of("test.jar")), "Jar file should not be created."); + } + } + + /** + * With @File as a part of jar command line, where the File is containing one or more + * non-existent files or directories + * The final jar should not be created and correct error message should be caught. + * IOException is triggered as expected. + */ + @Test + public void testNonExistentFileInputClassList() throws IOException { + touch("existingTestFile.txt"); + touch("classes.list"); + Files.writeString(Path.of("classes.list"), """ + existingTestFile.txt + nonExistentTestFile.txt + nonExistentDirectory + """); + onCompletion = () -> rm("existingTestFile.txt classes.list"); + try { + jar("cf test.jar @classes.list"); + Assert.fail("jar tool unexpectedly completed successfully"); + } catch (IOException e) { + String msg = e.getMessage().trim(); + Assert.assertTrue(msg.contains("nonExistentTestFile.txt : no such file or directory")); + Assert.assertTrue(msg.trim().contains("nonExistentDirectory : no such file or directory")); + Assert.assertTrue(Files.notExists(Path.of("test.jar")), "Jar file should not be created."); + } + + } + + /** + * Create a jar file; then with @File as a part of jar command line, where the File is containing one or more + * non-existent files or directories + * The final jar should not be created and correct error message should be caught. + * IOException is triggered as expected. + */ + @Test + public void testUpdateNonExistentFileInputClassList() throws IOException { + touch("existingTestFileUpdate.txt"); + touch("existingTestFileUpdate2.txt"); + touch("classesUpdate.list"); + Files.writeString(Path.of("classesUpdate.list"), """ + existingTestFileUpdate2.txt + nonExistentTestFileUpdate.txt + nonExistentDirectoryUpdate + """); + onCompletion = () -> rm("existingTestFileUpdate.txt existingTestFileUpdate2.txt " + + "classesUpdate.list testUpdate.jar"); + try { + jar("cf testUpdate.jar existingTestFileUpdate.txt"); + Assert.assertTrue(Files.exists(Path.of("testUpdate.jar"))); + jar("uf testUpdate.jar @classesUpdate.list"); + Assert.fail("jar tool unexpectedly completed successfully"); + } catch (IOException e) { + String msg = e.getMessage().trim(); + Assert.assertFalse(msg.contains("existingTestFileUpdate.txt : no such file or directory")); + Assert.assertTrue(msg.contains("nonExistentTestFileUpdate.txt : no such file or directory")); + Assert.assertTrue(msg.trim().contains("nonExistentDirectoryUpdate : no such file or directory")); + } + + } + private Stream mkpath(String... args) { return Arrays.stream(args).map(d -> Paths.get(".", d.split("/"))); } diff --git a/test/jdk/tools/jlink/plugins/SystemModuleDescriptors/ModuleMainClassTest.java b/test/jdk/tools/jlink/plugins/SystemModuleDescriptors/ModuleMainClassTest.java new file mode 100644 index 00000000000..15207909a07 --- /dev/null +++ b/test/jdk/tools/jlink/plugins/SystemModuleDescriptors/ModuleMainClassTest.java @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2024, 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.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.spi.ToolProvider; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import jdk.test.lib.compiler.CompilerUtils; +import jdk.test.lib.util.FileUtils; + +import static jdk.test.lib.process.ProcessTools.*; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.BeforeAll; +import static org.junit.jupiter.api.Assertions.*; + +/** + * @test + * @bug 8322809 + * @library /test/lib + * @modules jdk.compiler jdk.jlink + * @build jdk.test.lib.compiler.CompilerUtils + * jdk.test.lib.process.ProcessTools + * jdk.test.lib.util.FileUtils + * ModuleMainClassTest + * @run junit ModuleMainClassTest + */ + +public class ModuleMainClassTest { + private static final String JAVA_HOME = System.getProperty("java.home"); + private static final String TEST_SRC = System.getProperty("test.src"); + + private static final Path SRC_DIR = Path.of(TEST_SRC, "src"); + private static final Path MODS_DIR = Path.of("mods"); + private static final Path JMODS_DIR = Path.of("jmods"); + + private static final Path IMAGE = Path.of("image"); + + // the module names are sorted by the plugin and so these names cover + // the cases that are before and after the elements of `jdk.*` modules + // with main classes + private static String[] modules = new String[] {"com.foo", "net.foo"}; + + private static boolean hasJmods() { + if (!Files.exists(Paths.get(JAVA_HOME, "jmods"))) { + System.err.println("Test skipped. NO jmods directory"); + return false; + } + return true; + } + + @BeforeAll + public static void compileAll() throws Throwable { + if (!hasJmods()) return; + + for (String mn : modules) { + Path msrc = SRC_DIR.resolve(mn); + assertTrue(CompilerUtils.compile(msrc, MODS_DIR, + "--module-source-path", SRC_DIR.toString(), + "--add-exports", "java.base/jdk.internal.module=" + mn)); + } + + if (Files.exists(IMAGE)) { + FileUtils.deleteFileTreeUnchecked(IMAGE); + } + + // create JMOD files + Files.createDirectories(JMODS_DIR); + Stream.of(modules).forEach(mn -> + assertTrue(jmod("create", + "--class-path", MODS_DIR.resolve(mn).toString(), + "--main-class", mn + ".Main", + JMODS_DIR.resolve(mn + ".jmod").toString()) == 0) + ); + + // the run-time image created will have 4 modules with main classes + createImage(IMAGE, "com.foo"); + } + + @Test + public void testComFoo() throws Throwable { + if (!hasJmods()) return; + + Path java = IMAGE.resolve("bin").resolve("java"); + assertTrue(executeProcess(java.toString(), + "-m", "com.foo") + .outputTo(System.out) + .errorTo(System.out) + .getExitValue() == 0); + } + + @Test + public void testNetFoo() throws Throwable { + if (!hasJmods()) return; + + Path java = IMAGE.resolve("bin").resolve("java"); + assertTrue(executeProcess(java.toString(), + "-m", "net.foo") + .outputTo(System.out) + .errorTo(System.out) + .getExitValue() == 0); + } + + static final ToolProvider JLINK_TOOL = ToolProvider.findFirst("jlink") + .orElseThrow(() -> new RuntimeException("jlink tool not found")); + + static final ToolProvider JMOD_TOOL = ToolProvider.findFirst("jmod") + .orElseThrow(() -> new RuntimeException("jmod tool not found")); + + private static void createImage(Path outputDir, String... modules) throws Throwable { + assertTrue(JLINK_TOOL.run(System.out, System.out, + "--output", outputDir.toString(), + "--add-modules", Arrays.stream(modules).collect(Collectors.joining(",")), + "--module-path", JMODS_DIR.toString()) == 0); + } + + private static int jmod(String... options) { + System.out.println("jmod " + Arrays.asList(options)); + return JMOD_TOOL.run(System.out, System.out, options); + } +} diff --git a/test/jdk/tools/jlink/plugins/SystemModuleDescriptors/src/com.foo/com/foo/Main.java b/test/jdk/tools/jlink/plugins/SystemModuleDescriptors/src/com.foo/com/foo/Main.java new file mode 100644 index 00000000000..f8b230647fa --- /dev/null +++ b/test/jdk/tools/jlink/plugins/SystemModuleDescriptors/src/com.foo/com/foo/Main.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2024, 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 com.foo; + +import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleFinder; +import java.util.stream.Stream; + +/** + * Sanity test if SystemModules pre-resolved at link-time for com.foo + * with main class is loaded properly. + */ +public class Main { + public static void main(String... args) throws Exception { + ModuleDescriptor md = Main.class.getModule().getDescriptor(); + System.out.println(md); + + checkMainClass("com.foo", "com.foo.Main"); + checkMainClass("net.foo", "net.foo.Main"); + Stream.of("jdk.httpserver", "jdk.jfr").forEach(mn -> + ModuleFinder.ofSystem().find(mn).get().descriptor().mainClass() + .orElseThrow(() -> new RuntimeException(mn + " no main class")) + ); + } + + static void checkMainClass(String mn, String mainClass) { + String cn = ModuleFinder.ofSystem().find(mn).get().descriptor().mainClass().get(); + if (!cn.equals(mainClass)) { + throw new RuntimeException("Mismatched main class of module " + mn + ": " + cn + " expected: " + mainClass); + } + } +} diff --git a/test/hotspot/jtreg/gc/stress/gclocker/libTestGCLocker.c b/test/jdk/tools/jlink/plugins/SystemModuleDescriptors/src/com.foo/module-info.java similarity index 67% rename from test/hotspot/jtreg/gc/stress/gclocker/libTestGCLocker.c rename to test/jdk/tools/jlink/plugins/SystemModuleDescriptors/src/com.foo/module-info.java index 2ac2064775c..99107602506 100644 --- a/test/hotspot/jtreg/gc/stress/gclocker/libTestGCLocker.c +++ b/test/jdk/tools/jlink/plugins/SystemModuleDescriptors/src/com.foo/module-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 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,15 +21,7 @@ * questions. */ -#include - -JNIEXPORT void JNICALL -Java_gc_stress_gclocker_GCLockerStresser_fillWithRandomValues(JNIEnv* env, jclass clz, jbyteArray arr) { - jsize size = (*env)->GetArrayLength(env, arr); - jbyte* p = (*env)->GetPrimitiveArrayCritical(env, arr, NULL); - jsize i; - for (i = 0; i < size; i++) { - p[i] = i % 128; - } - (*env)->ReleasePrimitiveArrayCritical(env, arr, p, 0); +module com.foo { + requires jdk.httpserver; + requires net.foo; } diff --git a/test/hotspot/jtreg/gc/stress/gclocker/TestGCLockerWithSerial.java b/test/jdk/tools/jlink/plugins/SystemModuleDescriptors/src/net.foo/module-info.java similarity index 60% rename from test/hotspot/jtreg/gc/stress/gclocker/TestGCLockerWithSerial.java rename to test/jdk/tools/jlink/plugins/SystemModuleDescriptors/src/net.foo/module-info.java index 9de8fa88ca7..360a989d9b3 100644 --- a/test/hotspot/jtreg/gc/stress/gclocker/TestGCLockerWithSerial.java +++ b/test/jdk/tools/jlink/plugins/SystemModuleDescriptors/src/net.foo/module-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 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 @@ -19,22 +19,8 @@ * 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.stress.gclocker; - -/* - * @test TestGCLockerWithSerial - * @library / - * @requires vm.gc.Serial - * @requires vm.flavor != "minimal" - * @summary Stress Serial's GC locker by calling GetPrimitiveArrayCritical while concurrently filling up old gen. - * @run main/native/othervm/timeout=200 -Xlog:gc*=info -Xms1500m -Xmx1500m -XX:+UseSerialGC gc.stress.gclocker.TestGCLockerWithSerial - */ -public class TestGCLockerWithSerial { - public static void main(String[] args) { - String[] testArgs = {"2", "Tenured Gen"}; - TestGCLocker.main(testArgs); - } +module net.foo { + requires jdk.jfr; } diff --git a/test/jdk/tools/jlink/plugins/SystemModuleDescriptors/src/net.foo/net/foo/Main.java b/test/jdk/tools/jlink/plugins/SystemModuleDescriptors/src/net.foo/net/foo/Main.java new file mode 100644 index 00000000000..c147923e75a --- /dev/null +++ b/test/jdk/tools/jlink/plugins/SystemModuleDescriptors/src/net.foo/net/foo/Main.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2024, 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 net.foo; + +import java.lang.module.ModuleDescriptor; +import java.lang.module.ModuleFinder; +import java.util.stream.Stream; + +/** + * Sanity test if SystemModules pre-resolved at link-time for net.foo + * with main class is loaded properly. + */ +public class Main { + public static void main(String... args) throws Exception { + ModuleDescriptor md = Main.class.getModule().getDescriptor(); + System.out.println(md); + + checkMainClass("com.foo", "com.foo.Main"); + checkMainClass("net.foo", "net.foo.Main"); + Stream.of("jdk.httpserver", "jdk.jfr").forEach(mn -> + ModuleFinder.ofSystem().find(mn).get().descriptor().mainClass() + .orElseThrow(() -> new RuntimeException(mn + " no main class")) + ); + } + + static void checkMainClass(String mn, String mainClass) { + String cn = ModuleFinder.ofSystem().find(mn).get().descriptor().mainClass().get(); + if (!cn.equals(mainClass)) { + throw new RuntimeException("Mismatched main class of module " + mn + ": " + cn + " expected: " + mainClass); + } + } + +} diff --git a/test/langtools/TEST.groups b/test/langtools/TEST.groups index 8e521a56e02..e1ffd5d530b 100644 --- a/test/langtools/TEST.groups +++ b/test/langtools/TEST.groups @@ -63,10 +63,13 @@ langtools_jdeps = \ tools/all \ tools/jdeps +# All tests + +all = \ + :langtools_all + langtools_all = \ - jdk \ - lib \ - tools + / # Tiered testing definitions diff --git a/test/langtools/jdk/internal/shellsupport/doc/JavadocHelperTest.java b/test/langtools/jdk/internal/shellsupport/doc/JavadocHelperTest.java index 48106face35..d8539b8c656 100644 --- a/test/langtools/jdk/internal/shellsupport/doc/JavadocHelperTest.java +++ b/test/langtools/jdk/internal/shellsupport/doc/JavadocHelperTest.java @@ -30,7 +30,7 @@ * jdk.compiler/com.sun.tools.javac.main * jdk.compiler/jdk.internal.shellsupport.doc * @build toolbox.ToolBox toolbox.JarTask toolbox.JavacTask - * @run testng/timeout=900/othervm JavadocHelperTest + * @run testng/timeout=900/othervm -Xmx1024m JavadocHelperTest */ import java.io.IOException; diff --git a/test/langtools/jdk/jshell/VariablesTest.java b/test/langtools/jdk/jshell/VariablesTest.java index 51ccbd17d60..98a543e77a9 100644 --- a/test/langtools/jdk/jshell/VariablesTest.java +++ b/test/langtools/jdk/jshell/VariablesTest.java @@ -23,7 +23,7 @@ /* * @test - * @bug 8144903 8177466 8191842 8211694 8213725 8239536 8257236 8252409 8294431 + * @bug 8144903 8177466 8191842 8211694 8213725 8239536 8257236 8252409 8294431 8322003 8322532 * @summary Tests for EvaluationState.variables * @library /tools/lib * @modules jdk.compiler/com.sun.tools.javac.api @@ -621,4 +621,21 @@ public void varAnonymousClassAndStaticField() { //JDK-8294431 assertEval("var obj = new Object() { public static final String msg = \"hello\"; };"); } + public void underscoreAsLambdaParameter() { //JDK-8322532 + assertAnalyze("Func f = _ -> 0; int i;", + "Func f = _ -> 0;", + " int i;", true); + } + + public void intersectionTypeAsTypeArgument() { //JDK-8322003 + assertEval("interface Shape {}"); + assertEval("record Square(int edge) implements Shape {}"); + assertEval("record Circle(int radius) implements Shape {}"); + assertEval("java.util.function.Consumer printShape = System.out::println;"); + assertEval("Square square = new Square(1);"); + assertEval("Circle circle = new Circle(1);"); + assertEval("var shapes = java.util.List.of(square, circle);"); + assertEval("shapes.forEach(printShape);"); + } + } diff --git a/test/langtools/tools/javac/StringConcat/StringConcatWithAssignments.java b/test/langtools/tools/javac/StringConcat/StringConcatWithAssignments.java new file mode 100644 index 00000000000..468c46fea86 --- /dev/null +++ b/test/langtools/tools/javac/StringConcat/StringConcatWithAssignments.java @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2024, 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 + * @compile StringConcatWithAssignments.java + * @run main StringConcatWithAssignments + * @compile -XDstringConcat=inline StringConcatWithAssignments.java + * @run main StringConcatWithAssignments + * @compile -XDstringConcat=indy StringConcatWithAssignments.java + * @run main StringConcatWithAssignments + * @compile -XDstringConcat=indyWithConstants StringConcatWithAssignments.java + * @run main StringConcatWithAssignments + */ + +import java.util.Objects; +import java.util.function.Supplier; + +public class StringConcatWithAssignments { + public static void main(String[] args) { + StringConcatWithAssignments instance = new StringConcatWithAssignments(); + assertEquals("nulltrue", instance.assignment()); + assertEquals("nulltrue", instance.invocation()); + } + private String assignment() { + boolean b; + return ((((b = true) ? null : null) + "") + b); + } + private String invocation() { + StringBuilder sideEffect = new StringBuilder(); + Supplier provider = () -> { + sideEffect.append(true); + return true; + }; + return (((provider.get() ? null : null) + "") + sideEffect.toString()); + } + private static void assertEquals(Object o1, Object o2) { + if (!Objects.equals(o1, o2)) { + throw new AssertionError("Expected that '" + o1 + "' and " + + "'" + o2 + "' are equal."); + } + } +} diff --git a/test/langtools/tools/javac/classfiles/attributes/LineNumberTable/T8314275.java b/test/langtools/tools/javac/classfiles/attributes/LineNumberTable/T8314275.java new file mode 100644 index 00000000000..07a1e7c7575 --- /dev/null +++ b/test/langtools/tools/javac/classfiles/attributes/LineNumberTable/T8314275.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2024, 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 8314275 + * @summary Tests a line number table attribute for switch expression + * @library /tools/lib /tools/javac/lib ../lib + * @enablePreview + * @modules jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.main + * jdk.compiler/com.sun.tools.javac.util + * java.base/jdk.internal.classfile.impl + * @build toolbox.ToolBox InMemoryFileManager TestBase + * @build LineNumberTestBase TestCase + * @run main T8314275 + */ +import java.util.List; +public class T8314275 extends LineNumberTestBase { + public static void main(String[] args) throws Exception { + new T8314275().test(); + } + + public void test() throws Exception { + test(List.of(TEST_CASE)); + } + + private static final TestCase[] TEST_CASE = new TestCase[] { + new TestCase(""" + public class T8314275Expression { // 1 + private static double multiply(Integer i) { // 2 + double cr = 15; // 3 + cr = switch (i) { // 4 + case 1 -> cr * 1; // 5 + case 2 -> cr * 2; // 6 + default -> cr * 4; // 7 + }; // 8 + return cr; // 9 + } //10 + } //11 + """, + List.of(1, 3, 4, 5, 6, 7, 8, 9), + "T8314275Expression"), + new TestCase(""" + public class T8314275Statement { // 1 + private static double multiply(Integer i) { // 2 + double cr = 15; // 3 + switch (i) { // 4 + case 1: cr *= 1; break; // 5 + case 2: cr *= 2; break; // 6 + default: cr *= 4; // 7 + }; // 8 + return cr; // 9 + } //10 + } //11 + """, + List.of(1, 3, 4, 5, 6, 7, 9), + "T8314275Statement") + }; +} \ No newline at end of file diff --git a/test/langtools/tools/javac/recovery/AttrRecovery.java b/test/langtools/tools/javac/recovery/AttrRecovery.java index 607575b291f..2ab92a625d0 100644 --- a/test/langtools/tools/javac/recovery/AttrRecovery.java +++ b/test/langtools/tools/javac/recovery/AttrRecovery.java @@ -23,7 +23,7 @@ /* * @test - * @bug 8301580 + * @bug 8301580 8322159 * @summary Verify error recovery w.r.t. Attr * @library /tools/lib * @enablePreview @@ -87,4 +87,41 @@ class C { } } + @Test + public void testX() throws Exception { + String code = """ + public class C { + public C() { + Undefined.method(); + undefined1(); + Runnable r = this::undefined2; + overridable(this); //to verify ThisEscapeAnalyzer has been run + } + public void overridable(C c) {} + } + """; + Path curPath = Path.of("."); + List actual = new JavacTask(tb) + .options("-XDrawDiagnostics", "-XDdev", + "-XDshould-stop.at=FLOW", "-Xlint:this-escape") + .sources(code) + .outdir(curPath) + .run(Expect.FAIL) + .writeAll() + .getOutputLines(OutputKind.DIRECT); + + List expected = List.of( + "C.java:3:9: compiler.err.cant.resolve.location: kindname.variable, Undefined, , , (compiler.misc.location: kindname.class, C, null)", + "C.java:4:9: compiler.err.cant.resolve.location.args: kindname.method, undefined1, , , (compiler.misc.location: kindname.class, C, null)", + "C.java:5:22: compiler.err.invalid.mref: kindname.method, (compiler.misc.cant.resolve.location.args: kindname.method, undefined2, , , (compiler.misc.location: kindname.class, C, null))", + "C.java:6:20: compiler.warn.possible.this.escape", + "3 errors", + "1 warning" + ); + + if (!Objects.equals(actual, expected)) { + error("Expected: " + expected + ", but got: " + actual); + } + } + } diff --git a/test/langtools/tools/javac/switchexpr/ExpressionSwitch.java b/test/langtools/tools/javac/switchexpr/ExpressionSwitch.java index b5c94d3ce94..1c040052e69 100644 --- a/test/langtools/tools/javac/switchexpr/ExpressionSwitch.java +++ b/test/langtools/tools/javac/switchexpr/ExpressionSwitch.java @@ -1,12 +1,12 @@ /* * @test /nodynamiccopyright/ - * @bug 8206986 8222169 8224031 8240964 8267119 8268670 + * @bug 8206986 8222169 8224031 8240964 8267119 8268670 8321582 * @summary Check expression switch works. - * @compile/fail/ref=ExpressionSwitch-old.out --release 9 -XDrawDiagnostics ExpressionSwitch.java * @compile ExpressionSwitch.java * @run main ExpressionSwitch */ +// * @compile/fail/ref=ExpressionSwitch-old.out --release 9 -XDrawDiagnostics ExpressionSwitch.java import java.util.Objects; import java.util.function.Supplier; @@ -35,6 +35,16 @@ private void run() { localClass(T.A); assertEquals(castSwitchExpressions(T.A), "A"); testTypeInference(true, 0); + assertEquals(yieldPrimitiveDotClass("byte"), byte.class); + assertEquals(yieldPrimitiveDotClass("char"), char.class); + assertEquals(yieldPrimitiveDotClass("short"), short.class); + assertEquals(yieldPrimitiveDotClass("int"), int.class); + assertEquals(yieldPrimitiveDotClass("long"), long.class); + assertEquals(yieldPrimitiveDotClass("float"), float.class); + assertEquals(yieldPrimitiveDotClass("double"), double.class); + assertEquals(yieldPrimitiveDotClass("void"), void.class); + assertEquals(yieldPrimitiveDotClass("boolean"), boolean.class); + assertEquals(yieldPrimitiveDotClass("other"), null); } private String print(T t) { @@ -140,6 +150,21 @@ private boolean yieldUnaryNotOperator(String s, boolean b) { }; } + private Class yieldPrimitiveDotClass(String s) { + return switch (s) { + case "byte": yield byte.class; + case "char": yield char.class; + case "short": yield short.class; + case "int": yield int.class; + case "long": yield long.class; + case "float": yield float.class; + case "double": yield double.class; + case "void": yield void.class; + case "boolean": yield boolean.class; + default: yield null; + }; + } + private void localClass(T t) { String good = "good"; class L { diff --git a/test/lib-test/TEST.groups b/test/lib-test/TEST.groups index eb0c9b317ae..85067f310b1 100644 --- a/test/lib-test/TEST.groups +++ b/test/lib-test/TEST.groups @@ -1,5 +1,5 @@ # -# Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2020, 2024, 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,4 +21,15 @@ # questions. # -tier1 = . +# All tests + +all = \ + :libtest_all + +libtest_all = \ + / + +# Tiered testing definitions + +tier1 = \ + :all diff --git a/test/lib-test/jdk/test/lib/TestMutuallyExclusivePlatformPredicates.java b/test/lib-test/jdk/test/lib/TestMutuallyExclusivePlatformPredicates.java index 355cd8ac200..f8ce856bddd 100644 --- a/test/lib-test/jdk/test/lib/TestMutuallyExclusivePlatformPredicates.java +++ b/test/lib-test/jdk/test/lib/TestMutuallyExclusivePlatformPredicates.java @@ -53,7 +53,7 @@ private static enum MethodGroup { IGNORED("isEmulatedClient", "isDebugBuild", "isFastDebugBuild", "isMusl", "isSlowDebugBuild", "hasSA", "isRoot", "isTieredSupported", "areCustomLoadersSupportedForCDS", "isDefaultCDSArchiveSupported", - "isHardenedOSX", "hasOSXPlistEntries"); + "isHardenedOSX", "hasOSXPlistEntries", "isOracleLinux7"); public final List methodNames; diff --git a/test/lib/jdk/test/lib/Platform.java b/test/lib/jdk/test/lib/Platform.java index 25cb8bc3d1e..92663c65d0f 100644 --- a/test/lib/jdk/test/lib/Platform.java +++ b/test/lib/jdk/test/lib/Platform.java @@ -33,6 +33,7 @@ import java.security.AccessController; import java.security.PrivilegedAction; import java.util.concurrent.TimeUnit; +import java.util.regex.Matcher; import java.util.regex.Pattern; public class Platform { @@ -348,6 +349,20 @@ private static boolean isArch(String archnameRE) { .matches(); } + public static boolean isOracleLinux7() { + if (System.getProperty("os.name").toLowerCase().contains("linux") && + System.getProperty("os.version").toLowerCase().contains("el")) { + Pattern p = Pattern.compile("el(\\d+)"); + Matcher m = p.matcher(System.getProperty("os.version")); + if (m.find()) { + try { + return Integer.parseInt(m.group(1)) <= 7; + } catch (NumberFormatException nfe) {} + } + } + return false; + } + /** * Returns file extension of shared library, e.g. "so" on linux, "dll" on windows. * @return file extension diff --git a/test/lib/jdk/test/lib/containers/docker/DockerfileConfig.java b/test/lib/jdk/test/lib/containers/docker/DockerfileConfig.java index 37db2e8053e..9d73ad185f1 100644 --- a/test/lib/jdk/test/lib/containers/docker/DockerfileConfig.java +++ b/test/lib/jdk/test/lib/containers/docker/DockerfileConfig.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2024, 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 @@ -63,6 +63,11 @@ public static String getBaseImageVersion() { return version; } + // Ubuntu 22.04 ppc started to crash in libz inflateReset on Power8 based host + // those recent Ubuntu versions only work on Power9+ + if (Platform.isPPC()) { + return "20.04"; + } return "latest"; } } diff --git a/test/micro/org/openjdk/bench/vm/compiler/x86/ComputePI.java b/test/micro/org/openjdk/bench/vm/compiler/x86/ComputePI.java deleted file mode 100644 index 7d8e479172e..00000000000 --- a/test/micro/org/openjdk/bench/vm/compiler/x86/ComputePI.java +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright (c) 2023, 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.vm.compiler; - -import org.openjdk.jmh.annotations.Benchmark; -import org.openjdk.jmh.annotations.BenchmarkMode; -import org.openjdk.jmh.annotations.Fork; -import org.openjdk.jmh.annotations.Measurement; -import org.openjdk.jmh.annotations.Mode; -import org.openjdk.jmh.annotations.OutputTimeUnit; -import org.openjdk.jmh.annotations.Scope; -import org.openjdk.jmh.annotations.Setup; -import org.openjdk.jmh.annotations.State; -import org.openjdk.jmh.annotations.Warmup; - -import java.util.concurrent.TimeUnit; - -@State(Scope.Thread) -@BenchmarkMode(Mode.AverageTime) -@OutputTimeUnit(TimeUnit.NANOSECONDS) -@Warmup(iterations = 5, time = 5, timeUnit = TimeUnit.SECONDS) -@Measurement(iterations = 5, time = 5, timeUnit = TimeUnit.SECONDS) -@Fork(value = 3) -public class ComputePI { - - @Benchmark - public double compute_pi_int_dbl() { - double pi = 4.0; - boolean sign = false; - - for (int i = 3; i < 1000; i += 2) { - if (sign) { - pi += 4.0 / i; - } else { - pi -= 4.0 / i; - } - sign = !sign; - } - return pi; - } - - @Benchmark - public double compute_pi_int_flt() { - float pi = 4.0f; - boolean sign = false; - - for (int i = 3; i < 1000; i += 2) { - if (sign) { - pi += 4.0f / i; - } else { - pi -= 4.0f / i; - } - sign = !sign; - } - return pi; - } - - @Benchmark - public double compute_pi_long_dbl() { - double pi = 4.0; - boolean sign = false; - - for (long i = 3; i < 1000; i += 2) { - if (sign) { - pi += 4.0 / i; - } else { - pi -= 4.0 / i; - } - sign = !sign; - } - return pi; - } - - @Benchmark - public double compute_pi_long_flt() { - float pi = 4.0f; - boolean sign = false; - - for (long i = 3; i < 1000; i += 2) { - if (sign) { - pi += 4.0f / i; - } else { - pi -= 4.0f / i; - } - sign = !sign; - } - return pi; - } - - @Benchmark - public double compute_pi_flt_dbl() { - double pi = 4.0; - boolean sign = false; - - for (float i = 3.0f; i < 1000.0f; i += 2.0f) { - if (sign) { - pi += 4.0 / i; - } else { - pi -= 4.0 / i; - } - sign = !sign; - } - return pi; - } - - @Benchmark - public double compute_pi_dbl_flt() { - float pi = 4.0f; - boolean sign = false; - - for (float i = 3.0f; i < 1000.0f; i += 2.0f) { - if (sign) { - pi += 4.0f / i; - } else { - pi -= 4.0f / i; - } - sign = !sign; - } - return pi; - } -}