From 278de7acd21cc6f938aca561d02248e75c119e11 Mon Sep 17 00:00:00 2001 From: Maurizio Cimadamore Date: Wed, 18 Oct 2023 17:02:51 +0000 Subject: [PATCH 001/124] 8318458: Update javac and java manpages with restricted method options Reviewed-by: iris --- src/java.base/share/man/java.1 | 23 +++++++++++++++++++---- src/jdk.compiler/share/man/javac.1 | 2 ++ 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/src/java.base/share/man/java.1 b/src/java.base/share/man/java.1 index fdc35b26280..a72da6d7c11 100644 --- a/src/java.base/share/man/java.1 +++ b/src/java.base/share/man/java.1 @@ -521,6 +521,20 @@ Allows classes to depend on \f[B]preview features\f[R] [https://docs.oracle.com/en/java/javase/12/language/index.html#JSLAN-GUID-5A82FE0E-0CA4-4F1F-B075-564874FE2823] of the release. .TP +\f[V]--enable-native-access\f[R] \f[I]module\f[R][\f[V],\f[R]\f[I]module\f[R]...] +Native access involves access to code or data outside the Java runtime. +This is generally unsafe and, if done incorrectly, might crash the JVM +or result in memory corruption. +Methods that provide native access are restricted, and by default their +use causes warnings. +This option allows code in the specified modules to use restricted +methods without warnings. +\f[I]module\f[R] can be \f[V]ALL-UNNAMED\f[R] to indicate code on the +class path. +When this option is present, any use of restricted methods by code +outside the specified modules causes an +\f[V]IllegalCallerException\f[R]. +.TP \f[V]--finalization=\f[R]\f[I]value\f[R] Controls whether the JVM performs finalization of objects. Valid values are \[dq]enabled\[dq] and \[dq]disabled\[dq]. @@ -555,7 +569,7 @@ list; on other platforms it is a colon (\f[V]:\f[R]). .TP \f[V]--add-modules\f[R] \f[I]module\f[R][\f[V],\f[R]\f[I]module\f[R]...] Specifies the root modules to resolve in addition to the initial module. -\f[I]module\f[R] also can be \f[V]ALL-DEFAULT\f[R], +\f[I]module\f[R] can also be \f[V]ALL-DEFAULT\f[R], \f[V]ALL-SYSTEM\f[R], and \f[V]ALL-MODULE-PATH\f[R]. .TP \f[V]--list-modules\f[R] @@ -1117,13 +1131,14 @@ This option is similar to \f[V]-XX:ThreadStackSize\f[R]. \f[V]--add-reads\f[R] \f[I]module\f[R]\f[V]=\f[R]\f[I]target-module\f[R](\f[V],\f[R]\f[I]target-module\f[R])* Updates \f[I]module\f[R] to read the \f[I]target-module\f[R], regardless of the module declaration. -\f[I]target-module\f[R] can be all unnamed to read all unnamed modules. +\f[I]target-module\f[R] can be \f[V]ALL-UNNAMED\f[R] to read all unnamed +modules. .TP \f[V]--add-exports\f[R] \f[I]module\f[R]\f[V]/\f[R]\f[I]package\f[R]\f[V]=\f[R]\f[I]target-module\f[R](\f[V],\f[R]\f[I]target-module\f[R])* Updates \f[I]module\f[R] to export \f[I]package\f[R] to \f[I]target-module\f[R], regardless of module declaration. -The \f[I]target-module\f[R] can be all unnamed to export to all unnamed -modules. +\f[I]target-module\f[R] can be \f[V]ALL-UNNAMED\f[R] to export to all +unnamed modules. .TP \f[V]--add-opens\f[R] \f[I]module\f[R]\f[V]/\f[R]\f[I]package\f[R]\f[V]=\f[R]\f[I]target-module\f[R](\f[V],\f[R]\f[I]target-module\f[R])* Updates \f[I]module\f[R] to open \f[I]package\f[R] to diff --git a/src/jdk.compiler/share/man/javac.1 b/src/jdk.compiler/share/man/javac.1 index b5b6bf026b0..30b260ac648 100644 --- a/src/jdk.compiler/share/man/javac.1 +++ b/src/jdk.compiler/share/man/javac.1 @@ -759,6 +759,8 @@ processing. \f[V]removal\f[R]: Warns about the use of an API that has been marked for removal. .IP \[bu] 2 +\f[V]restricted\f[R]: Warns about the use of restricted methods. +.IP \[bu] 2 \f[V]requires-automatic\f[R]: Warns developers about the use of automatic modules in requires clauses. .IP \[bu] 2 From ab135683a6ba54c6d82a23a30abb154b92ba855e Mon Sep 17 00:00:00 2001 From: Mikhailo Seledtsov Date: Wed, 18 Oct 2023 18:05:00 +0000 Subject: [PATCH 002/124] 8318029: Minor improvement to logging output in container at-requires Reviewed-by: iklam --- test/jtreg-ext/requires/VMProps.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/jtreg-ext/requires/VMProps.java b/test/jtreg-ext/requires/VMProps.java index 94015b4fd08..7c5bfd6ab75 100644 --- a/test/jtreg-ext/requires/VMProps.java +++ b/test/jtreg-ext/requires/VMProps.java @@ -610,7 +610,7 @@ private boolean checkDockerSupport() throws IOException, InterruptedException { log("checkDockerSupport(): entering"); ProcessBuilder pb = new ProcessBuilder("which", Container.ENGINE_COMMAND); Map logFileNames = - redirectOutputToLogFile("checkDockerSupport(): which ", + redirectOutputToLogFile("checkDockerSupport(): which " + Container.ENGINE_COMMAND, pb, "which-container"); Process p = pb.start(); p.waitFor(10, TimeUnit.SECONDS); From ce8ebebc77f4ef73852364f6188b43c482337350 Mon Sep 17 00:00:00 2001 From: Naoto Sato Date: Wed, 18 Oct 2023 18:26:49 +0000 Subject: [PATCH 003/124] 8317979: Use TZ database style abbreviations in the CLDR locale provider Reviewed-by: rriggs, joehw, lancea, erikj, iris, ihse --- .../tools/cldrconverter/CLDRConverter.java | 145 +++++++++++++++++- make/modules/jdk.localedata/Gensrc.gmk | 6 +- .../test/java/time/format/TestUTCParse.java | 10 +- .../util/TimeZone/CLDRDisplayNamesTest.java | 16 +- test/jdk/sun/text/resources/LocaleData.cldr | 4 +- .../sun/text/resources/LocaleDataTest.java | 2 +- 6 files changed, 160 insertions(+), 23 deletions(-) diff --git a/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java b/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java index 49ed1c3aaa8..b6298c00c9a 100644 --- a/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java +++ b/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java @@ -30,7 +30,6 @@ import java.io.IOException; import java.io.UncheckedIOException; import java.nio.file.*; -import java.text.MessageFormat; import java.time.*; import java.util.*; import java.util.ResourceBundle.Control; @@ -92,6 +91,12 @@ public class CLDRConverter { static final String[] EMPTY_ZONE = {"", "", "", "", "", ""}; static final String META_ETCUTC_ZONE_NAME = "ETC_UTC"; + // constants used for TZDB short names + private static final String NBSP = "\u00A0"; + private static final String STD = "std"; + private static final String DST = "dst"; + private static final String NO_SUBST = "-"; + private static SupplementDataParseHandler handlerSuppl; private static LikelySubtagsParseHandler handlerLikelySubtags; private static WinZonesParseHandler handlerWinZones; @@ -123,6 +128,10 @@ public class CLDRConverter { static Map pluralRules; static Map dayPeriodRules; + // TZDB Short Names Map + private static final Map tzdbShortNamesMap = HashMap.newHashMap(512); + private static final Map tzdbSubstLetters = HashMap.newHashMap(512); + static enum DraftType { UNCONFIRMED, PROVISIONAL, @@ -284,6 +293,9 @@ public static void main(String[] args) throws Exception { pluralRules = generateRules(handlerPlurals); dayPeriodRules = generateRules(handlerDayPeriodRule); + // TZDB short names map + generateTZDBShortNamesMap(); + List bundles = readBundleList(); convertBundles(bundles); @@ -757,21 +769,25 @@ private static Map extractZoneNames(Map map, Str .orElse(tzid); Object data = map.get(TIMEZONE_ID_PREFIX + tzKey); - if (data instanceof String[]) { + if (data instanceof String[] tznames) { // Hack for UTC. UTC is an alias to Etc/UTC in CLDR if (tzid.equals("Etc/UTC") && !map.containsKey(TIMEZONE_ID_PREFIX + "UTC")) { - names.put(METAZONE_ID_PREFIX + META_ETCUTC_ZONE_NAME, data); + names.put(METAZONE_ID_PREFIX + META_ETCUTC_ZONE_NAME, tznames); names.put(tzid, META_ETCUTC_ZONE_NAME); names.put("UTC", META_ETCUTC_ZONE_NAME); } else { - names.put(tzid, data); + // TZDB short names + fillTZDBShortNames(tzid, tznames); + names.put(tzid, tznames); } } else { String meta = handlerMetaZones.get(tzKey); if (meta != null) { String metaKey = METAZONE_ID_PREFIX + meta; data = map.get(metaKey); - if (data instanceof String[]) { + if (data instanceof String[] tznames) { + // TZDB short names + fillTZDBShortNames(tzid, tznames); // Keep the metazone prefix here. names.put(metaKey, data); names.put(tzid, meta); @@ -1246,6 +1262,125 @@ private static Map coverageLevelsMap() throws Exception { return covMap; } + /* + * Generates two maps from TZ database files, where they have usual abbreviation + * of the time zone names as "FORMAT". + * + * `tzdbShortNamesMap` maps the time zone id, such as "America/Los_Angeles" to + * its FORMAT and Rule which determines the substitution. In "America/Los_Angeles" + * case, its FORMAT is "P%sT" and the Rule is "US". They are concatenated with + * an NBSP, so the eventual mapping will be: + * + * "America/Los_Angeles" -> "P%sTUS" + * + * The other map, `tzdbSubstLetters` maps the Rule to its substitution letters. + * The key of the map is the Rule name, appended with "std" or "dst" + * depending on the savings, e.g., + * + * "USstd" -> "S" + * "USdst" -> "D" + * + * These two mappings resolve the short names for time zones in each type, + * such as: + * + * Standard short name for "America/Los_Angeles" -> "PST" + * DST short name for "America/Los_Angeles" -> "PDT" + * Generic short name for "America/Los_Angeles" -> "PT" + */ + private static void generateTZDBShortNamesMap() throws IOException { + Files.walk(Path.of(tzDataDir), 1, FileVisitOption.FOLLOW_LINKS) + .filter(p -> p.toFile().isFile()) + .forEach(p -> { + try { + String zone = null; + String rule = null; + String format = null; + for (var line : Files.readAllLines(p)) { + if (line.contains("#STDOFF")) continue; + line = line.replaceAll("[ \t]*#.*", ""); + + // Zone line + if (line.startsWith("Zone")) { + var zl = line.split("[ \t]+", -1); + zone = zl[1]; + rule = zl[3]; + format = zl[4]; + } else { + if (zone != null) { + if (line.isBlank()) { + tzdbShortNamesMap.put(zone, format + NBSP + rule); + zone = null; + rule = null; + format = null; + } else { + var s = line.split("[ \t]+", -1); + rule = s[2]; + format = s[3]; + } + } + } + + // Rule line + if (line.startsWith("Rule")) { + var rl = line.split("[ \t]+", -1); + tzdbSubstLetters.put(rl[1] + NBSP + (rl[8].equals("0") ? STD : DST), + rl[9].replace(NO_SUBST, "")); + } + } + } catch (IOException ioe) { + throw new UncheckedIOException(ioe); + } + }); + } + + /* + * Fill the TZDB short names if there is no name provided by the CLDR + */ + private static void fillTZDBShortNames(String tzid, String[] names) { + var val = tzdbShortNamesMap.get(tzid); + if (val != null) { + var format = val.split(NBSP)[0]; + var rule = val.split(NBSP)[1]; + IntStream.of(1, 3, 5).forEach(i -> { + if (names[i] == null) { + if (format.contains("%s")) { + names[i] = switch (i) { + case 1 -> format.formatted(tzdbSubstLetters.get(rule + NBSP + STD)); + case 3 -> format.formatted(tzdbSubstLetters.get(rule + NBSP + DST)); + case 5 -> format.formatted(""); + default -> throw new InternalError(); + }; + } else if (format.contains("/")) { // such as "+08/+09" or "GMT/BST" + names[i] = switch (i) { + case 1, 5 -> convertGMTName(format.substring(0, format.indexOf("/"))); + case 3 -> convertGMTName(format.substring(format.indexOf("/") + 1)); + default -> throw new InternalError(); + }; + } else { + names[i] = convertGMTName(format); + } + } + }); + } + } + + /* + * Convert TZDB offsets to JDK's offsets, eg, "-08" to "GMT-08:00". + * If it cannot recognize the pattern, return the argument as is. + */ + private static String convertGMTName(String f) { + try { + // Should pre-fill GMT format once COMPAT is gone. + // Till then, fall back to GMT format at runtime, after COMPAT short + // names are populated + ZoneOffset.of(f); + return null; + } catch (DateTimeException dte) { + // textual representation. return as is + } + return f; + } + // for debug static void dumpMap(Map map) { map.entrySet().stream() diff --git a/make/modules/jdk.localedata/Gensrc.gmk b/make/modules/jdk.localedata/Gensrc.gmk index fc0e09dd8bb..df6400b16b1 100644 --- a/make/modules/jdk.localedata/Gensrc.gmk +++ b/make/modules/jdk.localedata/Gensrc.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2014, 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 @@ -36,6 +36,7 @@ TARGETS += $(GENSRC_LOCALEDATA) CLDR_DATA_DIR := $(TOPDIR)/make/data/cldr/common GENSRC_DIR := $(SUPPORT_OUTPUTDIR)/gensrc/jdk.localedata CLDR_GEN_DONE := $(GENSRC_DIR)/_cldr-gensrc.marker +TZ_DATA_DIR := $(TOPDIR)/src/java.base/share/data/tzdata $(CLDR_GEN_DONE): $(wildcard $(CLDR_DATA_DIR)/dtd/*.dtd) \ $(wildcard $(CLDR_DATA_DIR)/main/*.xml) \ @@ -47,7 +48,8 @@ $(CLDR_GEN_DONE): $(wildcard $(CLDR_DATA_DIR)/dtd/*.dtd) \ $(TOOL_CLDRCONVERTER) -base $(CLDR_DATA_DIR) \ -baselocales "en-US" \ -year $(COPYRIGHT_YEAR) \ - -o $(GENSRC_DIR)) + -o $(GENSRC_DIR) \ + -tzdatadir $(TZ_DATA_DIR)) $(TOUCH) $@ TARGETS += $(CLDR_GEN_DONE) 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 3f991810f8b..6da94f04f04 100644 --- a/test/jdk/java/time/test/java/time/format/TestUTCParse.java +++ b/test/jdk/java/time/test/java/time/format/TestUTCParse.java @@ -23,7 +23,7 @@ /* * @test * @modules jdk.localedata - * @bug 8303440 + * @bug 8303440 8317979 * @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/Los_Angeles" - // produces "UTC\u212208:00" + // Assuming CLDR's SHORT name for "America/Juneau" + // produces "UTC\u212209: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/Los_Angeles")); + var zdt = ZonedDateTime.of(2023, 3, 3, 0, 0, 0, 0, ZoneId.of("America/Juneau")); var formatted = fmt.format(zdt); - assertEquals(formatted, "UTC\u221208:00"); + assertEquals(formatted, "UTC\u221209:00"); assertEquals(fmt.parse(formatted).query(TemporalQueries.zoneId()), zdt.getZone()); } diff --git a/test/jdk/java/util/TimeZone/CLDRDisplayNamesTest.java b/test/jdk/java/util/TimeZone/CLDRDisplayNamesTest.java index 67a082410ec..2ff278a583c 100644 --- a/test/jdk/java/util/TimeZone/CLDRDisplayNamesTest.java +++ b/test/jdk/java/util/TimeZone/CLDRDisplayNamesTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -24,7 +24,7 @@ /* * @test * @bug 8005471 8008577 8129881 8130845 8136518 8181157 8210490 8220037 - * 8234347 8236548 + * 8234347 8236548 8317979 * @modules jdk.localedata * @run main/othervm -Djava.locale.providers=CLDR CLDRDisplayNamesTest * @summary Make sure that localized time zone names of CLDR are used @@ -48,27 +48,27 @@ public class CLDRDisplayNamesTest { { "ja-JP", "\u30a2\u30e1\u30ea\u30ab\u592a\u5e73\u6d0b\u6a19\u6e96\u6642", - "GMT-08:00", + "PST", "\u30a2\u30e1\u30ea\u30ab\u592a\u5e73\u6d0b\u590f\u6642\u9593", - "GMT-07:00", + "PDT", //"\u30a2\u30e1\u30ea\u30ab\u592a\u5e73\u6d0b\u6642\u9593", //"PT" }, { "zh-CN", "\u5317\u7f8e\u592a\u5e73\u6d0b\u6807\u51c6\u65f6\u95f4", - "GMT-08:00", + "PST", "\u5317\u7f8e\u592a\u5e73\u6d0b\u590f\u4ee4\u65f6\u95f4", - "GMT-07:00", + "PDT", //"\u5317\u7f8e\u592a\u5e73\u6d0b\u65f6\u95f4", //"PT", }, { "de-DE", "Nordamerikanische Westk\u00fcsten-Normalzeit", - "GMT-08:00", + "PST", "Nordamerikanische Westk\u00fcsten-Sommerzeit", - "GMT-07:00", + "PDT", //"Nordamerikanische Westk\u00fcstenzeit", //"PT", }, diff --git a/test/jdk/sun/text/resources/LocaleData.cldr b/test/jdk/sun/text/resources/LocaleData.cldr index 21f1d016cfc..a6b62961a07 100644 --- a/test/jdk/sun/text/resources/LocaleData.cldr +++ b/test/jdk/sun/text/resources/LocaleData.cldr @@ -5240,9 +5240,9 @@ FormatData/de/TimePatterns/0=HH:mm:ss zzzz FormatData/fi/AmPmMarkers/0=ap. FormatData/fi/AmPmMarkers/1=ip. -# bug 6507067 +# bug 6507067 8317979 TimeZoneNames/zh_TW/Asia\/Taipei/1=\u53f0\u5317\u6a19\u6e96\u6642\u9593 -TimeZoneNames/zh_TW/Asia\/Taipei/2= +TimeZoneNames/zh_TW/Asia\/Taipei/2=CST # bug 6645271 FormatData/hr_HR/DatePatterns/2=d. MMM y. diff --git a/test/jdk/sun/text/resources/LocaleDataTest.java b/test/jdk/sun/text/resources/LocaleDataTest.java index 2d76ca9e2ea..0d40ef9bde0 100644 --- a/test/jdk/sun/text/resources/LocaleDataTest.java +++ b/test/jdk/sun/text/resources/LocaleDataTest.java @@ -41,7 +41,7 @@ * 8187946 8195478 8181157 8179071 8193552 8202026 8204269 8202537 8208746 * 8209775 8221432 8227127 8230284 8231273 8233579 8234288 8250665 8255086 * 8251317 8274658 8283277 8283805 8265315 8287868 8295564 8284840 8296715 - * 8301206 8303472 + * 8301206 8303472 8317979 * @summary Verify locale data * @modules java.base/sun.util.resources * @modules jdk.localedata From e25a49a993f270c33f7929e629fb3075a11fdec9 Mon Sep 17 00:00:00 2001 From: "Daniel D. Daugherty" Date: Wed, 18 Oct 2023 20:20:39 +0000 Subject: [PATCH 004/124] 8318471: ProblemList compiler/sharedstubs/SharedTrampolineTest.java Reviewed-by: lmesnik --- test/hotspot/jtreg/ProblemList.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index c81d2825562..d2f024e193b 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -73,6 +73,8 @@ compiler/vectorapi/VectorLogicalOpIdentityTest.java 8302459 linux-x64,windows-x6 compiler/jvmci/TestUncaughtErrorInCompileMethod.java 8309073 generic-all +compiler/sharedstubs/SharedTrampolineTest.java 8318455 generic-all + ############################################################################# # :hotspot_gc From 24bc5bd104b8b4b96a61cffd3ec35cc795744eb9 Mon Sep 17 00:00:00 2001 From: Abhishek Kumar Date: Thu, 19 Oct 2023 04:21:45 +0000 Subject: [PATCH 005/124] 8318104: macOS 10.13 check in TabButtonAccessibility.m can be removed Reviewed-by: aivanov, prr --- .../native/libawt_lwawt/awt/a11y/TabButtonAccessibility.m | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/TabButtonAccessibility.m b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/TabButtonAccessibility.m index 2b22db80aa8..1507f4884c3 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/TabButtonAccessibility.m +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/TabButtonAccessibility.m @@ -84,10 +84,7 @@ - (void)performPressAction { - (NSAccessibilitySubrole)accessibilitySubrole { - if (@available(macOS 10.13, *)) { - return NSAccessibilityTabButtonSubrole; - } - return NSAccessibilityUnknownSubrole; + return NSAccessibilityTabButtonSubrole; } - (id)accessibilityValue From c0e154c876e586660b36af6441cd178bc8ebab89 Mon Sep 17 00:00:00 2001 From: Thomas Stuefe Date: Thu, 19 Oct 2023 06:25:53 +0000 Subject: [PATCH 006/124] 8318089: Class space not marked as such with NMT when CDS is off Reviewed-by: mli, dholmes --- src/hotspot/share/memory/metaspace.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/hotspot/share/memory/metaspace.cpp b/src/hotspot/share/memory/metaspace.cpp index 7394fbaf459..5c3087f1fa0 100644 --- a/src/hotspot/share/memory/metaspace.cpp +++ b/src/hotspot/share/memory/metaspace.cpp @@ -569,12 +569,6 @@ void Metaspace::initialize_class_space(ReservedSpace rs) { "wrong alignment"); MetaspaceContext::initialize_class_space_context(rs); - - // This does currently not work because rs may be the result of a split - // operation and NMT seems not to be able to handle splits. - // Will be fixed with JDK-8243535. - // MemTracker::record_virtual_memory_type((address)rs.base(), mtClass); - } // Returns true if class space has been setup (initialize_class_space). @@ -804,6 +798,9 @@ void Metaspace::global_initialize() { CompressedClassSpaceSize)); } + // Mark class space as such + MemTracker::record_virtual_memory_type((address)rs.base(), mtClass); + // Initialize space Metaspace::initialize_class_space(rs); From 80bd22d093b696b40a3380527b19d8d2c4e138f9 Mon Sep 17 00:00:00 2001 From: Andrey Turbanov Date: Thu, 19 Oct 2023 06:42:11 +0000 Subject: [PATCH 007/124] 8316144: Remove unused field jdk.internal.util.xml.impl.XMLStreamWriterImpl.Element._Depth Reviewed-by: lancea, joehw --- .../jdk/internal/util/xml/impl/XMLStreamWriterImpl.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/java.base/share/classes/jdk/internal/util/xml/impl/XMLStreamWriterImpl.java b/src/java.base/share/classes/jdk/internal/util/xml/impl/XMLStreamWriterImpl.java index d92c238d174..2aff75606a2 100644 --- a/src/java.base/share/classes/jdk/internal/util/xml/impl/XMLStreamWriterImpl.java +++ b/src/java.base/share/classes/jdk/internal/util/xml/impl/XMLStreamWriterImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -603,10 +603,6 @@ protected static class Element { * the parent element */ protected Element _parent; - /** - * The size of the stack. - */ - protected short _Depth; /** * indicate if an element is an empty one */ From 47bb1a1cefa242c39c22a8f2aa08d7d357c260b9 Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Thu, 19 Oct 2023 07:22:34 +0000 Subject: [PATCH 008/124] 8318415: Adjust describing comment of os_getChildren after 8315026 Reviewed-by: rriggs --- .../native/libjava/ProcessHandleImpl_macosx.c | 20 +++++++++++++------ .../native/libjava/ProcessHandleImpl_unix.c | 2 +- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/src/java.base/macosx/native/libjava/ProcessHandleImpl_macosx.c b/src/java.base/macosx/native/libjava/ProcessHandleImpl_macosx.c index 8987f0b97a4..e3d811cfca6 100644 --- a/src/java.base/macosx/native/libjava/ProcessHandleImpl_macosx.c +++ b/src/java.base/macosx/native/libjava/ProcessHandleImpl_macosx.c @@ -47,13 +47,21 @@ void os_initNative(JNIEnv *env, jclass clazz) {} /* - * Returns the children of the requested pid and optionally each parent. - * - * Use sysctl to accumulate any process whose parent pid is zero or matches. - * The resulting pids are stored into the array of longs. + * Return pids of active processes, and optionally parent pids and + * start times for each process. + * For a specific non-zero pid jpid, only the direct children are returned. + * If the pid jpid is zero, all active processes are returned. + * Uses sysctl to accumulates any process following the rules above. + * The resulting pids are stored into an array of longs named jarray. * The number of pids is returned if they all fit. - * If the parentArray is non-null, store the parent pid. - * If the array is too short, excess pids are not stored and + * If the parentArray is non-null, store also the parent pid. + * In this case the parentArray must have the same length as the result pid array. + * Of course in the case of a given non-zero pid all entries in the parentArray + * will contain this pid, so this array does only make sense in the case of a given + * zero pid. + * If the jstimesArray is non-null, store also the start time of the pid. + * In this case the jstimesArray must have the same length as the result pid array. + * If the array(s) (is|are) too short, excess pids are not stored and * the desired length is returned. */ jint os_getChildren(JNIEnv *env, jlong jpid, jlongArray jarray, diff --git a/src/java.base/unix/native/libjava/ProcessHandleImpl_unix.c b/src/java.base/unix/native/libjava/ProcessHandleImpl_unix.c index 6c0ea6e67a6..a54d5782547 100644 --- a/src/java.base/unix/native/libjava/ProcessHandleImpl_unix.c +++ b/src/java.base/unix/native/libjava/ProcessHandleImpl_unix.c @@ -485,7 +485,7 @@ void unix_getUserInfo(JNIEnv* env, jobject jinfo, uid_t uid) { } /* - * The following functions are common on Solaris, Linux and AIX. + * The following functions are for Linux */ #if defined (__linux__) From 1a098356dd3a157b12c2b5c527e61c8a628bdb2d Mon Sep 17 00:00:00 2001 From: Leo Korinth Date: Thu, 19 Oct 2023 09:26:15 +0000 Subject: [PATCH 009/124] 8317358: G1: Make TestMaxNewSize use createTestJvm Reviewed-by: tschatzl, sjohanss --- .../jtreg/gc/arguments/TestMaxNewSize.java | 40 +++++-------------- 1 file changed, 10 insertions(+), 30 deletions(-) diff --git a/test/hotspot/jtreg/gc/arguments/TestMaxNewSize.java b/test/hotspot/jtreg/gc/arguments/TestMaxNewSize.java index 03376308e39..6abcc9f84fe 100644 --- a/test/hotspot/jtreg/gc/arguments/TestMaxNewSize.java +++ b/test/hotspot/jtreg/gc/arguments/TestMaxNewSize.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -28,7 +28,8 @@ * @bug 7057939 * @summary Make sure that MaxNewSize always has a useful value after argument * processing. - * @requires vm.gc.Serial + * @key flag-sensitive + * @requires vm.gc.Serial & vm.opt.MaxNewSize == null & vm.opt.NewRatio == null & vm.opt.NewSize == null & vm.opt.OldSize == null & vm.opt.x.Xms == null & vm.opt.x.Xmx == null * @library /test/lib * @library / * @modules java.base/jdk.internal.misc @@ -42,7 +43,8 @@ * @bug 7057939 * @summary Make sure that MaxNewSize always has a useful value after argument * processing. - * @requires vm.gc.Parallel + * @key flag-sensitive + * @requires vm.gc.Parallel & vm.opt.MaxNewSize == null & vm.opt.NewRatio == null & vm.opt.NewSize == null & vm.opt.OldSize == null & vm.opt.x.Xms == null & vm.opt.x.Xmx == null * @library /test/lib * @library / * @modules java.base/jdk.internal.misc @@ -56,7 +58,8 @@ * @bug 7057939 * @summary Make sure that MaxNewSize always has a useful value after argument * processing. - * @requires vm.gc.G1 + * @key flag-sensitive + * @requires vm.gc.G1 & vm.opt.MaxNewSize == null & vm.opt.NewRatio == null & vm.opt.NewSize == null & vm.opt.OldSize == null & vm.opt.x.Xms == null & vm.opt.x.Xmx == null * @library /test/lib * @library / * @modules java.base/jdk.internal.misc @@ -79,46 +82,23 @@ public class TestMaxNewSize { private static void checkMaxNewSize(String[] flags, int heapsize) throws Exception { BigInteger actual = new BigInteger(getMaxNewSize(flags)); - System.out.println(actual); - if (actual.compareTo(new BigInteger((new Long(heapsize)).toString())) == 1) { + System.out.println("asserting: " + actual + " <= " + heapsize); + if (actual.compareTo(new BigInteger("" + heapsize)) > 0) { throw new RuntimeException("MaxNewSize value set to \"" + actual + "\", expected otherwise when running with the following flags: " + Arrays.asList(flags).toString()); } } - private static void checkIncompatibleNewSize(String[] flags) throws Exception { - ArrayList finalargs = new ArrayList(); - finalargs.addAll(Arrays.asList(flags)); - finalargs.add("-version"); - - ProcessBuilder pb = GCArguments.createJavaProcessBuilder(finalargs); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); - output.shouldContain("Initial young gen size set larger than the maximum young gen size"); - } - - private static boolean isRunningG1(String[] args) { - for (int i = 0; i < args.length; i++) { - if (args[i].contains("+UseG1GC")) { - return true; - } - } - return false; - } - private static String getMaxNewSize(String[] flags) throws Exception { ArrayList finalargs = new ArrayList(); finalargs.addAll(Arrays.asList(flags)); - if (isRunningG1(flags)) { - finalargs.add("-XX:G1HeapRegionSize=1M"); - } finalargs.add("-XX:+PrintFlagsFinal"); finalargs.add("-version"); - ProcessBuilder pb = GCArguments.createJavaProcessBuilder(finalargs); + ProcessBuilder pb = GCArguments.createTestJvm(finalargs); OutputAnalyzer output = new OutputAnalyzer(pb.start()); output.shouldHaveExitValue(0); String stdout = output.getStdout(); - //System.out.println(stdout); return getFlagValue("MaxNewSize", stdout); } From 15acf4b8d7cffcd0d74bf1b9c43cde9acaf31ea9 Mon Sep 17 00:00:00 2001 From: Maurizio Cimadamore Date: Thu, 19 Oct 2023 09:51:02 +0000 Subject: [PATCH 010/124] 8318324: Drop redundant default methods from FFM API Reviewed-by: jvernee --- .../java/lang/foreign/MemoryLayout.java | 75 +---- .../java/lang/foreign/MemorySegment.java | 252 +++------------- .../foreign/AbstractMemorySegmentImpl.java | 279 ++++++++++++++++++ .../foreign/layout/AbstractLayout.java | 78 +++++ 4 files changed, 407 insertions(+), 277 deletions(-) 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 ece3e4e22c1..db656ada136 100644 --- a/src/java.base/share/classes/java/lang/foreign/MemoryLayout.java +++ b/src/java.base/share/classes/java/lang/foreign/MemoryLayout.java @@ -26,14 +26,9 @@ package java.lang.foreign; import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodType; import java.lang.invoke.VarHandle; -import java.util.EnumSet; import java.util.Objects; import java.util.Optional; -import java.util.Set; -import java.util.function.Function; import java.util.stream.Stream; import jdk.internal.foreign.LayoutPath; @@ -44,7 +39,6 @@ import jdk.internal.foreign.layout.SequenceLayoutImpl; import jdk.internal.foreign.layout.StructLayoutImpl; import jdk.internal.foreign.layout.UnionLayoutImpl; -import jdk.internal.vm.annotation.ForceInline; /** * A memory layout describes the contents of a memory segment. @@ -404,35 +398,12 @@ public sealed interface MemoryLayout permits SequenceLayout, GroupLayout, Paddin * @throws IllegalArgumentException if {@code offset} or {@code index} is negative * @throws ArithmeticException if either the addition or multiplication overflows */ - @ForceInline - default long scale(long offset, long index) { - if (offset < 0) { - throw new IllegalArgumentException("Negative offset: " + offset); - } - if (index < 0) { - throw new IllegalArgumentException("Negative index: " + index); - } - - return Math.addExact(offset, Math.multiplyExact(byteSize(), index)); - } + long scale(long offset, long index); /** *{@return a method handle that can be used to invoke {@link #scale(long, long)} on this layout} */ - default MethodHandle scaleHandle() { - class Holder { - static final MethodHandle MH_SCALE; - static { - try { - MH_SCALE = MethodHandles.lookup().findVirtual(MemoryLayout.class, "scale", - MethodType.methodType(long.class, long.class, long.class)); - } catch (ReflectiveOperationException e) { - throw new ExceptionInInitializerError(e); - } - } - } - return Holder.MH_SCALE.bindTo(this); - } + MethodHandle scaleHandle(); /** * Computes the offset, in bytes, of the layout selected by the given layout path, where the initial layout in the @@ -444,10 +415,7 @@ class Holder { * @throws IllegalArgumentException if the layout path contains one or more open path elements. * @throws IllegalArgumentException if the layout path contains one or more dereference path elements. */ - default long byteOffset(PathElement... elements) { - return computePathOp(LayoutPath.rootPath(this), LayoutPath::offset, - EnumSet.of(PathKind.SEQUENCE_ELEMENT, PathKind.SEQUENCE_RANGE, PathKind.DEREF_ELEMENT), elements); - } + long byteOffset(PathElement... elements); /** * Creates a method handle that computes the offset, in bytes, of the layout selected @@ -482,10 +450,7 @@ default long byteOffset(PathElement... elements) { * @throws IllegalArgumentException if the layout path is not well-formed for this layout. * @throws IllegalArgumentException if the layout path contains one or more dereference path elements. */ - default MethodHandle byteOffsetHandle(PathElement... elements) { - return computePathOp(LayoutPath.rootPath(this), LayoutPath::offsetHandle, - EnumSet.of(PathKind.DEREF_ELEMENT), elements); - } + MethodHandle byteOffsetHandle(PathElement... elements); /** * Creates a var handle that accesses a memory segment at the offset selected by the given layout path, @@ -577,14 +542,7 @@ default MethodHandle byteOffsetHandle(PathElement... elements) { * @throws IllegalArgumentException if the layout path is not well-formed for this layout. * @throws IllegalArgumentException if the layout selected by the provided path is not a {@linkplain ValueLayout value layout}. */ - default VarHandle varHandle(PathElement... elements) { - Objects.requireNonNull(elements); - if (this instanceof ValueLayout vl && elements.length == 0) { - return vl.varHandle(); // fast path - } - return computePathOp(LayoutPath.rootPath(this), LayoutPath::dereferenceHandle, - Set.of(), elements); - } + VarHandle varHandle(PathElement... elements); /** * Creates a method handle which, given a memory segment, returns a {@linkplain MemorySegment#asSlice(long,long) slice} @@ -623,10 +581,7 @@ default VarHandle varHandle(PathElement... elements) { * @throws IllegalArgumentException if the layout path is not well-formed for this layout. * @throws IllegalArgumentException if the layout path contains one or more dereference path elements. */ - default MethodHandle sliceHandle(PathElement... elements) { - return computePathOp(LayoutPath.rootPath(this), LayoutPath::sliceHandle, - Set.of(PathKind.DEREF_ELEMENT), elements); - } + MethodHandle sliceHandle(PathElement... elements); /** * Returns the layout selected from the provided path, where the initial layout in the path is this layout. @@ -638,23 +593,7 @@ default MethodHandle sliceHandle(PathElement... elements) { * @throws IllegalArgumentException if the layout path contains one or more path elements that select one or more * sequence element indices, such as {@link PathElement#sequenceElement(long)} and {@link PathElement#sequenceElement(long, long)}). */ - default MemoryLayout select(PathElement... elements) { - return computePathOp(LayoutPath.rootPath(this), LayoutPath::layout, - EnumSet.of(PathKind.SEQUENCE_ELEMENT_INDEX, PathKind.SEQUENCE_RANGE, PathKind.DEREF_ELEMENT), elements); - } - - private static Z computePathOp(LayoutPath path, Function finalizer, - Set badKinds, PathElement... elements) { - Objects.requireNonNull(elements); - for (PathElement e : elements) { - LayoutPath.PathElementImpl pathElem = (LayoutPath.PathElementImpl)Objects.requireNonNull(e); - if (badKinds.contains(pathElem.kind())) { - throw new IllegalArgumentException(String.format("Invalid %s selection in layout path", pathElem.kind().description())); - } - path = pathElem.apply(path); - } - return finalizer.apply(path); - } + MemoryLayout select(PathElement... elements); /** * An element in a layout path. There 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 2bfdb4ec56e..5565eaf2461 100644 --- a/src/java.base/share/classes/java/lang/foreign/MemorySegment.java +++ b/src/java.base/share/classes/java/lang/foreign/MemorySegment.java @@ -573,10 +573,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl { * the alignment constraint specified by {@code layout}. * @return a slice of this memory segment. */ - default MemorySegment asSlice(long offset, MemoryLayout layout) { - Objects.requireNonNull(layout); - return asSlice(offset, layout.byteSize(), layout.byteAlignment()); - } + MemorySegment asSlice(long offset, MemoryLayout layout); /** * Returns a slice of this memory segment, at the given offset. The returned segment's address is the address @@ -788,10 +785,7 @@ default MemorySegment asSlice(long offset, MemoryLayout layout) { * @throws UnsupportedOperationException if this segment is {@linkplain #isReadOnly() read-only}. * @return this segment. */ - default MemorySegment copyFrom(MemorySegment src) { - MemorySegment.copy(src, 0, this, 0, src.byteSize()); - return this; - } + MemorySegment copyFrom(MemorySegment src); /** * Finds and returns the offset, in bytes, of the first mismatch between @@ -820,10 +814,7 @@ default MemorySegment copyFrom(MemorySegment src) { * @throws WrongThreadException if this method is called from a thread {@code T}, * such that {@code other.isAccessibleBy(T) == false}. */ - default long mismatch(MemorySegment other) { - Objects.requireNonNull(other); - return MemorySegment.mismatch(this, 0, byteSize(), other, 0, other.byteSize()); - } + long mismatch(MemorySegment other); /** * Determines whether the contents of this mapped segment is resident in physical @@ -1068,9 +1059,7 @@ default long mismatch(MemorySegment other) { * @throws WrongThreadException if this method is called from a thread {@code T}, * such that {@code isAccessibleBy(T) == false}. */ - default String getString(long offset) { - return getString(offset, sun.nio.cs.UTF_8.INSTANCE); - } + String getString(long offset); /** * Reads a null-terminated string from this segment at the given offset, using the provided charset. @@ -1099,10 +1088,7 @@ default String getString(long offset) { * such that {@code isAccessibleBy(T) == false}. * @throws IllegalArgumentException if {@code charset} is not a {@linkplain StandardCharsets standard charset}. */ - default String getString(long offset, Charset charset) { - Objects.requireNonNull(charset); - return StringSupport.read(this, offset, charset); - } + String getString(long offset, Charset charset); /** * Writes the given string into this segment at the given offset, converting it to a null-terminated byte sequence @@ -1123,10 +1109,7 @@ default String getString(long offset, Charset charset) { * @throws WrongThreadException if this method is called from a thread {@code T}, * such that {@code isAccessibleBy(T) == false}. */ - default void setString(long offset, String str) { - Objects.requireNonNull(str); - setString(offset, str, sun.nio.cs.UTF_8.INSTANCE); - } + void setString(long offset, String str); /** * Writes the given string into this segment at the given offset, converting it to a null-terminated byte sequence @@ -1160,11 +1143,7 @@ default void setString(long offset, String str) { * such that {@code isAccessibleBy(T) == false}. * @throws IllegalArgumentException if {@code charset} is not a {@linkplain StandardCharsets standard charset}. */ - default void setString(long offset, String str, Charset charset) { - Objects.requireNonNull(charset); - Objects.requireNonNull(str); - StringSupport.write(this, offset, charset, str); - } + void setString(long offset, String str, Charset charset); /** * Creates a memory segment that is backed by the same region of memory that backs the given {@link Buffer} instance. @@ -1411,10 +1390,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()}. */ - @ForceInline - default byte get(ValueLayout.OfByte layout, long offset) { - return (byte) layout.varHandle().get(this, offset); - } + byte get(ValueLayout.OfByte layout, long offset); /** * Writes a byte into this segment at the given offset, with the given layout. @@ -1431,10 +1407,7 @@ default byte get(ValueLayout.OfByte layout, long offset) { * @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()}. * @throws UnsupportedOperationException if this segment is {@linkplain #isReadOnly() read-only}. */ - @ForceInline - default void set(ValueLayout.OfByte layout, long offset, byte value) { - layout.varHandle().set(this, offset, value); - } + void set(ValueLayout.OfByte layout, long offset, byte value); /** * Reads a boolean from this segment at the given offset, with the given layout. @@ -1450,10 +1423,7 @@ default void set(ValueLayout.OfByte layout, long offset, byte value) { * incompatible with the alignment constraint in the provided layout. * @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()}. */ - @ForceInline - default boolean get(ValueLayout.OfBoolean layout, long offset) { - return (boolean) layout.varHandle().get(this, offset); - } + boolean get(ValueLayout.OfBoolean layout, long offset); /** * Writes a boolean into this segment at the given offset, with the given layout. @@ -1470,10 +1440,7 @@ default boolean get(ValueLayout.OfBoolean layout, long offset) { * @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()}. * @throws UnsupportedOperationException if this segment is {@linkplain #isReadOnly() read-only}. */ - @ForceInline - default void set(ValueLayout.OfBoolean layout, long offset, boolean value) { - layout.varHandle().set(this, offset, value); - } + void set(ValueLayout.OfBoolean layout, long offset, boolean value); /** * Reads a char from this segment at the given offset, with the given layout. @@ -1489,10 +1456,7 @@ default void set(ValueLayout.OfBoolean layout, long offset, boolean value) { * incompatible with the alignment constraint in the provided layout. * @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()}. */ - @ForceInline - default char get(ValueLayout.OfChar layout, long offset) { - return (char) layout.varHandle().get(this, offset); - } + char get(ValueLayout.OfChar layout, long offset); /** * Writes a char into this segment at the given offset, with the given layout. @@ -1509,10 +1473,7 @@ default char get(ValueLayout.OfChar layout, long offset) { * @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()}. * @throws UnsupportedOperationException if this segment is {@linkplain #isReadOnly() read-only}. */ - @ForceInline - default void set(ValueLayout.OfChar layout, long offset, char value) { - layout.varHandle().set(this, offset, value); - } + void set(ValueLayout.OfChar layout, long offset, char value); /** * Reads a short from this segment at the given offset, with the given layout. @@ -1528,10 +1489,7 @@ default void set(ValueLayout.OfChar layout, long offset, char value) { * incompatible with the alignment constraint in the provided layout. * @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()}. */ - @ForceInline - default short get(ValueLayout.OfShort layout, long offset) { - return (short) layout.varHandle().get(this, offset); - } + short get(ValueLayout.OfShort layout, long offset); /** * Writes a short into this segment at the given offset, with the given layout. @@ -1548,10 +1506,7 @@ default short get(ValueLayout.OfShort layout, long offset) { * @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()}. * @throws UnsupportedOperationException if this segment is {@linkplain #isReadOnly() read-only}. */ - @ForceInline - default void set(ValueLayout.OfShort layout, long offset, short value) { - layout.varHandle().set(this, offset, value); - } + void set(ValueLayout.OfShort layout, long offset, short value); /** * Reads an int from this segment at the given offset, with the given layout. @@ -1567,10 +1522,7 @@ default void set(ValueLayout.OfShort layout, long offset, short value) { * incompatible with the alignment constraint in the provided layout. * @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()}. */ - @ForceInline - default int get(ValueLayout.OfInt layout, long offset) { - return (int) layout.varHandle().get(this, offset); - } + int get(ValueLayout.OfInt layout, long offset); /** * Writes an int into this segment at the given offset, with the given layout. @@ -1587,10 +1539,7 @@ default int get(ValueLayout.OfInt layout, long offset) { * @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()}. * @throws UnsupportedOperationException if this segment is {@linkplain #isReadOnly() read-only}. */ - @ForceInline - default void set(ValueLayout.OfInt layout, long offset, int value) { - layout.varHandle().set(this, offset, value); - } + void set(ValueLayout.OfInt layout, long offset, int value); /** * Reads a float from this segment at the given offset, with the given layout. @@ -1606,10 +1555,7 @@ default void set(ValueLayout.OfInt layout, long offset, int value) { * incompatible with the alignment constraint in the provided layout. * @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()}. */ - @ForceInline - default float get(ValueLayout.OfFloat layout, long offset) { - return (float)layout.varHandle().get(this, offset); - } + float get(ValueLayout.OfFloat layout, long offset); /** * Writes a float into this segment at the given offset, with the given layout. @@ -1626,10 +1572,7 @@ default float get(ValueLayout.OfFloat layout, long offset) { * @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()}. * @throws UnsupportedOperationException if this segment is {@linkplain #isReadOnly() read-only}. */ - @ForceInline - default void set(ValueLayout.OfFloat layout, long offset, float value) { - layout.varHandle().set(this, offset, value); - } + void set(ValueLayout.OfFloat layout, long offset, float value); /** * Reads a long from this segment at the given offset, with the given layout. @@ -1645,10 +1588,7 @@ default void set(ValueLayout.OfFloat layout, long offset, float value) { * incompatible with the alignment constraint in the provided layout. * @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()}. */ - @ForceInline - default long get(ValueLayout.OfLong layout, long offset) { - return (long) layout.varHandle().get(this, offset); - } + long get(ValueLayout.OfLong layout, long offset); /** * Writes a long into this segment at the given offset, with the given layout. @@ -1665,10 +1605,7 @@ default long get(ValueLayout.OfLong layout, long offset) { * @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()}. * @throws UnsupportedOperationException if this segment is {@linkplain #isReadOnly() read-only}. */ - @ForceInline - default void set(ValueLayout.OfLong layout, long offset, long value) { - layout.varHandle().set(this, offset, value); - } + void set(ValueLayout.OfLong layout, long offset, long value); /** * Reads a double from this segment at the given offset, with the given layout. @@ -1684,10 +1621,7 @@ default void set(ValueLayout.OfLong layout, long offset, long value) { * incompatible with the alignment constraint in the provided layout. * @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()}. */ - @ForceInline - default double get(ValueLayout.OfDouble layout, long offset) { - return (double) layout.varHandle().get(this, offset); - } + double get(ValueLayout.OfDouble layout, long offset); /** * Writes a double into this segment at the given offset, with the given layout. @@ -1704,10 +1638,7 @@ default double get(ValueLayout.OfDouble layout, long offset) { * @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()}. * @throws UnsupportedOperationException if this segment is {@linkplain #isReadOnly() read-only}. */ - @ForceInline - default void set(ValueLayout.OfDouble layout, long offset, double value) { - layout.varHandle().set(this, offset, value); - } + void set(ValueLayout.OfDouble layout, long offset, double value); /** * Reads an address from this segment at the given offset, with the given layout. The read address is wrapped in @@ -1729,10 +1660,7 @@ default void set(ValueLayout.OfDouble layout, long offset, double value) { * incompatible with the alignment constraint in {@code T}. * @throws IndexOutOfBoundsException if {@code offset > byteSize() - layout.byteSize()}. */ - @ForceInline - default MemorySegment get(AddressLayout layout, long offset) { - return (MemorySegment) layout.varHandle().get(this, offset); - } + MemorySegment get(AddressLayout layout, long offset); /** * Writes an address into this segment at the given offset, with the given layout. @@ -1750,10 +1678,7 @@ default MemorySegment get(AddressLayout layout, long offset) { * @throws UnsupportedOperationException if this segment is {@linkplain #isReadOnly() read-only}. * @throws UnsupportedOperationException if {@code value} is not a {@linkplain #isNative() native} segment. */ - @ForceInline - default void set(AddressLayout layout, long offset, MemorySegment value) { - layout.varHandle().set(this, offset, value); - } + void set(AddressLayout layout, long offset, MemorySegment value); /** * Reads a byte from this segment at the given index, scaled by the given layout size. @@ -1772,12 +1697,7 @@ default void set(AddressLayout layout, long offset, MemorySegment value) { * @throws IndexOutOfBoundsException if {@code index * byteSize()} overflows. * @throws IndexOutOfBoundsException if {@code index * byteSize() > byteSize() - layout.byteSize()}. */ - @ForceInline - default byte getAtIndex(ValueLayout.OfByte layout, long index) { - Utils.checkElementAlignment(layout, "Layout alignment greater than its size"); - // note: we know size is a small value (as it comes from ValueLayout::byteSize()) - return (byte) layout.varHandle().get(this, index * layout.byteSize()); - } + byte getAtIndex(ValueLayout.OfByte layout, long index); /** * Reads a boolean from this segment at the given index, scaled by the given layout size. @@ -1796,12 +1716,7 @@ default byte getAtIndex(ValueLayout.OfByte layout, long index) { * @throws IndexOutOfBoundsException if {@code index * byteSize()} overflows. * @throws IndexOutOfBoundsException if {@code index * byteSize() > byteSize() - layout.byteSize()}. */ - @ForceInline - default boolean getAtIndex(ValueLayout.OfBoolean layout, long index) { - Utils.checkElementAlignment(layout, "Layout alignment greater than its size"); - // note: we know size is a small value (as it comes from ValueLayout::byteSize()) - return (boolean) layout.varHandle().get(this, index * layout.byteSize()); - } + boolean getAtIndex(ValueLayout.OfBoolean layout, long index); /** * Reads a char from this segment at the given index, scaled by the given layout size. @@ -1820,12 +1735,7 @@ default boolean getAtIndex(ValueLayout.OfBoolean layout, long index) { * @throws IndexOutOfBoundsException if {@code index * byteSize()} overflows. * @throws IndexOutOfBoundsException if {@code index * byteSize() > byteSize() - layout.byteSize()}. */ - @ForceInline - default char getAtIndex(ValueLayout.OfChar layout, long index) { - Utils.checkElementAlignment(layout, "Layout alignment greater than its size"); - // note: we know size is a small value (as it comes from ValueLayout::byteSize()) - return (char) layout.varHandle().get(this, index * layout.byteSize()); - } + char getAtIndex(ValueLayout.OfChar layout, long index); /** * Writes a char into this segment at the given index, scaled by the given layout size. @@ -1845,12 +1755,7 @@ default char getAtIndex(ValueLayout.OfChar layout, long index) { * @throws IndexOutOfBoundsException if {@code index * byteSize() > byteSize() - layout.byteSize()}. * @throws UnsupportedOperationException if this segment is {@linkplain #isReadOnly() read-only}. */ - @ForceInline - default void setAtIndex(ValueLayout.OfChar layout, long index, char value) { - Utils.checkElementAlignment(layout, "Layout alignment greater than its size"); - // note: we know size is a small value (as it comes from ValueLayout::byteSize()) - layout.varHandle().set(this, index * layout.byteSize(), value); - } + void setAtIndex(ValueLayout.OfChar layout, long index, char value); /** * Reads a short from this segment at the given index, scaled by the given layout size. @@ -1869,12 +1774,7 @@ default void setAtIndex(ValueLayout.OfChar layout, long index, char value) { * @throws IndexOutOfBoundsException if {@code index * byteSize()} overflows. * @throws IndexOutOfBoundsException if {@code index * byteSize() > byteSize() - layout.byteSize()}. */ - @ForceInline - default short getAtIndex(ValueLayout.OfShort layout, long index) { - Utils.checkElementAlignment(layout, "Layout alignment greater than its size"); - // note: we know size is a small value (as it comes from ValueLayout::byteSize()) - return (short) layout.varHandle().get(this, index * layout.byteSize()); - } + short getAtIndex(ValueLayout.OfShort layout, long index); /** * Writes a byte into this segment at the given index, scaled by the given layout size. @@ -1894,13 +1794,7 @@ default short getAtIndex(ValueLayout.OfShort layout, long index) { * @throws IndexOutOfBoundsException if {@code index * byteSize() > byteSize() - layout.byteSize()}. * @throws UnsupportedOperationException if this segment is {@linkplain #isReadOnly() read-only}. */ - @ForceInline - default void setAtIndex(ValueLayout.OfByte layout, long index, byte value) { - Utils.checkElementAlignment(layout, "Layout alignment greater than its size"); - // note: we know size is a small value (as it comes from ValueLayout::byteSize()) - layout.varHandle().set(this, index * layout.byteSize(), value); - - } + void setAtIndex(ValueLayout.OfByte layout, long index, byte value); /** * Writes a boolean into this segment at the given index, scaled by the given layout size. @@ -1920,12 +1814,7 @@ default void setAtIndex(ValueLayout.OfByte layout, long index, byte value) { * @throws IndexOutOfBoundsException if {@code index * byteSize() > byteSize() - layout.byteSize()}. * @throws UnsupportedOperationException if this segment is {@linkplain #isReadOnly() read-only}. */ - @ForceInline - default void setAtIndex(ValueLayout.OfBoolean layout, long index, boolean value) { - Utils.checkElementAlignment(layout, "Layout alignment greater than its size"); - // note: we know size is a small value (as it comes from ValueLayout::byteSize()) - layout.varHandle().set(this, index * layout.byteSize(), value); - } + void setAtIndex(ValueLayout.OfBoolean layout, long index, boolean value); /** * Writes a short into this segment at the given index, scaled by the given layout size. @@ -1945,12 +1834,7 @@ default void setAtIndex(ValueLayout.OfBoolean layout, long index, boolean value) * @throws IndexOutOfBoundsException if {@code index * byteSize() > byteSize() - layout.byteSize()}. * @throws UnsupportedOperationException if this segment is {@linkplain #isReadOnly() read-only}. */ - @ForceInline - default void setAtIndex(ValueLayout.OfShort layout, long index, short value) { - Utils.checkElementAlignment(layout, "Layout alignment greater than its size"); - // note: we know size is a small value (as it comes from ValueLayout::byteSize()) - layout.varHandle().set(this, index * layout.byteSize(), value); - } + void setAtIndex(ValueLayout.OfShort layout, long index, short value); /** * Reads an int from this segment at the given index, scaled by the given layout size. @@ -1969,12 +1853,7 @@ default void setAtIndex(ValueLayout.OfShort layout, long index, short value) { * @throws IndexOutOfBoundsException if {@code index * byteSize()} overflows. * @throws IndexOutOfBoundsException if {@code index * byteSize() > byteSize() - layout.byteSize()}. */ - @ForceInline - default int getAtIndex(ValueLayout.OfInt layout, long index) { - Utils.checkElementAlignment(layout, "Layout alignment greater than its size"); - // note: we know size is a small value (as it comes from ValueLayout::byteSize()) - return (int) layout.varHandle().get(this, index * layout.byteSize()); - } + int getAtIndex(ValueLayout.OfInt layout, long index); /** * Writes an int into this segment at the given index, scaled by the given layout size. @@ -1994,12 +1873,7 @@ default int getAtIndex(ValueLayout.OfInt layout, long index) { * @throws IndexOutOfBoundsException if {@code index * byteSize() > byteSize() - layout.byteSize()}. * @throws UnsupportedOperationException if this segment is {@linkplain #isReadOnly() read-only}. */ - @ForceInline - default void setAtIndex(ValueLayout.OfInt layout, long index, int value) { - Utils.checkElementAlignment(layout, "Layout alignment greater than its size"); - // note: we know size is a small value (as it comes from ValueLayout::byteSize()) - layout.varHandle().set(this, index * layout.byteSize(), value); - } + void setAtIndex(ValueLayout.OfInt layout, long index, int value); /** * Reads a float from this segment at the given index, scaled by the given layout size. @@ -2018,12 +1892,7 @@ default void setAtIndex(ValueLayout.OfInt layout, long index, int value) { * @throws IndexOutOfBoundsException if {@code index * byteSize()} overflows. * @throws IndexOutOfBoundsException if {@code index * byteSize() > byteSize() - layout.byteSize()}. */ - @ForceInline - default float getAtIndex(ValueLayout.OfFloat layout, long index) { - Utils.checkElementAlignment(layout, "Layout alignment greater than its size"); - // note: we know size is a small value (as it comes from ValueLayout::byteSize()) - return (float) layout.varHandle().get(this, index * layout.byteSize()); - } + float getAtIndex(ValueLayout.OfFloat layout, long index); /** * Writes a float into this segment at the given index, scaled by the given layout size. @@ -2043,12 +1912,7 @@ default float getAtIndex(ValueLayout.OfFloat layout, long index) { * @throws IndexOutOfBoundsException if {@code index * byteSize() > byteSize() - layout.byteSize()}. * @throws UnsupportedOperationException if this segment is {@linkplain #isReadOnly() read-only}. */ - @ForceInline - default void setAtIndex(ValueLayout.OfFloat layout, long index, float value) { - Utils.checkElementAlignment(layout, "Layout alignment greater than its size"); - // note: we know size is a small value (as it comes from ValueLayout::byteSize()) - layout.varHandle().set(this, index * layout.byteSize(), value); - } + void setAtIndex(ValueLayout.OfFloat layout, long index, float value); /** * Reads a long from this segment at the given index, scaled by the given layout size. @@ -2067,12 +1931,7 @@ default void setAtIndex(ValueLayout.OfFloat layout, long index, float value) { * @throws IndexOutOfBoundsException if {@code index * byteSize()} overflows. * @throws IndexOutOfBoundsException if {@code index * byteSize() > byteSize() - layout.byteSize()}. */ - @ForceInline - default long getAtIndex(ValueLayout.OfLong layout, long index) { - Utils.checkElementAlignment(layout, "Layout alignment greater than its size"); - // note: we know size is a small value (as it comes from ValueLayout::byteSize()) - return (long) layout.varHandle().get(this, index * layout.byteSize()); - } + long getAtIndex(ValueLayout.OfLong layout, long index); /** * Writes a long into this segment at the given index, scaled by the given layout size. @@ -2092,12 +1951,7 @@ default long getAtIndex(ValueLayout.OfLong layout, long index) { * @throws IndexOutOfBoundsException if {@code index * byteSize() > byteSize() - layout.byteSize()}. * @throws UnsupportedOperationException if this segment is {@linkplain #isReadOnly() read-only}. */ - @ForceInline - default void setAtIndex(ValueLayout.OfLong layout, long index, long value) { - Utils.checkElementAlignment(layout, "Layout alignment greater than its size"); - // note: we know size is a small value (as it comes from ValueLayout::byteSize()) - layout.varHandle().set(this, index * layout.byteSize(), value); - } + void setAtIndex(ValueLayout.OfLong layout, long index, long value); /** * Reads a double from this segment at the given index, scaled by the given layout size. @@ -2116,12 +1970,7 @@ default void setAtIndex(ValueLayout.OfLong layout, long index, long value) { * @throws IndexOutOfBoundsException if {@code index * byteSize()} overflows. * @throws IndexOutOfBoundsException if {@code index * byteSize() > byteSize() - layout.byteSize()}. */ - @ForceInline - default double getAtIndex(ValueLayout.OfDouble layout, long index) { - Utils.checkElementAlignment(layout, "Layout alignment greater than its size"); - // note: we know size is a small value (as it comes from ValueLayout::byteSize()) - return (double) layout.varHandle().get(this, index * layout.byteSize()); - } + double getAtIndex(ValueLayout.OfDouble layout, long index); /** * Writes a double into this segment at the given index, scaled by the given layout size. @@ -2141,12 +1990,7 @@ default double getAtIndex(ValueLayout.OfDouble layout, long index) { * @throws IndexOutOfBoundsException if {@code index * byteSize() > byteSize() - layout.byteSize()}. * @throws UnsupportedOperationException if this segment is {@linkplain #isReadOnly() read-only}. */ - @ForceInline - default void setAtIndex(ValueLayout.OfDouble layout, long index, double value) { - Utils.checkElementAlignment(layout, "Layout alignment greater than its size"); - // note: we know size is a small value (as it comes from ValueLayout::byteSize()) - layout.varHandle().set(this, index * layout.byteSize(), value); - } + void setAtIndex(ValueLayout.OfDouble layout, long index, double value); /** * Reads an address from this segment at the given at the given index, scaled by the given layout size. The read address is wrapped in @@ -2171,12 +2015,7 @@ default void setAtIndex(ValueLayout.OfDouble layout, long index, double value) { * @throws IndexOutOfBoundsException if {@code index * byteSize()} overflows. * @throws IndexOutOfBoundsException if {@code index * byteSize() > byteSize() - layout.byteSize()}. */ - @ForceInline - default MemorySegment getAtIndex(AddressLayout layout, long index) { - Utils.checkElementAlignment(layout, "Layout alignment greater than its size"); - // note: we know size is a small value (as it comes from ValueLayout::byteSize()) - return (MemorySegment) layout.varHandle().get(this, index * layout.byteSize()); - } + MemorySegment getAtIndex(AddressLayout layout, long index); /** * Writes an address into this segment at the given index, scaled by the given layout size. @@ -2197,12 +2036,7 @@ default MemorySegment getAtIndex(AddressLayout layout, long index) { * @throws UnsupportedOperationException if this segment is {@linkplain #isReadOnly() read-only}. * @throws UnsupportedOperationException if {@code value} is not a {@linkplain #isNative() native} segment. */ - @ForceInline - default void setAtIndex(AddressLayout layout, long index, MemorySegment value) { - Utils.checkElementAlignment(layout, "Layout alignment greater than its size"); - // note: we know size is a small value (as it comes from ValueLayout::byteSize()) - layout.varHandle().set(this, index * layout.byteSize(), value); - } + void setAtIndex(AddressLayout layout, long index, MemorySegment value); /** * Compares the specified object with this memory segment for equality. Returns {@code true} if and only if the specified 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 63132f7f89c..8b674a90c33 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/AbstractMemorySegmentImpl.java +++ b/src/java.base/share/classes/jdk/internal/foreign/AbstractMemorySegmentImpl.java @@ -36,6 +36,7 @@ import java.nio.IntBuffer; import java.nio.LongBuffer; import java.nio.ShortBuffer; +import java.nio.charset.Charset; import java.util.*; import java.util.function.BiFunction; import java.util.function.Consumer; @@ -122,6 +123,12 @@ public MemorySegment asSlice(long offset, long newSize, long byteAlignment) { return asSliceNoCheck(offset, newSize); } + @Override + public MemorySegment asSlice(long offset, MemoryLayout layout) { + Objects.requireNonNull(layout); + return asSlice(offset, layout.byteSize(), layout.byteAlignment()); + } + @Override @CallerSensitive public final MemorySegment reinterpret(long newSize, Arena arena, Consumer cleanup) { @@ -272,6 +279,18 @@ public final Optional asOverlappingSlice(MemorySegment other) { return Optional.empty(); } + @Override + public MemorySegment copyFrom(MemorySegment src) { + MemorySegment.copy(src, 0, this, 0, src.byteSize()); + return this; + } + + @Override + public long mismatch(MemorySegment other) { + Objects.requireNonNull(other); + return MemorySegment.mismatch(this, 0, byteSize(), other, 0, other.byteSize()); + } + @Override public void load() { throw notAMappedSegment(); @@ -732,4 +751,264 @@ private static long getBaseAndScale(Class arrayType) { throw new IllegalArgumentException("Not a supported array class: " + arrayType.getSimpleName()); } } + + // accessors + + @ForceInline + @Override + public byte get(ValueLayout.OfByte layout, long offset) { + return (byte) layout.varHandle().get(this, offset); + } + + @ForceInline + @Override + public void set(ValueLayout.OfByte layout, long offset, byte value) { + layout.varHandle().set(this, offset, value); + } + + @ForceInline + @Override + public boolean get(ValueLayout.OfBoolean layout, long offset) { + return (boolean) layout.varHandle().get(this, offset); + } + + @ForceInline + @Override + public void set(ValueLayout.OfBoolean layout, long offset, boolean value) { + layout.varHandle().set(this, offset, value); + } + + @ForceInline + @Override + public char get(ValueLayout.OfChar layout, long offset) { + return (char) layout.varHandle().get(this, offset); + } + + @ForceInline + @Override + public void set(ValueLayout.OfChar layout, long offset, char value) { + layout.varHandle().set(this, offset, value); + } + + @ForceInline + @Override + public short get(ValueLayout.OfShort layout, long offset) { + return (short) layout.varHandle().get(this, offset); + } + + @ForceInline + @Override + public void set(ValueLayout.OfShort layout, long offset, short value) { + layout.varHandle().set(this, offset, value); + } + + @ForceInline + @Override + public int get(ValueLayout.OfInt layout, long offset) { + return (int) layout.varHandle().get(this, offset); + } + + @ForceInline + @Override + public void set(ValueLayout.OfInt layout, long offset, int value) { + layout.varHandle().set(this, offset, value); + } + + @ForceInline + @Override + public float get(ValueLayout.OfFloat layout, long offset) { + return (float) layout.varHandle().get(this, offset); + } + + @ForceInline + @Override + public void set(ValueLayout.OfFloat layout, long offset, float value) { + layout.varHandle().set(this, offset, value); + } + + @ForceInline + @Override + public long get(ValueLayout.OfLong layout, long offset) { + return (long) layout.varHandle().get(this, offset); + } + + @ForceInline + @Override + public void set(ValueLayout.OfLong layout, long offset, long value) { + layout.varHandle().set(this, offset, value); + } + + @ForceInline + @Override + public double get(ValueLayout.OfDouble layout, long offset) { + return (double) layout.varHandle().get(this, offset); + } + + @ForceInline + @Override + public void set(ValueLayout.OfDouble layout, long offset, double value) { + layout.varHandle().set(this, offset, value); + } + + @ForceInline + @Override + public MemorySegment get(AddressLayout layout, long offset) { + return (MemorySegment) layout.varHandle().get(this, offset); + } + + @ForceInline + @Override + public void set(AddressLayout layout, long offset, MemorySegment value) { + layout.varHandle().set(this, offset, value); + } + + @ForceInline + @Override + public byte getAtIndex(ValueLayout.OfByte layout, long index) { + Utils.checkElementAlignment(layout, "Layout alignment greater than its size"); + return (byte) layout.varHandle().get(this, index * layout.byteSize()); + } + + @ForceInline + @Override + public boolean getAtIndex(ValueLayout.OfBoolean layout, long index) { + Utils.checkElementAlignment(layout, "Layout alignment greater than its size"); + return (boolean) layout.varHandle().get(this, index * layout.byteSize()); + } + + @ForceInline + @Override + public char getAtIndex(ValueLayout.OfChar layout, long index) { + Utils.checkElementAlignment(layout, "Layout alignment greater than its size"); + return (char) layout.varHandle().get(this, index * layout.byteSize()); + } + + @ForceInline + @Override + public void setAtIndex(ValueLayout.OfChar layout, long index, char value) { + Utils.checkElementAlignment(layout, "Layout alignment greater than its size"); + layout.varHandle().set(this, index * layout.byteSize(), value); + } + + @ForceInline + @Override + public short getAtIndex(ValueLayout.OfShort layout, long index) { + Utils.checkElementAlignment(layout, "Layout alignment greater than its size"); + return (short) layout.varHandle().get(this, index * layout.byteSize()); + } + + @ForceInline + @Override + public void setAtIndex(ValueLayout.OfByte layout, long index, byte value) { + Utils.checkElementAlignment(layout, "Layout alignment greater than its size"); + layout.varHandle().set(this, index * layout.byteSize(), value); + } + + @ForceInline + @Override + public void setAtIndex(ValueLayout.OfBoolean layout, long index, boolean value) { + Utils.checkElementAlignment(layout, "Layout alignment greater than its size"); + layout.varHandle().set(this, index * layout.byteSize(), value); + } + + @ForceInline + @Override + public void setAtIndex(ValueLayout.OfShort layout, long index, short value) { + Utils.checkElementAlignment(layout, "Layout alignment greater than its size"); + layout.varHandle().set(this, index * layout.byteSize(), value); + } + + @ForceInline + @Override + public int getAtIndex(ValueLayout.OfInt layout, long index) { + Utils.checkElementAlignment(layout, "Layout alignment greater than its size"); + return (int) layout.varHandle().get(this, index * layout.byteSize()); + } + + @ForceInline + @Override + public void setAtIndex(ValueLayout.OfInt layout, long index, int value) { + Utils.checkElementAlignment(layout, "Layout alignment greater than its size"); + layout.varHandle().set(this, index * layout.byteSize(), value); + } + + @ForceInline + @Override + public float getAtIndex(ValueLayout.OfFloat layout, long index) { + Utils.checkElementAlignment(layout, "Layout alignment greater than its size"); + return (float) layout.varHandle().get(this, index * layout.byteSize()); + } + + @ForceInline + @Override + public void setAtIndex(ValueLayout.OfFloat layout, long index, float value) { + Utils.checkElementAlignment(layout, "Layout alignment greater than its size"); + layout.varHandle().set(this, index * layout.byteSize(), value); + } + + @ForceInline + @Override + public long getAtIndex(ValueLayout.OfLong layout, long index) { + Utils.checkElementAlignment(layout, "Layout alignment greater than its size"); + return (long) layout.varHandle().get(this, index * layout.byteSize()); + } + + @ForceInline + @Override + public void setAtIndex(ValueLayout.OfLong layout, long index, long value) { + Utils.checkElementAlignment(layout, "Layout alignment greater than its size"); + layout.varHandle().set(this, index * layout.byteSize(), value); + } + + @ForceInline + @Override + public double getAtIndex(ValueLayout.OfDouble layout, long index) { + Utils.checkElementAlignment(layout, "Layout alignment greater than its size"); + return (double) layout.varHandle().get(this, index * layout.byteSize()); + } + + @ForceInline + @Override + public void setAtIndex(ValueLayout.OfDouble layout, long index, double value) { + Utils.checkElementAlignment(layout, "Layout alignment greater than its size"); + layout.varHandle().set(this, index * layout.byteSize(), value); + } + + @ForceInline + @Override + public MemorySegment getAtIndex(AddressLayout layout, long index) { + Utils.checkElementAlignment(layout, "Layout alignment greater than its size"); + return (MemorySegment) layout.varHandle().get(this, index * layout.byteSize()); + } + + @ForceInline + @Override + public void setAtIndex(AddressLayout layout, long index, MemorySegment value) { + Utils.checkElementAlignment(layout, "Layout alignment greater than its size"); + layout.varHandle().set(this, index * layout.byteSize(), value); + } + + @Override + public String getString(long offset) { + return getString(offset, sun.nio.cs.UTF_8.INSTANCE); + } + + @Override + public String getString(long offset, Charset charset) { + Objects.requireNonNull(charset); + return StringSupport.read(this, offset, charset); + } + + @Override + public void setString(long offset, String str) { + Objects.requireNonNull(str); + setString(offset, str, sun.nio.cs.UTF_8.INSTANCE); + } + + @Override + public void setString(long offset, String str, Charset charset) { + Objects.requireNonNull(charset); + Objects.requireNonNull(str); + StringSupport.write(this, offset, charset, str); + } } 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 eb67ad5e3af..42baaa69270 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 @@ -25,16 +25,26 @@ */ package jdk.internal.foreign.layout; +import jdk.internal.foreign.LayoutPath; +import jdk.internal.foreign.LayoutPath.PathElementImpl.PathKind; import jdk.internal.foreign.Utils; import java.lang.foreign.GroupLayout; import java.lang.foreign.MemoryLayout; +import java.lang.foreign.MemoryLayout.PathElement; import java.lang.foreign.SequenceLayout; import java.lang.foreign.StructLayout; import java.lang.foreign.UnionLayout; import java.lang.foreign.ValueLayout; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.lang.invoke.VarHandle; +import java.util.EnumSet; import java.util.Objects; import java.util.Optional; +import java.util.Set; +import java.util.function.Function; public abstract sealed class AbstractLayout & MemoryLayout> permits AbstractGroupLayout, PaddingLayoutImpl, SequenceLayoutImpl, ValueLayouts.AbstractValueLayout { @@ -140,4 +150,72 @@ private static long requirePowerOfTwoAndGreaterOrEqualToOne(long value) { return 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); + } + + return Math.addExact(offset, Math.multiplyExact(byteSize(), index)); + } + + public MethodHandle scaleHandle() { + class Holder { + static final MethodHandle MH_SCALE; + static { + try { + MH_SCALE = MethodHandles.lookup().findVirtual(MemoryLayout.class, "scale", + MethodType.methodType(long.class, long.class, long.class)); + } catch (ReflectiveOperationException e) { + throw new ExceptionInInitializerError(e); + } + } + } + return Holder.MH_SCALE.bindTo(this); + } + + + public long byteOffset(PathElement... elements) { + return computePathOp(LayoutPath.rootPath((MemoryLayout) this), LayoutPath::offset, + EnumSet.of(PathKind.SEQUENCE_ELEMENT, PathKind.SEQUENCE_RANGE, PathKind.DEREF_ELEMENT), elements); + } + + public MethodHandle byteOffsetHandle(PathElement... elements) { + return computePathOp(LayoutPath.rootPath((MemoryLayout) this), LayoutPath::offsetHandle, + EnumSet.of(PathKind.DEREF_ELEMENT), elements); + } + + public VarHandle varHandle(PathElement... elements) { + Objects.requireNonNull(elements); + if (this instanceof ValueLayout vl && elements.length == 0) { + return vl.varHandle(); // fast path + } + return computePathOp(LayoutPath.rootPath((MemoryLayout) this), LayoutPath::dereferenceHandle, + Set.of(), elements); + } + + public MethodHandle sliceHandle(PathElement... elements) { + return computePathOp(LayoutPath.rootPath((MemoryLayout) this), LayoutPath::sliceHandle, + Set.of(PathKind.DEREF_ELEMENT), elements); + } + + public MemoryLayout select(PathElement... elements) { + return computePathOp(LayoutPath.rootPath((MemoryLayout) this), LayoutPath::layout, + EnumSet.of(PathKind.SEQUENCE_ELEMENT_INDEX, PathKind.SEQUENCE_RANGE, PathKind.DEREF_ELEMENT), elements); + } + + private static Z computePathOp(LayoutPath path, Function finalizer, + Set badKinds, PathElement... elements) { + Objects.requireNonNull(elements); + for (PathElement e : elements) { + LayoutPath.PathElementImpl pathElem = (LayoutPath.PathElementImpl)Objects.requireNonNull(e); + if (badKinds.contains(pathElem.kind())) { + throw new IllegalArgumentException(String.format("Invalid %s selection in layout path", pathElem.kind().description())); + } + path = pathElem.apply(path); + } + return finalizer.apply(path); + } } From 3c70f2c1e9fb91cd5d7a66ef1e2a39672230208c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Jeli=C5=84ski?= Date: Thu, 19 Oct 2023 10:36:35 +0000 Subject: [PATCH 011/124] 8318418: hsdis build fails with system binutils on Ubuntu Reviewed-by: erikj, ihse --- make/autoconf/lib-hsdis.m4 | 5 +++-- src/utils/hsdis/binutils/hsdis-binutils.c | 3 +-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/make/autoconf/lib-hsdis.m4 b/make/autoconf/lib-hsdis.m4 index 470a0ae8358..974d0e8b793 100644 --- a/make/autoconf/lib-hsdis.m4 +++ b/make/autoconf/lib-hsdis.m4 @@ -1,5 +1,5 @@ # -# Copyright (c) 2021, 2022, 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 @@ -236,7 +236,8 @@ AC_DEFUN([LIB_SETUP_HSDIS_BINUTILS], if test "x$BINUTILS_DIR" = xsystem; then AC_CHECK_LIB(bfd, bfd_openr, [ HSDIS_LIBS="-lbfd" ], [ binutils_system_error="libbfd not found" ]) AC_CHECK_LIB(opcodes, disassembler, [ HSDIS_LIBS="$HSDIS_LIBS -lopcodes" ], [ binutils_system_error="libopcodes not found" ]) - AC_CHECK_LIB(iberty, xmalloc, [ HSDIS_LIBS="$HSDIS_LIBS -liberty" ], [ binutils_system_error="libiberty not found" ]) + # libiberty is not required on Ubuntu + AC_CHECK_LIB(iberty, xmalloc, [ HSDIS_LIBS="$HSDIS_LIBS -liberty" ]) AC_CHECK_LIB(z, deflate, [ HSDIS_LIBS="$HSDIS_LIBS -lz" ], [ binutils_system_error="libz not found" ]) HSDIS_CFLAGS="-DLIBARCH_$OPENJDK_TARGET_CPU_LEGACY_LIB" elif test "x$BINUTILS_DIR" != x; then diff --git a/src/utils/hsdis/binutils/hsdis-binutils.c b/src/utils/hsdis/binutils/hsdis-binutils.c index 279ed53ba5d..28e374e05fc 100644 --- a/src/utils/hsdis/binutils/hsdis-binutils.c +++ b/src/utils/hsdis/binutils/hsdis-binutils.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -57,7 +57,6 @@ #include #include -#include #include #include From defc7e0f8d32e2dc62568f34d86d8f77a759e6ce Mon Sep 17 00:00:00 2001 From: Per Minborg Date: Thu, 19 Oct 2023 10:47:53 +0000 Subject: [PATCH 012/124] 8318454: TestLayoutPaths broken on Big Endian platforms after JDK-8317837 Reviewed-by: mdoerr, mcimadamore --- test/jdk/java/foreign/TestLayoutPaths.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/test/jdk/java/foreign/TestLayoutPaths.java b/test/jdk/java/foreign/TestLayoutPaths.java index c3692b1fb9d..f04814f5849 100644 --- a/test/jdk/java/foreign/TestLayoutPaths.java +++ b/test/jdk/java/foreign/TestLayoutPaths.java @@ -42,7 +42,6 @@ import static java.lang.foreign.MemoryLayout.PathElement.groupElement; import static java.lang.foreign.MemoryLayout.PathElement.sequenceElement; import static java.lang.foreign.ValueLayout.JAVA_INT; -import static java.lang.foreign.ValueLayout.JAVA_LONG; import static java.lang.foreign.ValueLayout.JAVA_SHORT; import static org.testng.Assert.*; @@ -139,8 +138,8 @@ public void testByteOffsetHandleBadRange() { @Test public void testBadAlignmentOfRoot() { MemoryLayout struct = MemoryLayout.structLayout( - JAVA_INT, - JAVA_SHORT.withName("x")); + JAVA_INT.withOrder(ByteOrder.LITTLE_ENDIAN), + JAVA_SHORT.withOrder(ByteOrder.LITTLE_ENDIAN).withName("x")); assertEquals(struct.byteAlignment(), 4); try (Arena arena = Arena.ofConfined()) { From 9cf334fb6488188ea4236e5d156b11245bace88f Mon Sep 17 00:00:00 2001 From: Zhengyu Gu Date: Thu, 19 Oct 2023 13:56:16 +0000 Subject: [PATCH 013/124] 8318383: Remove duplicated checks in os::get_native_stack() in posix implementation Reviewed-by: dholmes, stuefe --- src/hotspot/os/posix/os_posix.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/hotspot/os/posix/os_posix.cpp b/src/hotspot/os/posix/os_posix.cpp index c302a5d031c..11dbead5d39 100644 --- a/src/hotspot/os/posix/os_posix.cpp +++ b/src/hotspot/os/posix/os_posix.cpp @@ -156,13 +156,10 @@ int os::get_native_stack(address* stack, int frames, int toSkip) { stack[frame_idx ++] = fr.pc(); } if (fr.fp() == nullptr || fr.cb() != nullptr || - fr.sender_pc() == nullptr || os::is_first_C_frame(&fr)) break; - - if (fr.sender_pc() && !os::is_first_C_frame(&fr)) { - fr = os::get_sender_for_C_frame(&fr); - } else { + fr.sender_pc() == nullptr || os::is_first_C_frame(&fr)) { break; } + fr = os::get_sender_for_C_frame(&fr); } num_of_frames = frame_idx; for (; frame_idx < frames; frame_idx ++) { From 599560a832386d9c61aca24450d6efa65156f663 Mon Sep 17 00:00:00 2001 From: Alex Menkov Date: Thu, 19 Oct 2023 18:12:16 +0000 Subject: [PATCH 014/124] 8317635: Improve GetClassFields test to verify correctness of field order Reviewed-by: cjplummer, sspitsyn --- .../nsk/jvmti/GetClassFields/getclfld007.java | 82 ++++++++-- .../getclfld007/TestDescription.java | 9 +- .../getclfld007/getclfld007.cpp | 147 ++++++------------ 3 files changed, 124 insertions(+), 114 deletions(-) diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetClassFields/getclfld007.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetClassFields/getclfld007.java index 79f4fc16ca9..91ef81c00c8 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetClassFields/getclfld007.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetClassFields/getclfld007.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -24,6 +24,15 @@ package nsk.jvmti.GetClassFields; import java.io.PrintStream; +import java.io.InputStream; +import java.util.List; +import java.util.ArrayList; + +import jdk.internal.org.objectweb.asm.ClassReader; +import jdk.internal.org.objectweb.asm.ClassVisitor; +import jdk.internal.org.objectweb.asm.FieldVisitor; +import jdk.internal.org.objectweb.asm.Opcodes; + public class getclfld007 { @@ -40,7 +49,7 @@ public class getclfld007 { } } - native static void check(int i, Class cls); + native static void check(Class cls, String[] expectedFields); native static int getRes(); public static void main(String args[]) { @@ -52,22 +61,64 @@ public static void main(String args[]) { public static int run(String args[], PrintStream out) { try { - check(0, Class.forName(InnerClass1.class.getName())); - check(1, Class.forName(InnerInterface.class.getName())); - check(2, Class.forName(InnerClass2.class.getName())); - check(3, Class.forName(OuterClass1.class.getName())); - check(4, Class.forName(OuterClass2.class.getName())); - check(5, Class.forName(OuterClass3.class.getName())); - check(6, Class.forName(OuterInterface1.class.getName())); - check(7, Class.forName(OuterInterface2.class.getName())); - check(8, Class.forName(OuterClass4.class.getName())); - check(9, Class.forName(OuterClass5.class.getName())); - } catch (ClassNotFoundException e) { + check(Class.forName(InnerClass1.class.getName())); + check(Class.forName(InnerInterface.class.getName())); + check(Class.forName(InnerClass2.class.getName())); + check(Class.forName(OuterClass1.class.getName())); + check(Class.forName(OuterClass2.class.getName())); + check(Class.forName(OuterClass3.class.getName())); + check(Class.forName(OuterInterface1.class.getName())); + check(Class.forName(OuterInterface2.class.getName())); + check(Class.forName(OuterClass4.class.getName())); + check(Class.forName(OuterClass5.class.getName())); + } catch (Exception e) { throw new RuntimeException(e); } return getRes(); } + + static void check(Class cls) throws Exception { + FieldExplorer explorer = new FieldExplorer(cls); + List fields = explorer.get(); + check(cls, fields.toArray(new String[0])); + } + + // helper class to get list of the class fields + // in the order they appear in the class file + static class FieldExplorer extends ClassVisitor { + private final Class cls; + private List fieldNameAndSig = new ArrayList<>(); + private FieldExplorer(Class cls) { + super(Opcodes.ASM7); + this.cls = cls; + } + + @Override + public FieldVisitor visitField(int access, String name, String descriptor, String signature, Object value) { + System.out.println(" field '" + name + "', type = " + descriptor); + fieldNameAndSig.add(name); + fieldNameAndSig.add(descriptor); + return super.visitField(access, name, descriptor, signature, value); + } + + private InputStream getClassBytes() throws Exception { + String clsName = cls.getName(); + String clsPath = clsName.replace('.', '/') + ".class"; + return cls.getClassLoader().getResourceAsStream(clsPath); + } + + // each field is represented by 2 Strings in the list: name and type descriptor + public List get() throws Exception { + System.out.println("Class " + cls.getName()); + try (InputStream classBytes = getClassBytes()) { + ClassReader classReader = new ClassReader(classBytes); + classReader.accept(this, 0); + } + return fieldNameAndSig; + } + } + static class InnerClass1 { String fld_1; void meth(String s) { @@ -119,8 +170,13 @@ public int meth_i2() { } } +// class with multiple fields to verify correctness of the field order class OuterClass5 extends OuterClass4 { int fld_i1 = 1; + String fld_s1 = "str"; + int fld_i2 = 2; + String fld_s2 = "str2"; + public int meth_i1() { return 1; } diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetClassFields/getclfld007/TestDescription.java b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetClassFields/getclfld007/TestDescription.java index 4df311688bd..80f5d6f580d 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetClassFields/getclfld007/TestDescription.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetClassFields/getclfld007/TestDescription.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 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 @@ -31,9 +31,9 @@ * DESCRIPTION * The test exercises JVMTI function * GetClassFields(clazz, fieldCountPtr, fieldsPtr). - * The test checks if the function returns the expected list of fields. - * That is the field list contains only directly declared (not inherited) - * fields. + * The test checks if the function returns the expected list of fields: + * - the list contains only directly declared (not inherited) fields; + * - fields are returned in the order they occur in the class file. * COMMENTS * Ported from JVMDI. * Test fixed due to test bug: @@ -45,6 +45,7 @@ * * @library /vmTestbase * /test/lib + * @modules java.base/jdk.internal.org.objectweb.asm * @run main/othervm/native -agentlib:getclfld007 nsk.jvmti.GetClassFields.getclfld007 */ diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetClassFields/getclfld007/getclfld007.cpp b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetClassFields/getclfld007/getclfld007.cpp index 597c34787c6..93da371fd54 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetClassFields/getclfld007/getclfld007.cpp +++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/GetClassFields/getclfld007/getclfld007.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -33,69 +33,25 @@ extern "C" { #define PASSED 0 #define STATUS_FAILED 2 -typedef struct { - const char *name; - const char *sig; -} fld_info; - -typedef struct { - const char *name; - jint fcount; - fld_info *flds; -} class_info; - static jvmtiEnv *jvmti = NULL; static jint result = PASSED; -static jboolean printdump = JNI_FALSE; - -static fld_info f0[] = { - { "fld_1", "Ljava/lang/String;" } -}; - -static fld_info f1[] = { - { "fld_n1", "I" } -}; - -static fld_info f2[] = { - { "fld_n2", "I" } -}; - -static fld_info f4[] = { - { "fld_o2", "I" } -}; - -static fld_info f5[] = { - { "fld_o3", "I" } -}; - -static fld_info f6[] = { - { "fld_i1", "I" } -}; - -static fld_info f7[] = { - { "fld_i2", "I" } -}; - -static fld_info f8[] = { - { "fld_i2", "I" } -}; - -static fld_info f9[] = { - { "fld_i1", "I" } -}; - -static class_info classes[] = { - { "InnerClass1", 1, f0 }, - { "InnerInterface", 1, f1 }, - { "InnerClass2", 1, f2 }, - { "OuterClass1", 0, NULL }, - { "OuterClass2", 1, f4 }, - { "OuterClass3", 1, f5 }, - { "OuterInterface1", 1, f6 }, - { "OuterInterface2", 1, f7 }, - { "OuterClass4", 1, f8 }, - { "OuterClass5", 1, f9 } -}; + + +// compares 'value' with jobject_arr[index] +static bool equals_str(JNIEnv *env, const char *value, jobjectArray jobject_arr, jint index) { + jstring jstr = (jstring)env->GetObjectArrayElement(jobject_arr, index); + const char* utf = env->GetStringUTFChars(jstr, NULL); + bool res = false; + if (utf != NULL) { + res = strcmp(value, utf) == 0; + env->ReleaseStringUTFChars(jstr, utf); + } else { + printf("GetStringUTFChars failed\n"); + result = STATUS_FAILED; + } + env->DeleteLocalRef(jstr); + return res; +} #ifdef STATIC_BUILD JNIEXPORT jint JNICALL Agent_OnLoad_getclfld007(JavaVM *jvm, char *options, void *reserved) { @@ -111,10 +67,6 @@ JNIEXPORT jint JNI_OnLoad_getclfld007(JavaVM *jvm, char *options, void *reserved jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) { jint res; - if (options != NULL && strcmp(options, "printdump") == 0) { - printdump = JNI_TRUE; - } - res = jvm->GetEnv((void **) &jvmti, JVMTI_VERSION_1_1); if (res != JNI_OK || jvmti == NULL) { printf("Wrong result of a valid call to GetEnv!\n"); @@ -125,61 +77,62 @@ jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) { } JNIEXPORT void JNICALL -Java_nsk_jvmti_GetClassFields_getclfld007_check(JNIEnv *env, jclass cls, jint i, jclass clazz) { +Java_nsk_jvmti_GetClassFields_getclfld007_check(JNIEnv *env, jclass cls, jclass clazz, jobjectArray fieldArr) { jvmtiError err; jint fcount; jfieldID *fields; - char *name, *sig, *generic; + char *name, *sig; int j; if (jvmti == NULL) { printf("JVMTI client was not properly loaded!\n"); + fflush(0); result = STATUS_FAILED; return; } - if (printdump == JNI_TRUE) { - printf(">>> %s:\n", classes[i].name); - } + // fieldArr contains 2 elements for each field + jint field_count = env->GetArrayLength(fieldArr) / 2; err = jvmti->GetClassFields(clazz, &fcount, &fields); if (err != JVMTI_ERROR_NONE) { - printf("(GetClassFields#%d) unexpected error: %s (%d)\n", - i, TranslateError(err), err); + printf("GetClassFields unexpected error: %s (%d)\n", + TranslateError(err), err); + fflush(0); result = STATUS_FAILED; return; } - if (fcount != classes[i].fcount) { - printf("(%d) wrong number of fields: %d, expected: %d\n", - i, fcount, classes[i].fcount); + if (fcount != field_count) { + printf("wrong number of fields: %d, expected: %d\n", + fcount, field_count); result = STATUS_FAILED; } for (j = 0; j < fcount; j++) { if (fields[j] == NULL) { - printf("(%d:%d) fieldID = null\n", i, j); - } else { - err = jvmti->GetFieldName(clazz, fields[j], - &name, &sig, &generic); - if (err != JVMTI_ERROR_NONE) { - printf("(GetFieldName#%d:%d) unexpected error: %s (%d)\n", - i, j, TranslateError(err), err); - } else { - if (printdump == JNI_TRUE) { - printf(">>> [%d]: %s, sig = \"%s\"\n", j, name, sig); - } - if ((j < classes[i].fcount) && - (name == NULL || sig == NULL || - strcmp(name, classes[i].flds[j].name) != 0 || - strcmp(sig, classes[i].flds[j].sig) != 0)) { - printf("(%d:%d) wrong field: \"%s%s\"", i, j, name, sig); - printf(", expected: \"%s%s\"\n", - classes[i].flds[j].name, classes[i].flds[j].sig); - result = STATUS_FAILED; - } - } + printf("(%d) fieldID = null\n", j); + result = STATUS_FAILED; + continue; + } + err = jvmti->GetFieldName(clazz, fields[j], &name, &sig, NULL); + if (err != JVMTI_ERROR_NONE) { + printf("(GetFieldName#%d) unexpected error: %s (%d)\n", + j, TranslateError(err), err); + result = STATUS_FAILED; + continue; + } + printf(">>> [%d]: %s, sig = \"%s\"\n", j, name, sig); + if ((j < field_count) && + (name == NULL || sig == NULL || + !equals_str(env, name, fieldArr, j * 2) || + !equals_str(env, sig, fieldArr, j * 2 + 1))) { + printf("(%d) wrong field: \"%s%s\"", j, name, sig); + result = STATUS_FAILED; } + jvmti->Deallocate((unsigned char *)name); + jvmti->Deallocate((unsigned char *)sig); } + fflush(0); } JNIEXPORT int JNICALL From cc8f8da293914c25cb15d38caad994bc761a3957 Mon Sep 17 00:00:00 2001 From: Justin Lu Date: Thu, 19 Oct 2023 18:25:43 +0000 Subject: [PATCH 015/124] 8318322: Update IANA Language Subtag Registry to Version 2023-10-16 Reviewed-by: naoto, iris, lancea, srl --- .../data/lsrdata/language-subtag-registry.txt | 52 ++++++++++++++++++- .../Locale/LanguageSubtagRegistryTest.java | 4 +- 2 files changed, 53 insertions(+), 3 deletions(-) diff --git a/src/java.base/share/data/lsrdata/language-subtag-registry.txt b/src/java.base/share/data/lsrdata/language-subtag-registry.txt index 85e0822ed13..c6937ee80f1 100644 --- a/src/java.base/share/data/lsrdata/language-subtag-registry.txt +++ b/src/java.base/share/data/lsrdata/language-subtag-registry.txt @@ -1,4 +1,4 @@ -File-Date: 2023-08-02 +File-Date: 2023-10-16 %% Type: language Subtag: aa @@ -44880,6 +44880,11 @@ Description: Cherokee Added: 2005-10-16 %% Type: script +Subtag: Chis +Description: Chisoi +Added: 2023-10-16 +%% +Type: script Subtag: Chrs Description: Chorasmian Added: 2019-09-11 @@ -44975,6 +44980,11 @@ Description: Ge'ez Added: 2005-10-16 %% Type: script +Subtag: Gara +Description: Garay +Added: 2023-10-16 +%% +Type: script Subtag: Geok Description: Khutsuri (Asomtavruli and Nuskhuri) Added: 2005-10-16 @@ -45020,6 +45030,11 @@ Description: Gujarati Added: 2005-10-16 %% Type: script +Subtag: Gukh +Description: Gurung Khema +Added: 2023-10-16 +%% +Type: script Subtag: Guru Description: Gurmukhi Added: 2005-10-16 @@ -45190,6 +45205,11 @@ Description: Kpelle Added: 2010-04-10 %% Type: script +Subtag: Krai +Description: Kirat Rai +Added: 2023-10-16 +%% +Type: script Subtag: Kthi Description: Kaithi Added: 2007-12-05 @@ -45437,6 +45457,11 @@ Description: Santali Added: 2006-07-21 %% Type: script +Subtag: Onao +Description: Ol Onal +Added: 2023-10-16 +%% +Type: script Subtag: Orkh Description: Old Turkic Description: Orkhon Runic @@ -45616,6 +45641,11 @@ Description: Siddhamātṛkā Added: 2013-12-02 %% Type: script +Subtag: Sidt +Description: Sidetic +Added: 2023-10-16 +%% +Type: script Subtag: Sind Description: Khudawadi Description: Sindhi @@ -45719,6 +45749,11 @@ Description: Tai Viet Added: 2007-12-05 %% Type: script +Subtag: Tayo +Description: Tai Yo +Added: 2023-10-16 +%% +Type: script Subtag: Telu Description: Telugu Added: 2005-10-16 @@ -45767,11 +45802,26 @@ Description: Tangsa Added: 2021-03-05 %% Type: script +Subtag: Todr +Description: Todhri +Added: 2023-10-16 +%% +Type: script +Subtag: Tols +Description: Tolong Siki +Added: 2023-10-16 +%% +Type: script Subtag: Toto Description: Toto Added: 2020-05-12 %% Type: script +Subtag: Tutg +Description: Tulu-Tigalari +Added: 2023-10-16 +%% +Type: script Subtag: Ugar Description: Ugaritic Added: 2005-10-16 diff --git a/test/jdk/java/util/Locale/LanguageSubtagRegistryTest.java b/test/jdk/java/util/Locale/LanguageSubtagRegistryTest.java index aa8e8c2c6f5..d0141b304a8 100644 --- a/test/jdk/java/util/Locale/LanguageSubtagRegistryTest.java +++ b/test/jdk/java/util/Locale/LanguageSubtagRegistryTest.java @@ -24,9 +24,9 @@ /* * @test * @bug 8025703 8040211 8191404 8203872 8222980 8225435 8241082 8242010 8247432 - * 8258795 8267038 8287180 8302512 8304761 8306031 8308021 8313702 + * 8258795 8267038 8287180 8302512 8304761 8306031 8308021 8313702 8318322 * @summary Checks the IANA language subtag registry data update - * (LSR Revision: 2023-08-02) with Locale and Locale.LanguageRange + * (LSR Revision: 2023-10-16) with Locale and Locale.LanguageRange * class methods. * @run main LanguageSubtagRegistryTest */ From 17409500369bd8503782b2e6f4e885e33837087a Mon Sep 17 00:00:00 2001 From: Smita Kamath Date: Thu, 19 Oct 2023 18:27:51 +0000 Subject: [PATCH 016/124] 8314901: AES-GCM interleaved implementation using AVX2 instructions Reviewed-by: sviswanathan, djelinski --- src/hotspot/cpu/x86/assembler_x86.cpp | 17 + src/hotspot/cpu/x86/assembler_x86.hpp | 2 + src/hotspot/cpu/x86/macroAssembler_x86.cpp | 11 + src/hotspot/cpu/x86/macroAssembler_x86.hpp | 3 + src/hotspot/cpu/x86/stubGenerator_x86_64.hpp | 15 + .../cpu/x86/stubGenerator_x86_64_aes.cpp | 653 +++++++++++++++++- src/hotspot/cpu/x86/stubRoutines_x86.hpp | 2 +- .../crypto/provider/GaloisCounterMode.java | 10 +- 8 files changed, 706 insertions(+), 7 deletions(-) diff --git a/src/hotspot/cpu/x86/assembler_x86.cpp b/src/hotspot/cpu/x86/assembler_x86.cpp index 43e08269504..088a89d3758 100644 --- a/src/hotspot/cpu/x86/assembler_x86.cpp +++ b/src/hotspot/cpu/x86/assembler_x86.cpp @@ -1332,6 +1332,11 @@ void Assembler::addb(Address dst, Register src) { emit_operand(src, dst, 0); } +void Assembler::addb(Register dst, int imm8) { + (void) prefix_and_encode(dst->encoding(), true); + emit_arith_b(0x80, 0xC0, dst, imm8); +} + void Assembler::addw(Register dst, Register src) { emit_int8(0x66); (void)prefix_and_encode(dst->encoding(), src->encoding()); @@ -5319,6 +5324,18 @@ void Assembler::vpshufb(XMMRegister dst, XMMRegister nds, XMMRegister src, int v emit_int16(0x00, (0xC0 | encode)); } +void Assembler::vpshufb(XMMRegister dst, XMMRegister nds, Address src, int vector_len) { + assert(vector_len == AVX_128bit ? VM_Version::supports_avx() : + vector_len == AVX_256bit ? VM_Version::supports_avx2() : + vector_len == AVX_512bit ? VM_Version::supports_avx512bw() : 0, ""); + InstructionMark im(this); + InstructionAttr attributes(vector_len, /* rex_w */ false, /* legacy_mode */ _legacy_mode_bw, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_address_attributes(/* tuple_type */ EVEX_FVM, /* input_size_in_bits */ EVEX_NObit); + simd_prefix(dst, nds, src, VEX_SIMD_66, VEX_OPCODE_0F_38, &attributes); + emit_int8(0x00); + emit_operand(dst, src, 0); +} + void Assembler::pshufb(XMMRegister dst, Address src) { assert(VM_Version::supports_ssse3(), ""); InstructionMark im(this); diff --git a/src/hotspot/cpu/x86/assembler_x86.hpp b/src/hotspot/cpu/x86/assembler_x86.hpp index abd6aaf9b1e..ebd65663896 100644 --- a/src/hotspot/cpu/x86/assembler_x86.hpp +++ b/src/hotspot/cpu/x86/assembler_x86.hpp @@ -986,6 +986,7 @@ class Assembler : public AbstractAssembler { void addb(Address dst, int imm8); void addb(Address dst, Register src); + void addb(Register dst, int imm8); void addw(Register dst, Register src); void addw(Address dst, int imm16); void addw(Address dst, Register src); @@ -1952,6 +1953,7 @@ class Assembler : public AbstractAssembler { void pshufb(XMMRegister dst, XMMRegister src); void pshufb(XMMRegister dst, Address src); void vpshufb(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); + void vpshufb(XMMRegister dst, XMMRegister nds, Address src, int vector_len); void evpshufb(XMMRegister dst, KRegister mask, XMMRegister nds, XMMRegister src, bool merge, int vector_len); diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.cpp b/src/hotspot/cpu/x86/macroAssembler_x86.cpp index 26135c65418..da38f6976ff 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.cpp @@ -9280,6 +9280,17 @@ void MacroAssembler::evporq(XMMRegister dst, XMMRegister nds, AddressLiteral src } } +void MacroAssembler::vpshufb(XMMRegister dst, XMMRegister nds, AddressLiteral src, int vector_len, Register rscratch) { + assert(rscratch != noreg || always_reachable(src), "missing"); + + if (reachable(src)) { + vpshufb(dst, nds, as_Address(src), vector_len); + } else { + lea(rscratch, src); + vpshufb(dst, nds, Address(rscratch, 0), vector_len); + } +} + void MacroAssembler::vpternlogq(XMMRegister dst, int imm8, XMMRegister src2, AddressLiteral src3, int vector_len, Register rscratch) { assert(rscratch != noreg || always_reachable(src3), "missing"); diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.hpp b/src/hotspot/cpu/x86/macroAssembler_x86.hpp index fad9d0c7d3c..ab461aaffdf 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.hpp @@ -1795,6 +1795,9 @@ class MacroAssembler: public Assembler { using Assembler::evporq; void evporq(XMMRegister dst, XMMRegister nds, AddressLiteral src, int vector_len, Register rscratch = noreg); + using Assembler::vpshufb; + void vpshufb(XMMRegister dst, XMMRegister nds, AddressLiteral src, int vector_len, Register rscratch = noreg); + using Assembler::vpternlogq; void vpternlogq(XMMRegister dst, int imm8, XMMRegister src2, AddressLiteral src3, int vector_len, Register rscratch = noreg); diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64.hpp b/src/hotspot/cpu/x86/stubGenerator_x86_64.hpp index 8657080b8f7..3b568ace836 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64.hpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64.hpp @@ -327,6 +327,10 @@ class StubGenerator: public StubCodeGenerator { void aesgcm_encrypt(Register in, Register len, Register ct, Register out, Register key, Register state, Register subkeyHtbl, Register avx512_subkeyHtbl, Register counter); + // AVX2 AES Galois Counter Mode implementation + address generate_avx2_galoisCounterMode_AESCrypt(); + void aesgcm_avx2(Register in, Register len, Register ct, Register out, Register key, + Register state, Register subkeyHtbl, Register counter); // Vector AES Counter implementation address generate_counterMode_VectorAESCrypt(); @@ -353,6 +357,17 @@ class StubGenerator: public StubCodeGenerator { XMMRegister aad_hashx, Register in, Register out, Register data, Register pos, bool reduction, XMMRegister addmask, bool no_ghash_input, Register rounds, Register ghash_pos, bool final_reduction, int index, XMMRegister counter_inc_mask); + // AVX2 AES-GCM related functions + void initial_blocks_avx2(XMMRegister ctr, Register rounds, Register key, Register len, + Register in, Register out, Register ct, XMMRegister aad_hashx, Register pos); + void gfmul_avx2(XMMRegister GH, XMMRegister HK); + void generateHtbl_8_block_avx2(Register htbl); + void ghash8_encrypt8_parallel_avx2(Register key, Register subkeyHtbl, XMMRegister ctr_blockx, Register in, + Register out, Register ct, Register pos, bool out_order, Register rounds, + XMMRegister xmm1, XMMRegister xmm2, XMMRegister xmm3, XMMRegister xmm4, + XMMRegister xmm5, XMMRegister xmm6, XMMRegister xmm7, XMMRegister xmm8); + void ghash_last_8_avx2(Register subkeyHtbl); + // Load key and shuffle operation void ev_load_key(XMMRegister xmmdst, Register key, int offset, XMMRegister xmm_shuf_mask); void ev_load_key(XMMRegister xmmdst, Register key, int offset, Register rscratch); diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64_aes.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64_aes.cpp index f758fcc64ec..322cf296949 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64_aes.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64_aes.cpp @@ -1,5 +1,5 @@ /* -* Copyright (c) 2019, 2021, Intel Corporation. All rights reserved. +* Copyright (c) 2019, 2023, Intel Corporation. All rights reserved. * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -81,6 +81,30 @@ static address counter_mask_linc1_addr() { return (address)COUNTER_MASK_LINC1; } +ATTRIBUTE_ALIGNED(16) uint64_t COUNTER_MASK_LINC1F[] = { + 0x0000000000000000UL, 0x0100000000000000UL, +}; + +static address counter_mask_linc1f_addr() { + return (address)COUNTER_MASK_LINC1F; +} + +ATTRIBUTE_ALIGNED(16) uint64_t COUNTER_MASK_LINC2[] = { + 0x0000000000000002UL, 0x0000000000000000UL, +}; + +static address counter_mask_linc2_addr() { + return (address)COUNTER_MASK_LINC2; +} + +ATTRIBUTE_ALIGNED(16) uint64_t COUNTER_MASK_LINC2F[] = { + 0x0000000000000000UL, 0x0200000000000000UL, +}; + +static address counter_mask_linc2f_addr() { + return (address)COUNTER_MASK_LINC2F; +} + ATTRIBUTE_ALIGNED(64) static const uint64_t COUNTER_MASK_LINC4[] = { 0x0000000000000004UL, 0x0000000000000000UL, 0x0000000000000004UL, 0x0000000000000000UL, @@ -163,6 +187,9 @@ void StubGenerator::generate_aes_stubs() { StubRoutines::_galoisCounterMode_AESCrypt = generate_galoisCounterMode_AESCrypt(); } else { StubRoutines::_cipherBlockChaining_decryptAESCrypt = generate_cipherBlockChaining_decryptAESCrypt_Parallel(); + if (VM_Version::supports_avx2()) { + StubRoutines::_galoisCounterMode_AESCrypt = generate_avx2_galoisCounterMode_AESCrypt(); + } } } @@ -264,6 +291,90 @@ address StubGenerator::generate_galoisCounterMode_AESCrypt() { return start; } +// AVX2 Vector AES Galois Counter Mode implementation. +// +// Inputs: Windows | Linux +// in = rcx (c_rarg0) | rsi (c_rarg0) +// len = rdx (c_rarg1) | rdi (c_rarg1) +// ct = r8 (c_rarg2) | rdx (c_rarg2) +// out = r9 (c_rarg3) | rcx (c_rarg3) +// key = rdi | r8 (c_rarg4) +// state = r13 | r9 (c_rarg5) +// subkeyHtbl = r11 | r11 +// counter = rsi | r12 +// +// Output: +// rax - number of processed bytes +address StubGenerator::generate_avx2_galoisCounterMode_AESCrypt() { + __ align(CodeEntryAlignment); + StubCodeMark mark(this, "StubRoutines", "galoisCounterMode_AESCrypt"); + address start = __ pc(); + + const Register in = c_rarg0; + const Register len = c_rarg1; + const Register ct = c_rarg2; + const Register out = c_rarg3; + // and updated with the incremented counter in the end + #ifndef _WIN64 + const Register key = c_rarg4; + const Register state = c_rarg5; + const Address subkeyH_mem(rbp, 2 * wordSize); + const Register subkeyHtbl = r11; + const Address counter_mem(rbp, 3 * wordSize); + const Register counter = r12; + #else + const Address key_mem(rbp, 6 * wordSize); + const Register key = rdi; + const Address state_mem(rbp, 7 * wordSize); + const Register state = r13; + const Address subkeyH_mem(rbp, 8 * wordSize); + const Register subkeyHtbl = r11; + const Address counter_mem(rbp, 9 * wordSize); + const Register counter = rsi; + #endif + __ enter(); + // Save state before entering routine + __ push(r12); + __ push(r13); + __ push(r14); + __ push(r15); + __ push(rbx); +#ifdef _WIN64 + // on win64, fill len_reg from stack position + __ push(rsi); + __ push(rdi); + __ movptr(key, key_mem); + __ movptr(state, state_mem); +#endif + __ movptr(subkeyHtbl, subkeyH_mem); + __ movptr(counter, counter_mem); + + // Save rsp + __ movq(r14, rsp); + // Align stack + __ andq(rsp, -64); + __ subptr(rsp, 16 * longSize); // Create space on the stack for saving AES entries + + aesgcm_avx2(in, len, ct, out, key, state, subkeyHtbl, counter); + __ vzeroupper(); + __ movq(rsp, r14); + // Restore state before leaving routine + #ifdef _WIN64 + __ pop(rdi); + __ pop(rsi); + #endif + __ pop(rbx); + __ pop(r15); + __ pop(r14); + __ pop(r13); + __ pop(r12); + + __ leave(); // required for proper stackwalking of RuntimeStub frame + __ ret(0); + + return start; +} + // Vector AES Counter implementation address StubGenerator::generate_counterMode_VectorAESCrypt() { __ align(CodeEntryAlignment); @@ -3181,4 +3292,544 @@ void StubGenerator::aesgcm_encrypt(Register in, Register len, Register ct, Regis __ movq(rax, pos); } +//Implements data * hashkey mod (128, 127, 126, 121, 0) +//Inputs: +//GH and HK - 128 bits each +//Output: +//GH = GH * Hashkey mod poly +//Temp registers: xmm1, xmm2, xmm3, r15 +void StubGenerator::gfmul_avx2(XMMRegister GH, XMMRegister HK) { + const XMMRegister T1 = xmm1; + const XMMRegister T2 = xmm2; + const XMMRegister T3 = xmm3; + + __ vpclmulqdq(T1, GH, HK, 0x11); // %%T1 = a1*b1 + __ vpclmulqdq(T2, GH, HK, 0x00); // %%T2 = a0*b0 + __ vpclmulqdq(T3, GH, HK, 0x01); // %%T3 = a1*b0 + __ vpclmulqdq(GH, GH, HK, 0x10); // %%GH = a0*b1 + __ vpxor(GH, GH, T3, Assembler::AVX_128bit); + + __ vpsrldq(T3, GH, 8, Assembler::AVX_128bit); // shift-R %%GH 2 DWs + __ vpslldq(GH, GH, 8, Assembler::AVX_128bit); // shift-L %%GH 2 DWs + + __ vpxor(T1, T1, T3, Assembler::AVX_128bit); + __ vpxor(GH, GH, T2, Assembler::AVX_128bit); + + //first phase of the reduction + __ movdqu(T3, ExternalAddress(ghash_polynomial_reduction_addr()), r15 /*rscratch*/); + __ vpclmulqdq(T2, T3, GH, 0x01); + __ vpslldq(T2, T2, 8, Assembler::AVX_128bit); // shift-L %%T2 2 DWs + + __ vpxor(GH, GH, T2, Assembler::AVX_128bit); // first phase of the reduction complete + //second phase of the reduction + __ vpclmulqdq(T2, T3, GH, 0x00); + __ vpsrldq(T2, T2, 4, Assembler::AVX_128bit); // shift-R %%T2 1 DW (Shift-R only 1-DW to obtain 2-DWs shift-R) + + __ vpclmulqdq(GH, T3, GH, 0x10); + __ vpslldq(GH, GH, 4, Assembler::AVX_128bit); // shift-L %%GH 1 DW (Shift-L 1-DW to obtain result with no shifts) + + __ vpxor(GH, GH, T2, Assembler::AVX_128bit); // second phase of the reduction complete + __ vpxor(GH, GH, T1, Assembler::AVX_128bit); // the result is in %%GH +} + +//Generate 8 constants from the given subkeyH. +//Input: +//htbl - table containing the initial subkeyH +//Output: +//htbl - containing 8 H constants +//Temp registers: xmm0, xmm1, xmm2, xmm3, xmm6, xmm11, xmm12, r15, rbx +void StubGenerator::generateHtbl_8_block_avx2(Register htbl) { + const XMMRegister HK = xmm6; + + __ movdqu(HK, Address(htbl, 0)); + __ movdqu(xmm1, ExternalAddress(ghash_long_swap_mask_addr()), rbx /*rscratch*/); + __ vpshufb(HK, HK, xmm1, Assembler::AVX_128bit); + + __ movdqu(xmm11, ExternalAddress(ghash_polynomial_addr()), rbx /*rscratch*/); + __ movdqu(xmm12, ExternalAddress(ghash_polynomial_two_one_addr()), rbx /*rscratch*/); + // Compute H ^ 2 from the input subkeyH + __ vpsrlq(xmm1, xmm6, 63, Assembler::AVX_128bit); + __ vpsllq(xmm6, xmm6, 1, Assembler::AVX_128bit); + __ vpslldq(xmm2, xmm1, 8, Assembler::AVX_128bit); + __ vpsrldq(xmm1, xmm1, 8, Assembler::AVX_128bit); + + __ vpor(xmm6, xmm6, xmm2, Assembler::AVX_128bit); + + __ vpshufd(xmm2, xmm1, 0x24, Assembler::AVX_128bit); + __ vpcmpeqd(xmm2, xmm2, xmm12, Assembler::AVX_128bit); + __ vpand(xmm2, xmm2, xmm11, Assembler::AVX_128bit); + __ vpxor(xmm6, xmm6, xmm2, Assembler::AVX_128bit); + __ movdqu(Address(htbl, 1 * 16), xmm6); // H * 2 + __ movdqu(xmm0, xmm6); + for (int i = 2; i < 9; i++) { + gfmul_avx2(xmm6, xmm0); + __ movdqu(Address(htbl, i * 16), xmm6); + } +} + +#define aesenc_step_avx2(t_key)\ +__ aesenc(xmm1, t_key);\ +__ aesenc(xmm2, t_key);\ +__ aesenc(xmm3, t_key);\ +__ aesenc(xmm4, t_key);\ +__ aesenc(xmm5, t_key);\ +__ aesenc(xmm6, t_key);\ +__ aesenc(xmm7, t_key);\ +__ aesenc(xmm8, t_key);\ + +#define ghash_step_avx2(ghdata, hkey) \ +__ vpclmulqdq(xmm11, ghdata, hkey, 0x11);\ +__ vpxor(xmm12, xmm12, xmm11, Assembler::AVX_128bit);\ +__ vpclmulqdq(xmm11, ghdata, hkey, 0x00);\ +__ vpxor(xmm15, xmm15, xmm11, Assembler::AVX_128bit);\ +__ vpclmulqdq(xmm11, ghdata, hkey, 0x01);\ +__ vpxor(xmm14, xmm14, xmm11, Assembler::AVX_128bit);\ +__ vpclmulqdq(xmm11, ghdata, hkey, 0x10);\ +__ vpxor(xmm14, xmm14, xmm11, Assembler::AVX_128bit);\ + +//Encrypts and hashes 8 blocks in an interleaved fashion. +//Inputs: +//key - key for aes operations +//subkeyHtbl - table containing H constants +//ctr_blockx - counter for aes operations +//in - input buffer +//out - output buffer +//ct - ciphertext buffer +//pos - holds the length processed in this method +//in_order - boolean that indicates if incrementing counter without shuffling is needed +//rounds - number of aes rounds calculated based on key length +//xmm1-xmm8 - holds encrypted counter values +//Outputs: +//xmm1-xmm8 - updated encrypted counter values +//ctr_blockx - updated counter value +//out - updated output buffer +//Temp registers: xmm0, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15, rbx +void StubGenerator::ghash8_encrypt8_parallel_avx2(Register key, Register subkeyHtbl, XMMRegister ctr_blockx, Register in, + Register out, Register ct, Register pos, bool in_order, Register rounds, + XMMRegister xmm1, XMMRegister xmm2, XMMRegister xmm3, XMMRegister xmm4, + XMMRegister xmm5, XMMRegister xmm6, XMMRegister xmm7, XMMRegister xmm8) { + const XMMRegister t1 = xmm0; + const XMMRegister t2 = xmm10; + const XMMRegister t3 = xmm11; + const XMMRegister t4 = xmm12; + const XMMRegister t5 = xmm13; + const XMMRegister t6 = xmm14; + const XMMRegister t7 = xmm15; + Label skip_reload, last_aes_rnd, aes_192, aes_256; + + __ movdqu(t2, xmm1); + for (int i = 0; i <= 6; i++) { + __ movdqu(Address(rsp, 16 * i), as_XMMRegister(i + 2)); + } + + if (in_order) { + __ vpaddd(xmm1, ctr_blockx, ExternalAddress(counter_mask_linc1_addr()), Assembler::AVX_128bit, rbx /*rscratch*/); //Increment counter by 1 + __ movdqu(t5, ExternalAddress(counter_mask_linc2_addr()), rbx /*rscratch*/); + __ vpaddd(xmm2, ctr_blockx, t5, Assembler::AVX_128bit); + for (int rnum = 1; rnum <= 6; rnum++) { + __ vpaddd(as_XMMRegister(rnum + 2), as_XMMRegister(rnum), t5, Assembler::AVX_128bit); + } + __ movdqu(ctr_blockx, xmm8); + + __ movdqu(t5, ExternalAddress(counter_shuffle_mask_addr()), rbx /*rscratch*/); + for (int rnum = 1; rnum <= 8; rnum++) { + __ vpshufb(as_XMMRegister(rnum), as_XMMRegister(rnum), t5, Assembler::AVX_128bit); //perform a 16Byte swap + } + } else { + __ vpaddd(xmm1, ctr_blockx, ExternalAddress(counter_mask_linc1f_addr()), Assembler::AVX_128bit, rbx /*rscratch*/); //Increment counter by 1 + __ vmovdqu(t5, ExternalAddress(counter_mask_linc2f_addr()), Assembler::AVX_128bit, rbx /*rscratch*/); + __ vpaddd(xmm2, ctr_blockx, t5, Assembler::AVX_128bit); + for (int rnum = 1; rnum <= 6; rnum++) { + __ vpaddd(as_XMMRegister(rnum + 2), as_XMMRegister(rnum), t5, Assembler::AVX_128bit); + } + __ movdqu(ctr_blockx, xmm8); + } + + load_key(t1, key, 16 * 0, rbx /*rscratch*/); + for (int rnum = 1; rnum <= 8; rnum++) { + __ vpxor(as_XMMRegister(rnum), as_XMMRegister(rnum), t1, Assembler::AVX_128bit); + } + + load_key(t1, key, 16 * 1, rbx /*rscratch*/); + aesenc_step_avx2(t1); + + load_key(t1, key, 16 * 2, rbx /*rscratch*/); + aesenc_step_avx2(t1); + + __ movdqu(t5, (Address(subkeyHtbl, 8 * 16))); + __ vpclmulqdq(t4, t2, t5, 0x11); //t4 = a1*b1 + __ vpclmulqdq(t7, t2, t5, 0x00); //t7 = a0*b0 + __ vpclmulqdq(t6, t2, t5, 0x01); //t6 = a1*b0 + __ vpclmulqdq(t5, t2, t5, 0x10); //t5 = a0*b1 + __ vpxor(t6, t6, t5, Assembler::AVX_128bit); + + for (int i = 3, j = 0; i <= 8; i++, j++) { + load_key(t1, key, 16 * i, rbx /*rscratch*/); + aesenc_step_avx2(t1); + __ movdqu(t1, Address(rsp, 16 * j)); + __ movdqu(t5, (Address(subkeyHtbl, (7 - j) * 16))); + ghash_step_avx2(t1, t5); + } + + load_key(t1, key, 16 * 9, rbx /*rscratch*/); + aesenc_step_avx2(t1); + + __ movdqu(t1, Address(rsp, 16 * 6)); + __ movdqu(t5, (Address(subkeyHtbl, 1 * 16))); + + __ vpclmulqdq(t3, t1, t5, 0x00); + __ vpxor(t7, t7, t3, Assembler::AVX_128bit); + + __ vpclmulqdq(t3, t1, t5, 0x01); + __ vpxor(t6, t6, t3, Assembler::AVX_128bit); + + __ vpclmulqdq(t3, t1, t5, 0x10); + __ vpxor(t6, t6, t3, Assembler::AVX_128bit); + + __ vpclmulqdq(t3, t1, t5, 0x11); + __ vpxor(t1, t4, t3, Assembler::AVX_128bit); + + __ vpslldq(t3, t6, 8, Assembler::AVX_128bit); //shift-L t3 2 DWs + __ vpsrldq(t6, t6, 8, Assembler::AVX_128bit); //shift-R t2 2 DWs + __ vpxor(t7, t7, t3, Assembler::AVX_128bit); + __ vpxor(t1, t1, t6, Assembler::AVX_128bit); // accumulate the results in t1:t7 + + load_key(t5, key, 16 * 10, rbx /*rscratch*/); + __ cmpl(rounds, 52); + __ jcc(Assembler::less, last_aes_rnd); + + __ bind(aes_192); + aesenc_step_avx2(t5); + load_key(t5, key, 16 * 11, rbx /*rscratch*/); + aesenc_step_avx2(t5); + load_key(t5, key, 16 * 12, rbx /*rscratch*/); + __ cmpl(rounds, 60); + __ jcc(Assembler::less, last_aes_rnd); + + __ bind(aes_256); + aesenc_step_avx2(t5); + load_key(t5, key, 16 * 13, rbx /*rscratch*/); + aesenc_step_avx2(t5); + load_key(t5, key, 16 * 14, rbx /*rscratch*/); + __ bind(last_aes_rnd); + for (int rnum = 1; rnum <= 8; rnum++) { + __ aesenclast(as_XMMRegister(rnum), t5); + } + + for (int i = 0; i <= 7; i++) { + __ movdqu(t2, Address(in, pos, Address::times_1, 16 * i)); + __ vpxor(as_XMMRegister(i + 1), as_XMMRegister(i + 1), t2, Assembler::AVX_128bit); + } + + //first phase of the reduction + __ vmovdqu(t3, ExternalAddress(ghash_polynomial_reduction_addr()), Assembler::AVX_128bit, rbx /*rscratch*/); + + __ vpclmulqdq(t2, t3, t7, 0x01); + __ vpslldq(t2, t2, 8, Assembler::AVX_128bit); //shift-L xmm2 2 DWs + + __ vpxor(t7, t7, t2, Assembler::AVX_128bit); //first phase of the reduction complete + + //Write to the Ciphertext buffer + for (int i = 0; i <= 7; i++) { + __ movdqu(Address(out, pos, Address::times_1, 16 * i), as_XMMRegister(i + 1)); + } + + __ cmpptr(ct, out); + __ jcc(Assembler::equal, skip_reload); + for (int i = 0; i <= 7; i++) { + __ movdqu(as_XMMRegister(i + 1), Address(in, pos, Address::times_1, 16 * i)); + } + + __ bind(skip_reload); + //second phase of the reduction + __ vpclmulqdq(t2, t3, t7, 0x00); + __ vpsrldq(t2, t2, 4, Assembler::AVX_128bit); //shift-R t2 1 DW (Shift-R only 1-DW to obtain 2-DWs shift-R) + + __ vpclmulqdq(t4, t3, t7, 0x10); + __ vpslldq(t4, t4, 4, Assembler::AVX_128bit); //shift-L t4 1 DW (Shift-L 1-DW to obtain result with no shifts) + __ vpxor(t4, t4, t2, Assembler::AVX_128bit); //second phase of the reduction complete + __ vpxor(t1, t1, t4, Assembler::AVX_128bit); //the result is in t1 + + //perform a 16Byte swap + __ movdqu(t7, ExternalAddress(counter_shuffle_mask_addr()), rbx /*rscratch*/); + for (int rnum = 1; rnum <= 8; rnum++) { + __ vpshufb(as_XMMRegister(rnum), as_XMMRegister(rnum), t7, Assembler::AVX_128bit); + } + __ vpxor(xmm1, xmm1, t1, Assembler::AVX_128bit); +} + +//GHASH the last 8 ciphertext blocks. +//Input: +//subkeyHtbl - table containing H constants +//Output: +//xmm14 - calculated aad hash +//Temp registers: xmm0, xmm10, xmm11, xmm12, xmm13, xmm15, rbx +void StubGenerator::ghash_last_8_avx2(Register subkeyHtbl) { + const XMMRegister t1 = xmm0; + const XMMRegister t2 = xmm10; + const XMMRegister t3 = xmm11; + const XMMRegister t4 = xmm12; + const XMMRegister t5 = xmm13; + const XMMRegister t6 = xmm14; + const XMMRegister t7 = xmm15; + + //Karatsuba Method + __ movdqu(t5, Address(subkeyHtbl, 8 * 16)); + + __ vpshufd(t2, xmm1, 78, Assembler::AVX_128bit); + __ vpshufd(t3, t5, 78, Assembler::AVX_128bit); + __ vpxor(t2, t2, xmm1, Assembler::AVX_128bit); + __ vpxor(t3, t3, t5, Assembler::AVX_128bit); + + __ vpclmulqdq(t6, xmm1, t5, 0x11); + __ vpclmulqdq(t7, xmm1, t5, 0x00); + + __ vpclmulqdq(xmm1, t2, t3, 0x00); + + for (int i = 7, rnum = 2; rnum <= 8; i--, rnum++) { + __ movdqu(t5, Address(subkeyHtbl, i * 16)); + __ vpshufd(t2, as_XMMRegister(rnum), 78, Assembler::AVX_128bit); + __ vpshufd(t3, t5, 78, Assembler::AVX_128bit); + __ vpxor(t2, t2, as_XMMRegister(rnum), Assembler::AVX_128bit); + __ vpxor(t3, t3, t5, Assembler::AVX_128bit); + __ vpclmulqdq(t4, as_XMMRegister(rnum), t5, 0x11); + __ vpxor(t6, t6, t4, Assembler::AVX_128bit); + __ vpclmulqdq(t4, as_XMMRegister(rnum), t5, 0x00); + __ vpxor(t7, t7, t4, Assembler::AVX_128bit); + __ vpclmulqdq(t2, t2, t3, 0x00); + __ vpxor(xmm1, xmm1, t2, Assembler::AVX_128bit); + } + + __ vpxor(xmm1, xmm1, t6, Assembler::AVX_128bit); + __ vpxor(t2, xmm1, t7, Assembler::AVX_128bit); + + __ vpslldq(t4, t2, 8, Assembler::AVX_128bit); + __ vpsrldq(t2, t2, 8, Assembler::AVX_128bit); + + __ vpxor(t7, t7, t4, Assembler::AVX_128bit); + __ vpxor(t6, t6, t2, Assembler::AVX_128bit); // holds the result of the accumulated carry-less multiplications + + //first phase of the reduction + __ movdqu(t3, ExternalAddress(ghash_polynomial_reduction_addr()), rbx /*rscratch*/); + + __ vpclmulqdq(t2, t3, t7, 0x01); + __ vpslldq(t2, t2, 8, Assembler::AVX_128bit); // shift-L t2 2 DWs + + __ vpxor(t7, t7, t2, Assembler::AVX_128bit);//first phase of the reduction complete + + //second phase of the reduction + __ vpclmulqdq(t2, t3, t7, 0x00); + __ vpsrldq(t2, t2, 4, Assembler::AVX_128bit); //shift-R t2 1 DW (Shift-R only 1-DW to obtain 2-DWs shift-R) + + __ vpclmulqdq(t4, t3, t7, 0x10); + __ vpslldq(t4, t4, 4, Assembler::AVX_128bit); //shift-L t4 1 DW (Shift-L 1-DW to obtain result with no shifts) + __ vpxor(t4, t4, t2, Assembler::AVX_128bit); //second phase of the reduction complete + __ vpxor(t6, t6, t4, Assembler::AVX_128bit); //the result is in t6 +} + +//Encrypt initial number of 8 blocks +//Inputs: +//ctr - counter for aes operations +//rounds - number of aes rounds calculated based on key length +//key - key for aes operations +//len - input length to be processed +//in - input buffer +//out - output buffer +//ct - ciphertext buffer +//aad_hashx - input aad hash +//pos - holds the length processed in this method +//Outputs: +//xmm1-xmm8 - holds updated encrypted counter values +//ctr - updated counter value +//pos - updated position +//len - updated length +//out - updated output buffer +//Temp registers: xmm0, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15 +void StubGenerator::initial_blocks_avx2(XMMRegister ctr, Register rounds, Register key, Register len, Register in, + Register out, Register ct, XMMRegister aad_hashx, Register pos) { + const XMMRegister t1 = xmm12; + const XMMRegister t2 = xmm13; + const XMMRegister t3 = xmm14; + const XMMRegister t4 = xmm15; + const XMMRegister t5 = xmm11; + const XMMRegister t6 = xmm10; + const XMMRegister t_key = xmm0; + + Label skip_reload, last_aes_rnd, aes_192, aes_256; + //Move AAD_HASH to temp reg t3 + __ movdqu(t3, aad_hashx); + //Prepare 8 counter blocks and perform rounds of AES cipher on + //them, load plain/cipher text and store cipher/plain text. + __ movdqu(xmm1, ctr); + __ movdqu(t5, ExternalAddress(counter_mask_linc1_addr()), rbx /*rscratch*/); + __ movdqu(t6, ExternalAddress(counter_mask_linc2_addr()), rbx /*rscratch*/ ); + __ vpaddd(xmm2, xmm1, t5, Assembler::AVX_128bit); + for (int rnum = 1; rnum <= 6; rnum++) { + __ vpaddd(as_XMMRegister(rnum + 2), as_XMMRegister(rnum), t6, Assembler::AVX_128bit); + } + __ movdqu(ctr, xmm8); + + __ movdqu(t5, ExternalAddress(counter_shuffle_mask_addr()), rbx /*rscratch*/); + for (int rnum = 1; rnum <= 8; rnum++) { + __ vpshufb(as_XMMRegister(rnum), as_XMMRegister(rnum), t5, Assembler::AVX_128bit); //perform a 16Byte swap + } + + load_key(t_key, key, 16 * 0, rbx /*rscratch*/); + for (int rnum = 1; rnum <= 8; rnum++) { + __ vpxor(as_XMMRegister(rnum), as_XMMRegister(rnum), t_key, Assembler::AVX_128bit); + } + + for (int i = 1; i <= 9; i++) { + load_key(t_key, key, 16 * i, rbx /*rscratch*/); + aesenc_step_avx2(t_key); + } + + load_key(t_key, key, 16 * 10, rbx /*rscratch*/); + __ cmpl(rounds, 52); + __ jcc(Assembler::less, last_aes_rnd); + + __ bind(aes_192); + aesenc_step_avx2(t_key); + load_key(t_key, key, 16 * 11, rbx /*rscratch*/); + aesenc_step_avx2(t_key); + load_key(t_key, key, 16 * 12, rbx /*rscratch*/); + __ cmpl(rounds, 60); + __ jcc(Assembler::less, last_aes_rnd); + + __ bind(aes_256); + aesenc_step_avx2(t_key); + load_key(t_key, key, 16 * 13, rbx /*rscratch*/); + aesenc_step_avx2(t_key); + load_key(t_key, key, 16 * 14, rbx /*rscratch*/); + + __ bind(last_aes_rnd); + for (int rnum = 1; rnum <= 8; rnum++) { + __ aesenclast(as_XMMRegister(rnum), t_key); + } + + //XOR and store data + for (int i = 0; i <= 7; i++) { + __ movdqu(t1, Address(in, pos, Address::times_1, 16 * i)); + __ vpxor(as_XMMRegister(i + 1), as_XMMRegister(i + 1), t1, Assembler::AVX_128bit); + __ movdqu(Address(out, pos, Address::times_1, 16 * i), as_XMMRegister(i + 1)); + } + + __ cmpptr(ct, out); + __ jcc(Assembler::equal, skip_reload); + for (int i = 0; i <= 7; i++) { + __ movdqu(as_XMMRegister(i + 1), Address(in, pos, Address::times_1, 16 * i)); + } + + __ bind(skip_reload); + //Update len with the number of blocks processed + __ subl(len, 128); + __ addl(pos, 128); + + __ movdqu(t4, ExternalAddress(counter_shuffle_mask_addr()), rbx /*rscratch*/); + for (int rnum = 1; rnum <= 8; rnum++) { + __ vpshufb(as_XMMRegister(rnum), as_XMMRegister(rnum), t4, Assembler::AVX_128bit); + } + // Combine GHASHed value with the corresponding ciphertext + __ vpxor(xmm1, xmm1, t3, Assembler::AVX_128bit); +} + +//AES-GCM interleaved implementation +//Inputs: +//in - input buffer +//len- message length to be processed +//ct - cipher text buffer +//out - output buffer +//key - key for aes operations +//state - address of aad hash for ghash computation +//subkeyHtbl- table consisting of H constants +//counter - address of counter for aes operations +//Output: +//(counter) - updated in memory counter value +//(state) - updated in memory aad hash +//rax - length processed +//(out) - output buffer updated +//len - updated length +//Temp registers: xmm0-xmm15, r10, r15, rbx +void StubGenerator::aesgcm_avx2(Register in, Register len, Register ct, Register out, Register key, + Register state, Register subkeyHtbl, Register counter) { + const Register pos = rax; + const Register rounds = r10; + const XMMRegister ctr_blockx = xmm9; + const XMMRegister aad_hashx = xmm8; + Label encrypt_done, encrypt_by_8_new, encrypt_by_8; + + //This routine should be called only for message sizes of 128 bytes or more. + //Macro flow: + //process 8 16 byte blocks in initial_num_blocks. + //process 8 16 byte blocks at a time until all are done 'encrypt_by_8_new followed by ghash_last_8' + __ xorl(pos, pos); + + //Generate 8 constants for htbl + generateHtbl_8_block_avx2(subkeyHtbl); + + //Compute #rounds for AES based on the length of the key array + __ movl(rounds, Address(key, arrayOopDesc::length_offset_in_bytes() - arrayOopDesc::base_offset_in_bytes(T_INT))); + + //Load and shuffle state and counter values + __ movdqu(ctr_blockx, Address(counter, 0)); + __ movdqu(aad_hashx, Address(state, 0)); + __ vpshufb(ctr_blockx, ctr_blockx, ExternalAddress(counter_shuffle_mask_addr()), Assembler::AVX_128bit, rbx /*rscratch*/); + __ vpshufb(aad_hashx, aad_hashx, ExternalAddress(ghash_long_swap_mask_addr()), Assembler::AVX_128bit, rbx /*rscratch*/); + + initial_blocks_avx2(ctr_blockx, rounds, key, len, in, out, ct, aad_hashx, pos); + + //We need at least 128 bytes to proceed further. + __ cmpl(len, 128); + __ jcc(Assembler::less, encrypt_done); + + //in_order vs. out_order is an optimization to increment the counter without shuffling + //it back into little endian. r15d keeps track of when we need to increment in order so + //that the carry is handled correctly. + __ movdl(r15, ctr_blockx); + __ andl(r15, 255); + __ vpshufb(ctr_blockx, ctr_blockx, ExternalAddress(counter_shuffle_mask_addr()), Assembler::AVX_128bit, rbx /*rscratch*/); + + __ bind(encrypt_by_8_new); + __ cmpl(r15, 255 - 8); + __ jcc(Assembler::greater, encrypt_by_8); + + __ addb(r15, 8); + ghash8_encrypt8_parallel_avx2(key, subkeyHtbl, ctr_blockx, in, out, ct, pos, false, rounds, + xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, xmm8); + __ addl(pos, 128); + __ subl(len, 128); + __ cmpl(len, 128); + __ jcc(Assembler::greaterEqual, encrypt_by_8_new); + + __ vpshufb(ctr_blockx, ctr_blockx, ExternalAddress(counter_shuffle_mask_addr()), Assembler::AVX_128bit, rbx /*rscratch*/); + __ jmp(encrypt_done); + + __ bind(encrypt_by_8); + __ vpshufb(ctr_blockx, ctr_blockx, ExternalAddress(counter_shuffle_mask_addr()), Assembler::AVX_128bit, rbx /*rscratch*/); + + __ addb(r15, 8); + ghash8_encrypt8_parallel_avx2(key, subkeyHtbl, ctr_blockx, in, out, ct, pos, true, rounds, + xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7, xmm8); + + __ vpshufb(ctr_blockx, ctr_blockx, ExternalAddress(counter_shuffle_mask_addr()), Assembler::AVX_128bit, rbx /*rscratch*/); + __ addl(pos, 128); + __ subl(len, 128); + __ cmpl(len, 128); + __ jcc(Assembler::greaterEqual, encrypt_by_8_new); + __ vpshufb(ctr_blockx, ctr_blockx, ExternalAddress(counter_shuffle_mask_addr()), Assembler::AVX_128bit, rbx /*rscratch*/); + + __ bind(encrypt_done); + ghash_last_8_avx2(subkeyHtbl); + + __ vpaddd(ctr_blockx, ctr_blockx, ExternalAddress(counter_mask_linc1_addr()), Assembler::AVX_128bit, rbx /*rscratch*/); + __ vpshufb(ctr_blockx, ctr_blockx, ExternalAddress(counter_shuffle_mask_addr()), Assembler::AVX_128bit, rbx /*rscratch*/); + __ movdqu(Address(counter, 0), ctr_blockx); //current_counter = xmm9 + __ vpshufb(xmm14, xmm14, ExternalAddress(ghash_long_swap_mask_addr()), Assembler::AVX_128bit, rbx /*rscratch*/); + __ movdqu(Address(state, 0), xmm14); //aad hash = xmm14 + //Xor out round keys + __ vpxor(xmm0, xmm0, xmm0, Assembler::AVX_128bit); + __ vpxor(xmm13, xmm13, xmm13, Assembler::AVX_128bit); + + } + #undef __ diff --git a/src/hotspot/cpu/x86/stubRoutines_x86.hpp b/src/hotspot/cpu/x86/stubRoutines_x86.hpp index a5246860c0f..375cefd5e1d 100644 --- a/src/hotspot/cpu/x86/stubRoutines_x86.hpp +++ b/src/hotspot/cpu/x86/stubRoutines_x86.hpp @@ -37,7 +37,7 @@ enum platform_dependent_constants { _continuation_stubs_code_size = 1000 LP64_ONLY(+1000), // AVX512 intrinsics add more code in 64-bit VM, // Windows have more code to save/restore registers - _compiler_stubs_code_size = 20000 LP64_ONLY(+30000) WINDOWS_ONLY(+2000), + _compiler_stubs_code_size = 20000 LP64_ONLY(+32000) WINDOWS_ONLY(+2000), _final_stubs_code_size = 10000 LP64_ONLY(+20000) WINDOWS_ONLY(+2000) ZGC_ONLY(+20000) }; diff --git a/src/java.base/share/classes/com/sun/crypto/provider/GaloisCounterMode.java b/src/java.base/share/classes/com/sun/crypto/provider/GaloisCounterMode.java index 686fe384707..bca020b74ed 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/GaloisCounterMode.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/GaloisCounterMode.java @@ -618,13 +618,13 @@ private static int implGCMCrypt(byte[] in, int inOfs, int inLen, byte[] ct, * Intrinsic for the combined AES Galois Counter Mode implementation. * AES and GHASH operations are combined in the intrinsic implementation. * - * Requires 768 bytes (48 AES blocks) to efficiently use the intrinsic. - * inLen that is less than 768 size block sizes, before or after this - * intrinsic is used, will be done by the calling method + * Requires PARALLEN_LEN bytes to efficiently use the intrinsic. + * The intrinsic returns the number of bytes processed. + * The remaining bytes will be processed by the calling method. * * Note: - * Only Intel processors with AVX512 that support vaes, vpclmulqdq, - * avx512dq, and avx512vl trigger this intrinsic. + * Intel processors with AVX2 support and above trigger this intrinsic. + * Some AARCH64 processors also trigger this intrinsic. * Other processors will always use GHASH and GCTR which may have their own * intrinsic support * From 684b91efbb22f16cd0952283e8c960846c39d1db Mon Sep 17 00:00:00 2001 From: Justin Lu Date: Thu, 19 Oct 2023 22:53:07 +0000 Subject: [PATCH 017/124] 8315064: j.text.ChoiceFormat provides no specification on quoting behavior Reviewed-by: naoto --- src/java.base/share/classes/java/text/ChoiceFormat.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/java.base/share/classes/java/text/ChoiceFormat.java b/src/java.base/share/classes/java/text/ChoiceFormat.java index ed49b11bd45..538454d669a 100644 --- a/src/java.base/share/classes/java/text/ChoiceFormat.java +++ b/src/java.base/share/classes/java/text/ChoiceFormat.java @@ -187,6 +187,12 @@ * * Note:The relation ≤ is not equivalent to <= * + *

If a Relation symbol is to be used within a Format pattern, + * it must be single quoted. For example, + * {@code new ChoiceFormat("1# '#'1 ").format(1)} returns {@code " #1 "}. + * Use two single quotes in a row to produce a literal single quote. For example, + * {@code new ChoiceFormat("1# ''one'' ").format(1)} returns {@code " 'one' "}. + * *

Below is an example of constructing a ChoiceFormat with a pattern: *

* {@snippet lang=java : From 8f5f44070a7c6dbbbd1005f9d0af5ab7c35179df Mon Sep 17 00:00:00 2001 From: Hannes Greule Date: Thu, 19 Oct 2023 23:24:28 +0000 Subject: [PATCH 018/124] 8317692: jcmd GC.heap_dump performance regression after JDK-8292818 Reviewed-by: amenkov, fparain --- src/hotspot/share/oops/fieldStreams.hpp | 103 +++++++++- src/hotspot/share/services/heapDumper.cpp | 14 +- .../HeapDump/FieldsInInstanceTest.java | 190 ++++++++++++++++++ 3 files changed, 299 insertions(+), 8 deletions(-) create mode 100644 test/hotspot/jtreg/serviceability/HeapDump/FieldsInInstanceTest.java diff --git a/src/hotspot/share/oops/fieldStreams.hpp b/src/hotspot/share/oops/fieldStreams.hpp index b72fcc99f56..47ecdddfa38 100644 --- a/src/hotspot/share/oops/fieldStreams.hpp +++ b/src/hotspot/share/oops/fieldStreams.hpp @@ -37,6 +37,7 @@ // iterates over fields that have been injected by the JVM. // AllFieldStream exposes all fields and should only be used in rare // cases. +// HierarchicalFieldStream allows to also iterate over fields of supertypes. class FieldStreamBase : public StackObj { protected: const Array* _fieldinfo_stream; @@ -135,7 +136,7 @@ class FieldStreamBase : public StackObj { } }; -// Iterate over only the internal fields +// Iterate over only the Java fields class JavaFieldStream : public FieldStreamBase { public: JavaFieldStream(const InstanceKlass* k): FieldStreamBase(k->fieldinfo_stream(), k->constants(), 0, k->java_fields_count()) {} @@ -179,4 +180,104 @@ class AllFieldStream : public FieldStreamBase { AllFieldStream(const InstanceKlass* k): FieldStreamBase(k->fieldinfo_stream(), k->constants()) {} }; +// Iterate over fields including the ones declared in supertypes +template +class HierarchicalFieldStream : public StackObj { + private: + const Array* _interfaces; + InstanceKlass* _next_klass; // null indicates no more type to visit + FieldStreamType _current_stream; + int _interface_index; + + void prepare() { + _next_klass = next_klass_with_fields(); + // special case: the initial klass has no fields. If any supertype has any fields, use that directly. + // if no such supertype exists, done() will return false already. + next_stream_if_done(); + } + + InstanceKlass* next_klass_with_fields() { + assert(_next_klass != nullptr, "reached end of types already"); + InstanceKlass* result = _next_klass; + do { + if (!result->is_interface() && result->super() != nullptr) { + result = result->java_super(); + } else if (_interface_index > 0) { + result = _interfaces->at(--_interface_index); + } else { + return nullptr; // we did not find any more supertypes with fields + } + } while (FieldStreamType(result).done()); + return result; + } + + // sets _current_stream to the next if the current is done and any more is available + void next_stream_if_done() { + if (_next_klass != nullptr && _current_stream.done()) { + _current_stream = FieldStreamType(_next_klass); + assert(!_current_stream.done(), "created empty stream"); + _next_klass = next_klass_with_fields(); + } + } + + public: + HierarchicalFieldStream(InstanceKlass* klass) : + _interfaces(klass->transitive_interfaces()), + _next_klass(klass), + _current_stream(FieldStreamType(klass)), + _interface_index(_interfaces->length()) { + prepare(); + } + + void next() { + _current_stream.next(); + next_stream_if_done(); + } + + bool done() const { return _next_klass == nullptr && _current_stream.done(); } + + // bridge functions from FieldStreamBase + + AccessFlags access_flags() const { + return _current_stream.access_flags(); + } + + FieldInfo::FieldFlags field_flags() const { + return _current_stream.field_flags(); + } + + Symbol* name() const { + return _current_stream.name(); + } + + Symbol* signature() const { + return _current_stream.signature(); + } + + Symbol* generic_signature() const { + return _current_stream.generic_signature(); + } + + int offset() const { + return _current_stream.offset(); + } + + bool is_contended() const { + return _current_stream.is_contended(); + } + + int contended_group() const { + return _current_stream.contended_group(); + } + + FieldInfo to_FieldInfo() { + return _current_stream.to_FieldInfo(); + } + + fieldDescriptor& field_descriptor() const { + return _current_stream.field_descriptor(); + } + +}; + #endif // SHARE_OOPS_FIELDSTREAMS_HPP diff --git a/src/hotspot/share/services/heapDumper.cpp b/src/hotspot/share/services/heapDumper.cpp index 347dfa3c17b..fb2b618f3e6 100644 --- a/src/hotspot/share/services/heapDumper.cpp +++ b/src/hotspot/share/services/heapDumper.cpp @@ -38,6 +38,7 @@ #include "memory/allocation.inline.hpp" #include "memory/resourceArea.hpp" #include "memory/universe.hpp" +#include "oops/fieldStreams.inline.hpp" #include "oops/klass.inline.hpp" #include "oops/objArrayKlass.hpp" #include "oops/objArrayOop.inline.hpp" @@ -50,7 +51,6 @@ #include "runtime/javaThread.inline.hpp" #include "runtime/jniHandles.hpp" #include "runtime/os.hpp" -#include "runtime/reflectionUtils.hpp" #include "runtime/threads.hpp" #include "runtime/threadSMR.hpp" #include "runtime/vframe.hpp" @@ -935,7 +935,7 @@ u4 DumperSupport::instance_size(Klass* k) { InstanceKlass* ik = InstanceKlass::cast(k); u4 size = 0; - for (FieldStream fld(ik, false, false); !fld.eos(); fld.next()) { + for (HierarchicalFieldStream fld(ik); !fld.done(); fld.next()) { if (!fld.access_flags().is_static()) { size += sig2size(fld.signature()); } @@ -947,7 +947,7 @@ u4 DumperSupport::get_static_fields_size(InstanceKlass* ik, u2& field_count) { field_count = 0; u4 size = 0; - for (FieldStream fldc(ik, true, true); !fldc.eos(); fldc.next()) { + for (JavaFieldStream fldc(ik); !fldc.done(); fldc.next()) { if (fldc.access_flags().is_static()) { field_count++; size += sig2size(fldc.signature()); @@ -981,7 +981,7 @@ void DumperSupport::dump_static_fields(AbstractDumpWriter* writer, Klass* k) { InstanceKlass* ik = InstanceKlass::cast(k); // dump the field descriptors and raw values - for (FieldStream fld(ik, true, true); !fld.eos(); fld.next()) { + for (JavaFieldStream fld(ik); !fld.done(); fld.next()) { if (fld.access_flags().is_static()) { Symbol* sig = fld.signature(); @@ -1015,7 +1015,7 @@ void DumperSupport::dump_static_fields(AbstractDumpWriter* writer, Klass* k) { void DumperSupport::dump_instance_fields(AbstractDumpWriter* writer, oop o) { InstanceKlass* ik = InstanceKlass::cast(o->klass()); - for (FieldStream fld(ik, false, false); !fld.eos(); fld.next()) { + for (HierarchicalFieldStream fld(ik); !fld.done(); fld.next()) { if (!fld.access_flags().is_static()) { Symbol* sig = fld.signature(); dump_field_value(writer, sig->char_at(0), o, fld.offset()); @@ -1027,7 +1027,7 @@ void DumperSupport::dump_instance_fields(AbstractDumpWriter* writer, oop o) { u2 DumperSupport::get_instance_fields_count(InstanceKlass* ik) { u2 field_count = 0; - for (FieldStream fldc(ik, true, true); !fldc.eos(); fldc.next()) { + for (JavaFieldStream fldc(ik); !fldc.done(); fldc.next()) { if (!fldc.access_flags().is_static()) field_count++; } @@ -1039,7 +1039,7 @@ void DumperSupport::dump_instance_field_descriptors(AbstractDumpWriter* writer, InstanceKlass* ik = InstanceKlass::cast(k); // dump the field descriptors - for (FieldStream fld(ik, true, true); !fld.eos(); fld.next()) { + for (JavaFieldStream fld(ik); !fld.done(); fld.next()) { if (!fld.access_flags().is_static()) { Symbol* sig = fld.signature(); diff --git a/test/hotspot/jtreg/serviceability/HeapDump/FieldsInInstanceTest.java b/test/hotspot/jtreg/serviceability/HeapDump/FieldsInInstanceTest.java new file mode 100644 index 00000000000..72c52789051 --- /dev/null +++ b/test/hotspot/jtreg/serviceability/HeapDump/FieldsInInstanceTest.java @@ -0,0 +1,190 @@ +/* + * 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. + */ + +import java.io.File; +import java.lang.ref.Reference; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.TimeUnit; + +import jdk.test.lib.Asserts; +import jdk.test.lib.JDKToolLauncher; +import jdk.test.lib.apps.LingeredApp; +import jdk.test.lib.process.ProcessTools; +import jdk.test.lib.hprof.model.JavaClass; +import jdk.test.lib.hprof.model.JavaHeapObject; +import jdk.test.lib.hprof.model.JavaObject; +import jdk.test.lib.hprof.model.JavaThing; +import jdk.test.lib.hprof.model.Snapshot; +import jdk.test.lib.hprof.parser.Reader; + +/* + * @test + * @bug 8317692 + * @summary Verifies heap dump contains all fields of an instance + * @library /test/lib + * @run driver FieldsInInstanceTest + */ +class FieldsInInstanceTarg extends LingeredApp { + + public static void main(String[] args) { + B b = new B(); + NoFields2 nf = new NoFields2(); + NoParentFields npf = new NoParentFields(); + OnlyParentFields opf = new OnlyParentFields(); + DirectParentNoFields dpnf = new DirectParentNoFields(); + LingeredApp.main(args); + Reference.reachabilityFence(b); + Reference.reachabilityFence(nf); + Reference.reachabilityFence(npf); + Reference.reachabilityFence(opf); + Reference.reachabilityFence(dpnf); + } + + interface I { + int i = -10; + } + static abstract class A implements I { + static boolean b; + int a = 3; + String s = "Field"; + } + static class B extends A { + static String f = null; + int a = 7; + double s = 0.5d; + } + + // no fields: + interface I1 { + } + static class NoFields1 { + } + static class NoFields2 extends NoFields1 implements I1 { + } + + // no parent fields + static class NoParentFields extends NoFields1 implements I1 { + int i1 = 1; + int i2 = 2; + } + + // only parent fields + static class Parent1 { + int i3 = 3; + } + static class OnlyParentFields extends Parent1 { + } + + // in between parent with no fields + static class DirectParentNoFields extends OnlyParentFields { + int i = 17; + } +} + +public class FieldsInInstanceTest { + + public static void main(String[] args) throws Exception { + File dumpFile = new File("Myheapdump.hprof"); + createDump(dumpFile, args); + verifyDump(dumpFile); + } + + private static void createDump(File dumpFile, String[] extraOptions) throws Exception { + LingeredApp theApp = null; + try { + theApp = new FieldsInInstanceTarg(); + + List extraVMArgs = new ArrayList<>(); + extraVMArgs.addAll(Arrays.asList(extraOptions)); + LingeredApp.startApp(theApp, extraVMArgs.toArray(new String[0])); + + //jcmd GC.heap_dump + JDKToolLauncher launcher = JDKToolLauncher + .createUsingTestJDK("jcmd") + .addToolArg(Long.toString(theApp.getPid())) + .addToolArg("GC.heap_dump") + .addToolArg(dumpFile.getAbsolutePath()); + Process p = ProcessTools.startProcess("jcmd", new ProcessBuilder(launcher.getCommand())); + // If something goes wrong with heap dumping most likely we'll get crash of the target VM. + while (!p.waitFor(5, TimeUnit.SECONDS)) { + if (!theApp.getProcess().isAlive()) { + log("ERROR: target VM died, killing jcmd..."); + p.destroyForcibly(); + throw new Exception("Target VM died"); + } + } + + if (p.exitValue() != 0) { + throw new Exception("Jcmd exited with code " + p.exitValue()); + } + } finally { + LingeredApp.stopApp(theApp); + } + } + + private static void verifyDump(File dumpFile) throws Exception { + Asserts.assertTrue(dumpFile.exists(), "Heap dump file not found."); + + log("Reading " + dumpFile + "..."); + try (Snapshot snapshot = Reader.readFile(dumpFile.getPath(), true, 0)) { + log("Resolving snapshot..."); + snapshot.resolve(true); + log("Snapshot resolved."); + + List bFields = getFields(snapshot, FieldsInInstanceTarg.B.class); + // B has 2 instance fields, A has 2 instance fields + Asserts.assertEquals(bFields.size(), 4); + // JavaObject reverses the order of fields, so fields of B are at the end. + // Order is only specified for supertypes, so we check if values are *anywhere* in their range + // by using the toString output. + String asString = bFields.subList(2, 4).toString(); + Asserts.assertTrue(asString.contains("0.5"), "value for field B.s not found"); + Asserts.assertTrue(asString.contains("7"), "value for field B.a not found"); + asString = bFields.subList(0, 2).toString(); + Asserts.assertTrue(asString.contains("3"), "value for field A.a not found"); + Asserts.assertTrue(asString.contains("Field"), "value for field A.s not found"); + + Asserts.assertEquals(getFields(snapshot, FieldsInInstanceTarg.NoFields2.class).size(), 0); + + Asserts.assertEquals(getFields(snapshot, FieldsInInstanceTarg.NoParentFields.class).size(), 2); + + Asserts.assertEquals(getFields(snapshot, FieldsInInstanceTarg.OnlyParentFields.class).size(), 1); + + Asserts.assertEquals(getFields(snapshot, FieldsInInstanceTarg.DirectParentNoFields.class).size(), 2); + } + } + + private static List getFields(Snapshot snapshot, Class clazz) { + JavaObject javaObject = (JavaObject) snapshot.findClass(clazz.getName()).getInstances(false).nextElement(); + List fields = Arrays.asList(javaObject.getFields()); + log("Fields for " + clazz + " (including superclasses): " + fields); + return fields; + } + + private static void log(Object s) { + System.out.println(s); + } + +} \ No newline at end of file From c46a54e01815c5d441a958aa81451e66849ce774 Mon Sep 17 00:00:00 2001 From: Alan Bateman Date: Fri, 20 Oct 2023 05:56:26 +0000 Subject: [PATCH 019/124] 8312777: notifyJvmtiMount before notifyJvmtiUnmount Reviewed-by: mli, sspitsyn --- .../classes/java/lang/VirtualThread.java | 42 +++++++++---------- 1 file changed, 20 insertions(+), 22 deletions(-) diff --git a/src/java.base/share/classes/java/lang/VirtualThread.java b/src/java.base/share/classes/java/lang/VirtualThread.java index e3b94c4ef90..c0bd7d30932 100644 --- a/src/java.base/share/classes/java/lang/VirtualThread.java +++ b/src/java.base/share/classes/java/lang/VirtualThread.java @@ -106,7 +106,7 @@ final class VirtualThread extends BaseVirtualThread { * TIMED_PINNED -> RUNNING // unparked, continue execution on same carrier * * RUNNABLE -> RUNNING // continue execution - + * * RUNNING -> YIELDING // Thread.yield * YIELDING -> RUNNABLE // yield successful * YIELDING -> RUNNING // yield failed @@ -228,9 +228,6 @@ private void runContinuation() { return; } - // notify JVMTI before mount - notifyJvmtiMount(/*hide*/true); - mount(); try { cont.run(); @@ -303,7 +300,6 @@ private void submitFailed(RejectedExecutionException ree) { /** * Runs a task in the context of this virtual thread. */ - @ChangesCurrentThread private void run(Runnable task) { assert Thread.currentThread() == this && state == RUNNING; @@ -348,6 +344,9 @@ private void run(Runnable task) { @ChangesCurrentThread @ReservedStackAccess private void mount() { + // notify JVMTI before mount + notifyJvmtiMount(/*hide*/true); + // sets the carrier thread Thread carrier = Thread.currentCarrierThread(); setCarrierThread(carrier); @@ -384,6 +383,9 @@ private void unmount() { setCarrierThread(null); } carrier.clearInterrupt(); + + // notify JVMTI after unmount + notifyJvmtiUnmount(/*hide*/false); } /** @@ -448,13 +450,12 @@ private void afterYield() { assert carrierThread == null; int s = state(); + + // LockSupport.park/parkNanos if (s == PARKING || s == TIMED_PARKING) { int newState = (s == PARKING) ? PARKED : TIMED_PARKED; setState(newState); - // notify JVMTI that unmount has completed, thread is parked - notifyJvmtiUnmount(/*hide*/false); - // may have been unparked while parking if (parkPermit && compareAndSetState(newState, RUNNABLE)) { // lazy submit to continue on the current thread as carrier if possible @@ -465,11 +466,12 @@ private void afterYield() { } } - } else if (s == YIELDING) { // Thread.yield - setState(RUNNABLE); + return; + } - // notify JVMTI that unmount has completed, thread is runnable - notifyJvmtiUnmount(/*hide*/false); + // Thread.yield + if (s == YIELDING) { + setState(RUNNABLE); // external submit if there are no tasks in the local task queue if (currentThread() instanceof CarrierThread ct && ct.getQueuedTaskCount() == 0) { @@ -477,16 +479,17 @@ private void afterYield() { } else { submitRunContinuation(); } - } else { - assert false; + return; } + + assert false; } /** * Invoked after the continuation completes. */ private void afterDone() { - afterDone(true, true); + afterDone(true); } /** @@ -494,16 +497,11 @@ private void afterDone() { * state to TERMINATED and notifies anyone waiting for the thread to terminate. * * @param notifyContainer true if its container should be notified - * @param executed true if the thread executed, false if it failed to start */ - private void afterDone(boolean notifyContainer, boolean executed) { + private void afterDone(boolean notifyContainer) { assert carrierThread == null; setState(TERMINATED); - if (executed) { - notifyJvmtiUnmount(/*hide*/false); - } - // notify anyone waiting for this virtual thread to terminate CountDownLatch termination = this.termination; if (termination != null) { @@ -552,7 +550,7 @@ void start(ThreadContainer container) { started = true; } finally { if (!started) { - afterDone(addedToContainer, /*executed*/false); + afterDone(addedToContainer); } } } From d9ce525a1c27f41ef66c39b3ec18e3a87bbd8dd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Jeli=C5=84ski?= Date: Fri, 20 Oct 2023 06:18:18 +0000 Subject: [PATCH 020/124] 8318150: StaticProxySelector.select should not throw NullPointerExceptions Reviewed-by: jpai, dfuchs --- .../share/classes/java/net/ProxySelector.java | 19 ++-- .../java/net/ProxySelector/NullArguments.java | 88 ++++++++----------- 2 files changed, 50 insertions(+), 57 deletions(-) diff --git a/src/java.base/share/classes/java/net/ProxySelector.java b/src/java.base/share/classes/java/net/ProxySelector.java index f29c6738c52..40e11ef54e5 100644 --- a/src/java.base/share/classes/java/net/ProxySelector.java +++ b/src/java.base/share/classes/java/net/ProxySelector.java @@ -27,7 +27,6 @@ import java.io.IOException; import java.util.List; -import java.util.Locale; import sun.security.util.SecurityConstants; @@ -178,7 +177,8 @@ public static void setDefault(ProxySelector ps) { /** * Returns a ProxySelector which uses the given proxy address for all HTTP - * and HTTPS requests. If proxy is {@code null} then proxying is disabled. + * and HTTPS requests. If {@code proxyAddress} is {@code null} + * then proxying is disabled. * * @param proxyAddress * The address of the proxy @@ -207,13 +207,22 @@ static class StaticProxySelector extends ProxySelector { @Override public void connectFailed(URI uri, SocketAddress sa, IOException e) { + if (uri == null || sa == null || e == null) { + throw new IllegalArgumentException("Arguments can't be null."); + } /* ignore */ } @Override - public synchronized List select(URI uri) { - String scheme = uri.getScheme().toLowerCase(Locale.ROOT); - if (scheme.equals("http") || scheme.equals("https")) { + public List select(URI uri) { + if (uri == null) { + throw new IllegalArgumentException("URI can't be null"); + } + String scheme = uri.getScheme(); + if (scheme == null) { + throw new IllegalArgumentException("protocol can't be null"); + } + if (scheme.equalsIgnoreCase("http") || scheme.equalsIgnoreCase("https")) { return list; } else { return NO_PROXY_LIST; diff --git a/test/jdk/java/net/ProxySelector/NullArguments.java b/test/jdk/java/net/ProxySelector/NullArguments.java index dddaa15d7e1..6f0ce536156 100644 --- a/test/jdk/java/net/ProxySelector/NullArguments.java +++ b/test/jdk/java/net/ProxySelector/NullArguments.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -22,62 +22,46 @@ */ /* @test - * @bug 4937962 + * @bug 4937962 8318150 * @summary ProxySelector.connectFailed and .select never throw IllegalArgumentException + * @run junit NullArguments */ import java.net.*; -import java.util.List; import java.io.IOException; +import java.util.stream.Stream; + +import org.junit.jupiter.api.Assumptions; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import static org.junit.jupiter.api.Assertions.*; public class NullArguments { - public static void main(String[] args) { - ProxySelector ps = ProxySelector.getDefault(); - List p = null; - boolean ok = false; - if (ps != null) { - try { - p = ps.select(null); - } catch (IllegalArgumentException iae) { - System.out.println("OK"); - ok = true; - } - if (!ok) - throw new RuntimeException("Expected IllegalArgumentException!"); - URI uri = null; - try { - uri = new URI("http://java.sun.com"); - } catch (java.net.URISyntaxException use) { - // can't happen - } - SocketAddress sa = new InetSocketAddress("localhost", 80); - IOException ioe = new IOException("dummy IOE"); - ok = false; - try { - ps.connectFailed(uri, sa, null); - } catch (IllegalArgumentException iae) { - System.out.println("OK"); - ok = true; - } - if (!ok) - throw new RuntimeException("Expected IllegalArgumentException!"); - ok = false; - try { - ps.connectFailed(uri, null, ioe); - } catch (IllegalArgumentException iae) { - System.out.println("OK"); - ok = true; - } - if (!ok) - throw new RuntimeException("Expected IllegalArgumentException!"); - ok = false; - try { - ps.connectFailed(null, sa, ioe); - } catch (IllegalArgumentException iae) { - System.out.println("OK"); - ok = true; - } - if (!ok) - throw new RuntimeException("Expected IllegalArgumentException!"); - } + + public static Stream testProxies() { + return Stream.of( + ProxySelector.getDefault(), + ProxySelector.of(new InetSocketAddress(1234))); + } + + @ParameterizedTest + @MethodSource("testProxies") + void testNullArguments(ProxySelector ps) throws URISyntaxException { + Assumptions.assumeTrue(ps != null, "Skipping null selector"); + assertThrows(IllegalArgumentException.class, + () -> ps.select(null), + "Expected IllegalArgumentException!"); + URI uri = new URI("http://java.sun.com"); + SocketAddress sa = new InetSocketAddress("localhost", 80); + IOException ioe = new IOException("dummy IOE"); + assertThrows(IllegalArgumentException.class, + () -> ps.connectFailed(uri, sa, null), + "Expected IllegalArgumentException!"); + assertThrows(IllegalArgumentException.class, + () -> ps.connectFailed(uri, null, ioe), + "Expected IllegalArgumentException!"); + assertThrows(IllegalArgumentException.class, + () -> ps.connectFailed(null, sa, ioe), + "Expected IllegalArgumentException!"); } } From 387504c9e4b93d162dcef7c90c57c27295858d2e Mon Sep 17 00:00:00 2001 From: Stefan Karlsson Date: Fri, 20 Oct 2023 07:05:30 +0000 Subject: [PATCH 021/124] 8317575: AArch64: C2_MacroAssembler::fast_lock uses rscratch1 for cmpxchg result Reviewed-by: thartmann, kvn, aph --- src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp index cdf3ec7567a..5338eff0134 100644 --- a/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c2_MacroAssembler_aarch64.cpp @@ -117,7 +117,7 @@ void C2_MacroAssembler::fast_lock(Register objectReg, Register boxReg, Register // Try to CAS m->owner from NULL to current thread. add(tmp, disp_hdr, (in_bytes(ObjectMonitor::owner_offset())-markWord::monitor_value)); cmpxchg(tmp, zr, rthread, Assembler::xword, /*acquire*/ true, - /*release*/ true, /*weak*/ false, rscratch1); // Sets flags for result + /*release*/ true, /*weak*/ false, tmp3Reg); // Sets flags for result if (LockingMode != LM_LIGHTWEIGHT) { // Store a non-null value into the box to avoid looking like a re-entrant @@ -129,7 +129,7 @@ void C2_MacroAssembler::fast_lock(Register objectReg, Register boxReg, Register } br(Assembler::EQ, cont); // CAS success means locking succeeded - cmp(rscratch1, rthread); + cmp(tmp3Reg, rthread); br(Assembler::NE, cont); // Check for recursive locking // Recursive lock case From 292aad2c4901f2ffba37274763e1cc617711918e Mon Sep 17 00:00:00 2001 From: Stefan Karlsson Date: Fri, 20 Oct 2023 07:07:42 +0000 Subject: [PATCH 022/124] 8316436: ContinuationWrapper uses unhandled nullptr oop Reviewed-by: pchilanomate, eosterlund --- .../share/runtime/continuationWrapper.cpp | 11 +++----- .../runtime/continuationWrapper.inline.hpp | 25 ++++++++++--------- 2 files changed, 16 insertions(+), 20 deletions(-) diff --git a/src/hotspot/share/runtime/continuationWrapper.cpp b/src/hotspot/share/runtime/continuationWrapper.cpp index 3b967a07554..9ef02bed670 100644 --- a/src/hotspot/share/runtime/continuationWrapper.cpp +++ b/src/hotspot/share/runtime/continuationWrapper.cpp @@ -38,16 +38,12 @@ #include "runtime/stackChunkFrameStream.inline.hpp" ContinuationWrapper::ContinuationWrapper(const RegisterMap* map) - : _thread(map->thread()), - _entry(Continuation::get_continuation_entry_for_continuation(_thread, map->stack_chunk()->cont())), - _continuation(map->stack_chunk()->cont()) - { - assert(oopDesc::is_oop(_continuation),"Invalid cont: " INTPTR_FORMAT, p2i((void*)_continuation)); + : ContinuationWrapper(map->thread(), + Continuation::get_continuation_entry_for_continuation(map->thread(), map->stack_chunk()->cont()), + map->stack_chunk()->cont()) { assert(_entry == nullptr || _continuation == _entry->cont_oop(map->thread()), "cont: " INTPTR_FORMAT " entry: " INTPTR_FORMAT " entry_sp: " INTPTR_FORMAT, p2i( (oopDesc*)_continuation), p2i((oopDesc*)_entry->cont_oop(map->thread())), p2i(entrySP())); - disallow_safepoint(); - read(); } const frame ContinuationWrapper::last_frame() { @@ -96,4 +92,3 @@ bool ContinuationWrapper::chunk_invariant() const { return true; } #endif // ASSERT - diff --git a/src/hotspot/share/runtime/continuationWrapper.inline.hpp b/src/hotspot/share/runtime/continuationWrapper.inline.hpp index 03b2c726a0e..0215f765c5d 100644 --- a/src/hotspot/share/runtime/continuationWrapper.inline.hpp +++ b/src/hotspot/share/runtime/continuationWrapper.inline.hpp @@ -49,6 +49,7 @@ class ContinuationWrapper : public StackObj { // These oops are managed by SafepointOp oop _continuation; // jdk.internal.vm.Continuation instance stackChunkOop _tail; + bool _done; ContinuationWrapper(const ContinuationWrapper& cont); // no copy constructor @@ -58,6 +59,7 @@ class ContinuationWrapper : public StackObj { void disallow_safepoint() { #ifdef ASSERT + assert(!_done, ""); assert(_continuation != nullptr, ""); _current_thread = Thread::current(); if (_current_thread->is_Java_thread()) { @@ -69,16 +71,19 @@ class ContinuationWrapper : public StackObj { void allow_safepoint() { #ifdef ASSERT // we could have already allowed safepoints in done - if (_continuation != nullptr && _current_thread->is_Java_thread()) { + if (!_done && _current_thread->is_Java_thread()) { JavaThread::cast(_current_thread)->dec_no_safepoint_count(); } #endif } + ContinuationWrapper(JavaThread* thread, ContinuationEntry* entry, oop continuation); + public: void done() { allow_safepoint(); // must be done first - _continuation = nullptr; + _done = true; + *reinterpret_cast(&_continuation) = badHeapOopVal; *reinterpret_cast(&_tail) = badHeapOopVal; } @@ -140,23 +145,19 @@ class ContinuationWrapper : public StackObj { #endif }; -inline ContinuationWrapper::ContinuationWrapper(JavaThread* thread, oop continuation) - : _thread(thread), _entry(thread->last_continuation()), _continuation(continuation) - { +inline ContinuationWrapper::ContinuationWrapper(JavaThread* thread, ContinuationEntry* entry, oop continuation) + : _thread(thread), _entry(entry), _continuation(continuation), _done(false) { assert(oopDesc::is_oop(_continuation), "Invalid continuation object: " INTPTR_FORMAT, p2i((void*)_continuation)); disallow_safepoint(); read(); } +inline ContinuationWrapper::ContinuationWrapper(JavaThread* thread, oop continuation) + : ContinuationWrapper(thread, thread->last_continuation(), continuation) {} + inline ContinuationWrapper::ContinuationWrapper(oop continuation) - : _thread(nullptr), _entry(nullptr), _continuation(continuation) - { - assert(oopDesc::is_oop(_continuation), - "Invalid continuation object: " INTPTR_FORMAT, p2i((void*)_continuation)); - disallow_safepoint(); - read(); -} + : ContinuationWrapper(nullptr, nullptr, continuation) {} inline bool ContinuationWrapper::is_preempted() { return jdk_internal_vm_Continuation::is_preempted(_continuation); From bd3bc2c6181668b5856732666dc251136b7fbb99 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Fri, 20 Oct 2023 07:30:11 +0000 Subject: [PATCH 023/124] 8317350: Move code cache purging out of CodeCache::UnloadingScope Reviewed-by: ayang, iwalulya --- src/hotspot/share/code/codeCache.cpp | 1 - src/hotspot/share/code/codeCache.hpp | 5 +---- src/hotspot/share/gc/g1/g1ConcurrentMark.cpp | 9 +++++--- src/hotspot/share/gc/g1/g1FullCollector.cpp | 11 ++++++---- .../share/gc/parallel/psParallelCompact.cpp | 21 ++++++++++++------- src/hotspot/share/gc/serial/genMarkSweep.cpp | 21 ++++++++++++------- .../share/gc/shenandoah/shenandoahHeap.cpp | 20 +++++++++++------- 7 files changed, 54 insertions(+), 34 deletions(-) diff --git a/src/hotspot/share/code/codeCache.cpp b/src/hotspot/share/code/codeCache.cpp index 8c906fdb416..b0fbb17a7ae 100644 --- a/src/hotspot/share/code/codeCache.cpp +++ b/src/hotspot/share/code/codeCache.cpp @@ -1036,7 +1036,6 @@ CodeCache::UnloadingScope::UnloadingScope(BoolObjectClosure* is_alive) CodeCache::UnloadingScope::~UnloadingScope() { IsUnloadingBehaviour::set_current(_saved_behaviour); DependencyContext::cleaning_end(); - CodeCache::flush_unlinked_nmethods(); } void CodeCache::verify_oops() { diff --git a/src/hotspot/share/code/codeCache.hpp b/src/hotspot/share/code/codeCache.hpp index 8abc4043ae6..459df9b19f0 100644 --- a/src/hotspot/share/code/codeCache.hpp +++ b/src/hotspot/share/code/codeCache.hpp @@ -179,10 +179,7 @@ class CodeCache : AllStatic { // GC support static void verify_oops(); - // If any oops are not marked this method unloads (i.e., breaks root links - // to) any unmarked codeBlobs in the cache. Sets "marked_for_unloading" - // to "true" iff some code got unloaded. - // "unloading_occurred" controls whether metadata should be cleaned because of class unloading. + // Scope object managing code cache unloading behavior. class UnloadingScope: StackObj { ClosureIsUnloadingBehaviour _is_unloading_behaviour; IsUnloadingBehaviour* _saved_behaviour; diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp index 14ec4bf385b..da0e058cc32 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp @@ -1694,9 +1694,12 @@ void G1ConcurrentMark::weak_refs_work() { // Unload Klasses, String, Code Cache, etc. if (ClassUnloadingWithConcurrentMark) { GCTraceTime(Debug, gc, phases) debug("Class Unloading", _gc_timer_cm); - CodeCache::UnloadingScope scope(&g1_is_alive); - bool purged_classes = SystemDictionary::do_unloading(_gc_timer_cm); - _g1h->complete_cleaning(purged_classes); + { + CodeCache::UnloadingScope scope(&g1_is_alive); + bool unloading_occurred = SystemDictionary::do_unloading(_gc_timer_cm); + _g1h->complete_cleaning(unloading_occurred); + } + CodeCache::flush_unlinked_nmethods(); } } diff --git a/src/hotspot/share/gc/g1/g1FullCollector.cpp b/src/hotspot/share/gc/g1/g1FullCollector.cpp index 4381d515c6a..f225937a49f 100644 --- a/src/hotspot/share/gc/g1/g1FullCollector.cpp +++ b/src/hotspot/share/gc/g1/g1FullCollector.cpp @@ -319,10 +319,13 @@ void G1FullCollector::phase1_mark_live_objects() { // Class unloading and cleanup. if (ClassUnloading) { GCTraceTime(Debug, gc, phases) debug("Phase 1: Class Unloading and Cleanup", scope()->timer()); - CodeCache::UnloadingScope unloading_scope(&_is_alive); - // Unload classes and purge the SystemDictionary. - bool purged_class = SystemDictionary::do_unloading(scope()->timer()); - _heap->complete_cleaning(purged_class); + { + CodeCache::UnloadingScope unloading_scope(&_is_alive); + // Unload classes and purge the SystemDictionary. + bool unloading_occurred = SystemDictionary::do_unloading(scope()->timer()); + _heap->complete_cleaning(unloading_occurred); + } + CodeCache::flush_unlinked_nmethods(); } { diff --git a/src/hotspot/share/gc/parallel/psParallelCompact.cpp b/src/hotspot/share/gc/parallel/psParallelCompact.cpp index d0839cf576b..637a7d3955c 100644 --- a/src/hotspot/share/gc/parallel/psParallelCompact.cpp +++ b/src/hotspot/share/gc/parallel/psParallelCompact.cpp @@ -2052,19 +2052,26 @@ void PSParallelCompact::marking_phase(ParallelOldTracer *gc_tracer) { { GCTraceTime(Debug, gc, phases) tm_m("Class Unloading", &_gc_timer); - CodeCache::UnloadingScope scope(is_alive_closure()); - // Follow system dictionary roots and unload classes. - bool purged_class = SystemDictionary::do_unloading(&_gc_timer); + bool unloading_occurred; + { + CodeCache::UnloadingScope scope(is_alive_closure()); + + // Follow system dictionary roots and unload classes. + unloading_occurred = SystemDictionary::do_unloading(&_gc_timer); + + // Unload nmethods. + CodeCache::do_unloading(unloading_occurred); + } - // Unload nmethods. - CodeCache::do_unloading(purged_class); + // Release unloaded nmethods's memory. + CodeCache::flush_unlinked_nmethods(); // Prune dead klasses from subklass/sibling/implementor lists. - Klass::clean_weak_klass_links(purged_class); + Klass::clean_weak_klass_links(unloading_occurred); // Clean JVMCI metadata handles. - JVMCI_ONLY(JVMCI::do_unloading(purged_class)); + JVMCI_ONLY(JVMCI::do_unloading(unloading_occurred)); } { diff --git a/src/hotspot/share/gc/serial/genMarkSweep.cpp b/src/hotspot/share/gc/serial/genMarkSweep.cpp index 6200a1894f5..3228493b848 100644 --- a/src/hotspot/share/gc/serial/genMarkSweep.cpp +++ b/src/hotspot/share/gc/serial/genMarkSweep.cpp @@ -199,19 +199,26 @@ void GenMarkSweep::mark_sweep_phase1(bool clear_all_softrefs) { { GCTraceTime(Debug, gc, phases) tm_m("Class Unloading", gc_timer()); - CodeCache::UnloadingScope scope(&is_alive); - // Unload classes and purge the SystemDictionary. - bool purged_class = SystemDictionary::do_unloading(gc_timer()); + bool unloading_occurred; + { + CodeCache::UnloadingScope scope(&is_alive); - // Unload nmethods. - CodeCache::do_unloading(purged_class); + // Unload classes and purge the SystemDictionary. + unloading_occurred = SystemDictionary::do_unloading(gc_timer()); + + // Unload nmethods. + CodeCache::do_unloading(unloading_occurred); + } + + // Release unloaded nmethod's memory. + CodeCache::flush_unlinked_nmethods(); // Prune dead klasses from subklass/sibling/implementor lists. - Klass::clean_weak_klass_links(purged_class); + Klass::clean_weak_klass_links(unloading_occurred); // Clean JVMCI metadata handles. - JVMCI_ONLY(JVMCI::do_unloading(purged_class)); + JVMCI_ONLY(JVMCI::do_unloading(unloading_occurred)); } { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp index 75c2528b46e..3e266cd9b4d 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp @@ -1811,14 +1811,18 @@ void ShenandoahHeap::stw_unload_classes(bool full_gc) { ShenandoahPhaseTimings::full_gc_purge_class_unload : ShenandoahPhaseTimings::degen_gc_purge_class_unload; ShenandoahIsAliveSelector is_alive; - CodeCache::UnloadingScope scope(is_alive.is_alive_closure()); - ShenandoahGCPhase gc_phase(phase); - ShenandoahGCWorkerPhase worker_phase(phase); - bool purged_class = SystemDictionary::do_unloading(gc_timer()); - - uint num_workers = _workers->active_workers(); - ShenandoahClassUnloadingTask unlink_task(phase, num_workers, purged_class); - _workers->run_task(&unlink_task); + { + CodeCache::UnloadingScope scope(is_alive.is_alive_closure()); + ShenandoahGCPhase gc_phase(phase); + ShenandoahGCWorkerPhase worker_phase(phase); + bool unloading_occurred = SystemDictionary::do_unloading(gc_timer()); + + uint num_workers = _workers->active_workers(); + ShenandoahClassUnloadingTask unlink_task(phase, num_workers, unloading_occurred); + _workers->run_task(&unlink_task); + } + // Release unloaded nmethods's memory. + CodeCache::flush_unlinked_nmethods(); } { From bd02cfd96f80abd1559ea3531a21c28c1f670f5d Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Fri, 20 Oct 2023 07:32:16 +0000 Subject: [PATCH 024/124] 8318540: make test cannot run .jasm tests directly Reviewed-by: lmesnik, erikj --- make/RunTests.gmk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/make/RunTests.gmk b/make/RunTests.gmk index d328afce5f7..b82d2b2b601 100644 --- a/make/RunTests.gmk +++ b/make/RunTests.gmk @@ -357,7 +357,7 @@ ExpandJtregPath = \ # with test id: dir/Test.java#selection -> Test.java#selection -> .java#selection -> #selection # without: dir/Test.java -> Test.java -> .java -> <> TestID = \ - $(subst .sh,,$(subst .html,,$(subst .java,,$(suffix $(notdir $1))))) + $(subst .jasm,,$(subst .sh,,$(subst .html,,$(subst .java,,$(suffix $(notdir $1)))))) # The test id starting with a hash (#testid) will be stripped by all # evals in ParseJtregTestSelectionInner and will be reinserted by calling From 4812cabaa489e99481facddce69686a9fee29c44 Mon Sep 17 00:00:00 2001 From: Chen Liang Date: Fri, 20 Oct 2023 07:36:27 +0000 Subject: [PATCH 025/124] 8316587: Use ArraysSupport.vectorizedHashCode in Utf8EntryImpl Reviewed-by: asotona, redestad --- .../classfile/impl/AbstractPoolEntry.java | 39 ++++++++----------- .../bench/jdk/classfile/ReadMetadata.java | 20 +++++++++- 2 files changed, 35 insertions(+), 24 deletions(-) diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPoolEntry.java b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPoolEntry.java index 86a9bb10b58..da9737347d5 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPoolEntry.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPoolEntry.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 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 @@ -29,6 +29,8 @@ import java.nio.charset.StandardCharsets; import java.util.Arrays; +import jdk.internal.access.JavaLangAccess; +import jdk.internal.access.SharedSecrets; import jdk.internal.classfile.Classfile; import jdk.internal.classfile.constantpool.ClassEntry; import jdk.internal.classfile.constantpool.ConstantDynamicEntry; @@ -52,6 +54,8 @@ import jdk.internal.classfile.constantpool.PoolEntry; import jdk.internal.classfile.constantpool.StringEntry; import jdk.internal.classfile.constantpool.Utf8Entry; +import jdk.internal.util.ArraysSupport; + import java.lang.constant.ModuleDesc; import java.lang.constant.PackageDesc; @@ -142,6 +146,8 @@ public static final class Utf8EntryImpl extends AbstractPoolEntry implements Utf enum State { RAW, BYTE, CHAR, STRING } + private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess(); + private State state; private final byte[] rawBytes; // null if initialized directly from a string private final int offset; @@ -226,34 +232,21 @@ enum State { RAW, BYTE, CHAR, STRING } * two-times-three-byte format instead. */ private void inflate() { - int hash = 0; - boolean foundHigh = false; - - int px = offset; - int utfend = px + rawLen; - while (px < utfend) { - int c = (int) rawBytes[px] & 0xff; - if (c > 127) { - foundHigh = true; - break; - } - hash = 31 * hash + c; - px++; - } - - if (!foundHigh) { + int singleBytes = JLA.countPositives(rawBytes, offset, rawLen); + int hash = ArraysSupport.vectorizedHashCode(rawBytes, offset, singleBytes, 0, ArraysSupport.T_BOOLEAN); + if (singleBytes == rawLen) { this.hash = hashString(hash); charLen = rawLen; state = State.BYTE; } else { char[] chararr = new char[rawLen]; - int chararr_count = 0; + int chararr_count = singleBytes; // Inflate prefix of bytes to characters - for (int i = offset; i < px; i++) { - int c = (int) rawBytes[i] & 0xff; - chararr[chararr_count++] = (char) c; - } + JLA.inflateBytesToChars(rawBytes, offset, chararr, 0, singleBytes); + + int px = offset + singleBytes; + int utfend = offset + rawLen; while (px < utfend) { int c = (int) rawBytes[px] & 0xff; switch (c >> 4) { @@ -331,7 +324,7 @@ public String toString() { if (state != State.STRING) { stringValue = (chars != null) ? new String(chars, 0, charLen) - : new String(rawBytes, offset, charLen, StandardCharsets.UTF_8); + : new String(rawBytes, offset, charLen, StandardCharsets.ISO_8859_1); state = State.STRING; } return stringValue; diff --git a/test/micro/org/openjdk/bench/jdk/classfile/ReadMetadata.java b/test/micro/org/openjdk/bench/jdk/classfile/ReadMetadata.java index 5c19cfd8f94..e83fb4b6241 100644 --- a/test/micro/org/openjdk/bench/jdk/classfile/ReadMetadata.java +++ b/test/micro/org/openjdk/bench/jdk/classfile/ReadMetadata.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 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 @@ -72,6 +72,24 @@ public void jdkReadName(Blackhole bh) { } } + @Benchmark + @BenchmarkMode(Mode.Throughput) + public void jdkReadMemberNames(Blackhole bh) { + var cc = Classfile.of(); + for (byte[] bytes : classes) { + var cm = cc.parse(bytes); + bh.consume(cm.thisClass().asInternalName()); + for (var f : cm.fields()) { + bh.consume(f.fieldName().stringValue()); + bh.consume(f.fieldType().stringValue()); + } + for (var m : cm.methods()) { + bh.consume(m.methodName().stringValue()); + bh.consume(m.methodType().stringValue()); + } + } + } + @Benchmark @BenchmarkMode(Mode.Throughput) public void asmStreamCountFields(Blackhole bh) { From 138437f2cf4e965ba07212a10589a517f81623a8 Mon Sep 17 00:00:00 2001 From: Afshin Zafari Date: Fri, 20 Oct 2023 08:33:40 +0000 Subject: [PATCH 026/124] 8314438: NMT: Performance benchmarks are needed to have a baseline for comparison of improvements Reviewed-by: gziemski, ihse --- make/test/BuildMicrobenchmark.gmk | 1 + .../bench/vm/runtime/NMTBenchmark.java | 252 ++++++++++++++++++ 2 files changed, 253 insertions(+) create mode 100644 test/micro/org/openjdk/bench/vm/runtime/NMTBenchmark.java diff --git a/make/test/BuildMicrobenchmark.gmk b/make/test/BuildMicrobenchmark.gmk index d6caf33e875..0785688f09c 100644 --- a/make/test/BuildMicrobenchmark.gmk +++ b/make/test/BuildMicrobenchmark.gmk @@ -107,6 +107,7 @@ $(eval $(call SetupJavaCompilation, BUILD_JDK_MICROBENCHMARK, \ --add-exports java.base/jdk.internal.org.objectweb.asm=ALL-UNNAMED \ --add-exports java.base/jdk.internal.org.objectweb.asm.tree=ALL-UNNAMED \ --add-exports java.base/jdk.internal.vm=ALL-UNNAMED \ + --add-exports java.base/jdk.internal.misc=ALL-UNNAMED \ --add-exports java.base/jdk.internal.event=ALL-UNNAMED \ --add-exports java.base/jdk.internal.foreign=ALL-UNNAMED \ --enable-preview \ diff --git a/test/micro/org/openjdk/bench/vm/runtime/NMTBenchmark.java b/test/micro/org/openjdk/bench/vm/runtime/NMTBenchmark.java new file mode 100644 index 00000000000..9337b4df531 --- /dev/null +++ b/test/micro/org/openjdk/bench/vm/runtime/NMTBenchmark.java @@ -0,0 +1,252 @@ +/* + * 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.runtime; + +import org.openjdk.jmh.annotations.*; +import org.openjdk.jmh.infra.Blackhole; + +import jdk.internal.misc.Unsafe; +import java.util.concurrent.TimeUnit; + +/** + * The purpose of these microbenchmarks is to get the overhead of NMT in disable/summary/detail mode. + */ + +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.MILLISECONDS) +@State(Scope.Benchmark) +@Warmup(iterations = 2, time = 1, timeUnit = TimeUnit.SECONDS) +@Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS) +public abstract class NMTBenchmark { + static final int S = 1024; + + Unsafe unsafe; + long addresses[]; + + //@Param({"100000", "1000000"}) + @Param({"100000"}) + public int N; + + @Param({"0", "4"}) + public int THREADS; + + // Each TestThread instance allocates/frees a portion (`start` to `end`) of the `addresses` array. + // The thread index and a flag for doing allocate or freeing it are sent to the constructor. + private class TestThread extends Thread { + private int thr_index; + private int count; + private int start, end; + private boolean allocate; + + public TestThread(int index, boolean alloc_or_free) { + thr_index = index; + count = N / THREADS; + start = thr_index * count; + end = start + count; + allocate = alloc_or_free; + } + + public void run() { + for (int i = start; i < end; i++) { + if (allocate) { + alloc(i); + } else { + deallocate(i); + } + } + } + + // make a deeper and different stack trace + // NMT uses hash of stack trace to store them in a static table. + // So, if all allocations come from the same call-site, they all hashed into one entry in that table. + private void alloc(int i) { + if (i % 3 == 0) alloc0(i); + if (i % 3 == 1) alloc1(i); + if (i % 3 == 2) alloc2(i); + } + private void alloc0(int i) { + if (unsafe == null) return; + addresses[i] = unsafe.allocateMemory(S); + } + private void alloc1(int i) { alloc0(i); } + private void alloc2(int i) { alloc1(i); } + + private void deallocate(int i) { + if (unsafe == null) + return; + + if (addresses[i] != 0) { + unsafe.freeMemory(addresses[i]); + addresses[i] = 0; + } + } + } + + @Benchmark + public void mixAallocateFreeMemory(Blackhole bh) throws InterruptedException{ + + Unsafe unsafe = Unsafe.getUnsafe(); + if (unsafe == null) { + throw new InterruptedException(); + } + + addresses = new long[N]; + if (THREADS != 0) { // Multi-threaded + TestThread threads[] = new TestThread[THREADS]; + + for (int t = 0; t < THREADS; t++) { + // One half of threads allocate and the other half free the memory + threads[t] = new TestThread(t, t < (THREADS / 2) ? true : false); + threads[t].start(); + } + + for (int t = 0; t < THREADS; t++) { + try { + threads[t].join(); + } catch (InterruptedException ie) { + // do nothing + } + } + } else { // No threads used. + + for (int i = 0; i < N; i++) { + addresses[i] = unsafe.allocateMemory(S); + //Mixing alloc/free + if (i % 3 == 0) { + if (addresses[i] != 0) { + unsafe.freeMemory(addresses[i]); + addresses[i] = 0; + } + } + } + + for (int i = 0; i < N; i++) { + if (i % 2 == 0) { + if (addresses[i] != 0) { + unsafe.freeMemory(addresses[i]); + addresses[i] = 0; + } + } + } + + // free the rest of allocations + for (int i = 0; i < N; i++) { + if (addresses[i] != 0) { + unsafe.freeMemory(addresses[i]); + addresses[i] = 0; + } + } + } + } + + @Benchmark + public void onlyAllocateMemory() throws InterruptedException { + Unsafe unsafe = Unsafe.getUnsafe(); + if (unsafe == null) { + throw new InterruptedException(); + } + + addresses = new long[N]; + if (THREADS != 0) { // Multi-threaded + TestThread threads[] = new TestThread[THREADS]; + + for (int t = 0; t < THREADS; t++) { + // One half of threads allocate and the other half free the memory + threads[t] = new TestThread(t, t < (THREADS / 2) ? true : false); + threads[t].start(); + } + + for (int t = 0; t < THREADS; t++) { + try { + threads[t].join(); + } catch (InterruptedException ie) { + // do nothing + } + } + } else { // No threads used. + for (int i = 0; i < N; i++) { + addresses[i] = unsafe.allocateMemory(S); + } + } + } + + @Benchmark + public void mixAllocateReallocateMemory() throws InterruptedException { + Unsafe unsafe = Unsafe.getUnsafe(); + if (unsafe == null) { + throw new InterruptedException(); + } + + addresses = new long[N]; + if (THREADS != 0) { // Multi-threaded + TestThread threads[] = new TestThread[THREADS]; + + for (int t = 0; t < THREADS; t++) { + // One half of threads allocate and the other half free the memory + threads[t] = new TestThread(t, t < (THREADS / 2) ? true : false); + threads[t].start(); + } + + for (int t = 0; t < THREADS; t++) { + try { + threads[t].join(); + } catch (InterruptedException ie) { + // do nothing + } + } + } else { // No threads used. + for (int i = 0; i < N; i++) { + addresses[i] = unsafe.allocateMemory(S); + //Mixing alloc/realloc + if (i % 3 == 0) { + if (addresses[i] != 0) { + unsafe.reallocateMemory(addresses[i], S * 2); + addresses[i] = 0; + } + } + } + + for (int i = 0; i < N; i++) { + if (i % 2 == 0) { + if (addresses[i] != 0) { + unsafe.reallocateMemory(addresses[i], S / 2); + addresses[i] = 0; + } + } + } + } + } + + public static final String ADD_EXPORTS = "--add-exports"; + public static final String MISC_PACKAGE = "java.base/jdk.internal.misc=ALL-UNNAMED"; // used for Unsafe API + + @Fork(value = 2, jvmArgsPrepend = { "-XX:NativeMemoryTracking=off", ADD_EXPORTS, MISC_PACKAGE}) + public static class NMTOff extends NMTBenchmark { } + + @Fork(value = 2, jvmArgsPrepend = { "-XX:NativeMemoryTracking=summary", ADD_EXPORTS, MISC_PACKAGE}) + public static class NMTSummary extends NMTBenchmark { } + + @Fork(value = 2, jvmArgsPrepend = { "-XX:NativeMemoryTracking=detail", ADD_EXPORTS, MISC_PACKAGE}) + public static class NMTDetail extends NMTBenchmark { } +} From 8099261050a6c021f193d6dac94caa11dccbb5ec Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Fri, 20 Oct 2023 08:38:05 +0000 Subject: [PATCH 027/124] 8318489: Remove unused alignment_unit and alignment_offset Reviewed-by: thartmann --- src/hotspot/share/code/codeCache.cpp | 8 -------- src/hotspot/share/code/codeCache.hpp | 2 -- src/hotspot/share/memory/heap.cpp | 12 ------------ src/hotspot/share/memory/heap.hpp | 2 -- 4 files changed, 24 deletions(-) diff --git a/src/hotspot/share/code/codeCache.cpp b/src/hotspot/share/code/codeCache.cpp index b0fbb17a7ae..85ab194eba4 100644 --- a/src/hotspot/share/code/codeCache.cpp +++ b/src/hotspot/share/code/codeCache.cpp @@ -702,14 +702,6 @@ void CodeCache::metadata_do(MetadataClosure* f) { } } -int CodeCache::alignment_unit() { - return (int)_heaps->first()->alignment_unit(); -} - -int CodeCache::alignment_offset() { - return (int)_heaps->first()->alignment_offset(); -} - // Calculate the number of GCs after which an nmethod is expected to have been // used in order to not be classed as cold. void CodeCache::update_cold_gc_count() { diff --git a/src/hotspot/share/code/codeCache.hpp b/src/hotspot/share/code/codeCache.hpp index 459df9b19f0..0300179942f 100644 --- a/src/hotspot/share/code/codeCache.hpp +++ b/src/hotspot/share/code/codeCache.hpp @@ -151,8 +151,6 @@ class CodeCache : AllStatic { // Allocation/administration static CodeBlob* allocate(int size, CodeBlobType code_blob_type, bool handle_alloc_failure = true, CodeBlobType orig_code_blob_type = CodeBlobType::All); // allocates a new CodeBlob static void commit(CodeBlob* cb); // called when the allocated CodeBlob has been filled - static int alignment_unit(); // guaranteed alignment of all CodeBlobs - static int alignment_offset(); // guaranteed offset of first CodeBlob byte within alignment unit (i.e., allocation header) static void free(CodeBlob* cb); // frees a CodeBlob static void free_unused_tail(CodeBlob* cb, size_t used); // frees the unused tail of a CodeBlob (only used by TemplateInterpreter::initialize()) static bool contains(void *p); // returns whether p is included diff --git a/src/hotspot/share/memory/heap.cpp b/src/hotspot/share/memory/heap.cpp index 8d0bb12f5e9..3f584ccd1f1 100644 --- a/src/hotspot/share/memory/heap.cpp +++ b/src/hotspot/share/memory/heap.cpp @@ -488,18 +488,6 @@ CodeBlob* CodeHeap::find_blob(void* start) const { return (result != nullptr && result->blob_contains((address)start)) ? result : nullptr; } -size_t CodeHeap::alignment_unit() const { - // this will be a power of two - return _segment_size; -} - - -size_t CodeHeap::alignment_offset() const { - // The lowest address in any allocated block will be - // equal to alignment_offset (mod alignment_unit). - return sizeof(HeapBlock) & (_segment_size - 1); -} - // Returns the current block if available and used. // If not, it returns the subsequent block (if available), null otherwise. // Free blocks are merged, therefore there is at most one free block diff --git a/src/hotspot/share/memory/heap.hpp b/src/hotspot/share/memory/heap.hpp index da02eecae49..27ae8ec0c78 100644 --- a/src/hotspot/share/memory/heap.hpp +++ b/src/hotspot/share/memory/heap.hpp @@ -174,8 +174,6 @@ class CodeHeap : public CHeapObj { void* find_start(void* p) const; // returns the block containing p or null CodeBlob* find_blob(void* start) const; - size_t alignment_unit() const; // alignment of any block - size_t alignment_offset() const; // offset of first byte of any block, within the enclosing alignment unit static size_t header_size() { return sizeof(HeapBlock); } // returns the header size for each heap block size_t segment_size() const { return _segment_size; } // for CodeHeapState From 744f206fefb7e2eff17737a34da264f2eebbae09 Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Fri, 20 Oct 2023 08:38:23 +0000 Subject: [PATCH 028/124] 8318525: Atomic gtest should run as TEST_VM to access VM capabilities Reviewed-by: stefank, stuefe --- test/hotspot/gtest/runtime/test_atomic.cpp | 32 +++++++++++----------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/test/hotspot/gtest/runtime/test_atomic.cpp b/test/hotspot/gtest/runtime/test_atomic.cpp index 35b415319ce..e7c6f9e3f2b 100644 --- a/test/hotspot/gtest/runtime/test_atomic.cpp +++ b/test/hotspot/gtest/runtime/test_atomic.cpp @@ -53,7 +53,7 @@ struct AtomicAddTestSupport { } }; -TEST(AtomicAddTest, int32) { +TEST_VM(AtomicAddTest, int32) { using Support = AtomicAddTestSupport; Support().test_add(); Support().test_fetch_add(); @@ -61,14 +61,14 @@ TEST(AtomicAddTest, int32) { // 64bit Atomic::add is only supported on 64bit platforms. #ifdef _LP64 -TEST(AtomicAddTest, int64) { +TEST_VM(AtomicAddTest, int64) { using Support = AtomicAddTestSupport; Support().test_add(); Support().test_fetch_add(); } #endif // _LP64 -TEST(AtomicAddTest, ptr) { +TEST_VM(AtomicAddTest, ptr) { uint _test_values[10] = {}; uint* volatile _test_value{}; @@ -103,14 +103,14 @@ struct AtomicXchgTestSupport { } }; -TEST(AtomicXchgTest, int32) { +TEST_VM(AtomicXchgTest, int32) { using Support = AtomicXchgTestSupport; Support().test(); } // 64bit Atomic::xchg is only supported on 64bit platforms. #ifdef _LP64 -TEST(AtomicXchgTest, int64) { +TEST_VM(AtomicXchgTest, int64) { using Support = AtomicXchgTestSupport; Support().test(); } @@ -136,12 +136,12 @@ struct AtomicCmpxchgTestSupport { } }; -TEST(AtomicCmpxchgTest, int32) { +TEST_VM(AtomicCmpxchgTest, int32) { using Support = AtomicCmpxchgTestSupport; Support().test(); } -TEST(AtomicCmpxchgTest, int64) { +TEST_VM(AtomicCmpxchgTest, int64) { using Support = AtomicCmpxchgTestSupport; Support().test(); } @@ -186,7 +186,7 @@ struct AtomicCmpxchg1ByteStressSupport { } }; -TEST(AtomicCmpxchg1Byte, stress) { +TEST_VM(AtomicCmpxchg1Byte, stress) { AtomicCmpxchg1ByteStressSupport support; support.test(); } @@ -224,7 +224,7 @@ namespace AtomicEnumTestUnscoped { // Scope the enumerators. enum TestEnum { A, B, C }; } -TEST(AtomicEnumTest, unscoped_enum) { +TEST_VM(AtomicEnumTest, unscoped_enum) { using namespace AtomicEnumTestUnscoped; using Support = AtomicEnumTestSupport; @@ -235,7 +235,7 @@ TEST(AtomicEnumTest, unscoped_enum) { enum class AtomicEnumTestScoped { A, B, C }; -TEST(AtomicEnumTest, scoped_enum) { +TEST_VM(AtomicEnumTest, scoped_enum) { const AtomicEnumTestScoped B = AtomicEnumTestScoped::B; const AtomicEnumTestScoped C = AtomicEnumTestScoped::C; using Support = AtomicEnumTestSupport; @@ -329,28 +329,28 @@ const T AtomicBitopsTestSupport::_old_value; template const T AtomicBitopsTestSupport::_change_value; -TEST(AtomicBitopsTest, int8) { +TEST_VM(AtomicBitopsTest, int8) { AtomicBitopsTestSupport()(); } -TEST(AtomicBitopsTest, uint8) { +TEST_VM(AtomicBitopsTest, uint8) { AtomicBitopsTestSupport()(); } -TEST(AtomicBitopsTest, int32) { +TEST_VM(AtomicBitopsTest, int32) { AtomicBitopsTestSupport()(); } -TEST(AtomicBitopsTest, uint32) { +TEST_VM(AtomicBitopsTest, uint32) { AtomicBitopsTestSupport()(); } #ifdef _LP64 -TEST(AtomicBitopsTest, int64) { +TEST_VM(AtomicBitopsTest, int64) { AtomicBitopsTestSupport()(); } -TEST(AtomicBitopsTest, uint64) { +TEST_VM(AtomicBitopsTest, uint64) { AtomicBitopsTestSupport()(); } #endif // _LP64 From cd25d1a2bf4530d8fd4d0515b69e2199df9c102f Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Fri, 20 Oct 2023 08:40:51 +0000 Subject: [PATCH 029/124] 8318296: Move Space::initialize to ContiguousSpace Reviewed-by: tschatzl, iwalulya --- src/hotspot/share/gc/shared/space.cpp | 34 ++++++++++----------------- src/hotspot/share/gc/shared/space.hpp | 22 +++++++---------- 2 files changed, 22 insertions(+), 34 deletions(-) diff --git a/src/hotspot/share/gc/shared/space.cpp b/src/hotspot/share/gc/shared/space.cpp index 2e076b6ef22..763ff8c616d 100644 --- a/src/hotspot/share/gc/shared/space.cpp +++ b/src/hotspot/share/gc/shared/space.cpp @@ -46,24 +46,6 @@ #include "gc/serial/defNewGeneration.hpp" #endif -void Space::initialize(MemRegion mr, - bool clear_space, - bool mangle_space) { - HeapWord* bottom = mr.start(); - HeapWord* end = mr.end(); - assert(Universe::on_page_boundary(bottom) && Universe::on_page_boundary(end), - "invalid space boundaries"); - set_bottom(bottom); - set_end(end); - if (clear_space) clear(mangle_space); -} - -void Space::clear(bool mangle_space) { - if (ZapUnusedHeapArea && mangle_space) { - mangle_unused_area(); - } -} - ContiguousSpace::ContiguousSpace(): Space(), _compaction_top(nullptr), _next_compaction_space(nullptr), @@ -79,15 +61,25 @@ void ContiguousSpace::initialize(MemRegion mr, bool clear_space, bool mangle_space) { - Space::initialize(mr, clear_space, mangle_space); - set_compaction_top(bottom()); + HeapWord* bottom = mr.start(); + HeapWord* end = mr.end(); + assert(Universe::on_page_boundary(bottom) && Universe::on_page_boundary(end), + "invalid space boundaries"); + set_bottom(bottom); + set_end(end); + if (clear_space) { + clear(mangle_space); + } + set_compaction_top(bottom); _next_compaction_space = nullptr; } void ContiguousSpace::clear(bool mangle_space) { set_top(bottom()); set_saved_mark(); - Space::clear(mangle_space); + if (ZapUnusedHeapArea && mangle_space) { + mangle_unused_area(); + } _compaction_top = bottom(); } diff --git a/src/hotspot/share/gc/shared/space.hpp b/src/hotspot/share/gc/shared/space.hpp index 3729df804fb..d978aabc186 100644 --- a/src/hotspot/share/gc/shared/space.hpp +++ b/src/hotspot/share/gc/shared/space.hpp @@ -112,17 +112,6 @@ class Space: public CHeapObj { return MemRegion(bottom(), saved_mark_word()); } - // Initialization. - // "initialize" should be called once on a space, before it is used for - // any purpose. The "mr" arguments gives the bounds of the space, and - // the "clear_space" argument should be true unless the memory in "mr" is - // known to be zeroed. - virtual void initialize(MemRegion mr, bool clear_space, bool mangle_space); - - // The "clear" method must be called on a region that may have - // had allocation performed in it, but is now to be considered empty. - virtual void clear(bool mangle_space); - // For detecting GC bugs. Should only be called at GC boundaries, since // some unused space may be used as scratch space during GC's. // We also call this when expanding a space to satisfy an allocation @@ -264,9 +253,16 @@ class ContiguousSpace: public Space { ContiguousSpace(); ~ContiguousSpace(); - void initialize(MemRegion mr, bool clear_space, bool mangle_space) override; + // Initialization. + // "initialize" should be called once on a space, before it is used for + // any purpose. The "mr" arguments gives the bounds of the space, and + // the "clear_space" argument should be true unless the memory in "mr" is + // known to be zeroed. + void initialize(MemRegion mr, bool clear_space, bool mangle_space); - void clear(bool mangle_space) override; + // The "clear" method must be called on a region that may have + // had allocation performed in it, but is now to be considered empty. + virtual void clear(bool mangle_space); // Used temporarily during a compaction phase to hold the value // top should have when compaction is complete. From 8f4ebd892148f2c23fd11672a10aaf787a0be2eb Mon Sep 17 00:00:00 2001 From: Johannes Bechberger Date: Fri, 20 Oct 2023 08:52:46 +0000 Subject: [PATCH 030/124] 8317920: JDWP-agent sends broken exception event with onthrow option Reviewed-by: clanger, cjplummer --- .../share/native/libjdwp/debugInit.c | 47 ++++-- test/jdk/com/sun/jdi/JdwpOnThrowTest.java | 157 ++++++++++++++++++ .../jdk/com/sun/jdi/ThrowCaughtException.java | 36 ++++ test/jdk/com/sun/jdi/lib/jdb/Debuggee.java | 39 ++++- 4 files changed, 258 insertions(+), 21 deletions(-) create mode 100644 test/jdk/com/sun/jdi/JdwpOnThrowTest.java create mode 100644 test/jdk/com/sun/jdi/ThrowCaughtException.java diff --git a/src/jdk.jdwp.agent/share/native/libjdwp/debugInit.c b/src/jdk.jdwp.agent/share/native/libjdwp/debugInit.c index a2cda11ecd4..494e3f613e9 100644 --- a/src/jdk.jdwp.agent/share/native/libjdwp/debugInit.c +++ b/src/jdk.jdwp.agent/share/native/libjdwp/debugInit.c @@ -102,7 +102,7 @@ static void JNICALL cbEarlyVMDeath(jvmtiEnv*, JNIEnv *); static void JNICALL cbEarlyException(jvmtiEnv*, JNIEnv *, jthread, jmethodID, jlocation, jobject, jmethodID, jlocation); -static void initialize(JNIEnv *env, jthread thread, EventIndex triggering_ei); +static void initialize(JNIEnv *env, jthread thread, EventIndex triggering_ei, EventInfo *opt_info); static jboolean parseOptions(char *str); /* @@ -391,7 +391,7 @@ cbEarlyVMInit(jvmtiEnv *jvmti_env, JNIEnv *env, jthread thread) EXIT_ERROR(AGENT_ERROR_INTERNAL,"VM dead at VM_INIT time"); } if (initOnStartup) - initialize(env, thread, EI_VM_INIT); + initialize(env, thread, EI_VM_INIT, NULL); vmInitialized = JNI_TRUE; LOG_MISC(("END cbEarlyVMInit")); } @@ -444,6 +444,19 @@ cbEarlyException(jvmtiEnv *jvmti_env, JNIEnv *env, LOG_MISC(("VM is not initialized yet")); return; } + EventInfo info; + info.ei = EI_EXCEPTION; + info.thread = thread; + info.clazz = getMethodClass(jvmti_env, method); + info.method = method; + info.location = location; + info.object = exception; + if (gdata->vthreadsSupported) { + info.is_vthread = isVThread(thread); + } + info.u.exception.catch_clazz = getMethodClass(jvmti_env, catch_method); + info.u.exception.catch_method = catch_method; + info.u.exception.catch_location = catch_location; /* * We want to preserve any current exception that might get wiped @@ -458,24 +471,22 @@ cbEarlyException(jvmtiEnv *jvmti_env, JNIEnv *env, if (initOnUncaught && catch_method == NULL) { LOG_MISC(("Initializing on uncaught exception")); - initialize(env, thread, EI_EXCEPTION); + initialize(env, thread, EI_EXCEPTION, &info); } else if (initOnException != NULL) { - jclass clazz; - - /* Get class of exception thrown */ - clazz = JNI_FUNC_PTR(env,GetObjectClass)(env, exception); - if ( clazz != NULL ) { + jclass exception_clazz = JNI_FUNC_PTR(env, GetObjectClass)(env, exception); + /* check class of exception thrown */ + if ( exception_clazz != NULL ) { char *signature = NULL; /* initing on throw, check */ - error = classSignature(clazz, &signature, NULL); + error = classSignature(exception_clazz, &signature, NULL); LOG_MISC(("Checking specific exception: looking for %s, got %s", initOnException, signature)); if ( (error==JVMTI_ERROR_NONE) && (strcmp(signature, initOnException) == 0)) { LOG_MISC(("Initializing on specific exception")); - initialize(env, thread, EI_EXCEPTION); + initialize(env, thread, EI_EXCEPTION, &info); } else { error = AGENT_ERROR_INTERNAL; /* Just to cause restore */ } @@ -616,9 +627,11 @@ jniFatalError(JNIEnv *env, const char *msg, jvmtiError error, int exit_code) /* * Initialize debugger back end modules + * + * @param opt_info optional event info to use, might be null */ static void -initialize(JNIEnv *env, jthread thread, EventIndex triggering_ei) +initialize(JNIEnv *env, jthread thread, EventIndex triggering_ei, EventInfo *opt_info) { jvmtiError error; EnumerateArg arg; @@ -706,13 +719,13 @@ initialize(JNIEnv *env, jthread thread, EventIndex triggering_ei) * can get in the queue (from other not-yet-suspended threads) * before this one does. (Also need to handle allocation error below?) */ - EventInfo info; struct bag *initEventBag; - LOG_MISC(("triggering_ei != EI_VM_INIT")); + LOG_MISC(("triggering_ei == EI_EXCEPTION")); + JDI_ASSERT(triggering_ei == EI_EXCEPTION); + JDI_ASSERT(opt_info != NULL); initEventBag = eventHelper_createEventBag(); - (void)memset(&info,0,sizeof(info)); - info.ei = triggering_ei; - eventHelper_recordEvent(&info, 0, suspendPolicy, initEventBag); + threadControl_onEventHandlerEntry(currentSessionID, opt_info, NULL); + eventHelper_recordEvent(opt_info, 0, suspendPolicy, initEventBag); (void)eventHelper_reportEvents(currentSessionID, initEventBag); bagDestroyBag(initEventBag); } @@ -1368,7 +1381,7 @@ JNIEXPORT char const* JNICALL debugInit_startDebuggingViaCommand(JNIEnv* env, jt if (!startedViaJcmd) { startedViaJcmd = JNI_TRUE; is_first_start = JNI_TRUE; - initialize(env, thread, EI_VM_INIT); + initialize(env, thread, EI_VM_INIT, NULL); } bagEnumerateOver(transports, getFirstTransport, &spec); diff --git a/test/jdk/com/sun/jdi/JdwpOnThrowTest.java b/test/jdk/com/sun/jdi/JdwpOnThrowTest.java new file mode 100644 index 00000000000..d083b2a0e84 --- /dev/null +++ b/test/jdk/com/sun/jdi/JdwpOnThrowTest.java @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2023 SAP SE. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import com.sun.jdi.Bootstrap; +import com.sun.jdi.VirtualMachine; +import com.sun.jdi.connect.AttachingConnector; +import com.sun.jdi.connect.Connector; +import com.sun.jdi.connect.IllegalConnectorArgumentsException; +import com.sun.jdi.event.EventIterator; +import com.sun.jdi.event.EventQueue; +import com.sun.jdi.event.EventSet; +import com.sun.jdi.event.Event; +import com.sun.jdi.event.ExceptionEvent; +import lib.jdb.Debuggee; + +import java.io.IOException; +import java.net.ServerSocket; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +/* + * @test + * @bug 8317920 + * @summary Tests for JDWP agent to send valid exception event with onthrow option + * @library /test/lib + * + * @build ThrowCaughtException JdwpOnThrowTest + * @run main/othervm JdwpOnThrowTest + */ +public class JdwpOnThrowTest { + + private static long TIMEOUT = 10000; + + private static String ATTACH_CONNECTOR = "com.sun.jdi.SocketAttach"; + // cache socket attaching connector + private static AttachingConnector attachingConnector; + + public static void main(String[] args) throws Exception { + int port = findFreePort(); + try (Debuggee debuggee = Debuggee.launcher("ThrowCaughtException").setAddress("localhost:" + port) + .enableOnThrow("Ex", "Start").setSuspended(true).launch()) { + VirtualMachine vm = null; + try { + vm = attach("localhost", "" + port); + EventQueue queue = vm.eventQueue(); + log("Waiting for exception event"); + long start = System.currentTimeMillis(); + while (start + TIMEOUT > System.currentTimeMillis()) { + EventSet eventSet = queue.remove(TIMEOUT); + EventIterator eventIterator = eventSet.eventIterator(); + while(eventIterator.hasNext() && start + TIMEOUT > System.currentTimeMillis()) { + Event event = eventIterator.next(); + if (event instanceof ExceptionEvent ex) { + verifyExceptionEvent(ex); + log("Received exception event: " + event); + vm.dispose(); + return; + } + log("Received event: " + event); + } + } + throw new RuntimeException("ERROR: failed to receive exception event"); + } catch (IOException ex) { + throw new RuntimeException("ERROR: failed to attach", ex); + } + } + } + + private static void verifyExceptionEvent(ExceptionEvent ex) throws Exception { + if (ex.exception() == null) { + throw new RuntimeException("Exception is null"); + } + if (ex.exception().type() == null) { + throw new RuntimeException("Exception type is null"); + } + if (ex.exception().referenceType() == null) { + throw new RuntimeException("Exception reference type is null"); + } + if (ex.catchLocation() == null) { + throw new RuntimeException("Exception catch location is null"); + } + if (!ex.location().equals(ex.thread().frame(0).location())) { + throw new RuntimeException( + String.format("Throw location %s and location of first frame %s are not equal", + ex.location(), ex.thread().frame(0).location())); + } + if (!ex.exception().type().name().equals("Ex")) { + throw new RuntimeException("Exception has wrong type: " + ex.exception().type().name()); + } + } + + private static int findFreePort() { + try (ServerSocket socket = new ServerSocket(0)) { + return socket.getLocalPort(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + private static VirtualMachine attach(String address, String port) throws IOException { + if (attachingConnector == null) { + attachingConnector = (AttachingConnector)getConnector(ATTACH_CONNECTOR); + } + Map args = attachingConnector.defaultArguments(); + setConnectorArg(args, "hostname", address); + setConnectorArg(args, "port", port); + try { + return attachingConnector.attach(args); + } catch (IllegalConnectorArgumentsException e) { + // unexpected.. wrap in RuntimeException + throw new RuntimeException(e); + } + } + + private static Connector getConnector(String name) { + for (Connector connector : Bootstrap.virtualMachineManager().allConnectors()) { + if (connector.name().equalsIgnoreCase(name)) { + return connector; + } + } + throw new IllegalArgumentException("Connector " + name + " not found"); + } + + private static void setConnectorArg(Map args, String name, String value) { + Connector.Argument arg = args.get(name); + if (arg == null) { + throw new IllegalArgumentException("Argument " + name + " is not defined"); + } + arg.setValue(value); + } + + private static void log(Object o) { + System.out.println(String.valueOf(o)); + } + +} diff --git a/test/jdk/com/sun/jdi/ThrowCaughtException.java b/test/jdk/com/sun/jdi/ThrowCaughtException.java new file mode 100644 index 00000000000..38253ad8875 --- /dev/null +++ b/test/jdk/com/sun/jdi/ThrowCaughtException.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2023 SAP SE. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + public class ThrowCaughtException { + public static void main(String args[]) throws Exception { + try { + System.out.println("Start"); + throw new Ex(); + } catch (Exception e) { + System.out.println(e); + } + } +} + +class Ex extends RuntimeException { +} diff --git a/test/jdk/com/sun/jdi/lib/jdb/Debuggee.java b/test/jdk/com/sun/jdi/lib/jdb/Debuggee.java index e204b09f713..8d6f840254d 100644 --- a/test/jdk/com/sun/jdi/lib/jdb/Debuggee.java +++ b/test/jdk/com/sun/jdi/lib/jdb/Debuggee.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 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 @@ -68,6 +68,9 @@ public static class Launcher { private String transport = "dt_socket"; private String address = null; private boolean suspended = true; + private String onthrow = ""; + private boolean waitForPortPrint = true; + private String expectedOutputBeforeThrow = ""; private Launcher(String mainClass) { this.mainClass = mainClass; @@ -100,21 +103,31 @@ public Launcher setSuspended(boolean value) { return this; } + // required to pass non null port with address and emit string before the throw + public Launcher enableOnThrow(String value, String expectedOutputBeforeThrow) { + this.onthrow = value; + this.waitForPortPrint = false; + this.expectedOutputBeforeThrow = expectedOutputBeforeThrow; + return this; + } + public ProcessBuilder prepare() { List debuggeeArgs = new LinkedList<>(); if (vmOptions != null) { debuggeeArgs.add(vmOptions); } + String onthrowArgs = onthrow.isEmpty() ? "" : ",onthrow=" + onthrow + ",launch=exit"; debuggeeArgs.add("-agentlib:jdwp=transport=" + transport + (address == null ? "" : ",address=" + address) - + ",server=y,suspend=" + (suspended ? "y" : "n")); + + ",server=y,suspend=" + (suspended ? "y" : "n") + + onthrowArgs); debuggeeArgs.addAll(options); debuggeeArgs.add(mainClass); return ProcessTools.createTestJvm(debuggeeArgs); } public Debuggee launch(String name) { - return new Debuggee(prepare(), name); + return new Debuggee(prepare(), name, waitForPortPrint, expectedOutputBeforeThrow); } public Debuggee launch() { return launch("debuggee"); @@ -122,8 +135,20 @@ public Debuggee launch() { } // starts the process, waits for "Listening for transport" output and detects transport/address - private Debuggee(ProcessBuilder pb, String name) { + private Debuggee(ProcessBuilder pb, String name, boolean waitForPortPrint, String expectedOutputBeforeThrow) { JDWP.ListenAddress[] listenAddress = new JDWP.ListenAddress[1]; + if (!waitForPortPrint) { + try { + p = ProcessTools.startProcess(name, pb, s -> {output.add(s);}, s -> { + return s.equals(expectedOutputBeforeThrow); + }, 30, TimeUnit.SECONDS); + } catch (IOException | InterruptedException | TimeoutException ex) { + throw new RuntimeException("failed to launch debuggee", ex); + } + transport = null; + address = null; + return; + } try { p = ProcessTools.startProcess(name, pb, s -> output.add(s), // output consumer @@ -167,10 +192,16 @@ public String getOutput() { } String getTransport() { + if (transport == null) { + throw new IllegalStateException("transport is not available"); + } return transport; } public String getAddress() { + if (address == null) { + throw new IllegalStateException("address is not available"); + } return address; } From 6f1d8962df05e2b298f3ec354430159041b51bcd Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Fri, 20 Oct 2023 10:23:00 +0000 Subject: [PATCH 031/124] 8318510: Serial: Remove TenuredGeneration::block_size Reviewed-by: tschatzl, iwalulya --- src/hotspot/share/gc/serial/cardTableRS.cpp | 2 -- src/hotspot/share/gc/serial/generation.cpp | 8 -------- src/hotspot/share/gc/serial/generation.hpp | 5 ----- src/hotspot/share/gc/serial/tenuredGeneration.cpp | 2 +- src/hotspot/share/gc/serial/tenuredGeneration.hpp | 2 -- src/hotspot/share/gc/serial/tenuredGeneration.inline.hpp | 9 --------- 6 files changed, 1 insertion(+), 27 deletions(-) diff --git a/src/hotspot/share/gc/serial/cardTableRS.cpp b/src/hotspot/share/gc/serial/cardTableRS.cpp index 2c189da2747..e6682854b10 100644 --- a/src/hotspot/share/gc/serial/cardTableRS.cpp +++ b/src/hotspot/share/gc/serial/cardTableRS.cpp @@ -106,8 +106,6 @@ HeapWord* DirtyCardToOopClosure::get_actual_top(HeapWord* top, // Otherwise, it is possible that the object starting on the dirty // card spans the entire card, and that the store happened on a // later card. Figure out where the object ends. - assert(_sp->block_size(top_obj) == cast_to_oop(top_obj)->size(), - "Block size and object size mismatch"); top = top_obj + cast_to_oop(top_obj)->size(); } } else { diff --git a/src/hotspot/share/gc/serial/generation.cpp b/src/hotspot/share/gc/serial/generation.cpp index 0c011d813ba..daad60f406d 100644 --- a/src/hotspot/share/gc/serial/generation.cpp +++ b/src/hotspot/share/gc/serial/generation.cpp @@ -194,14 +194,6 @@ class GenerationBlockSizeClosure : public SpaceClosure { GenerationBlockSizeClosure(const HeapWord* p) { _p = p; size = 0; } }; -size_t Generation::block_size(const HeapWord* p) const { - GenerationBlockSizeClosure blk(p); - // Cast away const - ((Generation*)this)->space_iterate(&blk); - assert(blk.size > 0, "seems reasonable"); - return blk.size; -} - class GenerationBlockIsObjClosure : public SpaceClosure { public: const HeapWord* _p; diff --git a/src/hotspot/share/gc/serial/generation.hpp b/src/hotspot/share/gc/serial/generation.hpp index 2c0f72012ac..54e9d188a5b 100644 --- a/src/hotspot/share/gc/serial/generation.hpp +++ b/src/hotspot/share/gc/serial/generation.hpp @@ -331,11 +331,6 @@ class Generation: public CHeapObj { // non-object. virtual HeapWord* block_start(const void* addr) const; - // Requires "addr" to be the start of a chunk, and returns its size. - // "addr + size" is required to be the start of a new chunk, or the end - // of the active area of the heap. - virtual size_t block_size(const HeapWord* addr) const ; - // Requires "addr" to be the start of a block, and returns "TRUE" iff // the block is an object. virtual bool block_is_obj(const HeapWord* addr) const; diff --git a/src/hotspot/share/gc/serial/tenuredGeneration.cpp b/src/hotspot/share/gc/serial/tenuredGeneration.cpp index c36256090bb..28bb00fe2a3 100644 --- a/src/hotspot/share/gc/serial/tenuredGeneration.cpp +++ b/src/hotspot/share/gc/serial/tenuredGeneration.cpp @@ -477,7 +477,7 @@ void TenuredGeneration::complete_loaded_archive_space(MemRegion archive_space) { space->initialize_threshold(); HeapWord* start = archive_space.start(); while (start < archive_space.end()) { - size_t word_size = _the_space->block_size(start); + size_t word_size = cast_to_oop(start)->size();; space->alloc_block(start, start + word_size); start += word_size; } diff --git a/src/hotspot/share/gc/serial/tenuredGeneration.hpp b/src/hotspot/share/gc/serial/tenuredGeneration.hpp index 99eb72660b3..5a0e296e019 100644 --- a/src/hotspot/share/gc/serial/tenuredGeneration.hpp +++ b/src/hotspot/share/gc/serial/tenuredGeneration.hpp @@ -133,8 +133,6 @@ class TenuredGeneration: public Generation { bool no_allocs_since_save_marks(); - inline size_t block_size(const HeapWord* addr) const; - inline bool block_is_obj(const HeapWord* addr) const; virtual void collect(bool full, diff --git a/src/hotspot/share/gc/serial/tenuredGeneration.inline.hpp b/src/hotspot/share/gc/serial/tenuredGeneration.inline.hpp index 38d4aa02144..5d8bf32e2ce 100644 --- a/src/hotspot/share/gc/serial/tenuredGeneration.inline.hpp +++ b/src/hotspot/share/gc/serial/tenuredGeneration.inline.hpp @@ -65,15 +65,6 @@ HeapWord* TenuredGeneration::par_allocate(size_t word_size, return _the_space->par_allocate(word_size); } -size_t TenuredGeneration::block_size(const HeapWord* addr) const { - if (addr < _the_space->top()) { - return cast_to_oop(addr)->size(); - } else { - assert(addr == _the_space->top(), "non-block head arg to block_size"); - return _the_space->end() - _the_space->top(); - } -} - bool TenuredGeneration::block_is_obj(const HeapWord* addr) const { return addr < _the_space ->top(); } From b07da3ae15dc820d596484d51d972404fed67fb1 Mon Sep 17 00:00:00 2001 From: Maurizio Cimadamore Date: Fri, 20 Oct 2023 10:23:45 +0000 Subject: [PATCH 032/124] 8317819: Scope should reflect lifetime of underying resource (mainline) Reviewed-by: jvernee --- .../classes/java/lang/foreign/Arena.java | 20 +-- .../classes/java/lang/foreign/Linker.java | 6 +- .../java/lang/foreign/MemoryLayout.java | 6 +- .../java/lang/foreign/MemorySegment.java | 69 ++++++---- .../java/lang/foreign/SymbolLookup.java | 4 +- .../foreign/AbstractMemorySegmentImpl.java | 14 +- .../jdk/internal/foreign/GlobalSession.java | 41 +++++- .../foreign/MappedMemorySegmentImpl.java | 3 +- .../internal/foreign/MemorySessionImpl.java | 14 +- .../foreign/NativeMemorySegmentImpl.java | 3 +- .../internal/foreign/SegmentFactories.java | 16 +-- test/jdk/java/foreign/TestScope.java | 122 ++++++++++++++++++ 12 files changed, 254 insertions(+), 64 deletions(-) create mode 100644 test/jdk/java/foreign/TestScope.java 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 457847d76c6..45cb46d33d6 100644 --- a/src/java.base/share/classes/java/lang/foreign/Arena.java +++ b/src/java.base/share/classes/java/lang/foreign/Arena.java @@ -43,9 +43,10 @@ * to obtain native segments. *

* The simplest arena is the {@linkplain Arena#global() global arena}. The global arena - * features an unbounded lifetime. As such, native segments allocated with the global arena are always - * accessible and their backing regions of memory are never deallocated. Moreover, memory segments allocated with the - * global arena can be {@linkplain MemorySegment#isAccessibleBy(Thread) accessed} from any thread. + * features an unbounded lifetime. The scope of the global arena is the global scope. + * As such, native segments allocated with the global arena are always accessible and their backing regions + * of memory are never deallocated. + * Moreover, memory segments allocated with the global arena can be {@linkplain MemorySegment#isAccessibleBy(Thread) accessed} from any thread. * {@snippet lang = java: * MemorySegment segment = Arena.global().allocate(100, 1); // @highlight regex='global()' * ... @@ -53,7 +54,8 @@ *} *

* Alternatively, clients can obtain an {@linkplain Arena#ofAuto() automatic arena}, that is an arena - * which features a bounded lifetime that is managed, automatically, by the garbage collector. As such, the regions + * which features a bounded lifetime that is managed, automatically, by the garbage collector. The scope + * of an automatic arena is an automatic scope. As such, the regions * of memory backing memory segments allocated with the automatic arena are deallocated at some unspecified time * after the automatic arena (and all the segments allocated by it) becomes * unreachable, as shown below: @@ -67,11 +69,9 @@ * Rather than leaving deallocation in the hands of the Java runtime, clients will often wish to exercise control over * the timing of deallocation for regions of memory that back memory segments. Two kinds of arenas support this, * namely {@linkplain #ofConfined() confined} and {@linkplain #ofShared() shared} arenas. They both feature - * bounded lifetimes that are managed manually. For instance, the lifetime of a confined arena starts when the confined - * arena is created, and ends when the confined arena is {@linkplain #close() closed}. As a result, the regions of memory - * backing memory segments allocated with a confined arena are deallocated when the confined arena is closed. - * When this happens, all the segments allocated with the confined arena are invalidated, and subsequent access - * operations on these segments will fail {@link IllegalStateException}: + * bounded lifetimes that are managed manually. For instance, when a confined arena is {@linkplain #close() closed} + * successfully, its scope is {@linkplain Scope#isAlive() invalidated}. As a result, all the memory segments allocated + * by the arena can no longer be accessed, and their regions of memory are deallocated: * * {@snippet lang = java: * MemorySegment segment = null; @@ -219,7 +219,7 @@ static Arena ofAuto() { */ static Arena global() { class Holder { - static final Arena GLOBAL = MemorySessionImpl.GLOBAL.asArena(); + static final Arena GLOBAL = MemorySessionImpl.GLOBAL_SESSION.asArena(); } return Holder.GLOBAL; } diff --git a/src/java.base/share/classes/java/lang/foreign/Linker.java b/src/java.base/share/classes/java/lang/foreign/Linker.java index 9adca13b774..747e2b9270d 100644 --- a/src/java.base/share/classes/java/lang/foreign/Linker.java +++ b/src/java.base/share/classes/java/lang/foreign/Linker.java @@ -365,7 +365,7 @@ * * The size of the segment returned by the {@code malloc} downcall method handle is * zero. Moreover, the scope of the - * returned segment is a fresh scope that is always alive. To provide safe access to the segment, we must, + * returned segment is the global scope. To provide safe access to the segment, we must, * unsafely, resize the segment to the desired size (100, in this case). It might also be desirable to * attach the segment to some existing {@linkplain Arena arena}, so that the lifetime of the region of memory * backing the segment can be managed automatically, as for any other native segment created directly from Java code. @@ -563,7 +563,7 @@ static Linker nativeLinker() { *

* Moreover, if the provided function descriptor's return layout is an {@linkplain AddressLayout address layout}, * invoking the returned method handle will return a native segment associated with - * a fresh scope that is always alive. Under normal conditions, the size of the returned segment is {@code 0}. + * the global scope. Under normal conditions, the size of the returned segment is {@code 0}. * However, if the function descriptor's return layout has a {@linkplain AddressLayout#targetLayout() target layout} * {@code T}, then the size of the returned segment is set to {@code T.byteSize()}. *

@@ -602,7 +602,7 @@ static Linker nativeLinker() { * upcall stub segment will be deallocated when the provided confined arena is {@linkplain Arena#close() closed}. *

* An upcall stub argument whose corresponding layout is an {@linkplain AddressLayout address layout} - * is a native segment associated with a fresh scope that is always alive. + * is a native segment associated with the global scope. * Under normal conditions, the size of this segment argument is {@code 0}. * However, if the address layout has a {@linkplain AddressLayout#targetLayout() target layout} {@code T}, then the size of the * segment argument is set to {@code T.byteSize()}. 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 db656ada136..e527d7f203a 100644 --- a/src/java.base/share/classes/java/lang/foreign/MemoryLayout.java +++ b/src/java.base/share/classes/java/lang/foreign/MemoryLayout.java @@ -492,8 +492,8 @@ public sealed interface MemoryLayout permits SequenceLayout, GroupLayout, Paddin * *

* If the selected layout is an {@linkplain AddressLayout address layout}, calling {@link VarHandle#get(Object...)} - * on the returned var handle will return a new memory segment. The segment is associated with a fresh scope that is - * always alive. Moreover, the size of the segment depends on whether the address layout has a + * on the returned var handle will return a new memory segment. The segment is associated with the global scope. + * Moreover, the size of the segment depends on whether the address layout has a * {@linkplain AddressLayout#targetLayout() target layout}. More specifically: *

    *
  • If the address layout has a target layout {@code T}, then the size of the returned segment @@ -513,7 +513,7 @@ public sealed interface MemoryLayout permits SequenceLayout, GroupLayout, Paddin * {@snippet lang = "java": * VarHandle baseHandle = this.varHandle(P); * MemoryLayout target = ((AddressLayout)this.select(P)).targetLayout().get(); - * VarHandle targetHandle = target.varHandle(P'); + * VarHandle targetHandle = target.varHandle(P); * targetHandle = MethodHandles.insertCoordinates(targetHandle, 1, 0L); // always access nested targets at offset 0 * targetHandle = MethodHandles.collectCoordinates(targetHandle, 0, * baseHandle.toMethodHandle(VarHandle.AccessMode.GET)); 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 5565eaf2461..cdb8e53805a 100644 --- a/src/java.base/share/classes/java/lang/foreign/MemorySegment.java +++ b/src/java.base/share/classes/java/lang/foreign/MemorySegment.java @@ -376,7 +376,7 @@ * of memory whose size is not known, any access operations involving these segments cannot be validated. * In effect, a zero-length memory segment wraps an address, and it cannot be used without explicit intent * (see below);
  • - *
  • The segment is associated with a fresh scope that is always alive. Thus, while zero-length + *
  • The segment is associated with the global scope. Thus, while zero-length * memory segments cannot be accessed directly, they can be passed, opaquely, to other pointer-accepting foreign functions.
  • *
*

@@ -625,7 +625,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl { * MemorySegment cleanupSegment = MemorySegment.ofAddress(this.address()) * .reinterpret(byteSize()); * } - * That is, the cleanup action receives a segment that is associated with a fresh scope that is always alive, + * That is, the cleanup action receives a segment that is associated with the global scope, * and is accessible from any thread. The size of the segment accepted by the cleanup action is {@link #byteSize()}. *

* This method is restricted. @@ -664,7 +664,7 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl { * MemorySegment cleanupSegment = MemorySegment.ofAddress(this.address()) * .reinterpret(newSize); * } - * That is, the cleanup action receives a segment that is associated with a fresh scope that is always alive, + * That is, the cleanup action receives a segment that is associated with the global scope, * and is accessible from any thread. The size of the segment accepted by the cleanup action is {@code newSize}. *

* This method is restricted. @@ -1155,11 +1155,9 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl { *

* If the provided buffer has been obtained by calling {@link #asByteBuffer()} on a memory segment whose * {@linkplain Scope scope} is {@code S}, the returned segment will be associated with the - * same scope {@code S}. Otherwise, the scope of the returned segment is a fresh scope that is always alive. - *

- * The scope associated with the returned segment keeps the provided buffer reachable. As such, if - * the provided buffer is a direct buffer, its backing memory region will not be deallocated as long as the - * returned segment (or any of its slices) are kept reachable. + * same scope {@code S}. Otherwise, the scope of the returned segment is an automatic scope that keeps the provided + * buffer reachable. As such, if the provided buffer is a direct buffer, its backing memory region will not be + * deallocated as long as the returned segment (or any of its slices) are kept reachable. * * @param buffer the buffer instance to be turned into a new memory segment. * @return a memory segment, derived from the given buffer instance. @@ -1174,7 +1172,7 @@ static MemorySegment ofBuffer(Buffer buffer) { /** * Creates a heap segment backed by the on-heap region of memory that holds the given byte array. - * The scope of the returned segment is a fresh scope that is always alive, and keeps the given array reachable. + * The scope of the returned segment is an automatic scope that keeps the given array reachable. * The returned segment is always accessible, from any thread. Its {@link #address()} is set to zero. * * @param byteArray the primitive array backing the heap memory segment. @@ -1186,7 +1184,7 @@ static MemorySegment ofArray(byte[] byteArray) { /** * Creates a heap segment backed by the on-heap region of memory that holds the given char array. - * The scope of the returned segment is a fresh scope that is always alive, and keeps the given array reachable. + * The scope of the returned segment is an automatic scope that keeps the given array reachable. * The returned segment is always accessible, from any thread. Its {@link #address()} is set to zero. * * @param charArray the primitive array backing the heap segment. @@ -1198,7 +1196,7 @@ static MemorySegment ofArray(char[] charArray) { /** * Creates a heap segment backed by the on-heap region of memory that holds the given short array. - * The scope of the returned segment is a fresh scope that is always alive, and keeps the given array reachable. + * The scope of the returned segment is an automatic scope that keeps the given array reachable. * The returned segment is always accessible, from any thread. Its {@link #address()} is set to zero. * * @param shortArray the primitive array backing the heap segment. @@ -1210,7 +1208,7 @@ static MemorySegment ofArray(short[] shortArray) { /** * Creates a heap segment backed by the on-heap region of memory that holds the given int array. - * The scope of the returned segment is a fresh scope that is always alive, and keeps the given array reachable. + * The scope of the returned segment is an automatic scope that keeps the given array reachable. * The returned segment is always accessible, from any thread. Its {@link #address()} is set to zero. * * @param intArray the primitive array backing the heap segment. @@ -1222,7 +1220,7 @@ static MemorySegment ofArray(int[] intArray) { /** * Creates a heap segment backed by the on-heap region of memory that holds the given float array. - * The scope of the returned segment is a fresh scope that is always alive, and keeps the given array reachable. + * The scope of the returned segment is an automatic scope that keeps the given array reachable. * The returned segment is always accessible, from any thread. Its {@link #address()} is set to zero. * * @param floatArray the primitive array backing the heap segment. @@ -1234,7 +1232,7 @@ static MemorySegment ofArray(float[] floatArray) { /** * Creates a heap segment backed by the on-heap region of memory that holds the given long array. - * The scope of the returned segment is a fresh scope that is always alive, and keeps the given array reachable. + * The scope of the returned segment is an automatic scope that keeps the given array reachable. * The returned segment is always accessible, from any thread. Its {@link #address()} is set to zero. * * @param longArray the primitive array backing the heap segment. @@ -1246,7 +1244,7 @@ static MemorySegment ofArray(long[] longArray) { /** * Creates a heap segment backed by the on-heap region of memory that holds the given double array. - * The scope of the returned segment is a fresh scope that is always alive, and keeps the given array reachable. + * The scope of the returned segment is an automatic scope that keeps the given array reachable. * The returned segment is always accessible, from any thread. Its {@link #address()} is set to zero. * * @param doubleArray the primitive array backing the heap segment. @@ -1263,7 +1261,7 @@ static MemorySegment ofArray(double[] doubleArray) { /** * Creates a zero-length native segment from the given {@linkplain #address() address value}. - * The returned segment is associated with a scope that is always alive, and is accessible from any thread. + * The returned segment is associated with the global scope, and is accessible from any thread. *

* On 32-bit platforms, the given address value will be normalized such that the * highest-order ("leftmost") 32 bits of the {@link MemorySegment#address() address} @@ -1642,7 +1640,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr /** * Reads an address from this segment at the given offset, with the given layout. The read address is wrapped in - * a native segment, associated with a fresh scope that is always alive. Under normal conditions, + * a native segment, associated with the global scope. Under normal conditions, * the size of the returned segment is {@code 0}. However, if the provided address layout has a * {@linkplain AddressLayout#targetLayout() target layout} {@code T}, then the size of the returned segment * is set to {@code T.byteSize()}. @@ -1994,7 +1992,7 @@ static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long sr /** * Reads an address from this segment at the given at the given index, scaled by the given layout size. The read address is wrapped in - * a native segment, associated with a fresh scope that is always alive. Under normal conditions, + * a native segment, associated with the global scope. Under normal conditions, * the size of the returned segment is {@code 0}. However, if the provided address layout has a * {@linkplain AddressLayout#targetLayout() target layout} {@code T}, then the size of the returned segment * is set to {@code T.byteSize()}. @@ -2192,11 +2190,38 @@ static long mismatch(MemorySegment srcSegment, long srcFromOffset, long srcToOff /** * A scope models the lifetime of all the memory segments associated with it. That is, a memory segment - * cannot be accessed if its associated scope is not {@linkplain #isAlive() alive}. A new scope is typically - * obtained indirectly, by creating a new {@linkplain Arena arena}. + * cannot be accessed if its associated scope is not {@linkplain #isAlive() alive}. Scope instances can be compared + * for equality. That is, two scopes are considered {@linkplain #equals(Object) equal} if they denote the same lifetime. + *

+ * The lifetime of a memory segment can be either unbounded or bounded. An unbounded lifetime + * is modelled with the global scope. The global scope is always {@link #isAlive() alive}. As such, a segment + * associated with the global scope features trivial temporal bounds, and is always accessible. + * Segments associated with the global scope are: + *

    + *
  • Segments obtained from the {@linkplain Arena#global() global arena};
  • + *
  • Segments obtained from a raw address, using the {@link MemorySegment#ofAddress(long)} factory; and
  • + *
  • Zero-length memory segments.
  • + *
*

- * Scope instances can be compared for equality. That is, two scopes - * are considered {@linkplain #equals(Object)} if they denote the same lifetime. + * Conversely, a bounded lifetime is modelled with a segment scope that can be invalidated, either {@link Arena#close() explicitly}, + * or automatically, by the garbage collector. A segment scope that is invalidated automatically is an automatic scope. + * An automatic scope is always {@link #isAlive() alive} as long as it is reachable. + * Segments associated with an automatic scope are: + *

    + *
  • Segments obtained from an {@linkplain Arena#ofAuto() automatic arena};
  • + *
  • Segments obtained from a Java array, e.g. using the {@link MemorySegment#ofArray(int[])} factory;
  • + *
  • Segments obtained from a buffer, using the {@link MemorySegment#ofBuffer(Buffer)} factory; and
  • + *
  • Segments obtained from {@linkplain SymbolLookup#loaderLookup() loader lookup}.
  • + *
+ * If two memory segments are obtained from the same {@linkplain #ofBuffer(Buffer) buffer} + * or {@linkplain #ofArray(int[]) array}, the automatic scopes associated with said segments are considered + * {@linkplain #equals(Object) equal}, as the two segments have the same lifetime: + * {@snippet lang=java : + * byte[] arr = new byte[10]; + * MemorySegment segment1 = MemorySegment.ofArray(arr); + * MemorySegment segment2 = MemorySegment.ofArray(arr); + * assert segment1.scope().equals(segment2.scope()); + * } */ sealed interface Scope permits MemorySessionImpl { /** diff --git a/src/java.base/share/classes/java/lang/foreign/SymbolLookup.java b/src/java.base/share/classes/java/lang/foreign/SymbolLookup.java index aafe44b4d40..632543c9957 100644 --- a/src/java.base/share/classes/java/lang/foreign/SymbolLookup.java +++ b/src/java.base/share/classes/java/lang/foreign/SymbolLookup.java @@ -165,7 +165,7 @@ default SymbolLookup or(SymbolLookup other) { *

* Libraries associated with a class loader are unloaded when the class loader becomes * unreachable. The symbol lookup - * returned by this method is associated with a fresh {@linkplain MemorySegment.Scope scope} which keeps the caller's + * returned by this method is associated with an automatic {@linkplain MemorySegment.Scope scope} which keeps the caller's * class loader reachable. Therefore, libraries associated with the caller's class loader are kept loaded * (and their symbols available) as long as a loader lookup for that class loader, or any of the segments * obtained by it, is reachable. @@ -189,7 +189,7 @@ static SymbolLookup loaderLookup() { if ((loader == null || loader instanceof BuiltinClassLoader)) { loaderArena = Arena.global(); } else { - MemorySessionImpl session = MemorySessionImpl.heapSession(loader); + MemorySessionImpl session = MemorySessionImpl.createHeap(loader); loaderArena = session.asArena(); } return 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 8b674a90c33..bf8b1e79819 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/AbstractMemorySegmentImpl.java +++ b/src/java.base/share/classes/jdk/internal/foreign/AbstractMemorySegmentImpl.java @@ -55,6 +55,7 @@ import jdk.internal.util.ArraysSupport; import jdk.internal.util.Preconditions; import jdk.internal.vm.annotation.ForceInline; +import sun.nio.ch.DirectBuffer; import static java.lang.foreign.ValueLayout.JAVA_BYTE; @@ -556,7 +557,7 @@ public static AbstractMemorySegmentImpl ofBuffer(Buffer bb) { if (bufferSegment != null) { bufferScope = bufferSegment.scope; } else { - bufferScope = MemorySessionImpl.heapSession(bb); + bufferScope = MemorySessionImpl.createHeap(bufferRef(bb)); } if (base != null) { if (base instanceof byte[]) { @@ -584,6 +585,17 @@ public static AbstractMemorySegmentImpl ofBuffer(Buffer bb) { } } + private static Object bufferRef(Buffer buffer) { + if (buffer instanceof DirectBuffer directBuffer) { + // direct buffer, return either the buffer attachment (for slices and views), or the buffer itself + return directBuffer.attachment() != null ? + directBuffer.attachment() : directBuffer; + } else { + // heap buffer, return the underlying array + return NIO_ACCESS.getBufferBase(buffer); + } + } + private static int getScaleFactor(Buffer buffer) { if (buffer instanceof ByteBuffer) { return 0; diff --git a/src/java.base/share/classes/jdk/internal/foreign/GlobalSession.java b/src/java.base/share/classes/jdk/internal/foreign/GlobalSession.java index 2d78a66eb6f..c075778b5ee 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/GlobalSession.java +++ b/src/java.base/share/classes/jdk/internal/foreign/GlobalSession.java @@ -25,20 +25,23 @@ package jdk.internal.foreign; +import jdk.internal.access.JavaNioAccess; +import jdk.internal.access.SharedSecrets; import jdk.internal.vm.annotation.ForceInline; +import sun.nio.ch.DirectBuffer; + +import java.nio.Buffer; +import java.util.Objects; /** * The global, non-closeable, shared session. Similar to a shared session, but its {@link #close()} method throws unconditionally. * Adding new resources to the global session, does nothing: as the session can never become not-alive, there is nothing to track. * Acquiring and or releasing a memory session similarly does nothing. */ -final class GlobalSession extends MemorySessionImpl { - - final Object ref; +non-sealed class GlobalSession extends MemorySessionImpl { - public GlobalSession(Object ref) { + public GlobalSession() { super(null, null); - this.ref = ref; } @Override @@ -67,4 +70,32 @@ void addInternal(ResourceList.ResourceCleanup resource) { public void justClose() { throw nonCloseable(); } + + /** + * This is a global session that wraps a heap object. Possible objects are: Java arrays, buffers and + * class loaders. Objects of two heap sessions are compared by identity. That is, if the wrapped object is the same, + * then the resulting heap sessions are also considered equals. We do not compare the objects using + * {@link Object#equals(Object)}, as that would be problematic when comparing buffers, whose equality and + * hash codes are content-dependent. + */ + static class HeapSession extends GlobalSession { + + final Object ref; + + public HeapSession(Object ref) { + super(); + this.ref = Objects.requireNonNull(ref); + } + + @Override + public boolean equals(Object obj) { + return obj instanceof HeapSession session && + ref == session.ref; + } + + @Override + public int hashCode() { + return System.identityHashCode(ref); + } + } } diff --git a/src/java.base/share/classes/jdk/internal/foreign/MappedMemorySegmentImpl.java b/src/java.base/share/classes/jdk/internal/foreign/MappedMemorySegmentImpl.java index dce223c4683..e313780a348 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/MappedMemorySegmentImpl.java +++ b/src/java.base/share/classes/jdk/internal/foreign/MappedMemorySegmentImpl.java @@ -48,8 +48,7 @@ public MappedMemorySegmentImpl(long min, UnmapperProxy unmapper, long length, bo @Override ByteBuffer makeByteBuffer() { - return NIO_ACCESS.newMappedByteBuffer(unmapper, min, (int)length, null, - scope == MemorySessionImpl.GLOBAL ? null : this); + return NIO_ACCESS.newMappedByteBuffer(unmapper, min, (int)length, null, this); } @Override diff --git a/src/java.base/share/classes/jdk/internal/foreign/MemorySessionImpl.java b/src/java.base/share/classes/jdk/internal/foreign/MemorySessionImpl.java index c8c7dd2e543..33bac79999f 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/MemorySessionImpl.java +++ b/src/java.base/share/classes/jdk/internal/foreign/MemorySessionImpl.java @@ -33,6 +33,8 @@ import java.lang.invoke.VarHandle; import java.lang.ref.Cleaner; import java.util.Objects; + +import jdk.internal.foreign.GlobalSession.HeapSession; import jdk.internal.misc.ScopedMemoryAccess; import jdk.internal.vm.annotation.ForceInline; @@ -59,10 +61,10 @@ public abstract sealed class MemorySessionImpl static final VarHandle STATE; static final int MAX_FORKS = Integer.MAX_VALUE; - public static final MemorySessionImpl GLOBAL = new GlobalSession(null); - static final ScopedMemoryAccess.ScopedAccessError ALREADY_CLOSED = new ScopedMemoryAccess.ScopedAccessError(MemorySessionImpl::alreadyClosed); static final ScopedMemoryAccess.ScopedAccessError WRONG_THREAD = new ScopedMemoryAccess.ScopedAccessError(MemorySessionImpl::wrongThread); + // This is the session of all zero-length memory segments + public static final MemorySessionImpl GLOBAL_SESSION = new GlobalSession(); final ResourceList resourceList; final Thread owner; @@ -143,6 +145,10 @@ public static MemorySessionImpl createImplicit(Cleaner cleaner) { return new ImplicitSession(cleaner); } + public static MemorySessionImpl createHeap(Object ref) { + return new HeapSession(ref); + } + public abstract void release0(); public abstract void acquire0(); @@ -230,10 +236,6 @@ public void close() { abstract void justClose(); - public static MemorySessionImpl heapSession(Object ref) { - return new GlobalSession(ref); - } - /** * A list of all cleanup actions associated with a memory session. Cleanup actions are modelled as instances * of the {@link ResourceCleanup} class, and, together, form a linked list. Depending on whether a session diff --git a/src/java.base/share/classes/jdk/internal/foreign/NativeMemorySegmentImpl.java b/src/java.base/share/classes/jdk/internal/foreign/NativeMemorySegmentImpl.java index 5339d3fb8b7..5427c9f810f 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/NativeMemorySegmentImpl.java +++ b/src/java.base/share/classes/jdk/internal/foreign/NativeMemorySegmentImpl.java @@ -69,8 +69,7 @@ NativeMemorySegmentImpl dup(long offset, long size, boolean readOnly, MemorySess @Override ByteBuffer makeByteBuffer() { - return NIO_ACCESS.newDirectByteBuffer(min, (int) this.length, null, - scope == MemorySessionImpl.GLOBAL ? null : this); + return NIO_ACCESS.newDirectByteBuffer(min, (int) this.length, null, this); } @Override diff --git a/src/java.base/share/classes/jdk/internal/foreign/SegmentFactories.java b/src/java.base/share/classes/jdk/internal/foreign/SegmentFactories.java index c4f1d5a8a0f..9e9d60ecf89 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/SegmentFactories.java +++ b/src/java.base/share/classes/jdk/internal/foreign/SegmentFactories.java @@ -77,7 +77,7 @@ public static MemorySegment makeNativeSegmentUnchecked(long min, long byteSize, @ForceInline public static MemorySegment makeNativeSegmentUnchecked(long min, long byteSize) { ensureInitialized(); - return new NativeMemorySegmentImpl(min, byteSize, false, new GlobalSession(null)); + return new NativeMemorySegmentImpl(min, byteSize, false, MemorySessionImpl.GLOBAL_SESSION); } public static MemorySegment fromArray(byte[] arr) { @@ -85,7 +85,7 @@ public static MemorySegment fromArray(byte[] arr) { Objects.requireNonNull(arr); long byteSize = (long)arr.length * Unsafe.ARRAY_BYTE_INDEX_SCALE; return new OfByte(Unsafe.ARRAY_BYTE_BASE_OFFSET, arr, byteSize, false, - MemorySessionImpl.heapSession(arr)); + MemorySessionImpl.createHeap(arr)); } public static MemorySegment fromArray(short[] arr) { @@ -93,7 +93,7 @@ public static MemorySegment fromArray(short[] arr) { Objects.requireNonNull(arr); long byteSize = (long)arr.length * Unsafe.ARRAY_SHORT_INDEX_SCALE; return new OfShort(Unsafe.ARRAY_SHORT_BASE_OFFSET, arr, byteSize, false, - MemorySessionImpl.heapSession(arr)); + MemorySessionImpl.createHeap(arr)); } public static MemorySegment fromArray(int[] arr) { @@ -101,7 +101,7 @@ public static MemorySegment fromArray(int[] arr) { Objects.requireNonNull(arr); long byteSize = (long)arr.length * Unsafe.ARRAY_INT_INDEX_SCALE; return new OfInt(Unsafe.ARRAY_INT_BASE_OFFSET, arr, byteSize, false, - MemorySessionImpl.heapSession(arr)); + MemorySessionImpl.createHeap(arr)); } public static MemorySegment fromArray(char[] arr) { @@ -109,7 +109,7 @@ public static MemorySegment fromArray(char[] arr) { Objects.requireNonNull(arr); long byteSize = (long)arr.length * Unsafe.ARRAY_CHAR_INDEX_SCALE; return new OfChar(Unsafe.ARRAY_CHAR_BASE_OFFSET, arr, byteSize, false, - MemorySessionImpl.heapSession(arr)); + MemorySessionImpl.createHeap(arr)); } public static MemorySegment fromArray(float[] arr) { @@ -117,7 +117,7 @@ public static MemorySegment fromArray(float[] arr) { Objects.requireNonNull(arr); long byteSize = (long)arr.length * Unsafe.ARRAY_FLOAT_INDEX_SCALE; return new OfFloat(Unsafe.ARRAY_FLOAT_BASE_OFFSET, arr, byteSize, false, - MemorySessionImpl.heapSession(arr)); + MemorySessionImpl.createHeap(arr)); } public static MemorySegment fromArray(double[] arr) { @@ -125,7 +125,7 @@ public static MemorySegment fromArray(double[] arr) { Objects.requireNonNull(arr); long byteSize = (long)arr.length * Unsafe.ARRAY_DOUBLE_INDEX_SCALE; return new OfDouble(Unsafe.ARRAY_DOUBLE_BASE_OFFSET, arr, byteSize, false, - MemorySessionImpl.heapSession(arr)); + MemorySessionImpl.createHeap(arr)); } public static MemorySegment fromArray(long[] arr) { @@ -133,7 +133,7 @@ public static MemorySegment fromArray(long[] arr) { Objects.requireNonNull(arr); long byteSize = (long)arr.length * Unsafe.ARRAY_LONG_INDEX_SCALE; return new OfLong(Unsafe.ARRAY_LONG_BASE_OFFSET, arr, byteSize, false, - MemorySessionImpl.heapSession(arr)); + MemorySessionImpl.createHeap(arr)); } public static MemorySegment allocateSegment(long byteSize, long byteAlignment, MemorySessionImpl sessionImpl, diff --git a/test/jdk/java/foreign/TestScope.java b/test/jdk/java/foreign/TestScope.java new file mode 100644 index 00000000000..337dce7d0ca --- /dev/null +++ b/test/jdk/java/foreign/TestScope.java @@ -0,0 +1,122 @@ +/* + * 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 + * @run testng/othervm --enable-native-access=ALL-UNNAMED TestScope + */ + +import org.testng.annotations.*; + +import java.lang.foreign.Arena; +import java.lang.foreign.MemorySegment; +import java.lang.foreign.SymbolLookup; +import java.nio.ByteBuffer; +import java.nio.IntBuffer; + +import static org.testng.Assert.*; + +public class TestScope { + + static { + System.loadLibrary("LookupTest"); + } + + @Test + public void testDifferentArrayScope() { + MemorySegment.Scope scope1 = MemorySegment.ofArray(new byte[10]).scope(); + MemorySegment.Scope scope2 = MemorySegment.ofArray(new byte[10]).scope(); + assertNotEquals(scope1, scope2); + } + + @Test + public void testDifferentBufferScope() { + MemorySegment.Scope scope1 = MemorySegment.ofBuffer(ByteBuffer.allocateDirect(10)).scope(); + MemorySegment.Scope scope2 = MemorySegment.ofBuffer(ByteBuffer.allocateDirect(10)).scope(); + assertNotEquals(scope1, scope2); + } + + @Test + public void testDifferentArenaScope() { + MemorySegment.Scope scope1 = Arena.ofAuto().allocate(10).scope(); + MemorySegment.Scope scope2 = Arena.ofAuto().allocate(10).scope(); + assertNotEquals(scope1, scope2); + } + + @Test + public void testSameArrayScope() { + byte[] arr = new byte[10]; + assertEquals(MemorySegment.ofArray(arr).scope(), MemorySegment.ofArray(arr).scope()); + ByteBuffer buf = ByteBuffer.wrap(arr); + assertEquals(MemorySegment.ofArray(arr).scope(), MemorySegment.ofBuffer(buf).scope()); + testDerivedBufferScope(MemorySegment.ofArray(arr)); + } + + @Test + public void testSameBufferScope() { + ByteBuffer buf = ByteBuffer.allocateDirect(10); + assertEquals(MemorySegment.ofBuffer(buf).scope(), MemorySegment.ofBuffer(buf).scope()); + testDerivedBufferScope(MemorySegment.ofBuffer(buf)); + } + + @Test + public void testSameArenaScope() { + try (Arena arena = Arena.ofConfined()) { + MemorySegment segment1 = arena.allocate(10); + MemorySegment segment2 = arena.allocate(10); + assertEquals(segment1.scope(), segment2.scope()); + testDerivedBufferScope(segment1); + } + } + + @Test + public void testSameNativeScope() { + MemorySegment segment1 = MemorySegment.ofAddress(42); + MemorySegment segment2 = MemorySegment.ofAddress(43); + assertEquals(segment1.scope(), segment2.scope()); + assertEquals(segment1.scope(), segment2.reinterpret(10).scope()); + assertEquals(segment1.scope(), Arena.global().scope()); + testDerivedBufferScope(segment1.reinterpret(10)); + } + + @Test + public void testSameLookupScope() { + SymbolLookup loaderLookup = SymbolLookup.loaderLookup(); + MemorySegment segment1 = loaderLookup.find("f").get(); + MemorySegment segment2 = loaderLookup.find("c").get(); + assertEquals(segment1.scope(), segment2.scope()); + testDerivedBufferScope(segment1.reinterpret(10)); + } + + void testDerivedBufferScope(MemorySegment segment) { + ByteBuffer buffer = segment.asByteBuffer(); + MemorySegment.Scope expectedScope = segment.scope(); + assertEquals(MemorySegment.ofBuffer(buffer).scope(), expectedScope); + // buffer slices should have same scope + ByteBuffer slice = buffer.slice(0, 2); + assertEquals(expectedScope, MemorySegment.ofBuffer(slice).scope()); + // buffer views should have same scope + IntBuffer view = buffer.asIntBuffer(); + assertEquals(expectedScope, MemorySegment.ofBuffer(view).scope()); + } +} From 848ecc1621c347ab12dd3f421af82cb55c71e075 Mon Sep 17 00:00:00 2001 From: Maurizio Cimadamore Date: Fri, 20 Oct 2023 10:35:09 +0000 Subject: [PATCH 033/124] 8318538: Add a way to obtain a strided var handle from a layout Reviewed-by: jvernee, pminborg --- .../java/lang/foreign/MemoryLayout.java | 157 +++++++++++++++--- .../java/lang/foreign/MemorySegment.java | 15 +- .../foreign/layout/AbstractLayout.java | 4 + .../jdk/java/foreign/TestAdaptVarHandles.java | 4 +- test/jdk/java/foreign/TestArrayCopy.java | 3 +- .../bench/java/lang/foreign/JavaLayouts.java | 3 +- 6 files changed, 142 insertions(+), 44 deletions(-) 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 e527d7f203a..b3303ad75ac 100644 --- a/src/java.base/share/classes/java/lang/foreign/MemoryLayout.java +++ b/src/java.base/share/classes/java/lang/foreign/MemoryLayout.java @@ -269,19 +269,87 @@ * access modes. All other access modes will result in {@link UnsupportedOperationException} being thrown. Moreover, * while supported, access modes {@code get} and {@code set} might lead to word tearing. * - *

Working with variable-length structs

+ *

Working with variable-length arrays

* - * Memory layouts allow clients to describe the contents of a region of memory whose size is known statically. - * There are, however, cases, where the size of a region of memory is only known dynamically, as it depends - * on the value of one or more struct fields. Consider the following struct declaration in C: + * We have seen how sequence layouts are used to describe the contents of an array whose size is known statically. + * There are cases, however, where the array size is only known dynamically. We call such arrays variable-length arrays. + * There are two common kinds of variable-length arrays: + *
    + *
  • a toplevel variable-length array whose size depends on the value of some unrelated variable, or parameter;
  • + *
  • an variable-length array nested in a struct, whose size depends on the value of some other field in the enclosing struct.
  • + *
+ * While variable-length arrays cannot be modelled directly using sequence layouts, clients can still enjoy structured + * access to elements of variable-length arrays using var handles as demonstrated in the following sections. + * + *

Toplevel variable-length arrays

+ * + * Consider the following struct declaration in C: + * + * {@snippet lang=c : + * typedef struct { + * int x; + * int y; + * } Point; + * } + * + * In the above code, a point is modelled as two coordinates ({@code x} and {@code y} respectively). Now consider + * the following snippet of C code: + * + * {@snippet lang=c : + * int size = ... + * Point *points = (Point*)malloc(sizeof(Point) * size); + * for (int i = 0 ; i < size ; i++) { + * ... points[i].x ... + * } + * } + * + * Here, we allocate an array of point ({@code points}). Crucially, the size of the array is dynamically bound to the value + * of the {@code size} variable. Inside the loop, the {@code x} coordinate of all the points in the array is accessed. + *

+ * To model this code in Java, let's start by defining a layout for the {@code Point} struct, as follows: + * + * {@snippet lang=java : + * StructLayout POINT = MemoryLayout.structLayout( + * ValueLayout.JAVA_INT.withName("x"), + * ValueLayout.JAVA_INT.withName("y") + * ); + * } + * + * Since we know we need to create and access an array of points, it would be tempting to create a sequence layout modelling + * the variable-length array, and then derive the necessary access var handles from the sequence layout. But this approach + * is problematic, as the size of the variable-length array is not known. Instead, a var handle that provides structured + * access to the elements of a variable-length array can be obtained directly from the layout describing the array elements + * (e.g. the point layout), as demonstrated below: + * + * {@snippet lang=java : + * VarHandle POINT_ARR_X = POINT.arrayElementVarHandle(PathElement.groupElement("x")); + * + * int size = ... + * MemorySegment points = ... + * for (int i = 0 ; i < size ; i++) { + * ... POINT_ARR_X.get(segment, 0L, (long)i) ... + * } + * } + * + * Here, the coordinate {@code x} of subsequent point in the array is accessed using the {@code POINT_ARR_X} var + * handle, which is obtained using the {@link #arrayElementVarHandle(PathElement...)} method. This var handle + * features two {@code long} coordinates: the first is a base offset (set to {@code 0L}), while the + * second is a logical index that can be used to stride over all the elements of the point array. + *

+ * The base offset coordinate allows clients to express complex access operations, by injecting additional offset + * computation into the var handle (we will see an example of that below). In cases where the base offset is constant + * (as in the previous example) clients can, if desired, drop the base offset parameter and make the access expression + * simpler. This is achieved using the {@link java.lang.invoke.MethodHandles#insertCoordinates(VarHandle, int, Object...)} + * var handle adapter. + * + *

Nested variable-length arrays

+ * + * Consider the following struct declaration in C: * * {@snippet lang=c : * typedef struct { * int size; - * struct { - * int x; - * int y; - * } points[]; + * Point points[]; * } Polygon; * } * @@ -290,45 +358,37 @@ * the size of the {@code points} array is left unspecified in the C declaration, using a Flexible Array Member * (a feature standardized in C99). *

- * Memory layouts do not support sequence layouts whose size is unknown. As such, it is not possible to model - * the above struct directly. That said, clients can still enjoy structured access provided by memory layouts, as - * demonstrated below: + * Again, clients can perform structured access to elements in the nested variable-length array using the + * {@link #arrayElementVarHandle(PathElement...)} method, as demonstrated below: * * {@snippet lang=java : - * StructLayout POINT = MemoryLayout.structLayout( - * ValueLayout.JAVA_INT.withName("x"), - * ValueLayout.JAVA_INT.withName("y") - * ); - * * StructLayout POLYGON = MemoryLayout.structLayout( * ValueLayout.JAVA_INT.withName("size"), * MemoryLayout.sequenceLayout(0, POINT).withName("points") * ); * * VarHandle POLYGON_SIZE = POLYGON.varHandle(0, PathElement.groupElement("size")); - * VarHandle POINT_X = POINT.varHandle(PathElement.groupElement("x")); * long POINTS_OFFSET = POLYGON.byteOffset(PathElement.groupElement("points")); * } * - * Note how we have split the polygon struct in two. The {@code POLYGON} layout contains a sequence layout - * of size zero. The element layout of the sequence layout is the {@code POINT} layout, which defines - * the {@code x} and {@code y} coordinates, accordingly. The first layout is used to obtain a var handle - * that provides access to the polygon size; the second layout is used to obtain a var handle that provides - * access to the {@code x} coordinate of a point struct. Finally, an offset to the start of the variable-length - * {@code points} array is also obtained. + * The {@code POLYGON} layout contains a sequence layout of size zero. The element layout of the sequence layout + * is the {@code POINT} layout, shown previously. The polygon layout is used to obtain a var handle + * that provides access to the polygon size, as well as an offset ({@code POINTS_OFFSET}) to the start of the + * variable-length {@code points} array. *

* The {@code x} coordinates of all the points in a polygon can then be accessed as follows: * {@snippet lang=java : * MemorySegment polygon = ... * int size = POLYGON_SIZE.get(polygon, 0L); * for (int i = 0 ; i < size ; i++) { - * int x = POINT_X.get(polygon, POINT.scaleOffset(POINTS_OFFSET, i)); + * ... POINT_ARR_X.get(polygon, POINTS_OFFSET, (long)i) ... * } * } * Here, we first obtain the polygon size, using the {@code POLYGON_SIZE} var handle. Then, in a loop, we read - * the {@code x} coordinates of all the points in the polygon. This is done by providing a custom base offset to - * the {@code POINT_X} var handle. The custom offset is computed as {@code POINTS_OFFSET + (i * POINT.byteSize())}, where - * {@code i} is the loop induction variable. + * the {@code x} coordinates of all the points in the polygon. This is done by providing a custom offset + * (namely, {@code POINTS_OFFSET}) to the offset coordinate of the {@code POINT_ARR_X} var handle. As before, + * the loop induction variable {@code i} is passed as the index of the {@code POINT_ARR_X} var handle, + * to stride over all the elements of the variable-length array. * * @implSpec * Implementations of this interface are immutable, thread-safe and value-based. @@ -544,6 +604,49 @@ public sealed interface MemoryLayout permits SequenceLayout, GroupLayout, Paddin */ VarHandle varHandle(PathElement... elements); + /** + * Creates a var handle that accesses adjacent elements in a memory segment at offsets selected by the given layout path, + * where the accessed elements have this layout, and where the initial layout in the path is this layout. + *

+ * The returned var handle has the following characteristics: + *

    + *
  • its type is derived from the {@linkplain ValueLayout#carrier() carrier} of the + * selected value layout;
  • + *
  • it has a leading parameter of type {@code MemorySegment} representing the accessed segment
  • + *
  • a following {@code long} parameter, corresponding to the base offset, denoted as {@code B};
  • + *
  • a following {@code long} parameter, corresponding to the array index, denoted as {@code I0}. The array + * index is used to scale the accessed offset by this layout size;
  • + *
  • it has zero or more trailing access coordinates of type {@code long}, one for each + * open path element in the provided layout path, denoted as + * {@code I1, I2, ... In}, respectively. The order of these access coordinates corresponds to the order + * in which the open path elements occur in the provided layout path. + *
+ *

+ * If the provided layout path {@code P} contains no dereference elements, then the offset {@code O} of the access + * operation is computed as follows: + * + * {@snippet lang = "java": + * O = this.offsetHandle(P).invokeExact(this.scale(B, I0), I1, I2, ... In); + * } + *

+ * More formally, this method can be obtained from the {@link #varHandle(PathElement...)}, as follows: + * {@snippet lang = "java": + * MethodHandles.collectCoordinates(varHandle(elements), 1, scaleHandle()) + * } + * + * @apiNote + * As the leading index coordinate {@code I0} is not bound by any sequence layout, it can assume any non-negative + * value - provided that the resulting offset computation does not overflow, or that the computed offset does not fall + * outside the spatial bound of the accessed memory segment. As such, the var handles returned from this method can + * be especially useful when accessing variable-length arrays. + * + * @param elements the layout path elements. + * @return a var handle that accesses adjacent elements in a memory segment at offsets selected by the given layout path. + * @throws IllegalArgumentException if the layout path is not well-formed for this layout. + * @throws IllegalArgumentException if the layout selected by the provided path is not a {@linkplain ValueLayout value layout}. + */ + VarHandle arrayElementVarHandle(PathElement... elements); + /** * Creates a method handle which, given a memory segment, returns a {@linkplain MemorySegment#asSlice(long,long) slice} * corresponding to the layout selected by the given layout path, where the initial layout in the path is this layout. 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 cdb8e53805a..724286ce693 100644 --- a/src/java.base/share/classes/java/lang/foreign/MemorySegment.java +++ b/src/java.base/share/classes/java/lang/foreign/MemorySegment.java @@ -27,8 +27,6 @@ import java.io.UncheckedIOException; import java.lang.foreign.ValueLayout.OfInt; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.VarHandle; import java.nio.Buffer; import java.nio.ByteBuffer; import java.nio.ByteOrder; @@ -46,8 +44,6 @@ import jdk.internal.foreign.AbstractMemorySegmentImpl; import jdk.internal.foreign.MemorySessionImpl; import jdk.internal.foreign.SegmentFactories; -import jdk.internal.foreign.StringSupport; -import jdk.internal.foreign.Utils; import jdk.internal.javac.Restricted; import jdk.internal.reflect.CallerSensitive; import jdk.internal.vm.annotation.ForceInline; @@ -134,21 +130,18 @@ * int value = (int) intAtOffsetHandle.get(segment, 10L); // segment.get(ValueLayout.JAVA_INT, 10L) * } * - * The var handle returned by {@link ValueLayout#varHandle()} features a base offset parameter. This parameter - * allows clients to express complex access operations, by injecting additional offset computation into the var handle. - * For instance, a var handle that can be used to access an element of an {@code int} array at a given logical + * Alternatively, a var handle that can be used to access an element of an {@code int} array at a given logical * index can be created as follows: * * {@snippet lang=java: - * MethodHandle scale = ValueLayout.JAVA_INT.scaleHandle(); // (long, long)long * VarHandle intAtOffsetAndIndexHandle = - * MethodHandles.collectCoordinates(intAtOffsetHandle, 1, scale); // (MemorySegment, long, long) - * int value = (int) intAtOffsetAndIndexHandle.get(segment, 2L, 3L); // segment.get(ValueLayout.JAVA_INT, 2L + (3L * 4L)) + * ValueLayout.JAVA_INT.arrayElementVarHandle(); // (MemorySegment, long, long) + * int value = (int) intAtOffsetAndIndexHandle.get(segment, 2L, 3L); // segment.get(ValueLayout.JAVA_INT, 2L + (3L * 4L)) * } * *

* Clients can also drop the base offset parameter, in order to make the access expression simpler. This can be used to - * implement access operation such as {@link #getAtIndex(OfInt, long)}: + * implement access operations such as {@link #getAtIndex(OfInt, long)}: * * {@snippet lang=java: * VarHandle intAtIndexHandle = 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 42baaa69270..e4d931127af 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 @@ -196,6 +196,10 @@ public VarHandle varHandle(PathElement... elements) { Set.of(), elements); } + public VarHandle arrayElementVarHandle(PathElement... elements) { + return MethodHandles.collectCoordinates(varHandle(elements), 1, scaleHandle()); + } + public MethodHandle sliceHandle(PathElement... elements) { return computePathOp(LayoutPath.rootPath((MemoryLayout) this), LayoutPath::sliceHandle, Set.of(PathKind.DEREF_ELEMENT), elements); diff --git a/test/jdk/java/foreign/TestAdaptVarHandles.java b/test/jdk/java/foreign/TestAdaptVarHandles.java index 2849b308160..ebbef0ffb6b 100644 --- a/test/jdk/java/foreign/TestAdaptVarHandles.java +++ b/test/jdk/java/foreign/TestAdaptVarHandles.java @@ -82,8 +82,8 @@ public class TestAdaptVarHandles { } } - static final VarHandle intHandleIndexed = MethodHandles.collectCoordinates(ValueLayout.JAVA_INT.varHandle(), - 1, MethodHandles.insertArguments(ValueLayout.JAVA_INT.scaleHandle(), 0, 0L)); + static final VarHandle intHandleIndexed = MethodHandles.insertCoordinates( + ValueLayout.JAVA_INT.arrayElementVarHandle(), 1, 0L); static final VarHandle intHandle = MethodHandles.insertCoordinates(ValueLayout.JAVA_INT.varHandle(), 1, 0L); diff --git a/test/jdk/java/foreign/TestArrayCopy.java b/test/jdk/java/foreign/TestArrayCopy.java index dfe5c343f73..0a04f00e4f5 100644 --- a/test/jdk/java/foreign/TestArrayCopy.java +++ b/test/jdk/java/foreign/TestArrayCopy.java @@ -292,8 +292,7 @@ public static MemorySegment srcSegment(int bytesLength) { } private static VarHandle arrayVarHandle(ValueLayout layout) { - return MethodHandles.collectCoordinates(layout.varHandle(), - 1, MethodHandles.insertArguments(layout.scaleHandle(), 0, 0L)); + return MethodHandles.insertCoordinates(layout.arrayElementVarHandle(), 1, 0L); } public static MemorySegment truthSegment(MemorySegment srcSeg, CopyHelper helper, int indexShifts, CopyMode mode) { diff --git a/test/micro/org/openjdk/bench/java/lang/foreign/JavaLayouts.java b/test/micro/org/openjdk/bench/java/lang/foreign/JavaLayouts.java index c6e740113b8..a7cb973aaaf 100644 --- a/test/micro/org/openjdk/bench/java/lang/foreign/JavaLayouts.java +++ b/test/micro/org/openjdk/bench/java/lang/foreign/JavaLayouts.java @@ -44,7 +44,6 @@ public class JavaLayouts { static final VarHandle VH_LONG = arrayVarHandle(JAVA_LONG); private static VarHandle arrayVarHandle(ValueLayout layout) { - return MethodHandles.collectCoordinates(layout.varHandle(), - 1, MethodHandles.insertArguments(layout.scaleHandle(), 0, 0L)); + return MethodHandles.insertCoordinates(layout.arrayElementVarHandle(), 1, 0L); } } From a03767cf8868a200f5be74c4cf8cdf5f76f1e678 Mon Sep 17 00:00:00 2001 From: Jasmine Karthikeyan Date: Fri, 20 Oct 2023 10:44:58 +0000 Subject: [PATCH 034/124] 8318049: C2: assert(!failure) failed: Missed optimization opportunity in PhaseIterGVN Reviewed-by: epeter, thartmann --- src/hotspot/share/opto/phaseX.cpp | 9 +-- .../compiler/c2/TestNotifyCastToXor.java | 57 +++++++++++++++++++ 2 files changed, 62 insertions(+), 4 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/c2/TestNotifyCastToXor.java diff --git a/src/hotspot/share/opto/phaseX.cpp b/src/hotspot/share/opto/phaseX.cpp index e21b54dde26..f46eaffb3a5 100644 --- a/src/hotspot/share/opto/phaseX.cpp +++ b/src/hotspot/share/opto/phaseX.cpp @@ -1594,17 +1594,18 @@ void PhaseIterGVN::add_users_to_worklist( Node *n ) { } } - // If changed Cast input, notify down for Phi and Sub - both do "uncast" + // If changed Cast input, notify down for Phi, Sub, and Xor - all do "uncast" // Patterns: // ConstraintCast+ -> Sub // ConstraintCast+ -> Phi + // ConstraintCast+ -> Xor if (use->is_ConstraintCast()) { - auto push_phi_or_sub_uses_to_worklist = [&](Node* n){ - if (n->is_Phi() || n->is_Sub()) { + auto push_the_uses_to_worklist = [&](Node* n){ + if (n->is_Phi() || n->is_Sub() || n->Opcode() == Op_XorI || n->Opcode() == Op_XorL) { _worklist.push(n); } }; - ConstraintCastNode::visit_uncasted_uses(use, push_phi_or_sub_uses_to_worklist); + ConstraintCastNode::visit_uncasted_uses(use, push_the_uses_to_worklist); } // If changed LShift inputs, check RShift users for useless sign-ext if( use_op == Op_LShiftI ) { diff --git a/test/hotspot/jtreg/compiler/c2/TestNotifyCastToXor.java b/test/hotspot/jtreg/compiler/c2/TestNotifyCastToXor.java new file mode 100644 index 00000000000..88477e1ced9 --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/TestNotifyCastToXor.java @@ -0,0 +1,57 @@ +/* + * 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 8318049 + * @summary Test that xor nodes are properly notified when constraint casts change. + * @run main/othervm -Xcomp -XX:-TieredCompilation -XX:CompileOnly=compiler.c2.TestNotifyCastToXor::test + -XX:+IgnoreUnrecognizedVMOptions -XX:VerifyIterativeGVN=10 compiler.c2.TestNotifyCastToXor + */ + +package compiler.c2; + +public class TestNotifyCastToXor { + public static long longField = 0L; + + public static void test() { + int ind = -15; + + ind %= ind; + for (int i = 0; i < 40; ++i) { + int j = 1; + + do { + ind ^= (int)longField; + + // Dead loop + for (int k = 1; k < 1; k++) { + } + } while (j++ < 10); + } + } + + public static void main(String[] args) { + test(); + } +} From deadb9c8d76f41671d39bb2125a8745c25bdb819 Mon Sep 17 00:00:00 2001 From: Justin King Date: Fri, 20 Oct 2023 11:02:38 +0000 Subject: [PATCH 035/124] 8304684: Memory leak in DirectivesParser::set_option_flag Reviewed-by: kvn, dlong --- .../share/compiler/compilerDirectives.cpp | 28 +++++++-- .../share/compiler/compilerDirectives.hpp | 60 +++++++++++++++---- .../share/compiler/directivesParser.cpp | 26 +++++--- 3 files changed, 90 insertions(+), 24 deletions(-) diff --git a/src/hotspot/share/compiler/compilerDirectives.cpp b/src/hotspot/share/compiler/compilerDirectives.cpp index 0368a6ad744..20c576fce66 100644 --- a/src/hotspot/share/compiler/compilerDirectives.cpp +++ b/src/hotspot/share/compiler/compilerDirectives.cpp @@ -287,11 +287,12 @@ void DirectiveSet::init_control_intrinsic() { } DirectiveSet::DirectiveSet(CompilerDirectives* d) :_inlinematchers(nullptr), _directive(d) { -#define init_defaults_definition(name, type, dvalue, compiler) this->name##Option = dvalue; _ideal_phase_name_mask = 0; +#define init_defaults_definition(name, type, dvalue, compiler) this->name##Option = dvalue; compilerdirectives_common_flags(init_defaults_definition) compilerdirectives_c2_flags(init_defaults_definition) compilerdirectives_c1_flags(init_defaults_definition) +#undef init_defaults_definition memset(_modified, 0, sizeof(_modified)); _intrinsic_control_words.fill_in(/*default value*/TriBool()); } @@ -304,6 +305,12 @@ DirectiveSet::~DirectiveSet() { delete tmp; tmp = next; } + +#define free_string_flags(name, type, dvalue, cc_flag) if (_modified[name##Index]) os::free(const_cast(name##Option)); + compilerdirectives_common_string_flags(free_string_flags) + compilerdirectives_c2_string_flags(free_string_flags) + compilerdirectives_c1_string_flags(free_string_flags) +#undef free_string_flags } // A smart pointer of DirectiveSet. It uses Copy-on-Write strategy to avoid cloning. @@ -407,6 +414,7 @@ DirectiveSet* DirectiveSet::compilecommand_compatibility_init(const methodHandle compilerdirectives_common_flags(init_default_cc) compilerdirectives_c2_flags(init_default_cc) compilerdirectives_c1_flags(init_default_cc) +#undef init_default_cc // Parse PrintIdealPhaseName and create an efficient lookup mask #ifndef PRODUCT @@ -585,9 +593,21 @@ DirectiveSet* DirectiveSet::clone(DirectiveSet const* src) { } #define copy_members_definition(name, type, dvalue, cc_flag) set->name##Option = src->name##Option; - compilerdirectives_common_flags(copy_members_definition) - compilerdirectives_c2_flags(copy_members_definition) - compilerdirectives_c1_flags(copy_members_definition) + compilerdirectives_common_other_flags(copy_members_definition) + compilerdirectives_c2_other_flags(copy_members_definition) + compilerdirectives_c1_other_flags(copy_members_definition) + #undef copy_members_definition + +#define copy_string_members_definition(name, type, dvalue, cc_flag) \ + if (src->_modified[name##Index]) { \ + set->name##Option = os::strdup_check_oom(src->name##Option, mtCompiler); \ + } else { \ + set->name##Option = src->name##Option; \ + } + compilerdirectives_common_string_flags(copy_string_members_definition) + compilerdirectives_c2_string_flags(copy_string_members_definition) + compilerdirectives_c1_string_flags(copy_string_members_definition) +#undef copy_string_members_definition set->_intrinsic_control_words = src->_intrinsic_control_words; set->_ideal_phase_name_mask = src->_ideal_phase_name_mask; diff --git a/src/hotspot/share/compiler/compilerDirectives.hpp b/src/hotspot/share/compiler/compilerDirectives.hpp index 8c8dcb99f0d..439a4c2f925 100644 --- a/src/hotspot/share/compiler/compilerDirectives.hpp +++ b/src/hotspot/share/compiler/compilerDirectives.hpp @@ -35,7 +35,7 @@ #include "utilities/tribool.hpp" // Directives flag name, type, default value, compile command name - #define compilerdirectives_common_flags(cflags) \ + #define compilerdirectives_common_other_flags(cflags) \ cflags(Enable, bool, false, Unknown) \ cflags(Exclude, bool, false, Unknown) \ cflags(BreakAtExecute, bool, false, BreakAtExecute) \ @@ -51,18 +51,28 @@ cflags(DumpReplay, bool, false, DumpReplay) \ cflags(DumpInline, bool, false, DumpInline) \ cflags(CompilerDirectivesIgnoreCompileCommands, bool, CompilerDirectivesIgnoreCompileCommands, Unknown) \ - cflags(DisableIntrinsic, ccstrlist, DisableIntrinsic, DisableIntrinsic) \ - cflags(ControlIntrinsic, ccstrlist, ControlIntrinsic, ControlIntrinsic) \ cflags(RepeatCompilation, intx, RepeatCompilation, RepeatCompilation) +#define compilerdirectives_common_string_flags(cflags) \ + cflags(DisableIntrinsic, ccstrlist, DisableIntrinsic, DisableIntrinsic) \ + cflags(ControlIntrinsic, ccstrlist, ControlIntrinsic, ControlIntrinsic) +#define compilerdirectives_common_flags(cflags) \ + compilerdirectives_common_other_flags(cflags) \ + compilerdirectives_common_string_flags(cflags) #ifdef COMPILER1 - #define compilerdirectives_c1_flags(cflags) + #define compilerdirectives_c1_other_flags(cflags) + #define compilerdirectives_c1_string_flags(cflags) #else - #define compilerdirectives_c1_flags(cflags) + #define compilerdirectives_c1_other_flags(cflags) + #define compilerdirectives_c1_string_flags(cflags) #endif +#define compilerdirectives_c1_flags(cflags) \ + compilerdirectives_c1_other_flags(cflags) \ + compilerdirectives_c1_string_flags(cflags) + #ifdef COMPILER2 - #define compilerdirectives_c2_flags(cflags) \ + #define compilerdirectives_c2_other_flags(cflags) \ cflags(BlockLayoutByFrequency, bool, BlockLayoutByFrequency, BlockLayoutByFrequency) \ cflags(PrintOptoAssembly, bool, PrintOptoAssembly, PrintOptoAssembly) \ cflags(PrintIntrinsics, bool, PrintIntrinsics, PrintIntrinsics) \ @@ -70,7 +80,6 @@ NOT_PRODUCT(cflags(TraceOptoPipelining, bool, TraceOptoPipelining, TraceOptoPipe NOT_PRODUCT(cflags(TraceOptoOutput, bool, TraceOptoOutput, TraceOptoOutput)) \ NOT_PRODUCT(cflags(TraceEscapeAnalysis, bool, false, TraceEscapeAnalysis)) \ NOT_PRODUCT(cflags(PrintIdeal, bool, PrintIdeal, PrintIdeal)) \ -NOT_PRODUCT(cflags(PrintIdealPhase, ccstrlist, "", PrintIdealPhase)) \ cflags(TraceSpilling, bool, TraceSpilling, TraceSpilling) \ cflags(Vectorize, bool, false, Vectorize) \ cflags(CloneMapDebug, bool, false, CloneMapDebug) \ @@ -78,10 +87,17 @@ NOT_PRODUCT(cflags(IGVPrintLevel, intx, PrintIdealGraphLevel, IGVPrintLeve cflags(VectorizeDebug, uintx, 0, VectorizeDebug) \ cflags(IncrementalInlineForceCleanup, bool, IncrementalInlineForceCleanup, IncrementalInlineForceCleanup) \ cflags(MaxNodeLimit, intx, MaxNodeLimit, MaxNodeLimit) +#define compilerdirectives_c2_string_flags(cflags) \ +NOT_PRODUCT(cflags(PrintIdealPhase, ccstrlist, "", PrintIdealPhase)) #else - #define compilerdirectives_c2_flags(cflags) + #define compilerdirectives_c2_other_flags(cflags) + #define compilerdirectives_c2_string_flags(cflags) #endif +#define compilerdirectives_c2_flags(cflags) \ + compilerdirectives_c2_other_flags(cflags) \ + compilerdirectives_c2_string_flags(cflags) + class AbstractCompiler; class CompilerDirectives; class DirectiveSet; @@ -140,6 +156,7 @@ class DirectiveSet : public CHeapObj { compilerdirectives_common_flags(enum_of_flags) compilerdirectives_c2_flags(enum_of_flags) compilerdirectives_c1_flags(enum_of_flags) +#undef enum_of_flags number_of_flags } flags; @@ -150,12 +167,32 @@ class DirectiveSet : public CHeapObj { compilerdirectives_common_flags(flag_store_definition) compilerdirectives_c2_flags(flag_store_definition) compilerdirectives_c1_flags(flag_store_definition) +#undef flag_store_definition // Casting to get the same function signature for all setters. Used from parser. #define set_function_definition(name, type, dvalue, cc_flag) void set_##name(void* value) { type val = *(type*)value; name##Option = val; _modified[name##Index] = true; } - compilerdirectives_common_flags(set_function_definition) - compilerdirectives_c2_flags(set_function_definition) - compilerdirectives_c1_flags(set_function_definition) + compilerdirectives_common_other_flags(set_function_definition) + compilerdirectives_c2_other_flags(set_function_definition) + compilerdirectives_c1_other_flags(set_function_definition) +#undef set_function_definition + +// Casting to get the same function signature for all setters. Used from parser. +// +// IMPORTANT: Takes ownership, will use os::free. Ensure the memory was dynamically allocated on the +// C heap. +#define set_string_function_definition(name, type, dvalue, cc_flag) \ +void set_##name(void* value) { \ + if (_modified[name##Index]) { \ + os::free(const_cast(name##Option)); \ + } \ + type val = *(type*)value; \ + name##Option = val; \ + _modified[name##Index] = true; \ +} + compilerdirectives_common_string_flags(set_string_function_definition) + compilerdirectives_c2_string_flags(set_string_function_definition) + compilerdirectives_c1_string_flags(set_string_function_definition) +#undef set_string_function_definition void set_ideal_phase_mask(uint64_t mask) { _ideal_phase_name_mask = mask; }; uint64_t ideal_phase_mask() { return _ideal_phase_name_mask; }; @@ -174,6 +211,7 @@ void print(outputStream* st) { compilerdirectives_common_flags(print_function_definition) compilerdirectives_c2_flags(print_function_definition) compilerdirectives_c1_flags(print_function_definition) +#undef print_function_definition st->cr(); } }; diff --git a/src/hotspot/share/compiler/directivesParser.cpp b/src/hotspot/share/compiler/directivesParser.cpp index ae576d9170b..0f6978bade8 100644 --- a/src/hotspot/share/compiler/directivesParser.cpp +++ b/src/hotspot/share/compiler/directivesParser.cpp @@ -315,35 +315,43 @@ bool DirectivesParser::set_option_flag(JSON_TYPE t, JSON_VAL* v, const key* opti error(VALUE_ERROR, "Cannot use string value for a %s flag", flag_type_names[option_key->flag_type]); return false; } else { - char* s = NEW_C_HEAP_ARRAY(char, v->str.length+1, mtCompiler); + char* s = NEW_C_HEAP_ARRAY(char, v->str.length + 1, mtCompiler); strncpy(s, v->str.start, v->str.length + 1); s[v->str.length] = '\0'; - (set->*test)((void *)&s); + + bool valid = true; if (strncmp(option_key->name, "ControlIntrinsic", 16) == 0) { ControlIntrinsicValidator validator(s, false/*disabled_all*/); - if (!validator.is_valid()) { + valid = validator.is_valid(); + if (!valid) { error(VALUE_ERROR, "Unrecognized intrinsic detected in ControlIntrinsic: %s", validator.what()); - return false; } } else if (strncmp(option_key->name, "DisableIntrinsic", 16) == 0) { ControlIntrinsicValidator validator(s, true/*disabled_all*/); - if (!validator.is_valid()) { + valid = validator.is_valid(); + if (!valid) { error(VALUE_ERROR, "Unrecognized intrinsic detected in DisableIntrinsic: %s", validator.what()); - return false; } } else if (strncmp(option_key->name, "PrintIdealPhase", 15) == 0) { uint64_t mask = 0; PhaseNameValidator validator(s, mask); - if (!validator.is_valid()) { + valid = validator.is_valid(); + if (valid) { + set->set_ideal_phase_mask(mask); + } else { error(VALUE_ERROR, "Unrecognized phase name detected in PrintIdealPhase: %s", validator.what()); - return false; } - set->set_ideal_phase_mask(mask); } + + if (!valid) { + FREE_C_HEAP_ARRAY(char, s); + return false; + } + (set->*test)((void *)&s); // Takes ownership. } break; From 2c23391de76be0994d8367fdfba63a98e9faa63d Mon Sep 17 00:00:00 2001 From: Alexey Ivanov Date: Fri, 20 Oct 2023 11:02:58 +0000 Subject: [PATCH 036/124] 8318101: Additional test cases for CSSAttributeEqualityBug Reviewed-by: prr --- .../html/CSS/CSSAttributeEqualityBug.java | 26 +++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/test/jdk/javax/swing/text/html/CSS/CSSAttributeEqualityBug.java b/test/jdk/javax/swing/text/html/CSS/CSSAttributeEqualityBug.java index 7968f773bd5..304f1e83542 100644 --- a/test/jdk/javax/swing/text/html/CSS/CSSAttributeEqualityBug.java +++ b/test/jdk/javax/swing/text/html/CSS/CSSAttributeEqualityBug.java @@ -70,6 +70,8 @@ public class CSSAttributeEqualityBug { "background-position: 0 0", "background-position: 1cm 2cm", "background-position: 1em 2em", + + "border-width: medium", }; /** @@ -86,6 +88,14 @@ public class CSSAttributeEqualityBug { {"margin-top: 100%", "margin-top: 50%"}, }; + private static final String[][] EQUALS_WITH_SPACE = { + {"font-size: 42px", "font-size: 42 px"}, + {"font-size: 100%", "font-size: 100 %"}, + + {"width: 42px", "width: 42 px"}, + {"width: 100%", "width: 100 %"}, + }; + public static void main(String[] args) { final List failures = new ArrayList<>(); @@ -97,10 +107,14 @@ public static void main(String[] args) { .map(CSSAttributeEqualityBug::negativeTest) .filter(Objects::nonNull) .forEach(failures::add); + Arrays.stream(EQUALS_WITH_SPACE) + .map(CSSAttributeEqualityBug::positiveTest) + .filter(Objects::nonNull) + .forEach(failures::add); if (!failures.isEmpty()) { failures.forEach(System.err::println); - throw new RuntimeException(failures.size() + throw new RuntimeException("The test failed: " + failures.size() + " failure(s) detected: " + failures.get(0)); } @@ -115,6 +129,15 @@ private static String positiveTest(String cssDeclaration) { return assertEquals(a, b); } + private static String positiveTest(String[] cssDeclaration) { + StyleSheet ss = new StyleSheet(); + + AttributeSet a = ss.getDeclaration(cssDeclaration[0]); + AttributeSet b = ss.getDeclaration(cssDeclaration[1]); + + return assertEquals(a, b); + } + private static String negativeTest(String[] cssDeclaration) { StyleSheet ss = new StyleSheet(); @@ -145,4 +168,3 @@ private static String getErrorMessage(AttributeSet a, } } - From 71c99a0e59ff843d48f1c71fb045186e44f83943 Mon Sep 17 00:00:00 2001 From: Alexey Ivanov Date: Fri, 20 Oct 2023 11:04:24 +0000 Subject: [PATCH 037/124] 8318448: Link PopupMenu/PopupMenuLocation.java failure to JDK-8259913 Reviewed-by: prr --- test/jdk/ProblemList.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 00da124ce53..233bf26dc70 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -442,7 +442,7 @@ java/awt/event/MouseEvent/ClickDuringKeypress/ClickDuringKeypress.java 8233568 m java/awt/event/KeyEvent/DeadKey/DeadKeyMacOSXInputText.java 8233568 macosx-all java/awt/event/KeyEvent/DeadKey/deadKeyMacOSX.java 8233568 macosx-all java/awt/TrayIcon/RightClickWhenBalloonDisplayed/RightClickWhenBalloonDisplayed.java 8238720 windows-all -java/awt/PopupMenu/PopupMenuLocation.java 8238720,8315878 windows-all,macosx-aarch64 +java/awt/PopupMenu/PopupMenuLocation.java 8259913,8315878 windows-all,macosx-aarch64 java/awt/GridLayout/ComponentPreferredSize/ComponentPreferredSize.java 8238720 windows-all java/awt/GridLayout/ChangeGridSize/ChangeGridSize.java 8238720 windows-all java/awt/event/MouseEvent/FrameMouseEventAbsoluteCoordsTest/FrameMouseEventAbsoluteCoordsTest.java 8238720 windows-all From fe52917054ebed3009391487c304f1fad4271049 Mon Sep 17 00:00:00 2001 From: Claes Redestad Date: Fri, 20 Oct 2023 11:37:07 +0000 Subject: [PATCH 038/124] 8318457: Use prefix-less prepend methods directly to reduce branches in String concat expressions Reviewed-by: jlaskey, liach --- .../classes/java/lang/StringConcatHelper.java | 29 +++++++++-------- .../java/lang/invoke/StringConcatFactory.java | 31 ++++++++++++------- .../share/classes/java/util/FormatItem.java | 5 ++- 3 files changed, 35 insertions(+), 30 deletions(-) diff --git a/src/java.base/share/classes/java/lang/StringConcatHelper.java b/src/java.base/share/classes/java/lang/StringConcatHelper.java index eddfc7e6496..28b9b754bbd 100644 --- a/src/java.base/share/classes/java/lang/StringConcatHelper.java +++ b/src/java.base/share/classes/java/lang/StringConcatHelper.java @@ -138,7 +138,6 @@ static long mix(long lengthCoder, String value) { @PreviewFeature(feature=PreviewFeature.Feature.STRING_TEMPLATES) static long mix(long lengthCoder, FormatConcatItem value) { lengthCoder = value.mix(lengthCoder); - return checkOverflow(lengthCoder); } @@ -152,7 +151,7 @@ static long mix(long lengthCoder, FormatConcatItem value) { * @param value boolean value to encode * @return updated index (coder value retained) */ - private static long prepend(long indexCoder, byte[] buf, boolean value) { + static long prepend(long indexCoder, byte[] buf, boolean value) { int index = (int)indexCoder; if (indexCoder < UTF16) { if (value) { @@ -198,7 +197,7 @@ private static long prepend(long indexCoder, byte[] buf, boolean value) { */ static long prepend(long indexCoder, byte[] buf, boolean value, String prefix) { indexCoder = prepend(indexCoder, buf, value); - if (prefix != null) indexCoder = prepend(indexCoder, buf, prefix); + indexCoder = prepend(indexCoder, buf, prefix); return indexCoder; } @@ -212,7 +211,7 @@ static long prepend(long indexCoder, byte[] buf, boolean value, String prefix) { * @param value char value to encode * @return updated index (coder value retained) */ - private static long prepend(long indexCoder, byte[] buf, char value) { + static long prepend(long indexCoder, byte[] buf, char value) { if (indexCoder < UTF16) { buf[(int)(--indexCoder)] = (byte) (value & 0xFF); } else { @@ -234,7 +233,7 @@ private static long prepend(long indexCoder, byte[] buf, char value) { */ static long prepend(long indexCoder, byte[] buf, char value, String prefix) { indexCoder = prepend(indexCoder, buf, value); - if (prefix != null) indexCoder = prepend(indexCoder, buf, prefix); + indexCoder = prepend(indexCoder, buf, prefix); return indexCoder; } @@ -248,7 +247,7 @@ static long prepend(long indexCoder, byte[] buf, char value, String prefix) { * @param value integer value to encode * @return updated index (coder value retained) */ - private static long prepend(long indexCoder, byte[] buf, int value) { + static long prepend(long indexCoder, byte[] buf, int value) { if (indexCoder < UTF16) { return StringLatin1.getChars(value, (int)indexCoder, buf); } else { @@ -269,7 +268,7 @@ private static long prepend(long indexCoder, byte[] buf, int value) { */ static long prepend(long indexCoder, byte[] buf, int value, String prefix) { indexCoder = prepend(indexCoder, buf, value); - if (prefix != null) indexCoder = prepend(indexCoder, buf, prefix); + indexCoder = prepend(indexCoder, buf, prefix); return indexCoder; } @@ -283,7 +282,7 @@ static long prepend(long indexCoder, byte[] buf, int value, String prefix) { * @param value long value to encode * @return updated index (coder value retained) */ - private static long prepend(long indexCoder, byte[] buf, long value) { + static long prepend(long indexCoder, byte[] buf, long value) { if (indexCoder < UTF16) { return StringLatin1.getChars(value, (int)indexCoder, buf); } else { @@ -304,7 +303,7 @@ private static long prepend(long indexCoder, byte[] buf, long value) { */ static long prepend(long indexCoder, byte[] buf, long value, String prefix) { indexCoder = prepend(indexCoder, buf, value); - if (prefix != null) indexCoder = prepend(indexCoder, buf, prefix); + indexCoder = prepend(indexCoder, buf, prefix); return indexCoder; } @@ -318,7 +317,7 @@ static long prepend(long indexCoder, byte[] buf, long value, String prefix) { * @param value String value to encode * @return updated index (coder value retained) */ - private static long prepend(long indexCoder, byte[] buf, String value) { + static long prepend(long indexCoder, byte[] buf, String value) { indexCoder -= value.length(); if (indexCoder < UTF16) { value.getBytes(buf, (int)indexCoder, String.LATIN1); @@ -341,7 +340,7 @@ private static long prepend(long indexCoder, byte[] buf, String value) { */ static long prepend(long indexCoder, byte[] buf, String value, String prefix) { indexCoder = prepend(indexCoder, buf, value); - if (prefix != null) indexCoder = prepend(indexCoder, buf, prefix); + indexCoder = prepend(indexCoder, buf, prefix); return indexCoder; } @@ -357,8 +356,7 @@ static long prepend(long indexCoder, byte[] buf, String value, String prefix) { * @since 21 */ @PreviewFeature(feature=PreviewFeature.Feature.STRING_TEMPLATES) - private static long prepend(long indexCoder, byte[] buf, - FormatConcatItem value) { + static long prepend(long indexCoder, byte[] buf, FormatConcatItem value) { try { return value.prepend(indexCoder, buf); } catch (Error ex) { @@ -384,7 +382,7 @@ private static long prepend(long indexCoder, byte[] buf, static long prepend(long indexCoder, byte[] buf, FormatConcatItem value, String prefix) { indexCoder = prepend(indexCoder, buf, value); - if (prefix != null) indexCoder = prepend(indexCoder, buf, prefix); + indexCoder = prepend(indexCoder, buf, prefix); return indexCoder; } @@ -586,7 +584,8 @@ static MethodHandle selectPutChar(long indexCoder) { static MethodHandle lookupStatic(String name, MethodType methodType) { try { - return MethodHandles.lookup().findStatic(StringConcatHelper.class, name, methodType); + return MethodHandles.lookup() + .findStatic(StringConcatHelper.class, name, methodType); } catch (NoSuchMethodException|IllegalAccessException e) { throw new AssertionError(e); } diff --git a/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java b/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java index 6fa79baccb9..cc0abfef97c 100644 --- a/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java +++ b/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java @@ -700,19 +700,12 @@ private static MethodHandle foldInLastMixers(MethodHandle mh, long initialLength // Simple prependers, single argument. May be used directly or as a // building block for complex prepender combinators. private static MethodHandle prepender(String prefix, Class cl) { - MethodHandle prepend; - int idx = classIndex(cl); - if (prefix == null) { - prepend = NULL_PREPENDERS[idx]; - if (prepend == null) { - NULL_PREPENDERS[idx] = prepend = MethodHandles.insertArguments( - prepender(cl), 3, (String)null); - } + if (prefix == null || prefix.isEmpty()) { + return noPrefixPrepender(cl); } else { - prepend = MethodHandles.insertArguments( + return MethodHandles.insertArguments( prepender(cl), 3, prefix); } - return prepend; } private static MethodHandle prepender(Class cl) { @@ -729,6 +722,20 @@ private static MethodHandle prepender(Class cl) { return prepend; } + private static MethodHandle noPrefixPrepender(Class cl) { + int idx = classIndex(cl); + MethodHandle prepend = NO_PREFIX_PREPENDERS[idx]; + if (prepend == null) { + if (idx == STRING_CONCAT_ITEM) { + cl = FormatConcatItem.class; + } + NO_PREFIX_PREPENDERS[idx] = prepend = JLA.stringConcatHelper("prepend", + methodType(long.class, long.class, byte[].class, + Wrapper.asPrimitiveType(cl))).rebind(); + } + return prepend; + } + private static final int INT_IDX = 0, CHAR_IDX = 1, LONG_IDX = 2, @@ -995,7 +1002,7 @@ private static MethodHandle unaryConcat(Class cl) { } } - private static final @Stable MethodHandle[] NULL_PREPENDERS = new MethodHandle[TYPE_COUNT]; + private static final @Stable MethodHandle[] NO_PREFIX_PREPENDERS = new MethodHandle[TYPE_COUNT]; private static final @Stable MethodHandle[] PREPENDERS = new MethodHandle[TYPE_COUNT]; private static final @Stable MethodHandle[] MIXERS = new MethodHandle[TYPE_COUNT]; private static final long INITIAL_CODER = JLA.stringConcatInitialCoder(); @@ -1117,7 +1124,7 @@ public static MethodHandle makeConcatWithTemplate( Class ttype = ttypes[pos]; // (long,byte[],ttype) -> long - MethodHandle prepender = prepender(fragment.isEmpty() ? null : fragment, ttype); + MethodHandle prepender = prepender(fragment, ttype); // (byte[],long,ttypes...) -> String (unchanged) mh = MethodHandles.filterArgumentsWithCombiner(mh, 1, prepender,1, 0, 2 + pos); diff --git a/src/java.base/share/classes/java/util/FormatItem.java b/src/java.base/share/classes/java/util/FormatItem.java index 728d4aee3b7..9ac700ffa4f 100644 --- a/src/java.base/share/classes/java/util/FormatItem.java +++ b/src/java.base/share/classes/java/util/FormatItem.java @@ -61,7 +61,7 @@ class FormatItem { private static final MethodHandle STRING_PREPEND = JLA.stringConcatHelper("prepend", MethodType.methodType(long.class, long.class, byte[].class, - String.class, String.class)); + String.class)); private static final MethodHandle SELECT_GETCHAR_MH = JLA.stringConcatHelper("selectGetChar", @@ -87,8 +87,7 @@ private static long stringMix(long lengthCoder, String value) { private static long stringPrepend(long lengthCoder, byte[] buffer, String value) throws Throwable { - return (long)STRING_PREPEND.invokeExact(lengthCoder, buffer, value, - (String)null); + return (long)STRING_PREPEND.invokeExact(lengthCoder, buffer, value); } private static MethodHandle selectGetChar(long indexCoder) throws Throwable { From 40106422bd2ae3da98d028bdbab2c240a71081e3 Mon Sep 17 00:00:00 2001 From: Mahendra Chhipa Date: Fri, 20 Oct 2023 12:07:39 +0000 Subject: [PATCH 039/124] 8077371: Binary files in JAXP test should be removed Reviewed-by: joehw --- .../GregorianCalAndDurSerDataTemplate.java | 70 ++++++ .../GregorianCalAndDurSerDataUtil.java | 141 +++++++++++ .../GregorianCalendarAndDurationSerData.java | 33 +++ ...K6GregorianCalendarAndDurationSerData.java | 129 ++++++++++ .../jaxp/datatype/8033980/JDK6_Duration.ser | Bin 290 -> 0 bytes .../8033980/JDK6_XMLGregorianCalendar.ser | Bin 521 -> 0 bytes ...K7GregorianCalendarAndDurationSerData.java | 127 ++++++++++ .../jaxp/datatype/8033980/JDK7_Duration.ser | Bin 145 -> 0 bytes .../8033980/JDK7_XMLGregorianCalendar.ser | Bin 521 -> 0 bytes ...K8GregorianCalendarAndDurationSerData.java | 128 ++++++++++ .../jaxp/datatype/8033980/JDK8_Duration.ser | Bin 145 -> 0 bytes .../8033980/JDK8_XMLGregorianCalendar.ser | Bin 521 -> 0 bytes ...K9GregorianCalendarAndDurationSerData.java | 127 ++++++++++ .../jaxp/datatype/8033980/JDK9_Duration.ser | Bin 290 -> 0 bytes .../8033980/JDK9_XMLGregorianCalendar.ser | Bin 1208 -> 0 bytes .../datatype/8033980/SerializationTest.java | 225 ++++++++---------- 16 files changed, 860 insertions(+), 120 deletions(-) create mode 100644 test/jdk/javax/xml/jaxp/datatype/8033980/GregorianCalAndDurSerDataTemplate.java create mode 100644 test/jdk/javax/xml/jaxp/datatype/8033980/GregorianCalAndDurSerDataUtil.java create mode 100644 test/jdk/javax/xml/jaxp/datatype/8033980/GregorianCalendarAndDurationSerData.java create mode 100644 test/jdk/javax/xml/jaxp/datatype/8033980/JDK6GregorianCalendarAndDurationSerData.java delete mode 100644 test/jdk/javax/xml/jaxp/datatype/8033980/JDK6_Duration.ser delete mode 100644 test/jdk/javax/xml/jaxp/datatype/8033980/JDK6_XMLGregorianCalendar.ser create mode 100644 test/jdk/javax/xml/jaxp/datatype/8033980/JDK7GregorianCalendarAndDurationSerData.java delete mode 100644 test/jdk/javax/xml/jaxp/datatype/8033980/JDK7_Duration.ser delete mode 100644 test/jdk/javax/xml/jaxp/datatype/8033980/JDK7_XMLGregorianCalendar.ser create mode 100644 test/jdk/javax/xml/jaxp/datatype/8033980/JDK8GregorianCalendarAndDurationSerData.java delete mode 100644 test/jdk/javax/xml/jaxp/datatype/8033980/JDK8_Duration.ser delete mode 100644 test/jdk/javax/xml/jaxp/datatype/8033980/JDK8_XMLGregorianCalendar.ser create mode 100644 test/jdk/javax/xml/jaxp/datatype/8033980/JDK9GregorianCalendarAndDurationSerData.java delete mode 100644 test/jdk/javax/xml/jaxp/datatype/8033980/JDK9_Duration.ser delete mode 100644 test/jdk/javax/xml/jaxp/datatype/8033980/JDK9_XMLGregorianCalendar.ser diff --git a/test/jdk/javax/xml/jaxp/datatype/8033980/GregorianCalAndDurSerDataTemplate.java b/test/jdk/javax/xml/jaxp/datatype/8033980/GregorianCalAndDurSerDataTemplate.java new file mode 100644 index 00000000000..dfb12c4c0e9 --- /dev/null +++ b/test/jdk/javax/xml/jaxp/datatype/8033980/GregorianCalAndDurSerDataTemplate.java @@ -0,0 +1,70 @@ +/* + * 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. + */ + +/** + * This class provide the template for JDK version specific GregorianCalendarAndDurationSerData.java src file. + */ +public class GregorianCalAndDurSerDataTemplate { + public static final String ORACLE_COPY_RIGHT = """ + /* + * Copyright (c) %s, Oracle and/or its affiliates. All rights reserved. + * 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. + */ + \s + /** + * Mechanically generated %s specific serialization bytes for XMLGregorianCalendar and Duration data type. + * Do not edit this file. + */"""; + public static final String GREGO_CAL_DUR_SER_CLASS = """ + public class %sGregorianCalendarAndDurationSerData extends GregorianCalendarAndDurationSerData { + %s + %s + @Override + public byte[] getGregorianCalendarByteArray() { + return gregorianCalendarBytes; + } + \s + @Override + public byte[] getDurationBytes() { + return durationBytes; + } + };"""; +} diff --git a/test/jdk/javax/xml/jaxp/datatype/8033980/GregorianCalAndDurSerDataUtil.java b/test/jdk/javax/xml/jaxp/datatype/8033980/GregorianCalAndDurSerDataUtil.java new file mode 100644 index 00000000000..323ba4a802b --- /dev/null +++ b/test/jdk/javax/xml/jaxp/datatype/8033980/GregorianCalAndDurSerDataUtil.java @@ -0,0 +1,141 @@ +/* + * 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 + * @summary utility to generate Gregorian Calendar and Duration serialized data java classes. + * @run junit/manual GregorianCalAndDurSerDataUtil + */ + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectOutputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.time.LocalDate; +import java.util.Formatter; + +import javax.xml.datatype.DatatypeConfigurationException; +import javax.xml.datatype.DatatypeFactory; +import javax.xml.datatype.Duration; +import javax.xml.datatype.XMLGregorianCalendar; + +import static org.junit.jupiter.api.Assertions.assertTrue; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; + +/** + * Utility to generate the java source file for Gregorian Calendar and Duration serialized data + * for specific version of JDK to be added in SerializationTest. Execute this test with desired version + * of JDK to generate the java source file. + */ +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +public class GregorianCalAndDurSerDataUtil { + static String JDK = "JDK" + System.getProperty("java.version"); + static String testsrc = System.getProperty("test.src"); + final static String EXPECTED_CAL = "0001-01-01T00:00:00.0000000-05:00"; + final static String EXPECTED_DURATION = "P1Y1M1DT1H1M1S"; + String srcFilePrefix = JDK.toUpperCase().replace("-", "_"); + + + /** + * Create the serialized Bytes array and serialized bytes base64 string for GregorianCalender and Duration + * with jdk under test and generate the java source file. + * @throws DatatypeConfigurationException Unexpected. + * @throws IOException Unexpected. + */ + @BeforeAll + public void setup() throws DatatypeConfigurationException, IOException { + DatatypeFactory dtf = DatatypeFactory.newInstance(); + XMLGregorianCalendar xmlGregorianCalendar = dtf.newXMLGregorianCalendar(EXPECTED_CAL); + Duration duration = dtf.newDuration(EXPECTED_DURATION); + String copyRightStr = GregorianCalAndDurSerDataTemplate.ORACLE_COPY_RIGHT; + String classStr = GregorianCalAndDurSerDataTemplate.GREGO_CAL_DUR_SER_CLASS; + try(ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos); + ByteArrayOutputStream baos2 = new ByteArrayOutputStream(); ObjectOutputStream oos2 = new ObjectOutputStream(baos2)) { + //Serialize the given xmlGregorianCalendar + oos.writeObject(xmlGregorianCalendar); + //Serialize the given xml Duration + oos2.writeObject(duration); + Files.deleteIfExists(Path.of(testsrc,srcFilePrefix+"GregorianCalendarAndDurationSerData.java")); + + copyRightStr = String.format(copyRightStr, LocalDate.now().getYear(), JDK); + classStr = String.format(classStr, srcFilePrefix, generatePseudoCodeForGregCalSerBytes(baos), + generatePseudoCodeForDurationSerBytes(baos2)); + String srcStr = copyRightStr + "\n" + classStr; + Files.writeString(Path.of(testsrc,srcFilePrefix+"GregorianCalendarAndDurationSerData.java"), srcStr); + } + } + + /** + * Verify that Java source file is created. + */ + @Test + void testFileCreated() { + assertTrue(Files.exists(Path.of(testsrc,srcFilePrefix+"GregorianCalendarAndDurationSerData.java"))); + } + + /** + * Generates the Java Pseudo code for serialized Gregorian Calendar byte array. + * @param baos Serialized GregorianCalendar ByteArrayOutputStream. + * @return pseudocode String for serialized Gregorian Calendar byte array. + */ + public static String generatePseudoCodeForGregCalSerBytes(ByteArrayOutputStream baos) { + byte [] bytes = baos.toByteArray(); + StringBuilder sb = new StringBuilder(bytes.length * 5); + sb.append("private final byte[] gregorianCalendarBytes = {"); + return generatePseudoCode(sb, bytes); + } + + /** + * Generates the Java Pseudo code for serialized Duration byte array. + * @param baos Serialized Duration ByteArrayOutputStream. + * @return pseudocode String for serialized Duration byte array. + */ + public static String generatePseudoCodeForDurationSerBytes(ByteArrayOutputStream baos) { + byte [] bytesdur = baos.toByteArray(); + StringBuilder sb = new StringBuilder(bytesdur.length * 5); + sb.append("private final byte[] durationBytes = {"); + return generatePseudoCode(sb, bytesdur); + } + + private static String generatePseudoCode(StringBuilder sb, byte [] bytes) { + final int linelen = 8; +// HexFormat hex = HexFormat.of().withPrefix(" (byte) 0x").withSuffix(","); +// for (int i = 0; i < bytes.length; i += linelen) { +// sb.append("\n"); +// sb.append(hex.formatHex(bytes, i, Math.min(i + linelen, bytes.length))); +// } +// sb.append("};"); + Formatter fmt = new Formatter(sb); + for (int i = 0; i ykm6IAWOs#%z%inFnL#Y`CBc!a0z~foj4#3CSxlc2g#CF`UNa_dn?+GmY?Fvw}v$ m#&dOsyueNm^rY5PuAc6vkSA}S)%m<_kNXXI=ibQ}!wcITiM`!!+`QVZQiG~JBsHu_i zAN&9xkRPC;0f7>HA&4T|c;wyLnc2Y`R8s>y(2}K@V%kIu6AU`Uaxwv>Oejl6Va&Ri zCoDvZwwDk)Iq>%lMcN2dyBL!S(Qui>@LQ!a)HqZ^>~Wau=*)2Nq)?e94ppg@?YNJW z0|N`(3=m9f`KH(-0ANP9idOAC}Jz23BZit2Nm%GrLED zkQmqV#Q7;rO%=}skH@3e0w*r|YN5dj4dyhay!Ol5@#oF&N4DZSS6WRHh?b8JJ-%nf5^{>qecrN^zu)8`_mP5@! zpHx&FXXRX&)Hb#1lhKWyC8xn*Db`n%+7{V{a0D+Ek;>#L)Fehq*eoOq<3Z5I|=Iv9s_D*0ZFx-9jOPur`)M9AcLINM7sS^*9=!Jl*0q2( zDPWx=recvYnFnLzVz{DAc6vkSA}S)%m<_kNXXI=ibQ}!wcITiM`!!+`QVZQiG~JBsHu_i zAN&9xkRPC;0f7>HA&4T|c;wyLnc2Y`R8s>y(2}K@V%kIu6AU`Uaxwv>Oejl6Va&Ri zCoDvZwwDk)Iq>%lMcN2dyBL!S(Qui>@LQ!a)HqZ^>~Wau=*)2Nq)?e94ppg@?YNJW z0|N`(3=m9f`KH(-0ANP9idOAC}Jz23BZit2Nm%GrLED zkQmqV#Q7;rO%=}skH@3e0w*r|YN5dj4dyhay!Ol5@#oF&N4DZSS6WRHh?b8JJ-%nf5^{>qecrN^zu)8`_mP5@! zpHx&FXXRX&)Hb#1lhKWyC8xn*Db`n%+7{V{a0D+Ek;>#L)Fehq*eoOq<3Z5I|=Iv9s_D*0ZFx-9jOPur`)M9AcLINM7sS^*9=!Jl*0q2( zDPWx=recvYnFnLzVz{DAc6vkSA}S)%m<_kNXXI=ibQ}!wcITiM`!!+`QVZQiG~JBsHu_i zAN&9xkRPC;0f7>HA&4T|c;wyLnc2Y`R8s>y(2}K@V%kIu6AU`Uaxwv>Oejl6Va&Ri zCoDvZwwDk)Iq>%lMcN2dyBL!S(Qui>@LQ!a)HqZ^>~Wau=*)2Nq)?e94ppg@?YNJW z0|N`(3=m9f`KH(-0ANP9idOAC}Jz23BZit2Nm%GrLED zkQmqV#Q7;rO%=}skH@3e0w*r|YN5dj4dyhay!Ol5@#oF&N4DZSS6WRHh?b8JJ-%nf5^{>qecrN^zu)8`_mP5@! zpHx&FXXRX&)Hb#1lhKWyC8xn*Db`n%+7{V{a0D+Ek;>#L)Fehq*eoOq<ykm6IAWOs#%z%inFnL#Y`CBc!a0z~foj4#3CSxlc2g#CF`UNa_dn?+GmY?Fvw}v$ m#&dOsyueNm^rY5PuQbhPuMYL4T16+4OLY9_LBm$%qXtF!mbF{V>uQ%+aK%$|6 z66(~E?mc(`9w0A3MFRreVSDeC;y_eT;bzAk&&>CEf78#k}r+9+J3wQ;c#=vGMEKucaua-w--b_DiZ@j;J8v%r|>nq(C4&MDZzjrbG zzTJh`nLiSCSJ%pN7`QMYmHWrpIu@p~ds>~5(W8kaH-p3VLcgTS?vot}R}fbsSG7EZ zfy7)1TW4e;Ivh1#V{d-7W-gq0`?c};>6g1-ensU<%*Lh1^lwuvX{-$0f?>%c)9;BbHjMV``@&&r=izl8C(aQff% MAJi34OaGMdPe_7~{Qv*} diff --git a/test/jdk/javax/xml/jaxp/datatype/8033980/SerializationTest.java b/test/jdk/javax/xml/jaxp/datatype/8033980/SerializationTest.java index c8fa0d41d28..89fd6e050cb 100644 --- a/test/jdk/javax/xml/jaxp/datatype/8033980/SerializationTest.java +++ b/test/jdk/javax/xml/jaxp/datatype/8033980/SerializationTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 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 @@ -25,160 +25,145 @@ * @test * @bug 8033980 * @summary verify serialization compatibility for XMLGregorianCalendar and Duration - * @run main SerializationTest read + * @run junit SerializationTest */ -import java.io.*; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.util.stream.Stream; + import javax.xml.datatype.DatatypeConfigurationException; import javax.xml.datatype.DatatypeFactory; import javax.xml.datatype.Duration; import javax.xml.datatype.XMLGregorianCalendar; +import static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + /** - * use "read" to test compatibility - * SerializationTest read - * - * use "write" to create test files - * SerializationTest write javaVersion - * where javaVersion is 6, 7, 8, or 9 - * + * Verify serialization compatibility for XMLGregorianCalendar and Duration * @author huizhe.wang@oracle.com */ +@TestInstance(TestInstance.Lifecycle.PER_CLASS) public class SerializationTest { - final String FILENAME_CAL = "_XMLGregorianCalendar.ser"; - final String FILENAME_DURATION = "_Duration.ser"; - String filePath; - - { - filePath = System.getProperty("test.src"); - if (filePath == null) { - //current directory - filePath = System.getProperty("user.dir"); - } - filePath += File.separator; - } final String EXPECTED_CAL = "0001-01-01T00:00:00.0000000-05:00"; final String EXPECTED_DURATION = "P1Y1M1DT1H1M1S"; - static String[] JDK = {"JDK6", "JDK7", "JDK8", "JDK9"}; - - public static void main(String[] args) { - SerializationTest test = new SerializationTest(); - - if (args[0].equalsIgnoreCase("read")) { - test.testReadCal(); - test.testReadDuration(); - test.report(); - } else { - int ver = Integer.valueOf(args[1]).intValue(); - test.createTestFile(JDK[ver - 6]); - } + static String[] JDK = {System.getProperty("java.version"), "JDK6", "JDK7", "JDK8", "JDK9"}; - } + // If needed to add serialized data of more JDK versions, serialized data source file can be generated using + // GregorianCalAndDurSerDataUtil class. + private GregorianCalendarAndDurationSerData[] gregorianCalendarAndDurationSerData = {null, new JDK6GregorianCalendarAndDurationSerData(), + new JDK7GregorianCalendarAndDurationSerData(), new JDK8GregorianCalendarAndDurationSerData(), new JDK9GregorianCalendarAndDurationSerData()}; - public void testReadCal() { - try { - for (String javaVersion : JDK) { - XMLGregorianCalendar d1 = (XMLGregorianCalendar) fromFile( - javaVersion + FILENAME_CAL); - if (!d1.toString().equalsIgnoreCase(EXPECTED_CAL)) { - fail("Java version: " + javaVersion - + "\nExpected: " + EXPECTED_CAL - + "\nActual: " + d1.toString()); - } else { - success("testReadCal: read " + javaVersion + " serialized file, passed."); + /** + * Create the serialized Bytes array and serialized bytes base64 string for GregorianCalender and Duration + * with jdk under test. + * @throws DatatypeConfigurationException Unexpected. + * @throws IOException Unexpected. + */ + @BeforeAll + public void setup() throws DatatypeConfigurationException, IOException { + DatatypeFactory dtf = DatatypeFactory.newInstance(); + XMLGregorianCalendar xmlGregorianCalendar = dtf.newXMLGregorianCalendar(EXPECTED_CAL); + Duration duration = dtf.newDuration(EXPECTED_DURATION); + try(ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos); + ByteArrayOutputStream baos2 = new ByteArrayOutputStream(); ObjectOutputStream oos2 = new ObjectOutputStream(baos2)) { + //Serialize the given xmlGregorianCalendar + oos.writeObject(xmlGregorianCalendar); + //Serialize the given xml Duration + oos2.writeObject(duration); + // Create the Data for JDK under test. + gregorianCalendarAndDurationSerData[0] = new GregorianCalendarAndDurationSerData() { + @Override + public byte[] getGregorianCalendarByteArray() { + return baos.toByteArray(); } - } - } catch (ClassNotFoundException ex) { - fail("testReadCal: " + ex.getMessage()); - } catch (IOException ex) { - fail("testReadCal: " + ex.getMessage()); - } - } - public void testReadDuration() { - try { - for (String javaVersion : JDK) { - Duration d1 = (Duration) fromFile( - javaVersion + FILENAME_DURATION); - if (!d1.toString().equalsIgnoreCase(EXPECTED_DURATION)) { - fail("Java version: " + javaVersion - + "\nExpected: " + EXPECTED_DURATION - + "\nActual: " + d1.toString()); - } else { - success("testReadDuration: read " + javaVersion + " serialized file, passed."); + @Override + public byte[] getDurationBytes() { + return baos2.toByteArray(); } - } - } catch (ClassNotFoundException ex) { - fail("testReadDuration: " + ex.getMessage()); - } catch (IOException ex) { - fail("testReadDuration: " + ex.getMessage()); + }; } } /** - * Create test files - * - * @param javaVersion JDK version + * Provide data for JDK version and Gregorian Calendar serialized bytes. + * @return A Stream of arguments where each element is an array of size three. First element contain JDK version, + * second element contain object reference to GregorianCalendarAndDurationSerData specific to JDK version + * and third element contain expected Gregorian Calendar as string. */ - public void createTestFile(String javaVersion) { - try { - DatatypeFactory dtf = DatatypeFactory.newInstance(); - XMLGregorianCalendar c = dtf.newXMLGregorianCalendar(EXPECTED_CAL); - Duration d = dtf.newDuration(EXPECTED_DURATION); - toFile((Serializable) c, filePath + javaVersion + FILENAME_CAL); - toFile((Serializable) d, filePath + javaVersion + FILENAME_DURATION); - } catch (Exception e) { - fail(e.getMessage()); - } + + public Stream gregorianCalendarDataBytes() { + return Stream.of( + Arguments.of(JDK[0], gregorianCalendarAndDurationSerData[0], EXPECTED_CAL), + Arguments.of(JDK[1], gregorianCalendarAndDurationSerData[1], EXPECTED_CAL), + Arguments.of(JDK[2], gregorianCalendarAndDurationSerData[2], EXPECTED_CAL), + Arguments.of(JDK[3], gregorianCalendarAndDurationSerData[3], EXPECTED_CAL), + Arguments.of(JDK[4], gregorianCalendarAndDurationSerData[4], EXPECTED_CAL) + ); } /** - * Read the object from a file. + * Provide data for JDK version and Duration serialized bytes. + * @return A Stream of arguments where each element is an array of size three. First element contain JDK version, + * second element contain object reference to GregorianCalendarAndDurationSerData specific to JDK version + * and third element contain expected Duration as string. */ - private static Object fromFile(String filePath) throws IOException, - ClassNotFoundException { - InputStream streamIn = SerializationTest.class.getResourceAsStream( - filePath); - ObjectInputStream objectinputstream = new ObjectInputStream(streamIn); - Object o = objectinputstream.readObject(); - return o; + + public Stream durationData() { + return Stream.of(Arguments.of(JDK[0], gregorianCalendarAndDurationSerData[0], EXPECTED_DURATION), + Arguments.of(JDK[1], gregorianCalendarAndDurationSerData[1], EXPECTED_DURATION), + Arguments.of(JDK[2], gregorianCalendarAndDurationSerData[2], EXPECTED_DURATION), + Arguments.of(JDK[3], gregorianCalendarAndDurationSerData[3], EXPECTED_DURATION), + Arguments.of(JDK[4], gregorianCalendarAndDurationSerData[4], EXPECTED_DURATION)); } /** - * Write the object to a file. + * Verify that GregorianCalendar serialized with different old JDK versions can be deserialized correctly with + * JDK under test. + * @param javaVersion JDK version used to GregorianCalendar serialization. + * @param gcsd JDK version specific GregorianCalendarAndDurationSerData. + * @param gregorianDate String representation of GregorianCalendar Date. + * @throws IOException Unexpected. + * @throws ClassNotFoundException Unexpected. */ - private static void toFile(Serializable o, String filePath) throws IOException { - FileOutputStream fout = new FileOutputStream(filePath, true); - ObjectOutputStream oos = new ObjectOutputStream(fout); - oos.writeObject(o); - oos.close(); - } - - static String errMessage; - int passed = 0, failed = 0; - - void fail(String errMsg) { - if (errMessage == null) { - errMessage = errMsg; - } else { - errMessage = errMessage + "\n" + errMsg; - } - failed++; - } - void success(String msg) { - passed++; - System.out.println(msg); + @ParameterizedTest + @MethodSource("gregorianCalendarDataBytes") + public void testReadCalBytes(String javaVersion, GregorianCalendarAndDurationSerData gcsd, String gregorianDate) throws IOException, + ClassNotFoundException { + final ByteArrayInputStream bais = new ByteArrayInputStream(gcsd.getGregorianCalendarByteArray()); + final ObjectInputStream ois = new ObjectInputStream(bais); + final XMLGregorianCalendar xgc = (XMLGregorianCalendar) ois.readObject(); + assertEquals(gregorianDate, xgc.toString()); } - public void report() { - - System.out.println("\nNumber of tests passed: " + passed); - System.out.println("Number of tests failed: " + failed + "\n"); + /** + * Verify that Duration serialized with different old JDK versions can be deserialized correctly with + * JDK under test. + * @param javaVersion JDK version used to GregorianCalendar serialization. + * @param gcsd JDK version specific GregorianCalendarAndDurationSerData. + * @param duration String representation of Duration. + * @throws IOException Unexpected. + * @throws ClassNotFoundException Unexpected. + */ - if (errMessage != null) { - throw new RuntimeException(errMessage); - } + @ParameterizedTest + @MethodSource("durationData") + public void testReadDurationBytes(String javaVersion, GregorianCalendarAndDurationSerData gcsd, String duration) throws IOException, + ClassNotFoundException { + final ByteArrayInputStream bais = new ByteArrayInputStream(gcsd.getDurationBytes()); + final ObjectInputStream ois = new ObjectInputStream(bais); + final Duration d1 = (Duration) ois.readObject(); + assertEquals(duration, d1.toString().toUpperCase()); } } From 91442878b7b7b2e131621958de4942f30bbf3537 Mon Sep 17 00:00:00 2001 From: Maurizio Cimadamore Date: Fri, 20 Oct 2023 14:29:17 +0000 Subject: [PATCH 040/124] 8318601: Remove javadoc text about restricted methods Reviewed-by: alanb --- .../share/classes/java/lang/ModuleLayer.java | 4 ---- .../classes/java/lang/foreign/AddressLayout.java | 4 ---- .../share/classes/java/lang/foreign/Linker.java | 12 ------------ .../classes/java/lang/foreign/MemorySegment.java | 12 ------------ .../classes/java/lang/foreign/SymbolLookup.java | 8 -------- 5 files changed, 40 deletions(-) diff --git a/src/java.base/share/classes/java/lang/ModuleLayer.java b/src/java.base/share/classes/java/lang/ModuleLayer.java index b038c1efa27..814cdeb7e6d 100644 --- a/src/java.base/share/classes/java/lang/ModuleLayer.java +++ b/src/java.base/share/classes/java/lang/ModuleLayer.java @@ -305,10 +305,6 @@ public Controller addOpens(Module source, String pn, Module target) { * Enables native access for a module in the layer if the caller's module * has native access. * - *

This method is restricted. - * Restricted methods are unsafe, and, if used incorrectly, their use might crash - * the JVM or, worse, silently result in memory corruption. - * * @param target * The module to update * diff --git a/src/java.base/share/classes/java/lang/foreign/AddressLayout.java b/src/java.base/share/classes/java/lang/foreign/AddressLayout.java index 6c93f4b64ed..3e2e3dc2bc9 100644 --- a/src/java.base/share/classes/java/lang/foreign/AddressLayout.java +++ b/src/java.base/share/classes/java/lang/foreign/AddressLayout.java @@ -98,10 +98,6 @@ public sealed interface AddressLayout extends ValueLayout permits ValueLayouts.O * AddressLayout unboundedLayout = addressLayout.withTargetLayout( * MemoryLayout.sequenceLayout(Long.MAX_VALUE, ValueLayout.JAVA_BYTE)); *} - *

- * This method is restricted. - * Restricted methods are unsafe, and, if used incorrectly, their use might crash - * the JVM or, worse, silently result in memory corruption. * * @param layout the target layout. * @return an address layout with same characteristics as this layout, but with the provided target layout. diff --git a/src/java.base/share/classes/java/lang/foreign/Linker.java b/src/java.base/share/classes/java/lang/foreign/Linker.java index 747e2b9270d..738ff19a517 100644 --- a/src/java.base/share/classes/java/lang/foreign/Linker.java +++ b/src/java.base/share/classes/java/lang/foreign/Linker.java @@ -519,10 +519,6 @@ static Linker nativeLinker() { * {@snippet lang=java : * linker.downcallHandle(function).bindTo(symbol); * } - *

- * This method is restricted. - * Restricted methods are unsafe, and, if used incorrectly, their use might crash - * the JVM or, worse, silently result in memory corruption. * * @param address the native memory segment whose {@linkplain MemorySegment#address() base address} is the * address of the target foreign function. @@ -575,10 +571,6 @@ static Linker nativeLinker() { * {@link MemorySegment#copy(MemorySegment, long, MemorySegment, long, long)} methods may be thrown. * The returned method handle will additionally throw {@link NullPointerException} if any argument * passed to it is {@code null}. - *

- * This method is restricted. - * Restricted methods are unsafe, and, if used incorrectly, their use might crash - * the JVM or, worse, silently result in memory corruption. * * @param function the function descriptor of the target foreign function. * @param options the linker options associated with this linkage request. @@ -612,10 +604,6 @@ static Linker nativeLinker() { * try/catch block to catch any unexpected exceptions. This can be done using the * {@link java.lang.invoke.MethodHandles#catchException(MethodHandle, Class, MethodHandle)} method handle combinator, * and handle exceptions as desired in the corresponding catch block. - *

- * This method is restricted. - * Restricted methods are unsafe, and, if used incorrectly, their use might crash - * the JVM or, worse, silently result in memory corruption. * * @param target the target method handle. * @param function the upcall stub function descriptor. 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 724286ce693..6dca1b699e7 100644 --- a/src/java.base/share/classes/java/lang/foreign/MemorySegment.java +++ b/src/java.base/share/classes/java/lang/foreign/MemorySegment.java @@ -587,10 +587,6 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl { /** * Returns a new memory segment that has the same address and scope as this segment, but with the provided size. - *

- * This method is restricted. - * Restricted methods are unsafe, and, if used incorrectly, their use might crash - * the JVM or, worse, silently result in memory corruption. * * @param newSize the size of the returned segment. * @return a new memory segment that has the same address and scope as this segment, but the new @@ -620,10 +616,6 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl { * } * That is, the cleanup action receives a segment that is associated with the global scope, * and is accessible from any thread. The size of the segment accepted by the cleanup action is {@link #byteSize()}. - *

- * This method is restricted. - * Restricted methods are unsafe, and, if used incorrectly, their use might crash - * the JVM or, worse, silently result in memory corruption. * * @apiNote The cleanup action (if present) should take care not to leak the received segment to external * clients which might access the segment after its backing region of memory is no longer available. Furthermore, @@ -659,10 +651,6 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl { * } * That is, the cleanup action receives a segment that is associated with the global scope, * and is accessible from any thread. The size of the segment accepted by the cleanup action is {@code newSize}. - *

- * This method is restricted. - * Restricted methods are unsafe, and, if used incorrectly, their use might crash - * the JVM or, worse, silently result in memory corruption. * * @apiNote The cleanup action (if present) should take care not to leak the received segment to external * clients which might access the segment after its backing region of memory is no longer available. Furthermore, diff --git a/src/java.base/share/classes/java/lang/foreign/SymbolLookup.java b/src/java.base/share/classes/java/lang/foreign/SymbolLookup.java index 632543c9957..efab47a40f2 100644 --- a/src/java.base/share/classes/java/lang/foreign/SymbolLookup.java +++ b/src/java.base/share/classes/java/lang/foreign/SymbolLookup.java @@ -211,10 +211,6 @@ static SymbolLookup loaderLookup() { * For instance, if the provided arena is a confined arena, the library * associated with the returned lookup will be unloaded when the provided confined arena is * {@linkplain Arena#close() closed}. - *

- * This method is restricted. - * Restricted methods are unsafe, and, if used incorrectly, their use might crash - * the JVM or, worse, silently result in memory corruption. * * @implNote The process of resolving a library name is OS-specific. For instance, in a POSIX-compliant OS, * the library name is resolved according to the specification of the {@code dlopen} function for that OS. @@ -245,10 +241,6 @@ static SymbolLookup libraryLookup(String name, Arena arena) { * For instance, if the provided arena is a confined arena, the library * associated with the returned lookup will be unloaded when the provided confined arena is * {@linkplain Arena#close() closed}. - *

- * This method is restricted. - * Restricted methods are unsafe, and, if used incorrectly, their use might crash - * the JVM or, worse, silently result in memory corruption. * * @implNote On Linux, the functionalities provided by this factory method and the returned symbol lookup are * implemented using the {@code dlopen}, {@code dlsym} and {@code dlclose} functions. From 5a97411f857b0bc9e70b417efa76a5fd5f887fe0 Mon Sep 17 00:00:00 2001 From: Ilya Gavrilin Date: Fri, 20 Oct 2023 14:31:41 +0000 Subject: [PATCH 041/124] 8317971: RISC-V: implement copySignF/D and signumF/D intrinsics Reviewed-by: fyang, vkempik --- .../cpu/riscv/c2_MacroAssembler_riscv.cpp | 32 +++++++++++++ .../cpu/riscv/c2_MacroAssembler_riscv.hpp | 3 ++ src/hotspot/cpu/riscv/riscv.ad | 46 +++++++++++++++++++ src/hotspot/cpu/riscv/vm_version_riscv.cpp | 8 ++++ .../openjdk/bench/java/lang/MathBench.java | 2 +- 5 files changed, 90 insertions(+), 1 deletion(-) diff --git a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp index ac20e12946c..d4a86de58f3 100644 --- a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp @@ -1653,6 +1653,38 @@ void C2_MacroAssembler::round_double_mode(FloatRegister dst, FloatRegister src, bind(done); } +// According to Java SE specification, for floating-point signum operations, if +// on input we have NaN or +/-0.0 value we should return it, +// otherwise return +/- 1.0 using sign of input. +// one - gives us a floating-point 1.0 (got from matching rule) +// bool is_double - specifies single or double precision operations will be used. +void C2_MacroAssembler::signum_fp(FloatRegister dst, FloatRegister src, FloatRegister one, bool is_double) { + Register tmp1 = t0; + + Label done; + + is_double ? fclass_d(tmp1, src) + : fclass_s(tmp1, src); + + is_double ? fmv_d(dst, src) + : fmv_s(dst, src); + + //bitmask 0b1100011000 specifies this bits: + // 3 - src is -0 + // 4 - src is +0 + // 8 - src is signaling NaN + // 9 - src is a quiet NaN + andi(tmp1, tmp1, 0b1100011000); + + bnez(tmp1, done); + + // use floating-point 1.0 with a sign of input + is_double ? fsgnj_d(dst, one, src) + : fsgnj_s(dst, one, src); + + bind(done); +} + void C2_MacroAssembler::element_compare(Register a1, Register a2, Register result, Register cnt, Register tmp1, Register tmp2, VectorRegister vr1, VectorRegister vr2, VectorRegister vrs, bool islatin, Label &DONE) { Label loop; diff --git a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp index 7dd22389aa4..e46c62d5c9e 100644 --- a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp @@ -157,6 +157,9 @@ void round_double_mode(FloatRegister dst, FloatRegister src, int round_mode, Register tmp1, Register tmp2, Register tmp3); + void signum_fp(FloatRegister dst, FloatRegister src, FloatRegister one, + bool is_double); + // intrinsic methods implemented by rvv instructions void string_equals_v(Register r1, Register r2, Register result, Register cnt1, diff --git a/src/hotspot/cpu/riscv/riscv.ad b/src/hotspot/cpu/riscv/riscv.ad index caf39498cf9..553c189891a 100644 --- a/src/hotspot/cpu/riscv/riscv.ad +++ b/src/hotspot/cpu/riscv/riscv.ad @@ -7506,6 +7506,52 @@ instruct roundD_reg(fRegD dst, fRegD src, immI rmode, iRegLNoSp tmp1, iRegLNoSp ins_pipe(pipe_class_default); %} +// Copysign and signum intrinsics + +instruct copySignD_reg(fRegD dst, fRegD src1, fRegD src2, immD zero) %{ + match(Set dst (CopySignD src1 (Binary src2 zero))); + format %{ "CopySignD $dst $src1 $src2" %} + ins_encode %{ + FloatRegister dst = as_FloatRegister($dst$$reg), + src1 = as_FloatRegister($src1$$reg), + src2 = as_FloatRegister($src2$$reg); + __ fsgnj_d(dst, src1, src2); + %} + ins_pipe(fp_dop_reg_reg_d); +%} + +instruct copySignF_reg(fRegF dst, fRegF src1, fRegF src2) %{ + match(Set dst (CopySignF src1 src2)); + format %{ "CopySignF $dst $src1 $src2" %} + ins_encode %{ + FloatRegister dst = as_FloatRegister($dst$$reg), + src1 = as_FloatRegister($src1$$reg), + src2 = as_FloatRegister($src2$$reg); + __ fsgnj_s(dst, src1, src2); + %} + ins_pipe(fp_dop_reg_reg_s); +%} + +instruct signumD_reg(fRegD dst, fRegD src, immD zero, fRegD one) %{ + match(Set dst (SignumD src (Binary zero one))); + format %{ "signumD $dst, $src" %} + ins_encode %{ + __ signum_fp(as_FloatRegister($dst$$reg), as_FloatRegister($src$$reg), + as_FloatRegister($one$$reg), true /* is_double */); + %} + ins_pipe(pipe_class_default); +%} + +instruct signumF_reg(fRegF dst, fRegF src, immF zero, fRegF one) %{ + match(Set dst (SignumF src (Binary zero one))); + format %{ "signumF $dst, $src" %} + ins_encode %{ + __ signum_fp(as_FloatRegister($dst$$reg), as_FloatRegister($src$$reg), + as_FloatRegister($one$$reg), false /* is_double */); + %} + ins_pipe(pipe_class_default); +%} + // Arithmetic Instructions End // ============================================================================ diff --git a/src/hotspot/cpu/riscv/vm_version_riscv.cpp b/src/hotspot/cpu/riscv/vm_version_riscv.cpp index 9a88be33d90..6cec56832a2 100644 --- a/src/hotspot/cpu/riscv/vm_version_riscv.cpp +++ b/src/hotspot/cpu/riscv/vm_version_riscv.cpp @@ -191,6 +191,14 @@ void VM_Version::initialize() { FLAG_SET_DEFAULT(UseMD5Intrinsics, true); } + if (FLAG_IS_DEFAULT(UseCopySignIntrinsic)) { + FLAG_SET_DEFAULT(UseCopySignIntrinsic, true); + } + + if (FLAG_IS_DEFAULT(UseSignumIntrinsic)) { + FLAG_SET_DEFAULT(UseSignumIntrinsic, true); + } + if (UseRVV) { if (!ext_V.enabled()) { warning("RVV is not supported on this CPU"); diff --git a/test/micro/org/openjdk/bench/java/lang/MathBench.java b/test/micro/org/openjdk/bench/java/lang/MathBench.java index 6cd1353907e..c7dde019154 100644 --- a/test/micro/org/openjdk/bench/java/lang/MathBench.java +++ b/test/micro/org/openjdk/bench/java/lang/MathBench.java @@ -471,7 +471,7 @@ public float scalbFloatInt() { } @Benchmark - public double sigNumDouble() { + public double signumDouble() { return Math.signum(double4Dot1); } From b1228de623f3d26f982b4b1ee86af34b6ec14916 Mon Sep 17 00:00:00 2001 From: Thomas Stuefe Date: Fri, 20 Oct 2023 15:21:57 +0000 Subject: [PATCH 042/124] 8314588: gc/metaspace/TestMetaspaceInitialization.java failed "assert(capacity_until_gc >= committed_bytes) failed: capacity_until_gc: 3145728 < committed_bytes: 3211264" Reviewed-by: dholmes, coleenp --- src/hotspot/share/memory/metaspace.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/hotspot/share/memory/metaspace.cpp b/src/hotspot/share/memory/metaspace.cpp index 5c3087f1fa0..2145bb68b33 100644 --- a/src/hotspot/share/memory/metaspace.cpp +++ b/src/hotspot/share/memory/metaspace.cpp @@ -404,12 +404,11 @@ size_t MetaspaceGC::allowed_expansion() { size_t committed_bytes = MetaspaceUtils::committed_bytes(); size_t capacity_until_gc = capacity_until_GC(); - assert(capacity_until_gc >= committed_bytes, - "capacity_until_gc: " SIZE_FORMAT " < committed_bytes: " SIZE_FORMAT, - capacity_until_gc, committed_bytes); - size_t left_until_max = MaxMetaspaceSize - committed_bytes; - size_t left_until_GC = capacity_until_gc - committed_bytes; + // capacity_until_GC may have been decreased concurrently and may + // temporarily be lower than what metaspace has committed. Allow for that. + size_t left_until_GC = capacity_until_gc > committed_bytes ? + capacity_until_gc - committed_bytes : 0; size_t left_to_commit = MIN2(left_until_GC, left_until_max); log_trace(gc, metaspace, freelist)("allowed expansion words: " SIZE_FORMAT " (left_until_max: " SIZE_FORMAT ", left_until_GC: " SIZE_FORMAT ".", From 8065233e8b8976929e1975c9a74cf70bf3485ae2 Mon Sep 17 00:00:00 2001 From: Jorn Vernee Date: Fri, 20 Oct 2023 15:40:39 +0000 Subject: [PATCH 043/124] 8318598: FFM stylistic cleanups Co-authored-by: Per Minborg Co-authored-by: Maurizio Cimadamore Reviewed-by: mcimadamore --- .../foreign/AbstractMemorySegmentImpl.java | 111 ++++++------------ .../jdk/internal/foreign/ConfinedSession.java | 1 - .../foreign/HeapMemorySegmentImpl.java | 47 ++++---- .../jdk/internal/foreign/LayoutPath.java | 5 +- .../internal/foreign/MemorySessionImpl.java | 12 +- .../internal/foreign/SegmentFactories.java | 28 ++--- .../jdk/internal/foreign/SharedSession.java | 1 - .../jdk/internal/foreign/StringSupport.java | 2 +- .../jdk/internal/foreign/SystemLookup.java | 4 +- .../classes/jdk/internal/foreign/Utils.java | 33 ++++++ .../internal/foreign/abi/AbstractLinker.java | 2 +- .../jdk/internal/foreign/abi/Binding.java | 3 +- .../internal/foreign/abi/CapturableState.java | 1 - .../jdk/internal/foreign/abi/SharedUtils.java | 2 +- .../foreign/abi/SoftReferenceCache.java | 7 +- .../foreign/abi/aarch64/CallArranger.java | 7 +- .../abi/aarch64/macos/MacOsAArch64Linker.java | 2 +- .../windows/WindowsAArch64CallArranger.java | 2 +- .../aarch64/windows/WindowsAArch64Linker.java | 7 +- .../foreign/abi/fallback/FFIType.java | 1 + .../foreign/abi/fallback/FallbackLinker.java | 43 +++---- .../foreign/abi/ppc64/PPC64Architecture.java | 11 +- .../abi/riscv64/RISCV64Architecture.java | 1 - .../linux/LinuxRISCV64CallArranger.java | 8 +- .../foreign/abi/riscv64/linux/TypeClass.java | 57 ++++----- .../foreign/abi/s390/S390Architecture.java | 13 +- .../abi/s390/linux/LinuxS390CallArranger.java | 4 - .../foreign/abi/s390/linux/TypeClass.java | 5 +- .../foreign/abi/x64/sysv/CallArranger.java | 3 +- .../foreign/abi/x64/sysv/TypeClass.java | 55 +++++---- .../foreign/abi/x64/windows/CallArranger.java | 2 - .../foreign/abi/x64/windows/TypeClass.java | 2 +- .../foreign/layout/AbstractGroupLayout.java | 2 +- .../internal/foreign/layout/ValueLayouts.java | 2 +- 34 files changed, 230 insertions(+), 256 deletions(-) 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 bf8b1e79819..361a10cf49b 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/AbstractMemorySegmentImpl.java +++ b/src/java.base/share/classes/jdk/internal/foreign/AbstractMemorySegmentImpl.java @@ -49,7 +49,6 @@ import jdk.internal.access.SharedSecrets; import jdk.internal.access.foreign.UnmapperProxy; import jdk.internal.misc.ScopedMemoryAccess; -import jdk.internal.misc.Unsafe; import jdk.internal.reflect.CallerSensitive; import jdk.internal.reflect.Reflection; import jdk.internal.util.ArraysSupport; @@ -560,23 +559,23 @@ public static AbstractMemorySegmentImpl ofBuffer(Buffer bb) { bufferScope = MemorySessionImpl.createHeap(bufferRef(bb)); } if (base != null) { - if (base instanceof byte[]) { - return new HeapMemorySegmentImpl.OfByte(bbAddress + (pos << scaleFactor), base, size << scaleFactor, readOnly, bufferScope); - } else if (base instanceof short[]) { - return new HeapMemorySegmentImpl.OfShort(bbAddress + (pos << scaleFactor), base, size << scaleFactor, readOnly, bufferScope); - } else if (base instanceof char[]) { - return new HeapMemorySegmentImpl.OfChar(bbAddress + (pos << scaleFactor), base, size << scaleFactor, readOnly, bufferScope); - } else if (base instanceof int[]) { - return new HeapMemorySegmentImpl.OfInt(bbAddress + (pos << scaleFactor), base, size << scaleFactor, readOnly, bufferScope); - } else if (base instanceof float[]) { - return new HeapMemorySegmentImpl.OfFloat(bbAddress + (pos << scaleFactor), base, size << scaleFactor, readOnly, bufferScope); - } else if (base instanceof long[]) { - return new HeapMemorySegmentImpl.OfLong(bbAddress + (pos << scaleFactor), base, size << scaleFactor, readOnly, bufferScope); - } else if (base instanceof double[]) { - return new HeapMemorySegmentImpl.OfDouble(bbAddress + (pos << scaleFactor), base, size << scaleFactor, readOnly, bufferScope); - } else { - throw new AssertionError("Cannot get here"); - } + return switch (base) { + case byte[] __ -> + new HeapMemorySegmentImpl.OfByte(bbAddress + (pos << scaleFactor), base, size << scaleFactor, readOnly, bufferScope); + case short[] __ -> + new HeapMemorySegmentImpl.OfShort(bbAddress + (pos << scaleFactor), base, size << scaleFactor, readOnly, bufferScope); + case char[] __ -> + new HeapMemorySegmentImpl.OfChar(bbAddress + (pos << scaleFactor), base, size << scaleFactor, readOnly, bufferScope); + case int[] __ -> + new HeapMemorySegmentImpl.OfInt(bbAddress + (pos << scaleFactor), base, size << scaleFactor, readOnly, bufferScope); + case float[] __ -> + new HeapMemorySegmentImpl.OfFloat(bbAddress + (pos << scaleFactor), base, size << scaleFactor, readOnly, bufferScope); + case long[] __ -> + new HeapMemorySegmentImpl.OfLong(bbAddress + (pos << scaleFactor), base, size << scaleFactor, readOnly, bufferScope); + case double[] __ -> + new HeapMemorySegmentImpl.OfDouble(bbAddress + (pos << scaleFactor), base, size << scaleFactor, readOnly, bufferScope); + default -> throw new AssertionError("Cannot get here"); + }; } else if (unmapper == null) { return new NativeMemorySegmentImpl(bbAddress + (pos << scaleFactor), size << scaleFactor, readOnly, bufferScope); } else { @@ -596,26 +595,6 @@ private static Object bufferRef(Buffer buffer) { } } - private static int getScaleFactor(Buffer buffer) { - if (buffer instanceof ByteBuffer) { - return 0; - } else if (buffer instanceof CharBuffer) { - return 1; - } else if (buffer instanceof ShortBuffer) { - return 1; - } else if (buffer instanceof IntBuffer) { - return 2; - } else if (buffer instanceof FloatBuffer) { - return 2; - } else if (buffer instanceof LongBuffer) { - return 3; - } else if (buffer instanceof DoubleBuffer) { - return 3; - } else { - throw new AssertionError("Cannot get here"); - } - } - @ForceInline public static void copy(MemorySegment srcSegment, ValueLayout srcElementLayout, long srcOffset, MemorySegment dstSegment, ValueLayout dstElementLayout, long dstOffset, @@ -653,27 +632,25 @@ public static void copy(MemorySegment srcSegment, ValueLayout srcLayout, long sr Object dstArray, int dstIndex, int elementCount) { - long baseAndScale = getBaseAndScale(dstArray.getClass()); + var dstInfo = Utils.BaseAndScale.of(dstArray); if (dstArray.getClass().componentType() != srcLayout.carrier()) { throw new IllegalArgumentException("Incompatible value layout: " + srcLayout); } - int dstBase = (int)baseAndScale; - long dstWidth = (int)(baseAndScale >> 32); // Use long arithmetics below AbstractMemorySegmentImpl srcImpl = (AbstractMemorySegmentImpl)srcSegment; Utils.checkElementAlignment(srcLayout, "Source layout alignment greater than its size"); if (!srcImpl.isAlignedForElement(srcOffset, srcLayout)) { throw new IllegalArgumentException("Source segment incompatible with alignment constraints"); } - srcImpl.checkAccess(srcOffset, elementCount * dstWidth, true); + srcImpl.checkAccess(srcOffset, elementCount * dstInfo.scale(), true); Objects.checkFromIndexSize(dstIndex, elementCount, Array.getLength(dstArray)); - if (dstWidth == 1 || srcLayout.order() == ByteOrder.nativeOrder()) { + if (dstInfo.scale() == 1 || srcLayout.order() == ByteOrder.nativeOrder()) { ScopedMemoryAccess.getScopedMemoryAccess().copyMemory(srcImpl.sessionImpl(), null, srcImpl.unsafeGetBase(), srcImpl.unsafeGetOffset() + srcOffset, - dstArray, dstBase + (dstIndex * dstWidth), elementCount * dstWidth); + dstArray, dstInfo.base() + (dstIndex * dstInfo.scale()), elementCount * dstInfo.scale()); } else { ScopedMemoryAccess.getScopedMemoryAccess().copySwapMemory(srcImpl.sessionImpl(), null, srcImpl.unsafeGetBase(), srcImpl.unsafeGetOffset() + srcOffset, - dstArray, dstBase + (dstIndex * dstWidth), elementCount * dstWidth, dstWidth); + dstArray, dstInfo.base() + (dstIndex * dstInfo.scale()), elementCount * dstInfo.scale(), dstInfo.scale()); } } @@ -682,27 +659,25 @@ public static void copy(Object srcArray, int srcIndex, MemorySegment dstSegment, ValueLayout dstLayout, long dstOffset, int elementCount) { - long baseAndScale = getBaseAndScale(srcArray.getClass()); + var srcInfo = Utils.BaseAndScale.of(srcArray); if (srcArray.getClass().componentType() != dstLayout.carrier()) { throw new IllegalArgumentException("Incompatible value layout: " + dstLayout); } - int srcBase = (int)baseAndScale; - long srcWidth = (int)(baseAndScale >> 32); // Use long arithmetics below Objects.checkFromIndexSize(srcIndex, elementCount, Array.getLength(srcArray)); AbstractMemorySegmentImpl destImpl = (AbstractMemorySegmentImpl)dstSegment; Utils.checkElementAlignment(dstLayout, "Destination layout alignment greater than its size"); if (!destImpl.isAlignedForElement(dstOffset, dstLayout)) { throw new IllegalArgumentException("Destination segment incompatible with alignment constraints"); } - destImpl.checkAccess(dstOffset, elementCount * srcWidth, false); - if (srcWidth == 1 || dstLayout.order() == ByteOrder.nativeOrder()) { + destImpl.checkAccess(dstOffset, elementCount * srcInfo.scale(), false); + if (srcInfo.scale() == 1 || dstLayout.order() == ByteOrder.nativeOrder()) { ScopedMemoryAccess.getScopedMemoryAccess().copyMemory(null, destImpl.sessionImpl(), - srcArray, srcBase + (srcIndex * srcWidth), - destImpl.unsafeGetBase(), destImpl.unsafeGetOffset() + dstOffset, elementCount * srcWidth); + srcArray, srcInfo.base() + (srcIndex * srcInfo.scale()), + destImpl.unsafeGetBase(), destImpl.unsafeGetOffset() + dstOffset, elementCount * srcInfo.scale()); } else { ScopedMemoryAccess.getScopedMemoryAccess().copySwapMemory(null, destImpl.sessionImpl(), - srcArray, srcBase + (srcIndex * srcWidth), - destImpl.unsafeGetBase(), destImpl.unsafeGetOffset() + dstOffset, elementCount * srcWidth, srcWidth); + srcArray, srcInfo.base() + (srcIndex * srcInfo.scale()), + destImpl.unsafeGetBase(), destImpl.unsafeGetOffset() + dstOffset, elementCount * srcInfo.scale(), srcInfo.scale()); } } @@ -744,24 +719,16 @@ public static long mismatch(MemorySegment srcSegment, long srcFromOffset, long s return srcBytes != dstBytes ? bytes : -1; } - private static long getBaseAndScale(Class arrayType) { - if (arrayType.equals(byte[].class)) { - return (long) Unsafe.ARRAY_BYTE_BASE_OFFSET | ((long)Unsafe.ARRAY_BYTE_INDEX_SCALE << 32); - } else if (arrayType.equals(char[].class)) { - return (long) Unsafe.ARRAY_CHAR_BASE_OFFSET | ((long)Unsafe.ARRAY_CHAR_INDEX_SCALE << 32); - } else if (arrayType.equals(short[].class)) { - return (long)Unsafe.ARRAY_SHORT_BASE_OFFSET | ((long)Unsafe.ARRAY_SHORT_INDEX_SCALE << 32); - } else if (arrayType.equals(int[].class)) { - return (long)Unsafe.ARRAY_INT_BASE_OFFSET | ((long) Unsafe.ARRAY_INT_INDEX_SCALE << 32); - } else if (arrayType.equals(float[].class)) { - return (long)Unsafe.ARRAY_FLOAT_BASE_OFFSET | ((long)Unsafe.ARRAY_FLOAT_INDEX_SCALE << 32); - } else if (arrayType.equals(long[].class)) { - return (long)Unsafe.ARRAY_LONG_BASE_OFFSET | ((long)Unsafe.ARRAY_LONG_INDEX_SCALE << 32); - } else if (arrayType.equals(double[].class)) { - return (long)Unsafe.ARRAY_DOUBLE_BASE_OFFSET | ((long)Unsafe.ARRAY_DOUBLE_INDEX_SCALE << 32); - } else { - throw new IllegalArgumentException("Not a supported array class: " + arrayType.getSimpleName()); - } + private static int getScaleFactor(Buffer buffer) { + return switch (buffer) { + case ByteBuffer __ -> 0; + case CharBuffer __ -> 1; + case ShortBuffer __ -> 1; + case IntBuffer __ -> 2; + case FloatBuffer __ -> 2; + case LongBuffer __ -> 3; + case DoubleBuffer __ -> 3; + }; } // accessors diff --git a/src/java.base/share/classes/jdk/internal/foreign/ConfinedSession.java b/src/java.base/share/classes/jdk/internal/foreign/ConfinedSession.java index 4961cecde5e..4ff0df787c5 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/ConfinedSession.java +++ b/src/java.base/share/classes/jdk/internal/foreign/ConfinedSession.java @@ -27,7 +27,6 @@ import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; -import java.lang.ref.Cleaner; import jdk.internal.vm.annotation.ForceInline; diff --git a/src/java.base/share/classes/jdk/internal/foreign/HeapMemorySegmentImpl.java b/src/java.base/share/classes/jdk/internal/foreign/HeapMemorySegmentImpl.java index dd6a6e49edd..e1ea65ff308 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/HeapMemorySegmentImpl.java +++ b/src/java.base/share/classes/jdk/internal/foreign/HeapMemorySegmentImpl.java @@ -33,14 +33,13 @@ import jdk.internal.access.JavaNioAccess; import jdk.internal.access.SharedSecrets; -import jdk.internal.misc.Unsafe; import jdk.internal.vm.annotation.ForceInline; /** * Implementation for heap memory segments. A heap memory segment is composed by an offset and * a base object (typically an array). To enhance performances, the access to the base object needs to feature * sharp type information, as well as sharp null-check information. For this reason, many concrete subclasses - * of {@link HeapMemorySegmentImpl} are defined (e.g. {@link OfFloat}, so that each subclass can override the + * of {@link HeapMemorySegmentImpl} are defined (e.g. {@link OfFloat}), so that each subclass can override the * {@link HeapMemorySegmentImpl#unsafeGetBase()} method so that it returns an array of the correct (sharp) type. Note that * the field type storing the 'base' coordinate is just Object; similarly, all the constructor in the subclasses * accept an Object 'base' parameter instead of a sharper type (e.g. {@code byte[]}). This is deliberate, as @@ -49,13 +48,15 @@ */ abstract sealed class HeapMemorySegmentImpl extends AbstractMemorySegmentImpl { - private static final Unsafe UNSAFE = Unsafe.getUnsafe(); - private static final int BYTE_ARR_BASE = UNSAFE.arrayBaseOffset(byte[].class); + // Constants defining the maximum alignment supported by various kinds of heap arrays. + // While for most arrays, the maximum alignment is constant (the size, in bytes, of the array elements), + // note that the alignment of a long[]/double[] depends on the platform: it's 4-byte on x86, but 8 bytes on x64 + // (as specified by the JAVA_LONG layout constant). - private static final long MAX_ALIGN_1 = ValueLayout.JAVA_BYTE.byteAlignment(); - private static final long MAX_ALIGN_2 = ValueLayout.JAVA_SHORT.byteAlignment(); - private static final long MAX_ALIGN_4 = ValueLayout.JAVA_INT.byteAlignment(); - private static final long MAX_ALIGN_8 = ValueLayout.JAVA_LONG.byteAlignment(); + private static final long MAX_ALIGN_BYTE_ARRAY = ValueLayout.JAVA_BYTE.byteAlignment(); + private static final long MAX_ALIGN_SHORT_ARRAY = ValueLayout.JAVA_SHORT.byteAlignment(); + private static final long MAX_ALIGN_INT_ARRAY = ValueLayout.JAVA_INT.byteAlignment(); + private static final long MAX_ALIGN_LONG_ARRAY = ValueLayout.JAVA_LONG.byteAlignment(); final long offset; final Object base; @@ -88,7 +89,7 @@ ByteBuffer makeByteBuffer() { throw new UnsupportedOperationException("Not an address to an heap-allocated byte array"); } JavaNioAccess nioAccess = SharedSecrets.getJavaNioAccess(); - return nioAccess.newHeapByteBuffer(baseByte, (int)offset - BYTE_ARR_BASE, (int) byteSize(), null); + return nioAccess.newHeapByteBuffer(baseByte, (int)offset - Utils.BaseAndScale.BYTE.base(), (int) byteSize(), null); } // factories @@ -111,12 +112,12 @@ public byte[] unsafeGetBase() { @Override public long maxAlignMask() { - return MAX_ALIGN_1; + return MAX_ALIGN_BYTE_ARRAY; } @Override public long address() { - return offset - Unsafe.ARRAY_BYTE_BASE_OFFSET; + return offset - Utils.BaseAndScale.BYTE.base(); } } @@ -138,12 +139,12 @@ public char[] unsafeGetBase() { @Override public long maxAlignMask() { - return MAX_ALIGN_2; + return MAX_ALIGN_SHORT_ARRAY; } @Override public long address() { - return offset - Unsafe.ARRAY_CHAR_BASE_OFFSET; + return offset - Utils.BaseAndScale.CHAR.base(); } } @@ -165,12 +166,12 @@ public short[] unsafeGetBase() { @Override public long maxAlignMask() { - return MAX_ALIGN_2; + return MAX_ALIGN_SHORT_ARRAY; } @Override public long address() { - return offset - Unsafe.ARRAY_SHORT_BASE_OFFSET; + return offset - Utils.BaseAndScale.SHORT.base(); } } @@ -192,12 +193,12 @@ public int[] unsafeGetBase() { @Override public long maxAlignMask() { - return MAX_ALIGN_4; + return MAX_ALIGN_INT_ARRAY; } @Override public long address() { - return offset - Unsafe.ARRAY_INT_BASE_OFFSET; + return offset - Utils.BaseAndScale.INT.base(); } } @@ -219,12 +220,12 @@ public long[] unsafeGetBase() { @Override public long maxAlignMask() { - return MAX_ALIGN_8; + return MAX_ALIGN_LONG_ARRAY; } @Override public long address() { - return offset - Unsafe.ARRAY_LONG_BASE_OFFSET; + return offset - Utils.BaseAndScale.LONG.base(); } } @@ -246,12 +247,12 @@ public float[] unsafeGetBase() { @Override public long maxAlignMask() { - return MAX_ALIGN_4; + return MAX_ALIGN_INT_ARRAY; } @Override public long address() { - return offset - Unsafe.ARRAY_FLOAT_BASE_OFFSET; + return offset - Utils.BaseAndScale.FLOAT.base(); } } @@ -273,12 +274,12 @@ public double[] unsafeGetBase() { @Override public long maxAlignMask() { - return MAX_ALIGN_8; + return MAX_ALIGN_LONG_ARRAY; } @Override public long address() { - return offset - Unsafe.ARRAY_DOUBLE_BASE_OFFSET; + return offset - Utils.BaseAndScale.DOUBLE.base(); } } diff --git a/src/java.base/share/classes/jdk/internal/foreign/LayoutPath.java b/src/java.base/share/classes/jdk/internal/foreign/LayoutPath.java index f87bbf306c3..53d306e4bc6 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/LayoutPath.java +++ b/src/java.base/share/classes/jdk/internal/foreign/LayoutPath.java @@ -26,8 +26,6 @@ package jdk.internal.foreign; import jdk.internal.vm.annotation.ForceInline; -import jdk.internal.vm.annotation.Stable; - import java.lang.foreign.AddressLayout; import java.lang.foreign.GroupLayout; import java.lang.foreign.MemoryLayout; @@ -41,7 +39,6 @@ import java.lang.invoke.VarHandle; import java.util.Arrays; import java.util.List; -import java.util.Locale; import java.util.Objects; import java.util.function.UnaryOperator; import java.util.stream.IntStream; @@ -50,7 +47,7 @@ import static java.util.stream.Collectors.joining; /** - * This class provide support for constructing layout paths; that is, starting from a root path (see {@link #rootPath(MemoryLayout)}, + * This class provide support for constructing layout paths; that is, starting from a root path (see {@link #rootPath(MemoryLayout)}), * a path can be constructed by selecting layout elements using the selector methods provided by this class * (see {@link #sequenceElement()}, {@link #sequenceElement(long)}, {@link #sequenceElement(long, long)}, {@link #groupElement(String)}). * Once a path has been fully constructed, clients can ask for the offset associated with the layout element selected diff --git a/src/java.base/share/classes/jdk/internal/foreign/MemorySessionImpl.java b/src/java.base/share/classes/jdk/internal/foreign/MemorySessionImpl.java index 33bac79999f..b74ccf33936 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/MemorySessionImpl.java +++ b/src/java.base/share/classes/jdk/internal/foreign/MemorySessionImpl.java @@ -83,7 +83,7 @@ public Arena asArena() { } @ForceInline - public static final MemorySessionImpl toMemorySession(Arena arena) { + public static MemorySessionImpl toMemorySession(Arena arena) { return (MemorySessionImpl) arena.scope(); } @@ -99,10 +99,10 @@ public void addCloseAction(Runnable runnable) { } /** - * Add a cleanup action. If a failure occurred (because of a add vs. close race), call the cleanup action. + * Add a cleanup action. If a failure occurred (because of an add vs. close race), call the cleanup action. * This semantics is useful when allocating new memory segments, since we first do a malloc/mmap and _then_ * we register the cleanup (free/munmap) against the session; so, if registration fails, we still have to - * cleanup memory. From the perspective of the client, such a failure would manifest as a factory + * clean up memory. From the perspective of the client, such a failure would manifest as a factory * returning a segment that is already "closed" - which is always possible anyway (e.g. if the session * is closed _after_ the cleanup for the segment is registered but _before_ the factory returns the * new segment to the client). For this reason, it's not worth adding extra complexity to the segment @@ -201,7 +201,7 @@ public void checkValidStateRaw() { /** * Checks that this session is still alive (see {@link #isAlive()}). * @throws IllegalStateException if this session is already closed or if this is - * a confined session and this method is called outside of the owner thread. + * a confined session and this method is called outside the owner thread. */ public void checkValidState() { try { @@ -211,7 +211,7 @@ public void checkValidState() { } } - public static final void checkValidState(MemorySegment segment) { + public static void checkValidState(MemorySegment segment) { ((AbstractMemorySegmentImpl)segment).sessionImpl().checkValidState(); } @@ -227,7 +227,7 @@ public boolean isCloseable() { /** * Closes this session, executing any cleanup action (where provided). * @throws IllegalStateException if this session is already closed or if this is - * a confined session and this method is called outside of the owner thread. + * a confined session and this method is called outside the owner thread. */ public void close() { justClose(); diff --git a/src/java.base/share/classes/jdk/internal/foreign/SegmentFactories.java b/src/java.base/share/classes/jdk/internal/foreign/SegmentFactories.java index 9e9d60ecf89..17f141b4e8c 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/SegmentFactories.java +++ b/src/java.base/share/classes/jdk/internal/foreign/SegmentFactories.java @@ -83,56 +83,56 @@ public static MemorySegment makeNativeSegmentUnchecked(long min, long byteSize) public static MemorySegment fromArray(byte[] arr) { ensureInitialized(); Objects.requireNonNull(arr); - long byteSize = (long)arr.length * Unsafe.ARRAY_BYTE_INDEX_SCALE; - return new OfByte(Unsafe.ARRAY_BYTE_BASE_OFFSET, arr, byteSize, false, + long byteSize = (long)arr.length * Utils.BaseAndScale.BYTE.scale(); + return new OfByte(Utils.BaseAndScale.BYTE.base(), arr, byteSize, false, MemorySessionImpl.createHeap(arr)); } public static MemorySegment fromArray(short[] arr) { ensureInitialized(); Objects.requireNonNull(arr); - long byteSize = (long)arr.length * Unsafe.ARRAY_SHORT_INDEX_SCALE; - return new OfShort(Unsafe.ARRAY_SHORT_BASE_OFFSET, arr, byteSize, false, + long byteSize = (long)arr.length * Utils.BaseAndScale.SHORT.scale(); + return new OfShort(Utils.BaseAndScale.SHORT.base(), arr, byteSize, false, MemorySessionImpl.createHeap(arr)); } public static MemorySegment fromArray(int[] arr) { ensureInitialized(); Objects.requireNonNull(arr); - long byteSize = (long)arr.length * Unsafe.ARRAY_INT_INDEX_SCALE; - return new OfInt(Unsafe.ARRAY_INT_BASE_OFFSET, arr, byteSize, false, + long byteSize = (long)arr.length * Utils.BaseAndScale.INT.scale(); + return new OfInt(Utils.BaseAndScale.INT.base(), arr, byteSize, false, MemorySessionImpl.createHeap(arr)); } public static MemorySegment fromArray(char[] arr) { ensureInitialized(); Objects.requireNonNull(arr); - long byteSize = (long)arr.length * Unsafe.ARRAY_CHAR_INDEX_SCALE; - return new OfChar(Unsafe.ARRAY_CHAR_BASE_OFFSET, arr, byteSize, false, + long byteSize = (long)arr.length * Utils.BaseAndScale.CHAR.scale(); + return new OfChar(Utils.BaseAndScale.CHAR.base(), arr, byteSize, false, MemorySessionImpl.createHeap(arr)); } public static MemorySegment fromArray(float[] arr) { ensureInitialized(); Objects.requireNonNull(arr); - long byteSize = (long)arr.length * Unsafe.ARRAY_FLOAT_INDEX_SCALE; - return new OfFloat(Unsafe.ARRAY_FLOAT_BASE_OFFSET, arr, byteSize, false, + long byteSize = (long)arr.length * Utils.BaseAndScale.FLOAT.scale(); + return new OfFloat(Utils.BaseAndScale.FLOAT.base(), arr, byteSize, false, MemorySessionImpl.createHeap(arr)); } public static MemorySegment fromArray(double[] arr) { ensureInitialized(); Objects.requireNonNull(arr); - long byteSize = (long)arr.length * Unsafe.ARRAY_DOUBLE_INDEX_SCALE; - return new OfDouble(Unsafe.ARRAY_DOUBLE_BASE_OFFSET, arr, byteSize, false, + long byteSize = (long)arr.length * Utils.BaseAndScale.DOUBLE.scale(); + return new OfDouble(Utils.BaseAndScale.DOUBLE.base(), arr, byteSize, false, MemorySessionImpl.createHeap(arr)); } public static MemorySegment fromArray(long[] arr) { ensureInitialized(); Objects.requireNonNull(arr); - long byteSize = (long)arr.length * Unsafe.ARRAY_LONG_INDEX_SCALE; - return new OfLong(Unsafe.ARRAY_LONG_BASE_OFFSET, arr, byteSize, false, + long byteSize = (long)arr.length * Utils.BaseAndScale.LONG.scale(); + return new OfLong(Utils.BaseAndScale.LONG.base(), arr, byteSize, false, MemorySessionImpl.createHeap(arr)); } diff --git a/src/java.base/share/classes/jdk/internal/foreign/SharedSession.java b/src/java.base/share/classes/jdk/internal/foreign/SharedSession.java index 984d9d99921..8d54a1e2d8a 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/SharedSession.java +++ b/src/java.base/share/classes/jdk/internal/foreign/SharedSession.java @@ -27,7 +27,6 @@ import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; -import java.lang.ref.Cleaner; import jdk.internal.misc.ScopedMemoryAccess; import jdk.internal.vm.annotation.ForceInline; diff --git a/src/java.base/share/classes/jdk/internal/foreign/StringSupport.java b/src/java.base/share/classes/jdk/internal/foreign/StringSupport.java index eaa028cae39..8527d374fb2 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/StringSupport.java +++ b/src/java.base/share/classes/jdk/internal/foreign/StringSupport.java @@ -39,7 +39,7 @@ /** * Miscellaneous functions to read and write strings, in various charsets. */ -public class StringSupport { +public final class StringSupport { static final JavaLangAccess JAVA_LANG_ACCESS = SharedSecrets.getJavaLangAccess(); diff --git a/src/java.base/share/classes/jdk/internal/foreign/SystemLookup.java b/src/java.base/share/classes/jdk/internal/foreign/SystemLookup.java index 4d87b01d002..74fe8492f82 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/SystemLookup.java +++ b/src/java.base/share/classes/jdk/internal/foreign/SystemLookup.java @@ -75,7 +75,7 @@ private static SymbolLookup makeSystemLookup() { private static SymbolLookup makeWindowsLookup() { @SuppressWarnings("removal") - String systemRoot = AccessController.doPrivileged(new PrivilegedAction() { + String systemRoot = AccessController.doPrivileged(new PrivilegedAction<>() { @Override public String run() { return System.getenv("SystemRoot"); @@ -86,7 +86,7 @@ public String run() { Path msvcrt = system32.resolve("msvcrt.dll"); @SuppressWarnings("removal") - boolean useUCRT = AccessController.doPrivileged(new PrivilegedAction() { + boolean useUCRT = AccessController.doPrivileged(new PrivilegedAction<>() { @Override public Boolean run() { return Files.exists(ucrtbase); 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 3809aedba80..00ab90e9612 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/Utils.java +++ b/src/java.base/share/classes/jdk/internal/foreign/Utils.java @@ -43,6 +43,7 @@ import jdk.internal.access.SharedSecrets; import jdk.internal.foreign.abi.SharedUtils; +import jdk.internal.misc.Unsafe; import jdk.internal.vm.annotation.ForceInline; import sun.invoke.util.Wrapper; @@ -276,4 +277,36 @@ public static String toHexString(long value) { return "0x" + Long.toHexString(value); } + public record BaseAndScale(int base, long scale) { + + public static final BaseAndScale BYTE = + new BaseAndScale(Unsafe.ARRAY_BYTE_BASE_OFFSET, Unsafe.ARRAY_BYTE_INDEX_SCALE); + public static final BaseAndScale CHAR = + new BaseAndScale(Unsafe.ARRAY_CHAR_BASE_OFFSET, Unsafe.ARRAY_CHAR_INDEX_SCALE); + public static final BaseAndScale SHORT = + new BaseAndScale(Unsafe.ARRAY_SHORT_BASE_OFFSET, Unsafe.ARRAY_SHORT_INDEX_SCALE); + public static final BaseAndScale INT = + new BaseAndScale(Unsafe.ARRAY_INT_BASE_OFFSET, Unsafe.ARRAY_INT_INDEX_SCALE); + public static final BaseAndScale FLOAT = + new BaseAndScale(Unsafe.ARRAY_FLOAT_BASE_OFFSET, Unsafe.ARRAY_FLOAT_INDEX_SCALE); + public static final BaseAndScale LONG = + new BaseAndScale(Unsafe.ARRAY_LONG_BASE_OFFSET, Unsafe.ARRAY_LONG_INDEX_SCALE); + public static final BaseAndScale DOUBLE = + new BaseAndScale(Unsafe.ARRAY_DOUBLE_BASE_OFFSET, Unsafe.ARRAY_DOUBLE_INDEX_SCALE); + + public static BaseAndScale of(Object array) { + return switch (array) { + case byte[] __ -> BaseAndScale.BYTE; + case char[] __ -> BaseAndScale.CHAR; + case short[] __ -> BaseAndScale.SHORT; + case int[] __ -> BaseAndScale.INT; + case float[] __ -> BaseAndScale.FLOAT; + case long[] __ -> BaseAndScale.LONG; + case double[] __ -> BaseAndScale.DOUBLE; + default -> throw new IllegalArgumentException("Not a supported array class: " + array.getClass().getSimpleName()); + }; + } + + } + } diff --git a/src/java.base/share/classes/jdk/internal/foreign/abi/AbstractLinker.java b/src/java.base/share/classes/jdk/internal/foreign/abi/AbstractLinker.java index ae41d4f1756..2bb95e58155 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/abi/AbstractLinker.java +++ b/src/java.base/share/classes/jdk/internal/foreign/abi/AbstractLinker.java @@ -91,7 +91,7 @@ public final MethodHandle downcallHandle(FunctionDescriptor function, Option... return downcallHandle0(function, options); } - private final MethodHandle downcallHandle0(FunctionDescriptor function, Option... options) { + private MethodHandle downcallHandle0(FunctionDescriptor function, Option... options) { Objects.requireNonNull(function); Objects.requireNonNull(options); checkLayouts(function); diff --git a/src/java.base/share/classes/jdk/internal/foreign/abi/Binding.java b/src/java.base/share/classes/jdk/internal/foreign/abi/Binding.java index 5ff8508adf4..875b5d998e3 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/abi/Binding.java +++ b/src/java.base/share/classes/jdk/internal/foreign/abi/Binding.java @@ -32,7 +32,6 @@ import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; -import java.nio.ByteOrder; import java.util.ArrayList; import java.util.Deque; import java.util.List; @@ -57,7 +56,7 @@ * the CONVERT_ADDRESS operator 'unboxes' a MemoryAddress to a long, but 'boxes' a long to a MemoryAddress. * * Here are some examples of binding recipes derived from C declarations, and according to the Windows ABI (recipes are - * ABI-specific). Note that each argument has it's own recipe, which is indicated by '[number]:' (though, the only + * ABI-specific). Note that each argument has its own recipe, which is indicated by '[number]:' (though, the only * example that has multiple arguments is the one using varargs). * * -------------------- diff --git a/src/java.base/share/classes/jdk/internal/foreign/abi/CapturableState.java b/src/java.base/share/classes/jdk/internal/foreign/abi/CapturableState.java index c2a480ce54d..8689751a3c8 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/abi/CapturableState.java +++ b/src/java.base/share/classes/jdk/internal/foreign/abi/CapturableState.java @@ -33,7 +33,6 @@ import java.util.stream.Stream; import static java.lang.foreign.ValueLayout.JAVA_INT; -import static sun.security.action.GetPropertyAction.privilegedGetProperty; public enum CapturableState { GET_LAST_ERROR ("GetLastError", JAVA_INT, 1 << 0, Utils.IS_WINDOWS), diff --git a/src/java.base/share/classes/jdk/internal/foreign/abi/SharedUtils.java b/src/java.base/share/classes/jdk/internal/foreign/abi/SharedUtils.java index 90c3efbfe67..b08202e5e35 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/abi/SharedUtils.java +++ b/src/java.base/share/classes/jdk/internal/foreign/abi/SharedUtils.java @@ -178,7 +178,7 @@ private static MethodHandle adaptUpcallForIMR(MethodHandle target, boolean dropR if (dropReturn) { // no handling for return value, need to drop it target = dropReturn(target); } else { - // adjust return type so it matches the inferred type of the effective + // adjust return type so that it matches the inferred type of the effective // function descriptor target = target.asType(target.type().changeReturnType(MemorySegment.class)); } diff --git a/src/java.base/share/classes/jdk/internal/foreign/abi/SoftReferenceCache.java b/src/java.base/share/classes/jdk/internal/foreign/abi/SoftReferenceCache.java index 3e801600cb6..04565c66c86 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/abi/SoftReferenceCache.java +++ b/src/java.base/share/classes/jdk/internal/foreign/abi/SoftReferenceCache.java @@ -29,7 +29,7 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.function.Function; -class SoftReferenceCache { +final class SoftReferenceCache { private final Map cache = new ConcurrentHashMap<>(); public V get(K key, Function valueFactory) { @@ -41,10 +41,7 @@ public V get(K key, Function valueFactory) { private final class Node { private volatile SoftReference ref; - public Node() { - } - - public V get(K key, Function valueFactory) { + V get(K key, Function valueFactory) { V result; if (ref == null || (result = ref.get()) == null) { synchronized (this) { // don't let threads race on the valueFactory::apply call diff --git a/src/java.base/share/classes/jdk/internal/foreign/abi/aarch64/CallArranger.java b/src/java.base/share/classes/jdk/internal/foreign/abi/aarch64/CallArranger.java index ed3a0d6121e..efd5090e8d9 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/abi/aarch64/CallArranger.java +++ b/src/java.base/share/classes/jdk/internal/foreign/abi/aarch64/CallArranger.java @@ -37,7 +37,6 @@ import jdk.internal.foreign.abi.CallingSequenceBuilder; import jdk.internal.foreign.abi.DowncallLinker; import jdk.internal.foreign.abi.LinkerOptions; -import jdk.internal.foreign.abi.UpcallLinker; import jdk.internal.foreign.abi.SharedUtils; import jdk.internal.foreign.abi.VMStorage; import jdk.internal.foreign.abi.aarch64.linux.LinuxAArch64CallArranger; @@ -246,8 +245,8 @@ Homogeneous float aggregates (HFAs) can be copied in a field-wise manner, i.e. t | enough registers | some registers, but not enough | no registers ----------------+------------------+---------------------------------+------------------------- Linux | FW in regs | CW on the stack | CW on the stack - MacOs, non-VA | FW in regs | FW on the stack | FW on the stack - MacOs, VA | FW in regs | CW on the stack | CW on the stack + macOS, non-VA | FW in regs | FW on the stack | FW on the stack + macOS, VA | FW in regs | CW on the stack | CW on the stack Windows, non-VF | FW in regs | CW on the stack | CW on the stack Windows, VF | FW in regs | CW split between regs and stack | CW on the stack (where FW = Field-wise copy, CW = Chunk-wise copy, VA is a variadic argument, and VF is a variadic function) @@ -257,7 +256,7 @@ Homogeneous float aggregates (HFAs) can be copied in a field-wise manner, i.e. t | enough registers | some registers, but not enough | no registers ----------------+------------------+---------------------------------+------------------------- Linux | CW in regs | CW on the stack | CW on the stack - MacOs | CW in regs | CW on the stack | CW on the stack + macOS | CW in regs | CW on the stack | CW on the stack Windows, non-VF | CW in regs | CW on the stack | CW on the stack Windows, VF | CW in regs | CW split between regs and stack | CW on the stack */ diff --git a/src/java.base/share/classes/jdk/internal/foreign/abi/aarch64/macos/MacOsAArch64Linker.java b/src/java.base/share/classes/jdk/internal/foreign/abi/aarch64/macos/MacOsAArch64Linker.java index 3f380a04db8..0772c09fdb5 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/abi/aarch64/macos/MacOsAArch64Linker.java +++ b/src/java.base/share/classes/jdk/internal/foreign/abi/aarch64/macos/MacOsAArch64Linker.java @@ -39,7 +39,7 @@ import java.util.Map; /** - * ABI implementation for macOS on Apple silicon. Based on AAPCS with + * ABI implementation for macOS on Apple Silicon. Based on AAPCS with * changes to va_list and passing arguments on the stack. */ public final class MacOsAArch64Linker extends AbstractLinker { diff --git a/src/java.base/share/classes/jdk/internal/foreign/abi/aarch64/windows/WindowsAArch64CallArranger.java b/src/java.base/share/classes/jdk/internal/foreign/abi/aarch64/windows/WindowsAArch64CallArranger.java index a1caf3da65c..18df7387075 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/abi/aarch64/windows/WindowsAArch64CallArranger.java +++ b/src/java.base/share/classes/jdk/internal/foreign/abi/aarch64/windows/WindowsAArch64CallArranger.java @@ -52,7 +52,7 @@ public class WindowsAArch64CallArranger extends CallArranger { // // Although the AAPCS64 says r0-7 and v0-7 are all valid return // registers, it's not possible to generate a C function that uses - // r2-7 and v4-7 so they are omitted here. + // r2-7 and v4-7 so, they are omitted here. private static final ABIDescriptor WindowsAArch64AbiDescriptor = abiFor( new VMStorage[] { r0, r1, r2, r3, r4, r5, r6, r7, INDIRECT_RESULT}, new VMStorage[] { v0, v1, v2, v3, v4, v5, v6, v7 }, diff --git a/src/java.base/share/classes/jdk/internal/foreign/abi/aarch64/windows/WindowsAArch64Linker.java b/src/java.base/share/classes/jdk/internal/foreign/abi/aarch64/windows/WindowsAArch64Linker.java index 71d18d7b182..eac1d49c1dd 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/abi/aarch64/windows/WindowsAArch64Linker.java +++ b/src/java.base/share/classes/jdk/internal/foreign/abi/aarch64/windows/WindowsAArch64Linker.java @@ -47,13 +47,12 @@ public final class WindowsAArch64Linker extends AbstractLinker { static final Map CANONICAL_LAYOUTS = SharedUtils.canonicalLayouts(ValueLayout.JAVA_INT, ValueLayout.JAVA_LONG, ValueLayout.JAVA_CHAR); - private static WindowsAArch64Linker instance; public static WindowsAArch64Linker getInstance() { - if (instance == null) { - instance = new WindowsAArch64Linker(); + class Holder { + private static final WindowsAArch64Linker INSTANCE = new WindowsAArch64Linker(); } - return instance; + return Holder.INSTANCE; } @Override diff --git a/src/java.base/share/classes/jdk/internal/foreign/abi/fallback/FFIType.java b/src/java.base/share/classes/jdk/internal/foreign/abi/fallback/FFIType.java index f5e3c29fc81..c8fa729711a 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/abi/fallback/FFIType.java +++ b/src/java.base/share/classes/jdk/internal/foreign/abi/fallback/FFIType.java @@ -58,6 +58,7 @@ * } ffi_type; */ class FFIType { + static final ValueLayout SIZE_T = layoutFor((int)ADDRESS.byteSize()); private static final ValueLayout UNSIGNED_SHORT = JAVA_SHORT; private static final StructLayout LAYOUT = Utils.computePaddedStructLayout( diff --git a/src/java.base/share/classes/jdk/internal/foreign/abi/fallback/FallbackLinker.java b/src/java.base/share/classes/jdk/internal/foreign/abi/fallback/FallbackLinker.java index 8e688c06eac..40ebe3b99ca 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/abi/fallback/FallbackLinker.java +++ b/src/java.base/share/classes/jdk/internal/foreign/abi/fallback/FallbackLinker.java @@ -240,30 +240,25 @@ private static void writeValue(Object arg, MemoryLayout layout, MemorySegment ar private static void writeValue(Object arg, MemoryLayout layout, MemorySegment argSeg, Consumer acquireCallback) { - if (layout instanceof ValueLayout.OfBoolean bl) { - argSeg.set(bl, 0, (Boolean) arg); - } else if (layout instanceof ValueLayout.OfByte bl) { - argSeg.set(bl, 0, (Byte) arg); - } else if (layout instanceof ValueLayout.OfShort sl) { - argSeg.set(sl, 0, (Short) arg); - } else if (layout instanceof ValueLayout.OfChar cl) { - argSeg.set(cl, 0, (Character) arg); - } else if (layout instanceof ValueLayout.OfInt il) { - argSeg.set(il, 0, (Integer) arg); - } else if (layout instanceof ValueLayout.OfLong ll) { - argSeg.set(ll, 0, (Long) arg); - } else if (layout instanceof ValueLayout.OfFloat fl) { - argSeg.set(fl, 0, (Float) arg); - } else if (layout instanceof ValueLayout.OfDouble dl) { - argSeg.set(dl, 0, (Double) arg); - } else if (layout instanceof AddressLayout al) { - MemorySegment addrArg = (MemorySegment) arg; - acquireCallback.accept(addrArg); - argSeg.set(al, 0, addrArg); - } else if (layout instanceof GroupLayout) { - MemorySegment.copy((MemorySegment) arg, 0, argSeg, 0, argSeg.byteSize()); // by-value struct - } else { - assert layout == null; + switch (layout) { + case ValueLayout.OfBoolean bl -> argSeg.set(bl, 0, (Boolean) arg); + case ValueLayout.OfByte bl -> argSeg.set(bl, 0, (Byte) arg); + case ValueLayout.OfShort sl -> argSeg.set(sl, 0, (Short) arg); + case ValueLayout.OfChar cl -> argSeg.set(cl, 0, (Character) arg); + case ValueLayout.OfInt il -> argSeg.set(il, 0, (Integer) arg); + case ValueLayout.OfLong ll -> argSeg.set(ll, 0, (Long) arg); + case ValueLayout.OfFloat fl -> argSeg.set(fl, 0, (Float) arg); + case ValueLayout.OfDouble dl -> argSeg.set(dl, 0, (Double) arg); + case AddressLayout al -> { + MemorySegment addrArg = (MemorySegment) arg; + acquireCallback.accept(addrArg); + argSeg.set(al, 0, addrArg); + } + case GroupLayout __ -> + MemorySegment.copy((MemorySegment) arg, 0, argSeg, 0, argSeg.byteSize()); // by-value struct + case null, default -> { + assert layout == null; + } } } diff --git a/src/java.base/share/classes/jdk/internal/foreign/abi/ppc64/PPC64Architecture.java b/src/java.base/share/classes/jdk/internal/foreign/abi/ppc64/PPC64Architecture.java index 3a6eb89c9ec..d9391e4064a 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/abi/ppc64/PPC64Architecture.java +++ b/src/java.base/share/classes/jdk/internal/foreign/abi/ppc64/PPC64Architecture.java @@ -52,13 +52,12 @@ public boolean isStackType(int cls) { @Override public int typeSize(int cls) { - switch (cls) { - case StorageType.INTEGER: return INTEGER_REG_SIZE; - case StorageType.FLOAT: return FLOAT_REG_SIZE; + return switch (cls) { + case StorageType.INTEGER -> INTEGER_REG_SIZE; + case StorageType.FLOAT -> FLOAT_REG_SIZE; // STACK is deliberately omitted - } - - throw new IllegalArgumentException("Invalid Storage Class: " + cls); + default -> throw new IllegalArgumentException("Invalid Storage Class: " + cls); + }; } public interface StorageType { diff --git a/src/java.base/share/classes/jdk/internal/foreign/abi/riscv64/RISCV64Architecture.java b/src/java.base/share/classes/jdk/internal/foreign/abi/riscv64/RISCV64Architecture.java index 9c3d64be7ad..409b685baed 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/abi/riscv64/RISCV64Architecture.java +++ b/src/java.base/share/classes/jdk/internal/foreign/abi/riscv64/RISCV64Architecture.java @@ -32,7 +32,6 @@ import jdk.internal.foreign.abi.Architecture; import jdk.internal.foreign.abi.StubLocations; import jdk.internal.foreign.abi.VMStorage; -import jdk.internal.foreign.abi.riscv64.linux.TypeClass; public final class RISCV64Architecture implements Architecture { public static final Architecture INSTANCE = new RISCV64Architecture(); diff --git a/src/java.base/share/classes/jdk/internal/foreign/abi/riscv64/linux/LinuxRISCV64CallArranger.java b/src/java.base/share/classes/jdk/internal/foreign/abi/riscv64/linux/LinuxRISCV64CallArranger.java index 8da7a124abc..60959cf7544 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/abi/riscv64/linux/LinuxRISCV64CallArranger.java +++ b/src/java.base/share/classes/jdk/internal/foreign/abi/riscv64/linux/LinuxRISCV64CallArranger.java @@ -40,12 +40,10 @@ import jdk.internal.foreign.abi.CallingSequenceBuilder; import jdk.internal.foreign.abi.DowncallLinker; import jdk.internal.foreign.abi.LinkerOptions; -import jdk.internal.foreign.abi.UpcallLinker; import jdk.internal.foreign.abi.SharedUtils; import jdk.internal.foreign.abi.VMStorage; import jdk.internal.foreign.Utils; -import java.lang.foreign.ValueLayout; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodType; import java.util.List; @@ -150,7 +148,7 @@ public StorageCalculator(boolean forArguments) { this.forArguments = forArguments; } - // Aggregates or scalars passed on the stack are aligned to the greater of + // Aggregates or scalars passed on the stack are aligned to the greatest of // the type alignment and XLEN bits, but never more than the stack alignment. void alignStack(long alignment) { alignment = Utils.alignUp(Math.clamp(alignment, STACK_SLOT_SIZE, 16), STACK_SLOT_SIZE); @@ -253,8 +251,8 @@ protected BindingCalculator(boolean forArguments) { Map.entry(STRUCT_REGISTER_XF, STRUCT_REGISTER_X)); } - static class UnboxBindingCalculator extends BindingCalculator { - boolean forArguments; + static final class UnboxBindingCalculator extends BindingCalculator { + final boolean forArguments; UnboxBindingCalculator(boolean forArguments) { super(forArguments); diff --git a/src/java.base/share/classes/jdk/internal/foreign/abi/riscv64/linux/TypeClass.java b/src/java.base/share/classes/jdk/internal/foreign/abi/riscv64/linux/TypeClass.java index 380f0a83109..e00771d2e59 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/abi/riscv64/linux/TypeClass.java +++ b/src/java.base/share/classes/jdk/internal/foreign/abi/riscv64/linux/TypeClass.java @@ -78,7 +78,7 @@ public enum TypeClass { * Struct will be flattened while classifying. That is, struct{struct{int, double}} will be treated * same as struct{int, double} and struct{int[2]} will be treated same as struct{int, int}. * */ - private static record FieldCounter(long integerCnt, long floatCnt, long pointerCnt) { + private record FieldCounter(long integerCnt, long floatCnt, long pointerCnt) { static final FieldCounter EMPTY = new FieldCounter(0, 0, 0); static final FieldCounter SINGLE_INTEGER = new FieldCounter(1, 0, 0); static final FieldCounter SINGLE_FLOAT = new FieldCounter(0, 1, 0); @@ -128,39 +128,40 @@ FieldCounter add(FieldCounter other) { } } - public static record FlattenedFieldDesc(TypeClass typeClass, long offset, ValueLayout layout) { - - } + public record FlattenedFieldDesc(TypeClass typeClass, long offset, ValueLayout layout) { } private static List getFlattenedFieldsInner(long offset, MemoryLayout layout) { - if (layout instanceof ValueLayout valueLayout) { - TypeClass typeClass = classifyValueType(valueLayout); - return List.of(switch (typeClass) { - case INTEGER, FLOAT -> new FlattenedFieldDesc(typeClass, offset, valueLayout); - default -> throw new IllegalStateException("Should not reach here."); - }); - } else if (layout instanceof GroupLayout groupLayout) { - List fields = new ArrayList<>(); - for (MemoryLayout memberLayout : groupLayout.memberLayouts()) { - if (memberLayout instanceof PaddingLayout) { + return switch (layout) { + case ValueLayout valueLayout -> { + TypeClass typeClass = classifyValueType(valueLayout); + yield List.of(switch (typeClass) { + case INTEGER, FLOAT -> new FlattenedFieldDesc(typeClass, offset, valueLayout); + default -> throw new IllegalStateException("Should not reach here."); + }); + } + case GroupLayout groupLayout -> { + List fields = new ArrayList<>(); + for (MemoryLayout memberLayout : groupLayout.memberLayouts()) { + if (memberLayout instanceof PaddingLayout) { + offset += memberLayout.byteSize(); + continue; + } + fields.addAll(getFlattenedFieldsInner(offset, memberLayout)); offset += memberLayout.byteSize(); - continue; } - fields.addAll(getFlattenedFieldsInner(offset, memberLayout)); - offset += memberLayout.byteSize(); + yield fields; } - return fields; - } else if (layout instanceof SequenceLayout sequenceLayout) { - List fields = new ArrayList<>(); - MemoryLayout elementLayout = sequenceLayout.elementLayout(); - for (long i = 0; i < sequenceLayout.elementCount(); i++) { - fields.addAll(getFlattenedFieldsInner(offset, elementLayout)); - offset += elementLayout.byteSize(); + case SequenceLayout sequenceLayout -> { + List fields = new ArrayList<>(); + MemoryLayout elementLayout = sequenceLayout.elementLayout(); + for (long i = 0; i < sequenceLayout.elementCount(); i++) { + fields.addAll(getFlattenedFieldsInner(offset, elementLayout)); + offset += elementLayout.byteSize(); + } + yield fields; } - return fields; - } else { - throw new IllegalStateException("Cannot get here: " + layout); - } + case null, default -> throw new IllegalStateException("Cannot get here: " + layout); + }; } public static List getFlattenedFields(GroupLayout layout) { diff --git a/src/java.base/share/classes/jdk/internal/foreign/abi/s390/S390Architecture.java b/src/java.base/share/classes/jdk/internal/foreign/abi/s390/S390Architecture.java index bbafef2f3dc..146536f0bc4 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/abi/s390/S390Architecture.java +++ b/src/java.base/share/classes/jdk/internal/foreign/abi/s390/S390Architecture.java @@ -52,15 +52,12 @@ public boolean isStackType(int cls) { @Override public int typeSize(int cls) { - switch (cls) { - case StorageType.INTEGER: - return INTEGER_REG_SIZE; - case StorageType.FLOAT: - return FLOAT_REG_SIZE; + return switch (cls) { + case StorageType.INTEGER -> INTEGER_REG_SIZE; + case StorageType.FLOAT -> FLOAT_REG_SIZE; // STACK is deliberately omitted - } - - throw new IllegalArgumentException("Invalid Storage Class: " + cls); + default -> throw new IllegalArgumentException("Invalid Storage Class: " + cls); + }; } public interface StorageType { diff --git a/src/java.base/share/classes/jdk/internal/foreign/abi/s390/linux/LinuxS390CallArranger.java b/src/java.base/share/classes/jdk/internal/foreign/abi/s390/linux/LinuxS390CallArranger.java index 84392e45089..009cfb6227f 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/abi/s390/linux/LinuxS390CallArranger.java +++ b/src/java.base/share/classes/jdk/internal/foreign/abi/s390/linux/LinuxS390CallArranger.java @@ -37,19 +37,15 @@ import jdk.internal.foreign.abi.CallingSequenceBuilder; import jdk.internal.foreign.abi.DowncallLinker; import jdk.internal.foreign.abi.LinkerOptions; -import jdk.internal.foreign.abi.UpcallLinker; import jdk.internal.foreign.abi.SharedUtils; import jdk.internal.foreign.abi.VMStorage; import jdk.internal.foreign.Utils; -import java.lang.foreign.ValueLayout; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodType; import java.util.List; -import java.util.Map; import java.util.Optional; -import static jdk.internal.foreign.abi.s390.linux.TypeClass.*; import static jdk.internal.foreign.abi.s390.S390Architecture.*; import static jdk.internal.foreign.abi.s390.S390Architecture.Regs.*; diff --git a/src/java.base/share/classes/jdk/internal/foreign/abi/s390/linux/TypeClass.java b/src/java.base/share/classes/jdk/internal/foreign/abi/s390/linux/TypeClass.java index 095cb2c08a8..1f96fa4bf79 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/abi/s390/linux/TypeClass.java +++ b/src/java.base/share/classes/jdk/internal/foreign/abi/s390/linux/TypeClass.java @@ -96,10 +96,7 @@ static boolean isSingleFloatAggregate(MemoryLayout type) { return false; TypeClass baseArgClass = classifyValueType((ValueLayout) baseType); - if (baseArgClass != FLOAT) - return false; - - return true; + return baseArgClass == FLOAT; } private static TypeClass classifyStructType(MemoryLayout layout) { diff --git a/src/java.base/share/classes/jdk/internal/foreign/abi/x64/sysv/CallArranger.java b/src/java.base/share/classes/jdk/internal/foreign/abi/x64/sysv/CallArranger.java index 59224022e74..75e8d0926a1 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/abi/x64/sysv/CallArranger.java +++ b/src/java.base/share/classes/jdk/internal/foreign/abi/x64/sysv/CallArranger.java @@ -34,7 +34,6 @@ import jdk.internal.foreign.abi.DowncallLinker; import jdk.internal.foreign.abi.LinkerOptions; import jdk.internal.foreign.abi.SharedUtils; -import jdk.internal.foreign.abi.UpcallLinker; import jdk.internal.foreign.abi.VMStorage; import jdk.internal.foreign.abi.x64.X86_64Architecture; @@ -208,7 +207,7 @@ VMStorage[] structStorages(TypeClass typeClass) { return typeClass.classes.stream().map(c -> stackAlloc()).toArray(VMStorage[]::new); } - //ok, let's pass pass on registers + //ok, let's pass on registers VMStorage[] storage = new VMStorage[(int)(nIntegerReg + nVectorReg)]; for (int i = 0 ; i < typeClass.classes.size() ; i++) { boolean sse = typeClass.classes.get(i) == ArgumentClassImpl.SSE; diff --git a/src/java.base/share/classes/jdk/internal/foreign/abi/x64/sysv/TypeClass.java b/src/java.base/share/classes/jdk/internal/foreign/abi/x64/sysv/TypeClass.java index d970a543a23..7a6be52ba2f 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/abi/x64/sysv/TypeClass.java +++ b/src/java.base/share/classes/jdk/internal/foreign/abi/x64/sysv/TypeClass.java @@ -208,35 +208,40 @@ private static List[] groupByEightBytes(GroupLayout group) { return groups; } - private static void groupByEightBytes(MemoryLayout l, long offset, List[] groups) { - if (l instanceof GroupLayout group) { - for (MemoryLayout m : group.memberLayouts()) { - groupByEightBytes(m, offset, groups); - if (group instanceof StructLayout) { - offset += m.byteSize(); + private static void groupByEightBytes(MemoryLayout layout, + long offset, + List[] groups) { + switch (layout) { + case GroupLayout group -> { + for (MemoryLayout m : group.memberLayouts()) { + groupByEightBytes(m, offset, groups); + if (group instanceof StructLayout) { + offset += m.byteSize(); + } } } - } else if (l instanceof PaddingLayout) { - return; - } else if (l instanceof SequenceLayout seq) { - MemoryLayout elem = seq.elementLayout(); - for (long i = 0 ; i < seq.elementCount() ; i++) { - groupByEightBytes(elem, offset, groups); - offset += elem.byteSize(); + case PaddingLayout __ -> { } - } else if (l instanceof ValueLayout vl) { - List layouts = groups[(int)offset / 8]; - if (layouts == null) { - layouts = new ArrayList<>(); - groups[(int)offset / 8] = layouts; + case SequenceLayout seq -> { + MemoryLayout elem = seq.elementLayout(); + for (long i = 0; i < seq.elementCount(); i++) { + groupByEightBytes(elem, offset, groups); + offset += elem.byteSize(); + } } - // if the aggregate contains unaligned fields, it has class MEMORY - ArgumentClassImpl argumentClass = (offset % vl.byteAlignment()) == 0 ? - argumentClassFor(vl) : - ArgumentClassImpl.MEMORY; - layouts.add(argumentClass); - } else { - throw new IllegalStateException("Unexpected layout: " + l); + case ValueLayout vl -> { + List layouts = groups[(int) offset / 8]; + if (layouts == null) { + layouts = new ArrayList<>(); + groups[(int) offset / 8] = layouts; + } + // if the aggregate contains unaligned fields, it has class MEMORY + ArgumentClassImpl argumentClass = (offset % vl.byteAlignment()) == 0 ? + argumentClassFor(vl) : + ArgumentClassImpl.MEMORY; + layouts.add(argumentClass); + } + case null, default -> throw new IllegalStateException("Unexpected layout: " + layout); } } } diff --git a/src/java.base/share/classes/jdk/internal/foreign/abi/x64/windows/CallArranger.java b/src/java.base/share/classes/jdk/internal/foreign/abi/x64/windows/CallArranger.java index f905dae0fe5..4d4ad65b1c6 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/abi/x64/windows/CallArranger.java +++ b/src/java.base/share/classes/jdk/internal/foreign/abi/x64/windows/CallArranger.java @@ -33,7 +33,6 @@ import jdk.internal.foreign.abi.DowncallLinker; import jdk.internal.foreign.abi.LinkerOptions; import jdk.internal.foreign.abi.SharedUtils; -import jdk.internal.foreign.abi.UpcallLinker; import jdk.internal.foreign.abi.VMStorage; import jdk.internal.foreign.abi.x64.X86_64Architecture; @@ -42,7 +41,6 @@ import java.lang.foreign.GroupLayout; import java.lang.foreign.MemoryLayout; import java.lang.foreign.MemorySegment; -import java.lang.foreign.ValueLayout; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodType; import java.util.List; diff --git a/src/java.base/share/classes/jdk/internal/foreign/abi/x64/windows/TypeClass.java b/src/java.base/share/classes/jdk/internal/foreign/abi/x64/windows/TypeClass.java index 892e4c49318..04839b740dc 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/abi/x64/windows/TypeClass.java +++ b/src/java.base/share/classes/jdk/internal/foreign/abi/x64/windows/TypeClass.java @@ -38,7 +38,7 @@ enum TypeClass { VARARG_FLOAT; private static TypeClass classifyValueType(ValueLayout type, boolean isVararg) { - // No 128-bit integers in the Windows C ABI. There are __m128(i|d) intrinsic types but they act just + // No 128-bit integers in the Windows C ABI. There are __m128(i|d) intrinsic types but, they act just // like a struct when passing as an argument (passed by pointer). // https://docs.microsoft.com/en-us/cpp/cpp/m128?view=vs-2019 diff --git a/src/java.base/share/classes/jdk/internal/foreign/layout/AbstractGroupLayout.java b/src/java.base/share/classes/jdk/internal/foreign/layout/AbstractGroupLayout.java index 6c5fba7ea6b..a2e6ff36591 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/layout/AbstractGroupLayout.java +++ b/src/java.base/share/classes/jdk/internal/foreign/layout/AbstractGroupLayout.java @@ -40,7 +40,7 @@ * @implSpec * This class is immutable, thread-safe and value-based. */ -public sealed abstract class AbstractGroupLayout & MemoryLayout> +abstract sealed class AbstractGroupLayout & MemoryLayout> extends AbstractLayout permits StructLayoutImpl, UnionLayoutImpl { diff --git a/src/java.base/share/classes/jdk/internal/foreign/layout/ValueLayouts.java b/src/java.base/share/classes/jdk/internal/foreign/layout/ValueLayouts.java index 2567227abf6..cc61ed41a98 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/layout/ValueLayouts.java +++ b/src/java.base/share/classes/jdk/internal/foreign/layout/ValueLayouts.java @@ -59,7 +59,7 @@ public final class ValueLayouts { // Suppresses default constructor, ensuring non-instantiability. private ValueLayouts() {} - abstract sealed static class AbstractValueLayout & ValueLayout> extends AbstractLayout { + abstract static sealed class AbstractValueLayout & ValueLayout> extends AbstractLayout { static final int ADDRESS_SIZE_BYTES = Unsafe.ADDRESS_SIZE; From 52814994efc4831fdbc1f796ed1db6ae88cb616c Mon Sep 17 00:00:00 2001 From: sunyaqi Date: Fri, 20 Oct 2023 16:27:58 +0000 Subject: [PATCH 044/124] 8316563: test tools/jpackage/linux/LinuxResourceTest.java fails on CentOS Linux release 8.5.2111 and Fedora 27 Reviewed-by: asemenyuk, almatvee --- test/jdk/tools/jpackage/linux/LinuxResourceTest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/test/jdk/tools/jpackage/linux/LinuxResourceTest.java b/test/jdk/tools/jpackage/linux/LinuxResourceTest.java index 70bf389d312..f38e0763d28 100644 --- a/test/jdk/tools/jpackage/linux/LinuxResourceTest.java +++ b/test/jdk/tools/jpackage/linux/LinuxResourceTest.java @@ -102,6 +102,7 @@ public static void testHardcodedProperties() throws IOException { "License: APPLICATION_LICENSE_TYPE", "Prefix: %{dirname:APPLICATION_DIRECTORY}", "Provides: dont-install-me", + "%define _build_id_links none", "%description", "APPLICATION_DESCRIPTION", "%prep", From 200b5a27d4bc77e2628a80d8166ee5d6057ab0c5 Mon Sep 17 00:00:00 2001 From: Viktor Klang Date: Fri, 20 Oct 2023 16:31:46 +0000 Subject: [PATCH 045/124] 8318420: AbstractPipeline invokes overridden method in constructor Reviewed-by: psandoz --- .../java/util/stream/AbstractPipeline.java | 25 ++++++++++++------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/src/java.base/share/classes/java/util/stream/AbstractPipeline.java b/src/java.base/share/classes/java/util/stream/AbstractPipeline.java index 9517bc4f7b8..bba017d4144 100644 --- a/src/java.base/share/classes/java/util/stream/AbstractPipeline.java +++ b/src/java.base/share/classes/java/util/stream/AbstractPipeline.java @@ -134,12 +134,6 @@ abstract class AbstractPipeline> */ private boolean linkedOrConsumed; - /** - * True if there are any stateful ops in the pipeline; only valid for the - * source stage. - */ - private boolean sourceAnyStateful; - private Runnable sourceCloseAction; /** @@ -208,8 +202,6 @@ abstract class AbstractPipeline> this.sourceOrOpFlags = opFlags & StreamOpFlag.OP_MASK; this.combinedFlags = StreamOpFlag.combineOpFlags(opFlags, previousStage.combinedFlags); this.sourceStage = previousStage.sourceStage; - if (opIsStateful()) - sourceStage.sourceAnyStateful = true; this.depth = previousStage.depth + 1; } @@ -386,6 +378,21 @@ final int getStreamFlags() { return StreamOpFlag.toStreamFlags(combinedFlags); } + /** + * Returns whether any of the stages of the current segment is stateful + * or not. + * @return {@code true} if any stage in this segment is stateful, + * {@code false} if not. + */ + protected final boolean hasAnyStateful() { + var result = false; + for (var u = sourceStage.nextStage; + u != null && !(result = u.opIsStateful()) && u != this; + u = u.nextStage) { + } + return result; + } + /** * Get the source spliterator for this pipeline stage. For a sequential or * stateless parallel pipeline, this is the source spliterator. For a @@ -409,7 +416,7 @@ else if (sourceStage.sourceSupplier != null) { throw new IllegalStateException(MSG_CONSUMED); } - if (isParallel() && sourceStage.sourceAnyStateful) { + if (isParallel() && hasAnyStateful()) { // Adapt the source spliterator, evaluating each stateful op // in the pipeline up to and including this pipeline stage. // The depth and flags of each pipeline stage are adjusted accordingly. From 21215753c05681311be304f8994a97caa8e33ce2 Mon Sep 17 00:00:00 2001 From: Viktor Klang Date: Fri, 20 Oct 2023 16:32:11 +0000 Subject: [PATCH 046/124] 8318421: AbstractPipeline.sourceStageSpliterator() chases pointers needlessly Reviewed-by: psandoz --- .../java/util/stream/AbstractPipeline.java | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/java.base/share/classes/java/util/stream/AbstractPipeline.java b/src/java.base/share/classes/java/util/stream/AbstractPipeline.java index bba017d4144..cdf8a605618 100644 --- a/src/java.base/share/classes/java/util/stream/AbstractPipeline.java +++ b/src/java.base/share/classes/java/util/stream/AbstractPipeline.java @@ -262,8 +262,9 @@ final Node evaluateToArrayNode(IntFunction generator) { * @throws IllegalStateException if this pipeline stage is not the source * stage. */ - @SuppressWarnings("unchecked") + final Spliterator sourceStageSpliterator() { + // Ensures that this method is only ever called on the sourceStage if (this != sourceStage) throw new IllegalStateException(); @@ -271,16 +272,16 @@ final Spliterator sourceStageSpliterator() { throw new IllegalStateException(MSG_STREAM_LINKED); linkedOrConsumed = true; - if (sourceStage.sourceSpliterator != null) { + if (sourceSpliterator != null) { @SuppressWarnings("unchecked") - Spliterator s = sourceStage.sourceSpliterator; - sourceStage.sourceSpliterator = null; + Spliterator s = (Spliterator)sourceSpliterator; + sourceSpliterator = null; return s; } - else if (sourceStage.sourceSupplier != null) { + else if (sourceSupplier != null) { @SuppressWarnings("unchecked") - Spliterator s = (Spliterator) sourceStage.sourceSupplier.get(); - sourceStage.sourceSupplier = null; + Spliterator s = (Spliterator)sourceSupplier.get(); + sourceSupplier = null; return s; } else { @@ -309,8 +310,8 @@ public void close() { linkedOrConsumed = true; sourceSupplier = null; sourceSpliterator = null; - if (sourceStage.sourceCloseAction != null) { - Runnable closeAction = sourceStage.sourceCloseAction; + Runnable closeAction = sourceStage.sourceCloseAction; + if (closeAction != null) { sourceStage.sourceCloseAction = null; closeAction.run(); } From a045258ae2eb02daa17a9a9799a666f42daa7e20 Mon Sep 17 00:00:00 2001 From: Kevin Walls Date: Fri, 20 Oct 2023 16:38:39 +0000 Subject: [PATCH 047/124] 8209595: MonitorVmStartTerminate.java timed out Reviewed-by: sspitsyn, cjplummer, lmesnik --- .../MonitoredVm/MonitorVmStartTerminate.java | 59 +++++++++++++------ 1 file changed, 41 insertions(+), 18 deletions(-) diff --git a/test/jdk/sun/jvmstat/monitor/MonitoredVm/MonitorVmStartTerminate.java b/test/jdk/sun/jvmstat/monitor/MonitoredVm/MonitorVmStartTerminate.java index d98ab41f4ad..7e129c15e23 100644 --- a/test/jdk/sun/jvmstat/monitor/MonitoredVm/MonitorVmStartTerminate.java +++ b/test/jdk/sun/jvmstat/monitor/MonitoredVm/MonitorVmStartTerminate.java @@ -98,6 +98,7 @@ public static void main(String... args) throws Exception { System.out.println("Waiting for all processes to get started notification"); listener.started.acquire(PROCESS_COUNT); + System.out.println("Terminating all processes"); for (JavaProcess javaProcess : javaProcesses) { javaProcess.terminate(); } @@ -138,7 +139,7 @@ public void disconnected(HostEvent arg0) { } private void releaseStarted(Set ids) { - System.out.println("realeaseStarted(" + ids + ")"); + System.out.println("releaseStarted(" + ids + ")"); for (Integer id : ids) { releaseStarted(id); } @@ -149,11 +150,12 @@ private void releaseStarted(Integer id) { if (hasMainArgs(id, jp.getMainArgsIdentifier())) { // store id for terminated identification jp.setId(id); - System.out.println("RELEASED (id=" + jp.getId() + ", args=" + jp.getMainArgsIdentifier() + ")"); + System.out.println("RELEASED started (id=" + jp.getId() + ", args=" + jp.getMainArgsIdentifier() + ")"); started.release(); return; } } + System.out.println("releaseStarted: not a test pid: " + id); } private void releaseTerminated(Set ids) { @@ -166,23 +168,44 @@ private void releaseTerminated(Set ids) { private void releaseTerminated(Integer id) { for (JavaProcess jp : processes) { if (id.equals(jp.getId())) { - System.out.println("RELEASED (id=" + jp.getId() + ", args=" + jp.getMainArgsIdentifier() + ")"); + System.out.println("RELEASED terminated (id=" + jp.getId() + ", args=" + jp.getMainArgsIdentifier() + ")"); terminated.release(); return; } } } + private static final int ARGS_ATTEMPTS = 3; + private boolean hasMainArgs(Integer id, String args) { + VmIdentifier vmid = null; try { - VmIdentifier vmid = new VmIdentifier("//" + id.intValue()); - MonitoredVm target = host.getMonitoredVm(vmid); - String monitoredArgs = MonitoredVmUtil.mainArgs(target); - if (monitoredArgs != null && monitoredArgs.contains(args)) { - return true; + vmid = new VmIdentifier("//" + id.intValue()); + } catch (URISyntaxException e) { + System.out.println("hasMainArgs(" + id + "): " + e); + return false; + } + // Retry a failing attempt to check arguments for a match, + // as not recognizing a test process will cause timeout and failure. + for (int i = 0; i < ARGS_ATTEMPTS; i++) { + try { + MonitoredVm target = host.getMonitoredVm(vmid); + String monitoredArgs = MonitoredVmUtil.mainArgs(target); + System.out.println("hasMainArgs(" + id + "): has main args: '" + monitoredArgs + "'"); + if (monitoredArgs == null || monitoredArgs.equals("Unknown")) { + System.out.println("hasMainArgs(" + id + "): retry" ); + takeNap(); + continue; + } else if (monitoredArgs.contains(args)) { + return true; + } else { + return false; + } + } catch (MonitorException e) { + // Process probably not running or not ours, e.g. + // sun.jvmstat.monitor.MonitorException: Could not attach to PID + System.out.println("hasMainArgs(" + id + "): " + e); } - } catch (URISyntaxException | MonitorException e) { - // ok. process probably not running } return false; } @@ -247,14 +270,6 @@ private static void waitForRemoval(Path path) { } } - private static void takeNap() { - try { - Thread.sleep(100); - } catch (InterruptedException e) { - // ignore - } - } - private final String mainArgsIdentifier; private final ShutdownHook shutdownHook; private volatile Integer id; @@ -322,4 +337,12 @@ public String getMainArgsIdentifier() { return mainArgsIdentifier; } } + + public static void takeNap() { + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + // ignore + } + } } From 158293d2517695f8c5eaca1b46ecf0f1f9f09691 Mon Sep 17 00:00:00 2001 From: Harshitha Onkar Date: Fri, 20 Oct 2023 17:35:21 +0000 Subject: [PATCH 048/124] 8316030: Update Libpng to 1.6.40 Reviewed-by: prr, dnguyen --- src/java.desktop/share/legal/libpng.md | 8 +- .../native/libsplashscreen/libpng/CHANGES | 30 ++-- .../native/libsplashscreen/libpng/LICENSE | 6 +- .../native/libsplashscreen/libpng/README | 162 +++++++++--------- .../share/native/libsplashscreen/libpng/png.c | 8 +- .../share/native/libsplashscreen/libpng/png.h | 22 +-- .../native/libsplashscreen/libpng/pngconf.h | 2 +- .../native/libsplashscreen/libpng/pngget.c | 13 +- .../libsplashscreen/libpng/pnglibconf.h | 4 +- .../native/libsplashscreen/libpng/pngpriv.h | 6 +- .../native/libsplashscreen/libpng/pngset.c | 60 +++---- 11 files changed, 164 insertions(+), 157 deletions(-) diff --git a/src/java.desktop/share/legal/libpng.md b/src/java.desktop/share/legal/libpng.md index f11cfe580ce..f420ccd94ed 100644 --- a/src/java.desktop/share/legal/libpng.md +++ b/src/java.desktop/share/legal/libpng.md @@ -1,4 +1,4 @@ -## libpng v1.6.39 +## libpng v1.6.40 ### libpng License

@@ -9,8 +9,8 @@ COPYRIGHT NOTICE, DISCLAIMER, and LICENSE
 PNG Reference Library License version 2
 ---------------------------------------
 
-Copyright (c) 1995-2022 The PNG Reference Library Authors.
-Copyright (c) 2018-2022 Cosmin Truta
+Copyright (c) 1995-2023 The PNG Reference Library Authors.
+Copyright (c) 2018-2023 Cosmin Truta
 Copyright (c) 1998-2018 Glenn Randers-Pehrson
 Copyright (c) 1996-1997 Andreas Dilger
 Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -175,6 +175,7 @@ Authors, for copyright and licensing purposes.
  * Mike Klein
  * Pascal Massimino
  * Paul Schmidt
+ * Philippe Antoine
  * Qiang Zhou
  * Sam Bushell
  * Samuel Williams
@@ -193,6 +194,7 @@ Authors, for copyright and licensing purposes.
    - Matt Sarett
    - Mike Klein
    - Sami Boukortt
+   - Wan-Teh Chang
 
 The build projects, the build scripts, the test scripts, and other
 files in the "ci", "projects", "scripts" and "tests" directories, have
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/CHANGES b/src/java.desktop/share/native/libsplashscreen/libpng/CHANGES
index 468e1119a10..2d8c585c0e7 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/CHANGES
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/CHANGES
@@ -204,7 +204,7 @@ Version 0.97 [January, 1998]
   Added simple sRGB support (Glenn R-P)
   Easier conditional compiling, e.g.,
     define PNG_READ/WRITE_NOT_FULLY_SUPPORTED;
-    all configurable options can be selected from command-line instead
+    all configurable options can be selected from command line instead
     of having to edit pngconf.h (Glenn R-P)
   Fixed memory leak in pngwrite.c (free info_ptr->text) (Glenn R-P)
   Added more conditions for png_do_background, to avoid changing
@@ -942,7 +942,7 @@ Version 1.0.8 [July 24, 2000]
 Version 1.0.9beta1 [November 10, 2000]
   Fixed typo in scripts/makefile.hpux
   Updated makevms.com in scripts and contrib/* and contrib/* (Martin Zinser)
-  Fixed seqence-point bug in contrib/pngminus/png2pnm (Martin Zinser)
+  Fixed sequence-point bug in contrib/pngminus/png2pnm (Martin Zinser)
   Changed "cdrom.com" in documentation to "libpng.org"
   Revised pnggccrd.c to get it all working, and updated makefile.gcmmx (Greg).
   Changed type of "params" from voidp to png_voidp in png_read|write_png().
@@ -2295,7 +2295,7 @@ Version 1.4.0beta58 [May 14, 2009]
   Clarified usage of sig_bit versus sig_bit_p in example.c (Vincent Torri)
 
 Version 1.4.0beta59 [May 15, 2009]
-  Reformated sources in libpng style (3-space indentation, comment format)
+  Reformatted sources in libpng style (3-space indentation, comment format)
   Fixed typo in libpng docs (PNG_FILTER_AVE should be PNG_FILTER_AVG)
   Added sections about the git repository and our coding style to the
     documentation
@@ -2661,7 +2661,7 @@ Version 1.4.1beta06 [January 28, 2010]
 
 Version 1.4.1beta07 [February 6, 2010]
   Folded some long lines in the source files.
-  Added defineable PNG_USER_CHUNK_CACHE_MAX, PNG_USER_CHUNK_MALLOC_MAX,
+  Added definable PNG_USER_CHUNK_CACHE_MAX, PNG_USER_CHUNK_MALLOC_MAX,
     and a PNG_USER_LIMITS_SUPPORTED flag.
   Eliminated use of png_ptr->irowbytes and reused the slot in png_ptr as
     png_ptr->png_user_chunk_malloc_max.
@@ -3919,7 +3919,7 @@ Version 1.6.0beta08 [February 1, 2012]
     version checking to configure.ac
   Improved pngstest speed by not doing redundant tests and add const to
     the background parameter of png_image_finish_read. The --background
-    option is now done automagically only when required, so that commandline
+    option is now done automagically only when required, so that command-line
     option no longer exists.
   Cleaned up pngpriv.h to consistently declare all functions and data.
     Also eliminated PNG_CONST_DATA, which is apparently not needed but we
@@ -4052,7 +4052,7 @@ Version 1.6.0beta16 [March 6, 2012]
     (in fact this is harmless, but the PNG data produced may be sub-optimal).
 
 Version 1.6.0beta17 [March 10, 2012]
-  Fixed PNG_LIBPNG_BUILD_BASE_TYPE definition. 
+  Fixed PNG_LIBPNG_BUILD_BASE_TYPE definition.
   Reject all iCCP chunks after the first, even if the first one is invalid.
   Deflate/inflate was reworked to move common zlib calls into single
     functions [rw]util.c.  A new shared keyword check routine was also added
@@ -4962,7 +4962,7 @@ Version 1.6.13beta01 [July 4, 2014]
   Changed "if defined(__ARM_NEON__)" to
     "if (defined(__ARM_NEON__) || defined(__ARM_NEON))" (James Wu).
   Fixed clang no-warning builds: png_digit was defined but never used.
-    
+
 Version 1.6.13beta02 [July 21, 2014]
   Fixed an incorrect separator ("/" should be "\") in scripts/makefile.vcwin32
     (bug report from Wolfgang S. Kechel).  Bug was introduced in libpng-1.6.11.
@@ -5453,7 +5453,7 @@ Version 1.6.21beta01 [December 11, 2015]
 Version 1.6.21beta02 [December 14, 2015]
   Moved png_check_keyword() from pngwutil.c to pngset.c
   Removed LE/BE dependencies in pngvalid, to 'fix' the current problem
-    in the BigEndian tests by not testing it, making the BE code the same 
+    in the BigEndian tests by not testing it, making the BE code the same
     as the LE version.
   Fixes to pngvalid for various reduced build configurations (eliminate unused
     statics) and a fix for the case in rgb_to_gray when the digitize option
@@ -5517,7 +5517,7 @@ Version 1.6.22beta03 [March 9, 2016]
   Added a common-law trademark notice and export control information
     to the LICENSE file, png.h, and the man page.
   Restored "& 0xff" in png_save_uint_16() and png_save_uint_32() that
-    were accidentally removed from libpng-1.6.17. 
+    were accidentally removed from libpng-1.6.17.
   Changed PNG_INFO_cHNK and PNG_FREE_cHNK from 0xnnnn to 0xnnnnU in png.h
     (Robert C. Seacord).
   Removed dubious "#if INT_MAX" test from png.h that was added to
@@ -5927,7 +5927,7 @@ Version 1.6.32beta03 [August 2, 2017]
     (Bug report from the OSS-fuzz project).
 
 Version 1.6.32beta04 [August 2, 2017]
-  Replaced local eXIf_buf with info_ptr-eXIf_buf in png_handle_eXIf().
+  Replaced local eXIf_buf with info_ptr->eXIf_buf in png_handle_eXIf().
   Update libpng.3 and libpng-manual.txt about eXIf functions.
 
 Version 1.6.32beta05 [August 2, 2017]
@@ -5950,7 +5950,7 @@ Version 1.6.32beta09 [August 3, 2017]
   Require cmake-2.8.8 in CMakeLists.txt. Revised symlink creation,
     no longer using deprecated cmake LOCATION feature (Clifford Yapp).
   Fixed five-byte error in the calculation of IDAT maximum possible size.
-  
+
 Version 1.6.32beta10 [August 5, 2017]
   Moved chunk-length check into a png_check_chunk_length() private
     function (Suggested by Max Stepin).
@@ -6121,6 +6121,14 @@ Version 1.6.39 [November 20, 2022]
     removed the obsolete makefile.cegcc.
   Cleaned up the code and updated the internal documentation.
 
+Version 1.6.40 [June 21, 2023]
+  Fixed the eXIf chunk multiplicity checks.
+  Fixed a memory leak in pCAL processing.
+  Corrected the validity report about tRNS inside png_get_valid().
+  Fixed various build issues on *BSD, Mac and Windows.
+  Updated the configurations and the scripts for continuous integration.
+  Cleaned up the code, the build scripts, and the documentation.
+
 Send comments/corrections/commendations to png-mng-implement at lists.sf.net.
 Subscription is required; visit
 https://lists.sourceforge.net/lists/listinfo/png-mng-implement
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/LICENSE b/src/java.desktop/share/native/libsplashscreen/libpng/LICENSE
index 7ac90160ede..086d1c2fda6 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/LICENSE
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/LICENSE
@@ -4,8 +4,8 @@ COPYRIGHT NOTICE, DISCLAIMER, and LICENSE
 PNG Reference Library License version 2
 ---------------------------------------
 
- * Copyright (c) 1995-2022 The PNG Reference Library Authors.
- * Copyright (c) 2018-2022 Cosmin Truta.
+ * Copyright (c) 1995-2023 The PNG Reference Library Authors.
+ * Copyright (c) 2018-2023 Cosmin Truta.
  * Copyright (c) 2000-2002, 2004, 2006-2018 Glenn Randers-Pehrson.
  * Copyright (c) 1996-1997 Andreas Dilger.
  * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -131,4 +131,4 @@ The Contributing Authors and Group 42, Inc. specifically permit,
 without fee, and encourage the use of this source code as a component
 to supporting the PNG file format in commercial products.  If you use
 this source code in a product, acknowledgment is not required but would
-be appreciated.
\ No newline at end of file
+be appreciated.
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/README b/src/java.desktop/share/native/libsplashscreen/libpng/README
index 097a3c21841..dedd2c1639e 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/README
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/README
@@ -1,110 +1,108 @@
-README for libpng version 1.6.39
+README for libpng version 1.6.40
 ================================
 
-See the note about version numbers near the top of png.h.
-See INSTALL for instructions on how to install libpng.
+See the note about version numbers near the top of `png.h`.
+See `INSTALL` for instructions on how to install libpng.
 
-Libpng comes in several distribution formats.  Get libpng-*.tar.gz or
-libpng-*.tar.xz if you want UNIX-style line endings in the text files,
-or lpng*.7z or lpng*.zip if you want DOS-style line endings.
+Libpng comes in several distribution formats.  Get `libpng-*.tar.gz`
+or `libpng-*.tar.xz` if you want UNIX-style line endings in the text
+files, or `lpng*.7z` or `lpng*.zip` if you want DOS-style line endings.
 
-Version 0.89 was the first official release of libpng.  Don't let the
-fact that it's the first release fool you.  The libpng library has been
-in extensive use and testing since mid-1995.  By late 1997 it had
-finally gotten to the stage where there hadn't been significant
-changes to the API in some time, and people have a bad feeling about
-libraries with versions < 1.0.  Version 1.0.0 was released in
-March 1998.
+For a detailed description on using libpng, read `libpng-manual.txt`.
+For examples of libpng in a program, see `example.c` and `pngtest.c`.
+For usage information and restrictions (what little they are) on libpng,
+see `png.h`.  For a description on using zlib (the compression library
+used by libpng) and zlib's restrictions, see `zlib.h`.
 
-****
-Note that some of the changes to the png_info structure render this
-version of the library binary incompatible with libpng-0.89 or
-earlier versions if you are using a shared library.  The type of the
-"filler" parameter for png_set_filler() has changed from png_byte to
-png_uint_32, which will affect shared-library applications that use
-this function.
-
-To avoid problems with changes to the internals of the png info_struct,
-new APIs have been made available in 0.95 to avoid direct application
-access to info_ptr.  These functions are the png_set_ and
-png_get_ functions.  These functions should be used when
-accessing/storing the info_struct data, rather than manipulating it
-directly, to avoid such problems in the future.
-
-It is important to note that the APIs did not make current programs
-that access the info struct directly incompatible with the new
-library, through libpng-1.2.x.  In libpng-1.4.x, which was meant to
-be a transitional release, members of the png_struct and the
-info_struct can still be accessed, but the compiler will issue a
-warning about deprecated usage.  Since libpng-1.5.0, direct access
-to these structs is not allowed, and the definitions of the structs
-reside in private pngstruct.h and pnginfo.h header files that are not
-accessible to applications.  It is strongly suggested that new
-programs use the new APIs (as shown in example.c and pngtest.c), and
-older programs be converted to the new format, to facilitate upgrades
-in the future.
-****
-
-Additions since 0.90 include the ability to compile libpng as a
-Windows DLL, and new APIs for accessing data in the info struct.
-Experimental functions include the ability to set weighting and cost
-factors for row filter selection, direct reads of integers from buffers
-on big-endian processors that support misaligned data access, faster
-methods of doing alpha composition, and more accurate 16->8 bit color
-conversion.
-
-The additions since 0.89 include the ability to read from a PNG stream
-which has had some (or all) of the signature bytes read by the calling
-application.  This also allows the reading of embedded PNG streams that
-do not have the PNG file signature.  As well, it is now possible to set
-the library action on the detection of chunk CRC errors.  It is possible
-to set different actions based on whether the CRC error occurred in a
-critical or an ancillary chunk.
-
-For a detailed description on using libpng, read libpng-manual.txt.
-For examples of libpng in a program, see example.c and pngtest.c.  For
-usage information and restrictions (what little they are) on libpng,
-see png.h.  For a description on using zlib (the compression library
-used by libpng) and zlib's restrictions, see zlib.h
-
-I have included a general makefile, as well as several machine and
-compiler specific ones, but you may have to modify one for your own
-needs.
-
-You should use zlib 1.0.4 or later to run this, but it MAY work with
+You should use zlib 1.0.4 or later to run this, but it _may_ work with
 versions as old as zlib 0.95.  Even so, there are bugs in older zlib
 versions which can cause the output of invalid compression streams for
 some images.
 
 You should also note that zlib is a compression library that is useful
 for more things than just PNG files.  You can use zlib as a drop-in
-replacement for fread() and fwrite(), if you are so inclined.
+replacement for `fread()` and `fwrite()`, if you are so inclined.
 
 zlib should be available at the same place that libpng is, or at
-https://zlib.net.
+https://zlib.net .
 
 You may also want a copy of the PNG specification.  It is available
 as an RFC, a W3C Recommendation, and an ISO/IEC Standard.  You can find
 these at http://www.libpng.org/pub/png/pngdocs.html .
 
-This code is currently being archived at libpng.sourceforge.io in the
-[DOWNLOAD] area, and at http://libpng.download/src .
+This code is currently being archived at https://libpng.sourceforge.io
+in the download area, and at http://libpng.download/src .
 
 This release, based in a large way on Glenn's, Guy's and Andreas'
 earlier work, was created and will be supported by myself and the PNG
 development group.
 
-Send comments/corrections/commendations to png-mng-implement at
-lists.sourceforge.net (subscription required; visit
+Send comments, corrections and commendations to `png-mng-implement`
+at `lists.sourceforge.net`.  (Subscription is required; visit
 https://lists.sourceforge.net/lists/listinfo/png-mng-implement
-to subscribe).
+to subscribe.)
+
+Send general questions about the PNG specification to `png-mng-misc`
+at `lists.sourceforge.net`.  (Subscription is required; visit
+https://lists.sourceforge.net/lists/listinfo/png-mng-misc
+to subscribe.)
 
-Send general questions about the PNG specification to png-mng-misc
-at lists.sourceforge.net (subscription required; visit
-https://lists.sourceforge.net/lists/listinfo/png-mng-misc to
-subscribe).
+Historical notes
+----------------
+
+The libpng library has been in extensive use and testing since mid-1995.
+Version 0.89, published a year later, was the first official release.
+By late 1997, it had finally gotten to the stage where there hadn't
+been significant changes to the API in some time, and people have a bad
+feeling about libraries with versions below 1.0.  Version 1.0.0 was
+released in March 1998.
+
+Note that some of the changes to the `png_info` structure render this
+version of the library binary incompatible with libpng-0.89 or
+earlier versions if you are using a shared library.  The type of the
+`filler` parameter for `png_set_filler()` has changed from `png_byte`
+to `png_uint_32`, which will affect shared-library applications that
+use this function.
+
+To avoid problems with changes to the internals of the `info_struct`,
+new APIs have been made available in 0.95 to avoid direct application
+access to `info_ptr`.  These functions are the `png_set_` and
+`png_get_` functions.  These functions should be used when
+accessing/storing the `info_struct` data, rather than manipulating it
+directly, to avoid such problems in the future.
+
+It is important to note that the APIs did not make current programs
+that access the info struct directly incompatible with the new
+library, through libpng-1.2.x.  In libpng-1.4.x, which was meant to
+be a transitional release, members of the `png_struct` and the
+`info_struct` can still be accessed, but the compiler will issue a
+warning about deprecated usage.  Since libpng-1.5.0, direct access
+to these structs is not allowed, and the definitions of the structs
+reside in private `pngstruct.h` and `pnginfo.h` header files that are
+not accessible to applications.  It is strongly suggested that new
+programs use the new APIs (as shown in `example.c` and `pngtest.c`),
+and older programs be converted to the new format, to facilitate
+upgrades in the future.
+
+The additions since 0.89 include the ability to read from a PNG stream
+which has had some (or all) of the signature bytes read by the calling
+application.  This also allows the reading of embedded PNG streams that
+do not have the PNG file signature.  As well, it is now possible to set
+the library action on the detection of chunk CRC errors.  It is possible
+to set different actions based on whether the CRC error occurred in a
+critical or an ancillary chunk.
+
+The additions since 0.90 include the ability to compile libpng as a
+Windows DLL, and new APIs for accessing data in the `info_struct`.
+Experimental functions included the ability to set weighting and cost
+factors for row filter selection, direct reads of integers from buffers
+on big-endian processors that support misaligned data access, faster
+methods of doing alpha composition, and more accurate 16-to-8 bit color
+conversion.  Some of these experimental functions, such as the weighted
+filter heuristics, have since been removed.
 
-Files in this distribution:
+Files included in this distribution
+-----------------------------------
 
     ANNOUNCE      =>  Announcement of this version, with recent changes
     AUTHORS       =>  List of contributing authors
@@ -153,7 +151,7 @@ Files in this distribution:
         arm-neon/     =>  Optimized code for the ARM-NEON platform
         mips-msa/     =>  Optimized code for the MIPS-MSA platform
         powerpc-vsx/  =>  Optimized code for the POWERPC-VSX platform
-        examples/     =>  Example programs
+        examples/     =>  Examples of libpng usage
         gregbook/     =>  Source code for PNG reading and writing, from
                           "PNG: The Definitive Guide" by Greg Roelofs,
                           O'Reilly, 1999
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/png.c b/src/java.desktop/share/native/libsplashscreen/libpng/png.c
index 30181b6ff7c..91a92e5f718 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/png.c
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/png.c
@@ -29,7 +29,7 @@
  * However, the following notice accompanied the original version of this
  * file and, per its terms, should not be removed:
  *
- * Copyright (c) 2018-2022 Cosmin Truta
+ * Copyright (c) 2018-2023 Cosmin Truta
  * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
  * Copyright (c) 1996-1997 Andreas Dilger
  * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -42,7 +42,7 @@
 #include "pngpriv.h"
 
 /* Generate a compiler error if there is an old png.h in the search path. */
-typedef png_libpng_version_1_6_39 Your_png_h_is_not_version_1_6_39;
+typedef png_libpng_version_1_6_40 Your_png_h_is_not_version_1_6_40;
 
 #ifdef __GNUC__
 /* The version tests may need to be added to, but the problem warning has
@@ -843,8 +843,8 @@ png_get_copyright(png_const_structrp png_ptr)
    return PNG_STRING_COPYRIGHT
 #else
    return PNG_STRING_NEWLINE \
-      "libpng version 1.6.39" PNG_STRING_NEWLINE \
-      "Copyright (c) 2018-2022 Cosmin Truta" PNG_STRING_NEWLINE \
+      "libpng version 1.6.40" PNG_STRING_NEWLINE \
+      "Copyright (c) 2018-2023 Cosmin Truta" PNG_STRING_NEWLINE \
       "Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson" \
       PNG_STRING_NEWLINE \
       "Copyright (c) 1996-1997 Andreas Dilger" PNG_STRING_NEWLINE \
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/png.h b/src/java.desktop/share/native/libsplashscreen/libpng/png.h
index 3d9fa03de66..578841c9580 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/png.h
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/png.h
@@ -29,9 +29,9 @@
  * However, the following notice accompanied the original version of this
  * file and, per its terms, should not be removed:
  *
- * libpng version 1.6.39 - November 20, 2022
+ * libpng version 1.6.40
  *
- * Copyright (c) 2018-2022 Cosmin Truta
+ * Copyright (c) 2018-2023 Cosmin Truta
  * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
  * Copyright (c) 1996-1997 Andreas Dilger
  * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -43,7 +43,7 @@
  *   libpng versions 0.89, June 1996, through 0.96, May 1997: Andreas Dilger
  *   libpng versions 0.97, January 1998, through 1.6.35, July 2018:
  *     Glenn Randers-Pehrson
- *   libpng versions 1.6.36, December 2018, through 1.6.39, November 2022:
+ *   libpng versions 1.6.36, December 2018, through 1.6.40, June 2023:
  *     Cosmin Truta
  *   See also "Contributing Authors", below.
  */
@@ -55,8 +55,8 @@
  * PNG Reference Library License version 2
  * ---------------------------------------
  *
- *  * Copyright (c) 1995-2022 The PNG Reference Library Authors.
- *  * Copyright (c) 2018-2022 Cosmin Truta.
+ *  * Copyright (c) 1995-2023 The PNG Reference Library Authors.
+ *  * Copyright (c) 2018-2023 Cosmin Truta.
  *  * Copyright (c) 2000-2002, 2004, 2006-2018 Glenn Randers-Pehrson.
  *  * Copyright (c) 1996-1997 Andreas Dilger.
  *  * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -267,7 +267,7 @@
  *    ...
  *    1.5.30                  15    10530  15.so.15.30[.0]
  *    ...
- *    1.6.39                  16    10639  16.so.16.39[.0]
+ *    1.6.40                  16    10640  16.so.16.40[.0]
  *
  *    Henceforth the source version will match the shared-library major and
  *    minor numbers; the shared-library major version number will be used for
@@ -306,8 +306,8 @@
  */
 
 /* Version information for png.h - this should match the version in png.c */
-#define PNG_LIBPNG_VER_STRING "1.6.39"
-#define PNG_HEADER_VERSION_STRING " libpng version 1.6.39 - November 20, 2022\n"
+#define PNG_LIBPNG_VER_STRING "1.6.40"
+#define PNG_HEADER_VERSION_STRING " libpng version 1.6.40 - June 21, 2023\n"
 
 #define PNG_LIBPNG_VER_SONUM   16
 #define PNG_LIBPNG_VER_DLLNUM  16
@@ -315,7 +315,7 @@
 /* These should match the first 3 components of PNG_LIBPNG_VER_STRING: */
 #define PNG_LIBPNG_VER_MAJOR   1
 #define PNG_LIBPNG_VER_MINOR   6
-#define PNG_LIBPNG_VER_RELEASE 39
+#define PNG_LIBPNG_VER_RELEASE 40
 
 /* This should be zero for a public release, or non-zero for a
  * development version.  [Deprecated]
@@ -346,7 +346,7 @@
  * From version 1.0.1 it is:
  * XXYYZZ, where XX=major, YY=minor, ZZ=release
  */
-#define PNG_LIBPNG_VER 10639 /* 1.6.39 */
+#define PNG_LIBPNG_VER 10640 /* 1.6.40 */
 
 /* Library configuration: these options cannot be changed after
  * the library has been built.
@@ -456,7 +456,7 @@ extern "C" {
 /* This triggers a compiler error in png.c, if png.c and png.h
  * do not agree upon the version number.
  */
-typedef char* png_libpng_version_1_6_39;
+typedef char* png_libpng_version_1_6_40;
 
 /* Basic control structions.  Read libpng-manual.txt or libpng.3 for more info.
  *
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/pngconf.h b/src/java.desktop/share/native/libsplashscreen/libpng/pngconf.h
index d11e9ac346a..41cbc91d398 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/pngconf.h
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/pngconf.h
@@ -29,7 +29,7 @@
  * However, the following notice accompanied the original version of this
  * file and, per its terms, should not be removed:
  *
- * libpng version 1.6.39
+ * libpng version 1.6.40
  *
  * Copyright (c) 2018-2022 Cosmin Truta
  * Copyright (c) 1998-2002,2004,2006-2016,2018 Glenn Randers-Pehrson
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/pngget.c b/src/java.desktop/share/native/libsplashscreen/libpng/pngget.c
index 454d4e82273..6e510b27327 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/pngget.c
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/pngget.c
@@ -29,7 +29,7 @@
  * However, the following notice accompanied the original version of this
  * file and, per its terms, should not be removed:
  *
- * Copyright (c) 2018 Cosmin Truta
+ * Copyright (c) 2018-2023 Cosmin Truta
  * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
  * Copyright (c) 1996-1997 Andreas Dilger
  * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -49,7 +49,18 @@ png_get_valid(png_const_structrp png_ptr, png_const_inforp info_ptr,
     png_uint_32 flag)
 {
    if (png_ptr != NULL && info_ptr != NULL)
+   {
+#ifdef PNG_READ_tRNS_SUPPORTED
+      /* png_handle_PLTE() may have canceled a valid tRNS chunk but left the
+       * 'valid' flag for the detection of duplicate chunks. Do not report a
+       * valid tRNS chunk in this case.
+       */
+      if (flag == PNG_INFO_tRNS && png_ptr->num_trans == 0)
+         return(0);
+#endif
+
       return(info_ptr->valid & flag);
+   }
 
    return(0);
 }
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/pnglibconf.h b/src/java.desktop/share/native/libsplashscreen/libpng/pnglibconf.h
index 18b435d80ad..e98d49cf0cc 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/pnglibconf.h
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/pnglibconf.h
@@ -31,9 +31,9 @@
  * However, the following notice accompanied the original version of this
  * file and, per its terms, should not be removed:
  */
-/* libpng version 1.6.39 */
+/* libpng version 1.6.40 */
 
-/* Copyright (c) 2018-2022 Cosmin Truta */
+/* Copyright (c) 2018-2023 Cosmin Truta */
 /* Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson */
 
 /* This code is released under the libpng license. */
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/pngpriv.h b/src/java.desktop/share/native/libsplashscreen/libpng/pngpriv.h
index ec473298068..914d0b97b1d 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/pngpriv.h
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/pngpriv.h
@@ -29,7 +29,7 @@
  * However, the following notice accompanied the original version of this
  * file and, per its terms, should not be removed:
  *
- * Copyright (c) 2018-2022 Cosmin Truta
+ * Copyright (c) 2018-2023 Cosmin Truta
  * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
  * Copyright (c) 1996-1997 Andreas Dilger
  * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -654,7 +654,7 @@
 #define PNG_BACKGROUND_IS_GRAY     0x800U
 #define PNG_HAVE_PNG_SIGNATURE    0x1000U
 #define PNG_HAVE_CHUNK_AFTER_IDAT 0x2000U /* Have another chunk after IDAT */
-                   /*             0x4000U (unused) */
+#define PNG_WROTE_eXIf            0x4000U
 #define PNG_IS_READ_STRUCT        0x8000U /* Else is a write struct */
 
 /* Flags for the transformations the PNG library does on the image data */
@@ -1938,7 +1938,7 @@ PNG_INTERNAL_FUNCTION(void,png_ascii_from_fixed,(png_const_structrp png_ptr,
  */
 #define PNG_FP_INVALID  512  /* Available for callers as a distinct value */
 
-/* Result codes for the parser (boolean - true meants ok, false means
+/* Result codes for the parser (boolean - true means ok, false means
  * not ok yet.)
  */
 #define PNG_FP_MAYBE      0  /* The number may be valid in the future */
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/pngset.c b/src/java.desktop/share/native/libsplashscreen/libpng/pngset.c
index ea7decaa065..62612a02278 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/pngset.c
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/pngset.c
@@ -29,7 +29,7 @@
  * However, the following notice accompanied the original version of this
  * file and, per its terms, should not be removed:
  *
- * Copyright (c) 2018-2022 Cosmin Truta
+ * Copyright (c) 2018-2023 Cosmin Truta
  * Copyright (c) 1998-2018 Glenn Randers-Pehrson
  * Copyright (c) 1996-1997 Andreas Dilger
  * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
@@ -165,46 +165,40 @@ png_set_cHRM_XYZ(png_const_structrp png_ptr, png_inforp info_ptr, double red_X,
 #ifdef PNG_eXIf_SUPPORTED
 void PNGAPI
 png_set_eXIf(png_const_structrp png_ptr, png_inforp info_ptr,
-    png_bytep eXIf_buf)
+    png_bytep exif)
 {
   png_warning(png_ptr, "png_set_eXIf does not work; use png_set_eXIf_1");
   PNG_UNUSED(info_ptr)
-  PNG_UNUSED(eXIf_buf)
+  PNG_UNUSED(exif)
 }
 
 void PNGAPI
 png_set_eXIf_1(png_const_structrp png_ptr, png_inforp info_ptr,
-    png_uint_32 num_exif, png_bytep eXIf_buf)
+    png_uint_32 num_exif, png_bytep exif)
 {
-   int i;
+   png_bytep new_exif;
 
    png_debug1(1, "in %s storage function", "eXIf");
 
-   if (png_ptr == NULL || info_ptr == NULL)
+   if (png_ptr == NULL || info_ptr == NULL ||
+       (png_ptr->mode & PNG_WROTE_eXIf) != 0)
       return;
 
-   if (info_ptr->exif)
-   {
-      png_free(png_ptr, info_ptr->exif);
-      info_ptr->exif = NULL;
-   }
+   new_exif = png_voidcast(png_bytep, png_malloc_warn(png_ptr, num_exif));
 
-   info_ptr->num_exif = num_exif;
-
-   info_ptr->exif = png_voidcast(png_bytep, png_malloc_warn(png_ptr,
-       info_ptr->num_exif));
-
-   if (info_ptr->exif == NULL)
+   if (new_exif == NULL)
    {
       png_warning(png_ptr, "Insufficient memory for eXIf chunk data");
       return;
    }
 
-   info_ptr->free_me |= PNG_FREE_EXIF;
+   memcpy(new_exif, exif, (size_t)num_exif);
 
-   for (i = 0; i < (int) info_ptr->num_exif; i++)
-      info_ptr->exif[i] = eXIf_buf[i];
+   png_free_data(png_ptr, info_ptr, PNG_FREE_EXIF, 0);
 
+   info_ptr->num_exif = num_exif;
+   info_ptr->exif = new_exif;
+   info_ptr->free_me |= PNG_FREE_EXIF;
    info_ptr->valid |= PNG_INFO_eXIf;
 }
 #endif /* eXIf */
@@ -265,15 +259,13 @@ png_set_hIST(png_const_structrp png_ptr, png_inforp info_ptr,
    if (info_ptr->hist == NULL)
    {
       png_warning(png_ptr, "Insufficient memory for hIST chunk data");
-
       return;
    }
 
-   info_ptr->free_me |= PNG_FREE_HIST;
-
    for (i = 0; i < info_ptr->num_palette; i++)
       info_ptr->hist[i] = hist[i];
 
+   info_ptr->free_me |= PNG_FREE_HIST;
    info_ptr->valid |= PNG_INFO_hIST;
 }
 #endif
@@ -395,6 +387,8 @@ png_set_pCAL(png_const_structrp png_ptr, png_inforp info_ptr,
 
    memcpy(info_ptr->pcal_purpose, purpose, length);
 
+   info_ptr->free_me |= PNG_FREE_PCAL;
+
    png_debug(3, "storing X0, X1, type, and nparams in info");
    info_ptr->pcal_X0 = X0;
    info_ptr->pcal_X1 = X1;
@@ -411,7 +405,6 @@ png_set_pCAL(png_const_structrp png_ptr, png_inforp info_ptr,
    if (info_ptr->pcal_units == NULL)
    {
       png_warning(png_ptr, "Insufficient memory for pCAL units");
-
       return;
    }
 
@@ -423,7 +416,6 @@ png_set_pCAL(png_const_structrp png_ptr, png_inforp info_ptr,
    if (info_ptr->pcal_params == NULL)
    {
       png_warning(png_ptr, "Insufficient memory for pCAL params");
-
       return;
    }
 
@@ -441,7 +433,6 @@ png_set_pCAL(png_const_structrp png_ptr, png_inforp info_ptr,
       if (info_ptr->pcal_params[i] == NULL)
       {
          png_warning(png_ptr, "Insufficient memory for pCAL parameter");
-
          return;
       }
 
@@ -449,7 +440,6 @@ png_set_pCAL(png_const_structrp png_ptr, png_inforp info_ptr,
    }
 
    info_ptr->valid |= PNG_INFO_pCAL;
-   info_ptr->free_me |= PNG_FREE_PCAL;
 }
 #endif
 
@@ -506,18 +496,17 @@ png_set_sCAL_s(png_const_structrp png_ptr, png_inforp info_ptr,
 
    if (info_ptr->scal_s_height == NULL)
    {
-      png_free (png_ptr, info_ptr->scal_s_width);
+      png_free(png_ptr, info_ptr->scal_s_width);
       info_ptr->scal_s_width = NULL;
 
       png_warning(png_ptr, "Memory allocation failed while processing sCAL");
-
       return;
    }
 
    memcpy(info_ptr->scal_s_height, sheight, lengthh);
 
-   info_ptr->valid |= PNG_INFO_sCAL;
    info_ptr->free_me |= PNG_FREE_SCAL;
+   info_ptr->valid |= PNG_INFO_sCAL;
 }
 
 #  ifdef PNG_FLOATING_POINT_SUPPORTED
@@ -653,11 +642,10 @@ png_set_PLTE(png_structrp png_ptr, png_inforp info_ptr,
    if (num_palette > 0)
       memcpy(png_ptr->palette, palette, (unsigned int)num_palette *
           (sizeof (png_color)));
+
    info_ptr->palette = png_ptr->palette;
    info_ptr->num_palette = png_ptr->num_palette = (png_uint_16)num_palette;
-
    info_ptr->free_me |= PNG_FREE_PLTE;
-
    info_ptr->valid |= PNG_INFO_PLTE;
 }
 
@@ -1048,8 +1036,8 @@ png_set_tRNS(png_structrp png_ptr, png_inforp info_ptr,
               png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH));
           memcpy(info_ptr->trans_alpha, trans_alpha, (size_t)num_trans);
 
-          info_ptr->valid |= PNG_INFO_tRNS;
           info_ptr->free_me |= PNG_FREE_TRNS;
+          info_ptr->valid |= PNG_INFO_tRNS;
        }
        png_ptr->trans_alpha = info_ptr->trans_alpha;
    }
@@ -1082,8 +1070,8 @@ png_set_tRNS(png_structrp png_ptr, png_inforp info_ptr,
 
    if (num_trans != 0)
    {
-      info_ptr->valid |= PNG_INFO_tRNS;
       info_ptr->free_me |= PNG_FREE_TRNS;
+      info_ptr->valid |= PNG_INFO_tRNS;
    }
 }
 #endif
@@ -1117,11 +1105,11 @@ png_set_sPLT(png_const_structrp png_ptr,
    {
       /* Out of memory or too many chunks */
       png_chunk_report(png_ptr, "too many sPLT chunks", PNG_CHUNK_WRITE_ERROR);
-
       return;
    }
 
    png_free(png_ptr, info_ptr->splt_palettes);
+
    info_ptr->splt_palettes = np;
    info_ptr->free_me |= PNG_FREE_SPLT;
 
@@ -1275,11 +1263,11 @@ png_set_unknown_chunks(png_const_structrp png_ptr,
    {
       png_chunk_report(png_ptr, "too many unknown chunks",
           PNG_CHUNK_WRITE_ERROR);
-
       return;
    }
 
    png_free(png_ptr, info_ptr->unknown_chunks);
+
    info_ptr->unknown_chunks = np; /* safe because it is initialized */
    info_ptr->free_me |= PNG_FREE_UNKN;
 

From 4dfa3799a60cb11092b699db5bc0cc1f44d24484 Mon Sep 17 00:00:00 2001
From: Justin Lu 
Date: Fri, 20 Oct 2023 17:37:51 +0000
Subject: [PATCH 049/124] 7061097: [Doc] Inconsistenency between the spec and
 the implementation for DateFormat.Field

Reviewed-by: naoto
---
 src/java.base/share/classes/java/text/DateFormat.java | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/src/java.base/share/classes/java/text/DateFormat.java b/src/java.base/share/classes/java/text/DateFormat.java
index d5083f11965..e0d05d78a28 100644
--- a/src/java.base/share/classes/java/text/DateFormat.java
+++ b/src/java.base/share/classes/java/text/DateFormat.java
@@ -944,9 +944,12 @@ protected Field(String name, int calendarField) {
         /**
          * Returns the {@code Calendar} field associated with this
          * attribute. For example, if this represents the hours field of
-         * a {@code Calendar}, this would return
-         * {@code Calendar.HOUR}. If there is no corresponding
-         * {@code Calendar} constant, this will return -1.
+         * a {@code Calendar}, this method would return {@code Calendar.HOUR}.
+         * The return value of {@code -1} guarantees that this field does not
+         * represent any corresponding constant in {@code Calendar}.
+         *
+         * @implSpec The default implementation always returns {@code -1} if it does
+         * not represent any corresponding constant in {@code Calendar}.
          *
          * @return Calendar constant for this field
          * @see java.util.Calendar

From 66d90d5d9f8041c3a7a3f27febf83120bd1fcd4b Mon Sep 17 00:00:00 2001
From: Justin Lu 
Date: Fri, 20 Oct 2023 17:38:10 +0000
Subject: [PATCH 050/124] 8318107: Un-ProblemList LocaleProvidersRun and
 CalendarDataRegression

Reviewed-by: naoto
---
 test/jdk/ProblemList.txt | 2 --
 1 file changed, 2 deletions(-)

diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt
index 233bf26dc70..af5642f21c1 100644
--- a/test/jdk/ProblemList.txt
+++ b/test/jdk/ProblemList.txt
@@ -724,8 +724,6 @@ com/sun/jdi/InvokeHangTest.java                                 8218463 linux-al
 
 # jdk_util
 
-java/util/Locale/LocaleProvidersRun.java                        8268379 macosx-x64
-sun/util/locale/provider/CalendarDataRegression.java            8268379 macosx-x64
 java/util/concurrent/forkjoin/AsyncShutdownNow.java             8286352 linux-all,windows-x64
 java/util/concurrent/ExecutorService/CloseTest.java             8288899 macosx-aarch64
 

From d3ebb4a155be8ed93e79b6b58c645e861ec30267 Mon Sep 17 00:00:00 2001
From: Rajan Halade 
Date: Fri, 20 Oct 2023 18:25:09 +0000
Subject: [PATCH 051/124] 8317373: Add Telia Root CA v2

Reviewed-by: mullan
---
 .../share/data/cacerts/teliarootcav2          | 39 +++++++++++++++++++
 .../certification/CAInterop.java              | 14 +++++++
 .../security/lib/cacerts/VerifyCACerts.java   |  8 ++--
 3 files changed, 58 insertions(+), 3 deletions(-)
 create mode 100644 src/java.base/share/data/cacerts/teliarootcav2

diff --git a/src/java.base/share/data/cacerts/teliarootcav2 b/src/java.base/share/data/cacerts/teliarootcav2
new file mode 100644
index 00000000000..24ed624291f
--- /dev/null
+++ b/src/java.base/share/data/cacerts/teliarootcav2
@@ -0,0 +1,39 @@
+Owner: CN=Telia Root CA v2, O=Telia Finland Oyj, C=FI
+Issuer: CN=Telia Root CA v2, O=Telia Finland Oyj, C=FI
+Serial number: 1675f27d6fe7ae3e4acbe095b059e
+Valid from: Thu Nov 29 11:55:54 GMT 2018 until: Sun Nov 29 11:55:54 GMT 2043
+Signature algorithm name: SHA256withRSA
+Subject Public Key Algorithm: 4096-bit RSA key
+Version: 3
+-----BEGIN CERTIFICATE-----
+MIIFdDCCA1ygAwIBAgIPAWdfJ9b+euPkrL4JWwWeMA0GCSqGSIb3DQEBCwUAMEQx
+CzAJBgNVBAYTAkZJMRowGAYDVQQKDBFUZWxpYSBGaW5sYW5kIE95ajEZMBcGA1UE
+AwwQVGVsaWEgUm9vdCBDQSB2MjAeFw0xODExMjkxMTU1NTRaFw00MzExMjkxMTU1
+NTRaMEQxCzAJBgNVBAYTAkZJMRowGAYDVQQKDBFUZWxpYSBGaW5sYW5kIE95ajEZ
+MBcGA1UEAwwQVGVsaWEgUm9vdCBDQSB2MjCCAiIwDQYJKoZIhvcNAQEBBQADggIP
+ADCCAgoCggIBALLQPwe84nvQa5n44ndp586dpAO8gm2h/oFlH0wnrI4AuhZ76zBq
+AMCzdGh+sq/H1WKzej9Qyow2RCRj0jbpDIX2Q3bVTKFgcmfiKDOlyzG4OiIjNLh9
+vVYiQJ3q9HsDrWj8soFPmNB06o3lfc1jw6P23pLCWBnglrvFxKk9pXSW/q/5iaq9
+lRdU2HhE8Qx3FZLgmEKnpNaqIJLNwaCzlrI6hEKNfdWV5Nbb6WLEWLN5xYzTNTOD
+n3WhUidhOPFZPY5Q4L15POdslv5e2QJltI5c0BE0312/UqeBAMN/mUWZFdUXyApT
+7GPzmX3MaRKGwhfwAZ6/hLzRUssbkmbOpFPlob/E2wnW5olWK8jjfN7j/4nlNW4o
+6GwLI1GpJQXrSPjdscr6bAhR77cYbETKJuFzxokGgeWKrLDiKca5JLNrRBH0pUPC
+TEPlcDaMtjNXepUugqD0XBCzYYP2AgWGLnwtbNwDRm41k9V6lS/eINhbfpSQBGq6
+WT0EBXWdN6IOLj3rwaRSg/7Qa9RmjtzG6RJOHSpXqhC8fF6CfaamyfItufUXJ63R
+DolUK5X6wK0dmBR4M0KGCqlztft0DbcbMBnEWg4cJ7faGND/isgFuvGqHKI3t+ZI
+pEYslOqodmJHixBTB0hXbOKSTbauBcvcwUpej6w9GU7C7WB1K9vBykLVAgMBAAGj
+YzBhMB8GA1UdIwQYMBaAFHKs5DN5qkWH9v2sHZ7Wxy+G2CQ5MB0GA1UdDgQWBBRy
+rOQzeapFh/b9rB2e1scvhtgkOTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUw
+AwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAoDtZpwmUPjaE0n4vOaWWl/oRrfxn83EJ
+8rKJhGdEr7nv7ZbsnGTbMjBvZ5qsfl+yqwE2foH65IRe0qw24GtixX1LDoJt0nZi
+0f6X+J8wfBj5tFJ3gh1229MdqfDBmgC9bXXYfef6xzijnHDoRnkDry5023X4blMM
+A8iZGok1GTzTyVR8qPAs5m4HeW9q4ebqkYJpCh3DflminmtGFZhb069GHWLIzoBS
+SRE/yQQSwxN8PzuKlts8oB4KtItUsiRnDe+Cy748fdHif64W1lZYudogsYMVoe+K
+TTJvQS8TUoKU1xrBeKJR3Stwbbca+few4GeXVtt8YVMJAygCQMez2P2ccGrGKMOF
+6eLtGpOg3kuYooQ+BXcBlj37tCAPnHICehIv1aO6UXivKitEZU61/Qrowc15h2Er
+3oBXRb9n8ZuRXqWk7FlIEA04x7D6w0RtBPV4UBySllva9bguulvP5fBqnUsvWHMt
+Ty3EHD70sz+rFQ47GUGKpMFXEmZxTPpT41frYpUJnlTd0cI8Vzy9OK2YZLe4A5pT
+VmBds9hCG1xLEooc6+t9xnppxyd/pPiL8uSUZodL6ZQHCRJ5irLrdATczvREWeAW
+ysUsWNc8e89ihmpQfTU2Zqf7N+cox9jQraVplI/owd8k+BsHMYeB2F326CjYSlKA
+rBPuUBQemMc=
+-----END CERTIFICATE-----
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 2c6d787afad..dbdcb810c47 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
@@ -392,6 +392,16 @@
  * @run main/othervm -Djava.security.debug=certpath CAInterop affirmtrustpremiumeccca CRL
  */
 
+/*
+ * @test id=teliarootcav2
+ * @bug 8317373
+ * @summary Interoperability tests with Telia Root CA V2
+ * @library /test/lib
+ * @build jtreg.SkippedException ValidatePathWithURL CAInterop
+ * @run main/othervm -Djava.security.debug=certpath,ocsp CAInterop teliarootcav2 OCSP
+ * @run main/othervm -Djava.security.debug=certpath CAInterop teliarootcav2 CRL
+ */
+
 /**
  * Collection of certificate validation tests for interoperability with external CAs
  */
@@ -533,6 +543,10 @@ private CATestURLs getTestURLs(String alias) {
                     new CATestURLs("https://validpremiumecc.affirmtrust.com",
                             "https://revokedpremiumecc.affirmtrust.com");
 
+            case "teliarootcav2" ->
+                    new CATestURLs("https://juolukka.cover.telia.fi:10600",
+                            "https://juolukka.cover.telia.fi:10601");
+
             default -> throw new RuntimeException("No test setup found for: " + alias);
         };
     }
diff --git a/test/jdk/sun/security/lib/cacerts/VerifyCACerts.java b/test/jdk/sun/security/lib/cacerts/VerifyCACerts.java
index edd34c2e3a5..4cfe8aa9b88 100644
--- a/test/jdk/sun/security/lib/cacerts/VerifyCACerts.java
+++ b/test/jdk/sun/security/lib/cacerts/VerifyCACerts.java
@@ -28,7 +28,7 @@
  *      8209452 8209506 8210432 8195793 8216577 8222089 8222133 8222137 8222136
  *      8223499 8225392 8232019 8234245 8233223 8225068 8225069 8243321 8243320
  *      8243559 8225072 8258630 8259312 8256421 8225081 8225082 8225083 8245654
- *      8305975 8304760 8307134 8295894 8314960
+ *      8305975 8304760 8307134 8295894 8314960 8317373
  * @summary Check root CA entries in cacerts file
  */
 import java.io.ByteArrayInputStream;
@@ -47,12 +47,12 @@ public class VerifyCACerts {
             + File.separator + "security" + File.separator + "cacerts";
 
     // The numbers of certs now.
-    private static final int COUNT = 97;
+    private static final int COUNT = 98;
 
     // 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
-            = "35:5B:BF:02:F8:3E:34:0D:72:01:6C:EB:10:90:CA:A1:DD:B5:01:EF:D8:0C:5B:26:F5:EF:C5:C5:4B:9D:61:3E";
+            = "B3:2E:91:45:13:9B:CE:AC:65:58:DC:E2:8D:CB:35:3F:44:F5:59:AC:64:35:C0:DE:9F:2D:97:3B:4E:C0:E4:3E";
 
     // Hex formatter to upper case with ":" delimiter
     private static final HexFormat HEX = HexFormat.ofDelimiter(":").withUpperCase();
@@ -255,6 +255,8 @@ public class VerifyCACerts {
                     "34:9D:FA:40:58:C5:E2:63:12:3B:39:8A:E7:95:57:3C:4E:13:13:C8:3F:E6:8F:93:55:6C:D5:E8:03:1B:3C:7D");
             put("certignarootca [jdk]",
                     "D4:8D:3D:23:EE:DB:50:A4:59:E5:51:97:60:1C:27:77:4B:9D:7B:18:C9:4D:5A:05:95:11:A1:02:50:B9:31:68");
+            put("teliarootcav2 [jdk]",
+                    "24:2B:69:74:2F:CB:1E:5B:2A:BF:98:89:8B:94:57:21:87:54:4E:5B:4D:99:11:78:65:73:62:1F:6A:74:B8:2C");
         }
     };
 

From 77b2394c46bd304ffc0658cb758d971f1f2940b6 Mon Sep 17 00:00:00 2001
From: Mikhailo Seledtsov 
Date: Fri, 20 Oct 2023 19:25:43 +0000
Subject: [PATCH 052/124] 8318482: problemlist
 compiler/codecache/CheckLargePages.java on Linux-x64 until JDK-8317831 is
 fixed

Reviewed-by: lmesnik
---
 test/hotspot/jtreg/ProblemList.txt | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt
index d2f024e193b..8973b094b4a 100644
--- a/test/hotspot/jtreg/ProblemList.txt
+++ b/test/hotspot/jtreg/ProblemList.txt
@@ -75,6 +75,8 @@ compiler/jvmci/TestUncaughtErrorInCompileMethod.java 8309073 generic-all
 
 compiler/sharedstubs/SharedTrampolineTest.java 8318455 generic-all
 
+compiler/codecache/CheckLargePages.java 8317831 linux-x64
+
 #############################################################################
 
 # :hotspot_gc

From a1a62d9964393533eeab269d1f405c8f0db1e900 Mon Sep 17 00:00:00 2001
From: Brian Burkhalter 
Date: Fri, 20 Oct 2023 21:12:28 +0000
Subject: [PATCH 053/124] 8306308: (ch) Writer created by Channels::newWriter
 may lose data

Reviewed-by: djelinski, alanb
---
 .../classes/java/nio/channels/Channels.java   |   4 +-
 .../classes/sun/nio/cs/StreamEncoder.java     |  46 +++-----
 .../java/nio/channels/Channels/NewWriter.java | 102 ++++++++++++++++++
 3 files changed, 117 insertions(+), 35 deletions(-)
 create mode 100644 test/jdk/java/nio/channels/Channels/NewWriter.java

diff --git a/src/java.base/share/classes/java/nio/channels/Channels.java b/src/java.base/share/classes/java/nio/channels/Channels.java
index 80314d7447f..af3c6bdff73 100644
--- a/src/java.base/share/classes/java/nio/channels/Channels.java
+++ b/src/java.base/share/classes/java/nio/channels/Channels.java
@@ -541,7 +541,9 @@ public static Writer newWriter(WritableByteChannel ch,
                                    int minBufferCap)
     {
         Objects.requireNonNull(ch, "ch");
-        return StreamEncoder.forEncoder(ch, enc.reset(), minBufferCap);
+        Objects.requireNonNull(enc, "enc");
+        OutputStream out = newOutputStream(ch);
+        return StreamEncoder.forOutputStreamWriter(out, enc.reset());
     }
 
     /**
diff --git a/src/java.base/share/classes/sun/nio/cs/StreamEncoder.java b/src/java.base/share/classes/sun/nio/cs/StreamEncoder.java
index f922a787466..3a82030121a 100644
--- a/src/java.base/share/classes/sun/nio/cs/StreamEncoder.java
+++ b/src/java.base/share/classes/sun/nio/cs/StreamEncoder.java
@@ -31,7 +31,6 @@
 import java.io.Writer;
 import java.nio.ByteBuffer;
 import java.nio.CharBuffer;
-import java.nio.channels.WritableByteChannel;
 import java.nio.charset.Charset;
 import java.nio.charset.CharsetEncoder;
 import java.nio.charset.CoderResult;
@@ -79,17 +78,12 @@ public static StreamEncoder forOutputStreamWriter(OutputStream out,
         return new StreamEncoder(out, lock, enc);
     }
 
-
-    // Factory for java.nio.channels.Channels.newWriter
-
-    public static StreamEncoder forEncoder(WritableByteChannel ch,
-                                           CharsetEncoder enc,
-                                           int minBufferCap)
+    public static StreamEncoder forOutputStreamWriter(OutputStream out,
+                                                      CharsetEncoder enc)
     {
-        return new StreamEncoder(ch, enc, minBufferCap);
+        return new StreamEncoder(out, enc);
     }
 
-
     // -- Public methods corresponding to those in OutputStreamWriter --
 
     // All synchronization and state/argument checking is done in these public
@@ -252,9 +246,7 @@ private boolean isOpen() {
     private ByteBuffer bb;
     private final int maxBufferCapacity;
 
-    // Exactly one of these is non-null
     private final OutputStream out;
-    private final WritableByteChannel ch;
 
     // Leftover first char in a surrogate pair
     private boolean haveLeftoverChar = false;
@@ -271,7 +263,6 @@ private StreamEncoder(OutputStream out, Object lock, Charset cs) {
     private StreamEncoder(OutputStream out, Object lock, CharsetEncoder enc) {
         super(lock);
         this.out = out;
-        this.ch = null;
         this.cs = enc.charset();
         this.encoder = enc;
 
@@ -279,19 +270,14 @@ private StreamEncoder(OutputStream out, Object lock, CharsetEncoder enc) {
         this.maxBufferCapacity = MAX_BYTE_BUFFER_CAPACITY;
     }
 
-    private StreamEncoder(WritableByteChannel ch, CharsetEncoder enc, int mbc) {
-        this.out = null;
-        this.ch = ch;
+    private StreamEncoder(OutputStream out, CharsetEncoder enc) {
+        super();
+        this.out = out;
         this.cs = enc.charset();
         this.encoder = enc;
 
-        if (mbc > 0) {
-            this.bb = ByteBuffer.allocate(mbc);
-            this.maxBufferCapacity = mbc;
-        } else {
-            this.bb = ByteBuffer.allocate(INITIAL_BYTE_BUFFER_CAPACITY);
-            this.maxBufferCapacity = MAX_BYTE_BUFFER_CAPACITY;
-        }
+        this.bb = ByteBuffer.allocate(INITIAL_BYTE_BUFFER_CAPACITY);
+        this.maxBufferCapacity = MAX_BYTE_BUFFER_CAPACITY;
     }
 
     private void writeBytes() throws IOException {
@@ -302,12 +288,7 @@ private void writeBytes() throws IOException {
         int rem = (pos <= lim ? lim - pos : 0);
 
         if (rem > 0) {
-            if (ch != null) {
-                int wc = ch.write(bb);
-                assert wc == rem : rem;
-            } else {
-                out.write(bb.array(), bb.arrayOffset() + pos, rem);
-            }
+            out.write(bb.array(), bb.arrayOffset() + pos, rem);
         }
         bb.clear();
     }
@@ -408,13 +389,11 @@ void implFlushBuffer() throws IOException {
 
     void implFlush() throws IOException {
         implFlushBuffer();
-        if (out != null) {
-            out.flush();
-        }
+        out.flush();
     }
 
     void implClose() throws IOException {
-        try (ch; out) {
+        try (out) {
             flushLeftoverChar(null, true);
             for (;;) {
                 CoderResult cr = encoder.flush(bb);
@@ -430,8 +409,7 @@ void implClose() throws IOException {
 
             if (bb.position() > 0)
                 writeBytes();
-            if (out != null)
-                out.flush();
+            out.flush();
         } catch (IOException x) {
             encoder.reset();
             throw x;
diff --git a/test/jdk/java/nio/channels/Channels/NewWriter.java b/test/jdk/java/nio/channels/Channels/NewWriter.java
new file mode 100644
index 00000000000..95445f0b84a
--- /dev/null
+++ b/test/jdk/java/nio/channels/Channels/NewWriter.java
@@ -0,0 +1,102 @@
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+import java.io.Writer;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.ServerSocket;
+import java.net.StandardSocketOptions;
+import java.nio.ByteBuffer;
+import java.nio.channels.Channels;
+import java.nio.channels.IllegalBlockingModeException;
+import java.nio.channels.SocketChannel;
+import java.nio.channels.WritableByteChannel;
+import java.nio.charset.StandardCharsets;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+/**
+ * @test
+ * @bug 8295797
+ * @summary Test behavior of Channels.newWriter for WritableByteChannels
+ * @run junit NewWriter
+ */
+public class NewWriter {
+    private static final String STRING = "test";
+    private static final int COUNT = 5;
+    private static final int EXPECTED = COUNT*STRING.length();
+    private int actual = 0;
+
+    @Test
+    public void oneByteChannel() throws IOException {
+        try (Writer writer = Channels.newWriter(new WritableByteChannel() {
+            @Override
+            public int write(ByteBuffer src) {
+                System.out.print((char) src.get());
+                actual++;
+                return 1;
+            }
+
+            @Override
+            public boolean isOpen() {
+                return true;
+            }
+
+            @Override
+            public void close() {
+            }
+        }, StandardCharsets.UTF_8)) {
+            for (int i = 1; i <= COUNT; i++) {
+                writer.write(STRING);
+                writer.flush();
+                System.out.println(i);
+            }
+        }
+        assertEquals(EXPECTED, actual);
+    }
+
+    @Test
+    public void socketChannel() throws IOException {
+        Throwable thrown = assertThrows(IllegalBlockingModeException.class,
+        () -> {
+            try (ServerSocket ss = new ServerSocket();
+                 SocketChannel sc = SocketChannel.open()) {
+
+                InetAddress lb = InetAddress.getLoopbackAddress();
+                ss.bind(new InetSocketAddress(lb, 0));
+                sc.connect(ss.getLocalSocketAddress());
+                sc.configureBlocking(false);
+                sc.setOption(StandardSocketOptions.SO_SNDBUF, 8192);
+                try (Writer writer = Channels.newWriter(sc,
+                    StandardCharsets.UTF_8)) {
+                    for (int i = 1; i < Integer.MAX_VALUE; i++) {
+                        writer.write("test" + i);
+                    }
+                }
+            }
+        });
+    }
+}

From af2f4bfa837a18964e00de1e3077119cfa4c68e0 Mon Sep 17 00:00:00 2001
From: "Daniel D. Daugherty" 
Date: Fri, 20 Oct 2023 21:33:26 +0000
Subject: [PATCH 054/124] 8318622: ProblemList gc/cslocker/TestCSLocker.java on
 linux-x64 in Xcomp mode

Reviewed-by: naoto
---
 test/hotspot/jtreg/ProblemList-Xcomp.txt | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/test/hotspot/jtreg/ProblemList-Xcomp.txt b/test/hotspot/jtreg/ProblemList-Xcomp.txt
index 646c0e1905d..86c31456716 100644
--- a/test/hotspot/jtreg/ProblemList-Xcomp.txt
+++ b/test/hotspot/jtreg/ProblemList-Xcomp.txt
@@ -46,3 +46,5 @@ vmTestbase/nsk/jvmti/scenarios/capability/CM03/cm03t001/TestDescription.java 829
 
 gc/arguments/TestNewSizeFlags.java 8299116 macosx-aarch64
 compiler/interpreter/TestVerifyStackAfterDeopt.java 8316392 macosx-aarch64
+
+gc/cslocker/TestCSLocker.java 8310480 linux-x64

From 4cf195f00cae97dea6ec25751f56231530fb6aee Mon Sep 17 00:00:00 2001
From: Leonid Mesnik 
Date: Sat, 21 Oct 2023 03:35:52 +0000
Subject: [PATCH 055/124] 8318573: The nsk.share.jpda.SocketConnection should
 fail if socket was closed.

Reviewed-by: sspitsyn, cjplummer
---
 .../jtreg/vmTestbase/nsk/share/jpda/SocketConnection.java     | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/jpda/SocketConnection.java b/test/hotspot/jtreg/vmTestbase/nsk/share/jpda/SocketConnection.java
index e400b88e64b..cc724a1534b 100644
--- a/test/hotspot/jtreg/vmTestbase/nsk/share/jpda/SocketConnection.java
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jpda/SocketConnection.java
@@ -517,7 +517,9 @@ public Object readObject() {
         try {
             return doReadObject();
         } catch (EOFException e) {
-            return null;
+            e.printStackTrace(logger.getOutStream());
+            throw new Failure("Caught EOFException while reading an object from " + name + " connection."
+                    + " Check if debuggee process exited prematurely (crashed or killed).\n\t");
         } catch (Exception e) {
             e.printStackTrace(logger.getOutStream());
             throw new Failure("Caught Exception while reading an object from " + name + " connection:\n\t" + e);

From a876beb63d5d509b80366139ae4c6abe502efe1e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Laurent=20Bourg=C3=A8s?= 
Date: Sat, 21 Oct 2023 09:12:08 +0000
Subject: [PATCH 056/124] 8316741: BasicStroke.createStrokedShape miter-limits
 failing on small shapes

Reviewed-by: prr, dnguyen
---
 .../classes/sun/java2d/marlin/Renderer.java   |   1 +
 .../sun/java2d/marlin/RendererContext.java    |   3 +
 .../classes/sun/java2d/marlin/Stroker.java    |  45 +++++---
 .../classes/sun/java2d/marlin/Version.java    |   2 +-
 .../marlin/TestCreateStrokedShapeJoins.java   | 104 ++++++++++++++++++
 5 files changed, 136 insertions(+), 19 deletions(-)
 create mode 100644 test/jdk/sun/java2d/marlin/TestCreateStrokedShapeJoins.java

diff --git a/src/java.desktop/share/classes/sun/java2d/marlin/Renderer.java b/src/java.desktop/share/classes/sun/java2d/marlin/Renderer.java
index 54d80f6033b..a8a342af262 100644
--- a/src/java.desktop/share/classes/sun/java2d/marlin/Renderer.java
+++ b/src/java.desktop/share/classes/sun/java2d/marlin/Renderer.java
@@ -557,6 +557,7 @@ Renderer init(final int pix_boundsX, final int pix_boundsY,
                   final int pix_boundsWidth, final int pix_boundsHeight,
                   final int windingRule)
     {
+        this.rdrCtx.doRender = true;
         this.windingRule = windingRule;
 
         // bounds as half-open intervals: minX <= x < maxX and minY <= y < maxY
diff --git a/src/java.desktop/share/classes/sun/java2d/marlin/RendererContext.java b/src/java.desktop/share/classes/sun/java2d/marlin/RendererContext.java
index d599c7d035f..b258f4e25d8 100644
--- a/src/java.desktop/share/classes/sun/java2d/marlin/RendererContext.java
+++ b/src/java.desktop/share/classes/sun/java2d/marlin/RendererContext.java
@@ -78,6 +78,8 @@ static RendererContext createContext() {
     final MarlinCache cache;
     // flag indicating the shape is stroked (1) or filled (0)
     int stroking = 0;
+    // flag indicating to render the shape
+    boolean doRender = false;
     // flag indicating to clip the shape
     boolean doClip = false;
     // flag indicating if the path is closed or not (in advance) to handle properly caps
@@ -169,6 +171,7 @@ void dispose() {
             stats.totalOffHeap = 0L;
         }
         stroking   = 0;
+        doRender   = false;
         doClip     = false;
         closedPath = false;
         clipInvScale = 0.0d;
diff --git a/src/java.desktop/share/classes/sun/java2d/marlin/Stroker.java b/src/java.desktop/share/classes/sun/java2d/marlin/Stroker.java
index eb8969f2d71..59f93ed7d6d 100644
--- a/src/java.desktop/share/classes/sun/java2d/marlin/Stroker.java
+++ b/src/java.desktop/share/classes/sun/java2d/marlin/Stroker.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 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
@@ -170,25 +170,34 @@ Stroker init(final DPathConsumer2D pc2d,
             miterScaledLimit = miterLimit * lineWidth2;
             this.miterLimitSq = miterScaledLimit * miterScaledLimit;
 
-            final double limitMin = ((this.rdrCtx.clipInvScale == 0.0d) ? JOIN_ERROR
-                    : (JOIN_ERROR * this.rdrCtx.clipInvScale))
-                    + lineWidth2;
-
-            this.joinLimitMinSq = limitMin * limitMin;
+            if (rdrCtx.doRender) {
+                final double limitMin = ((this.rdrCtx.clipInvScale == 0.0d) ? JOIN_ERROR
+                        : (JOIN_ERROR * this.rdrCtx.clipInvScale))
+                        + lineWidth2;
 
+                this.joinLimitMinSq = limitMin * limitMin;
+            } else {
+                // createStrokedShape(): disable limit checks:
+                this.joinLimitMinSq = 0.0;
+            }
         } else if (joinStyle == JOIN_ROUND) {
-            // chord:  s = 2 r * sin( phi / 2)
-            // height: h = 2 r * sin( phi / 4)^2
-            // small angles (phi < 90):
-            // h = s^2 / (8 r)
-            // so s^2 = (8 h * r)
-
-            // height max (note ROUND_JOIN_ERROR = 8 * JOIN_ERROR)
-            final double limitMin = ((this.rdrCtx.clipInvScale == 0.0d) ? ROUND_JOIN_ERROR
-                    : (ROUND_JOIN_ERROR * this.rdrCtx.clipInvScale));
-
-            // chord limit (s^2):
-            this.joinLimitMinSq = limitMin * this.lineWidth2;
+            if (rdrCtx.doRender) {
+                // chord:  s = 2 r * sin( phi / 2)
+                // height: h = 2 r * sin( phi / 4)^2
+                // small angles (phi < 90):
+                // h = s^2 / (8 r)
+                // so s^2 = (8 h * r)
+
+                // height max (note ROUND_JOIN_ERROR = 8 * JOIN_ERROR)
+                final double limitMin = ((this.rdrCtx.clipInvScale == 0.0d) ? ROUND_JOIN_ERROR
+                        : (ROUND_JOIN_ERROR * this.rdrCtx.clipInvScale));
+
+                // chord limit (s^2):
+                this.joinLimitMinSq = limitMin * this.lineWidth2;
+            } else {
+                // createStrokedShape(): disable limit checks:
+                this.joinLimitMinSq = 0.0;
+            }
         }
         this.prev = CLOSE;
 
diff --git a/src/java.desktop/share/classes/sun/java2d/marlin/Version.java b/src/java.desktop/share/classes/sun/java2d/marlin/Version.java
index a9ecec5863f..76bdbe59338 100644
--- a/src/java.desktop/share/classes/sun/java2d/marlin/Version.java
+++ b/src/java.desktop/share/classes/sun/java2d/marlin/Version.java
@@ -27,7 +27,7 @@
 
 public final class Version {
 
-    private static final String VERSION = "marlin-0.9.4.6-Unsafe-OpenJDK";
+    private static final String VERSION = "marlin-0.9.4.6.1-Unsafe-OpenJDK";
 
     public static String getVersion() {
         return VERSION;
diff --git a/test/jdk/sun/java2d/marlin/TestCreateStrokedShapeJoins.java b/test/jdk/sun/java2d/marlin/TestCreateStrokedShapeJoins.java
new file mode 100644
index 00000000000..77672b47ba7
--- /dev/null
+++ b/test/jdk/sun/java2d/marlin/TestCreateStrokedShapeJoins.java
@@ -0,0 +1,104 @@
+/*
+ * 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.
+ */
+
+import java.io.*;
+import java.awt.*;
+import java.awt.image.*;
+import java.awt.geom.*;
+import java.util.Arrays;
+import javax.imageio.*;
+
+/**
+ * @test
+ * @bug 8316741
+ * @summary Verifies that Marlin renderer's Stroker generates properly joins
+ * in createStrokedShape()
+ * @run main TestCreateStrokedShapeJoins
+ */
+public class TestCreateStrokedShapeJoins {
+
+    static final boolean SAVE_IMAGE = false;
+
+    private final static int W = 200;
+
+    private final static int[] REF_COUNTS = new int[] {4561, 4790, 5499};
+
+    public static void main(String[] args) throws Exception {
+        final int[] test = new int[] {
+                test(BasicStroke.JOIN_BEVEL),
+                test(BasicStroke.JOIN_ROUND),
+                test(BasicStroke.JOIN_MITER)
+        };
+
+        System.out.println("test: " + Arrays.toString(test));
+        System.out.println("ref:  " + Arrays.toString(REF_COUNTS));
+
+        // check results:
+        for (int i = 0; i < REF_COUNTS.length; i++) {
+            if (test[i] != REF_COUNTS[i]) {
+                throw new RuntimeException("Invalid test[" + i + "]: " + test[i] + " != " + REF_COUNTS[i]);
+            }
+        }
+    }
+
+    private static int test(int join) throws Exception {
+        final BufferedImage image = new BufferedImage(W, W, BufferedImage.TYPE_INT_ARGB);
+        final Graphics2D g = image.createGraphics();
+        try {
+            g.setPaint(Color.BLACK);
+            g.fillRect(0, 0, W, W);
+            g.setPaint(Color.WHITE);
+            g.setTransform(new AffineTransform(W, 0, 0, W, 0, 0));
+
+            final BasicStroke stroke = new BasicStroke(0.15f, 0, join, 10);
+
+            final Path2D p = new Path2D.Float();
+            p.moveTo(0.95f, 0.6f);
+            p.lineTo(0.5f, 0.5f);
+            p.lineTo(0.95f, 0.4f);
+
+            final Shape outline = stroke.createStrokedShape(p);
+            g.fill(outline);
+        } finally {
+            g.dispose();
+        }
+        if (SAVE_IMAGE) {
+            final File file = new File("TestCreateStrokedShapeJoins-" + join + ".png");
+            System.out.println("Writing " + file.getAbsolutePath());
+            ImageIO.write(image, "png", file);
+        }
+        int count = 0;
+
+        for (int y = 0; y < W; y++) {
+            for (int x = 0; x < W; x++) {
+                final int rgb = image.getRGB(x, y);
+                final int b = rgb & 0xFF;
+
+                if (b != 0) {
+                    count++;
+                }
+            }
+        }
+        return count;
+    }
+}

From ecd25e7d6f9d69f9dbdbff0a4a9b9d6b19288593 Mon Sep 17 00:00:00 2001
From: Ioi Lam 
Date: Sat, 21 Oct 2023 15:43:36 +0000
Subject: [PATCH 057/124] 8318484: Initial version of cdsConfig.hpp

Reviewed-by: dholmes, ccheung, sspitsyn
---
 src/hotspot/share/cds/archiveHeapWriter.cpp   |  3 +-
 src/hotspot/share/cds/archiveUtils.cpp        |  3 +-
 src/hotspot/share/cds/cdsConfig.cpp           | 46 +++++++++++++++++++
 src/hotspot/share/cds/cdsConfig.hpp           | 42 +++++++++++++++++
 src/hotspot/share/cds/cppVtables.cpp          |  3 +-
 src/hotspot/share/cds/filemap.cpp             | 17 +++----
 src/hotspot/share/cds/heapShared.cpp          | 27 +++++------
 src/hotspot/share/cds/metaspaceShared.cpp     | 17 ++++---
 .../share/classfile/classFileParser.cpp       |  5 +-
 src/hotspot/share/classfile/classLoader.cpp   | 19 ++++----
 .../share/classfile/classLoader.inline.hpp    |  6 +--
 .../share/classfile/classLoaderExt.cpp        |  7 +--
 .../share/classfile/compactHashtable.cpp      |  5 +-
 .../share/classfile/defaultMethods.cpp        |  4 +-
 src/hotspot/share/classfile/dictionary.cpp    |  4 +-
 src/hotspot/share/classfile/javaClasses.cpp   |  5 +-
 src/hotspot/share/classfile/klassFactory.cpp  |  4 +-
 src/hotspot/share/classfile/stringTable.cpp   |  3 +-
 .../share/classfile/systemDictionary.cpp      |  3 +-
 .../classfile/systemDictionaryShared.cpp      | 31 +++++++------
 .../share/classfile/verificationType.cpp      |  4 +-
 src/hotspot/share/gc/shared/collectedHeap.cpp |  3 +-
 src/hotspot/share/interpreter/rewriter.cpp    |  4 +-
 .../interpreter/zero/bytecodeInterpreter.cpp  |  4 +-
 .../share/jfr/recorder/jfrRecorder.cpp        |  5 +-
 src/hotspot/share/memory/universe.cpp         |  3 +-
 src/hotspot/share/oops/constantPool.cpp       |  3 +-
 src/hotspot/share/oops/cpCache.cpp            |  5 +-
 src/hotspot/share/oops/instanceKlass.cpp      |  5 +-
 src/hotspot/share/oops/klass.cpp              | 12 ++---
 src/hotspot/share/oops/method.cpp             |  5 +-
 src/hotspot/share/oops/oop.cpp                |  3 +-
 src/hotspot/share/prims/jvm.cpp               |  5 +-
 src/hotspot/share/prims/jvmtiAgent.cpp        |  5 +-
 src/hotspot/share/runtime/arguments.cpp       |  5 +-
 src/hotspot/share/runtime/arguments.hpp       |  6 ---
 36 files changed, 220 insertions(+), 111 deletions(-)
 create mode 100644 src/hotspot/share/cds/cdsConfig.cpp
 create mode 100644 src/hotspot/share/cds/cdsConfig.hpp

diff --git a/src/hotspot/share/cds/archiveHeapWriter.cpp b/src/hotspot/share/cds/archiveHeapWriter.cpp
index 17f6e831dc0..3e7d42dd8f1 100644
--- a/src/hotspot/share/cds/archiveHeapWriter.cpp
+++ b/src/hotspot/share/cds/archiveHeapWriter.cpp
@@ -24,6 +24,7 @@
 
 #include "precompiled.hpp"
 #include "cds/archiveHeapWriter.hpp"
+#include "cds/cdsConfig.hpp"
 #include "cds/filemap.hpp"
 #include "cds/heapShared.hpp"
 #include "classfile/systemDictionary.hpp"
@@ -138,7 +139,7 @@ oop ArchiveHeapWriter::requested_obj_from_buffer_offset(size_t offset) {
 }
 
 oop ArchiveHeapWriter::source_obj_to_requested_obj(oop src_obj) {
-  assert(DumpSharedSpaces, "dump-time only");
+  assert(CDSConfig::is_dumping_heap(), "dump-time only");
   HeapShared::CachedOopInfo* p = HeapShared::archived_object_cache()->get(src_obj);
   if (p != nullptr) {
     return requested_obj_from_buffer_offset(p->buffer_offset());
diff --git a/src/hotspot/share/cds/archiveUtils.cpp b/src/hotspot/share/cds/archiveUtils.cpp
index 7f5a7f1d38c..b14dfc8c33e 100644
--- a/src/hotspot/share/cds/archiveUtils.cpp
+++ b/src/hotspot/share/cds/archiveUtils.cpp
@@ -26,6 +26,7 @@
 #include "cds/archiveBuilder.hpp"
 #include "cds/archiveHeapLoader.inline.hpp"
 #include "cds/archiveUtils.hpp"
+#include "cds/cdsConfig.hpp"
 #include "cds/classListParser.hpp"
 #include "cds/classListWriter.hpp"
 #include "cds/dynamicArchive.hpp"
@@ -173,7 +174,7 @@ char* DumpRegion::expand_top_to(char* newtop) {
 }
 
 void DumpRegion::commit_to(char* newtop) {
-  Arguments::assert_is_dumping_archive();
+  assert(CDSConfig::is_dumping_archive(), "sanity");
   char* base = _rs->base();
   size_t need_committed_size = newtop - base;
   size_t has_committed_size = _vs->committed_size();
diff --git a/src/hotspot/share/cds/cdsConfig.cpp b/src/hotspot/share/cds/cdsConfig.cpp
new file mode 100644
index 00000000000..284b27d62a4
--- /dev/null
+++ b/src/hotspot/share/cds/cdsConfig.cpp
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "cds/cdsConfig.hpp"
+#include "cds/heapShared.hpp"
+
+bool CDSConfig::is_dumping_archive() {
+  return is_dumping_static_archive() || is_dumping_dynamic_archive();
+}
+
+bool CDSConfig::is_dumping_static_archive() {
+  return DumpSharedSpaces;
+}
+
+bool CDSConfig::is_dumping_dynamic_archive() {
+  return DynamicDumpSharedSpaces;
+}
+
+#if INCLUDE_CDS_JAVA_HEAP
+bool CDSConfig::is_dumping_heap() {
+  // heap dump is not supported in dynamic dump
+  return is_dumping_static_archive() && HeapShared::can_write();
+}
+#endif // INCLUDE_CDS_JAVA_HEAP
diff --git a/src/hotspot/share/cds/cdsConfig.hpp b/src/hotspot/share/cds/cdsConfig.hpp
new file mode 100644
index 00000000000..30eb35a2e57
--- /dev/null
+++ b/src/hotspot/share/cds/cdsConfig.hpp
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ *
+ */
+
+#ifndef SHARE_CDS_CDSCONFIG_HPP
+#define SHARE_CDS_CDSCONFIG_HPP
+
+#include "memory/allStatic.hpp"
+#include "utilities/macros.hpp"
+
+class CDSConfig : public AllStatic {
+public:
+  // Basic CDS features
+  static bool      is_dumping_archive()                      NOT_CDS_RETURN_(false);
+  static bool      is_dumping_static_archive()               NOT_CDS_RETURN_(false);
+  static bool      is_dumping_dynamic_archive()              NOT_CDS_RETURN_(false);
+
+  // CDS archived heap
+  static bool      is_dumping_heap()                         NOT_CDS_JAVA_HEAP_RETURN_(false);
+};
+
+#endif // SHARE_CDS_CDSCONFIG_HPP
diff --git a/src/hotspot/share/cds/cppVtables.cpp b/src/hotspot/share/cds/cppVtables.cpp
index 94ec7cd9f19..e737052621e 100644
--- a/src/hotspot/share/cds/cppVtables.cpp
+++ b/src/hotspot/share/cds/cppVtables.cpp
@@ -25,6 +25,7 @@
 #include "precompiled.hpp"
 #include "cds/archiveUtils.hpp"
 #include "cds/archiveBuilder.hpp"
+#include "cds/cdsConfig.hpp"
 #include "cds/cppVtables.hpp"
 #include "cds/metaspaceShared.hpp"
 #include "logging/log.hpp"
@@ -240,7 +241,7 @@ intptr_t* CppVtables::get_archived_vtable(MetaspaceObj::Type msotype, address ob
     _orig_cpp_vtptrs_inited = true;
   }
 
-  Arguments::assert_is_dumping_archive();
+  assert(CDSConfig::is_dumping_archive(), "sanity");
   int kind = -1;
   switch (msotype) {
   case MetaspaceObj::SymbolType:
diff --git a/src/hotspot/share/cds/filemap.cpp b/src/hotspot/share/cds/filemap.cpp
index 61a7e845bae..daab34857c0 100644
--- a/src/hotspot/share/cds/filemap.cpp
+++ b/src/hotspot/share/cds/filemap.cpp
@@ -28,6 +28,7 @@
 #include "cds/archiveHeapWriter.hpp"
 #include "cds/archiveUtils.inline.hpp"
 #include "cds/cds_globals.hpp"
+#include "cds/cdsConfig.hpp"
 #include "cds/dynamicArchive.hpp"
 #include "cds/filemap.hpp"
 #include "cds/heapShared.hpp"
@@ -203,7 +204,7 @@ void FileMapHeader::populate(FileMapInfo *info, size_t core_region_alignment,
   _core_region_alignment = core_region_alignment;
   _obj_alignment = ObjectAlignmentInBytes;
   _compact_strings = CompactStrings;
-  if (DumpSharedSpaces && HeapShared::can_write()) {
+  if (CDSConfig::is_dumping_heap()) {
     _narrow_oop_mode = CompressedOops::mode();
     _narrow_oop_base = CompressedOops::base();
     _narrow_oop_shift = CompressedOops::shift();
@@ -302,7 +303,7 @@ void SharedClassPathEntry::init_as_non_existent(const char* path, TRAPS) {
 void SharedClassPathEntry::init(bool is_modules_image,
                                 bool is_module_path,
                                 ClassPathEntry* cpe, TRAPS) {
-  Arguments::assert_is_dumping_archive();
+  assert(CDSConfig::is_dumping_archive(), "sanity");
   _timestamp = 0;
   _filesize  = 0;
   _from_class_path_attr = false;
@@ -462,7 +463,7 @@ void SharedPathTable::dumptime_init(ClassLoaderData* loader_data, TRAPS) {
 }
 
 void FileMapInfo::allocate_shared_path_table(TRAPS) {
-  Arguments::assert_is_dumping_archive();
+  assert(CDSConfig::is_dumping_archive(), "sanity");
 
   ClassLoaderData* loader_data = ClassLoaderData::the_null_class_loader_data();
   ClassPathEntry* jrt = ClassLoader::get_jrt_entry();
@@ -509,7 +510,7 @@ int FileMapInfo::add_shared_classpaths(int i, const char* which, ClassPathEntry
 }
 
 void FileMapInfo::check_nonempty_dir_in_shared_path_table() {
-  Arguments::assert_is_dumping_archive();
+  assert(CDSConfig::is_dumping_archive(), "sanity");
 
   bool has_nonempty_dir = false;
 
@@ -536,7 +537,7 @@ void FileMapInfo::check_nonempty_dir_in_shared_path_table() {
 }
 
 void FileMapInfo::record_non_existent_class_path_entry(const char* path) {
-  Arguments::assert_is_dumping_archive();
+  assert(CDSConfig::is_dumping_archive(), "sanity");
   log_info(class, path)("non-existent Class-Path entry %s", path);
   if (_non_existent_class_paths == nullptr) {
     _non_existent_class_paths = new (mtClass) GrowableArray(10, mtClass);
@@ -545,7 +546,7 @@ void FileMapInfo::record_non_existent_class_path_entry(const char* path) {
 }
 
 int FileMapInfo::num_non_existent_class_paths() {
-  Arguments::assert_is_dumping_archive();
+  assert(CDSConfig::is_dumping_archive(), "sanity");
   if (_non_existent_class_paths != nullptr) {
     return _non_existent_class_paths->length();
   } else {
@@ -686,7 +687,7 @@ bool FileMapInfo::check_paths_existence(const char* paths) {
 }
 
 GrowableArray* FileMapInfo::create_dumptime_app_classpath_array() {
-  Arguments::assert_is_dumping_archive();
+  assert(CDSConfig::is_dumping_archive(), "sanity");
   GrowableArray* path_array = new GrowableArray(10);
   ClassPathEntry* cpe = ClassLoader::app_classpath_entries();
   while (cpe != nullptr) {
@@ -1508,7 +1509,7 @@ void FileMapRegion::print(outputStream* st, int region_index) {
 
 void FileMapInfo::write_region(int region, char* base, size_t size,
                                bool read_only, bool allow_exec) {
-  Arguments::assert_is_dumping_archive();
+  assert(CDSConfig::is_dumping_archive(), "sanity");
 
   FileMapRegion* r = region_at(region);
   char* requested_base;
diff --git a/src/hotspot/share/cds/heapShared.cpp b/src/hotspot/share/cds/heapShared.cpp
index 04fde9a31e3..5f5af09e65b 100644
--- a/src/hotspot/share/cds/heapShared.cpp
+++ b/src/hotspot/share/cds/heapShared.cpp
@@ -27,6 +27,7 @@
 #include "cds/archiveHeapLoader.hpp"
 #include "cds/archiveHeapWriter.hpp"
 #include "cds/archiveUtils.hpp"
+#include "cds/cdsConfig.hpp"
 #include "cds/cdsHeapVerifier.hpp"
 #include "cds/heapShared.hpp"
 #include "cds/metaspaceShared.hpp"
@@ -179,7 +180,7 @@ static void reset_states(oop obj, TRAPS) {
 }
 
 void HeapShared::reset_archived_object_states(TRAPS) {
-  assert(DumpSharedSpaces, "dump-time only");
+  assert(CDSConfig::is_dumping_heap(), "dump-time only");
   log_debug(cds)("Resetting platform loader");
   reset_states(SystemDictionary::java_platform_loader(), CHECK);
   log_debug(cds)("Resetting system loader");
@@ -206,12 +207,12 @@ void HeapShared::reset_archived_object_states(TRAPS) {
 HeapShared::ArchivedObjectCache* HeapShared::_archived_object_cache = nullptr;
 
 bool HeapShared::has_been_archived(oop obj) {
-  assert(DumpSharedSpaces, "dump-time only");
+  assert(CDSConfig::is_dumping_heap(), "dump-time only");
   return archived_object_cache()->get(obj) != nullptr;
 }
 
 int HeapShared::append_root(oop obj) {
-  assert(DumpSharedSpaces, "dump-time only");
+  assert(CDSConfig::is_dumping_heap(), "dump-time only");
 
   // No GC should happen since we aren't scanning _pending_roots.
   assert(Thread::current() == (Thread*)VMThread::vm_thread(), "should be in vm thread");
@@ -224,7 +225,7 @@ int HeapShared::append_root(oop obj) {
 }
 
 objArrayOop HeapShared::roots() {
-  if (DumpSharedSpaces) {
+  if (CDSConfig::is_dumping_heap()) {
     assert(Thread::current() == (Thread*)VMThread::vm_thread(), "should be in vm thread");
     if (!HeapShared::can_write()) {
       return nullptr;
@@ -241,7 +242,7 @@ objArrayOop HeapShared::roots() {
 // Returns an objArray that contains all the roots of the archived objects
 oop HeapShared::get_root(int index, bool clear) {
   assert(index >= 0, "sanity");
-  assert(!DumpSharedSpaces && UseSharedSpaces, "runtime only");
+  assert(!CDSConfig::is_dumping_heap() && UseSharedSpaces, "runtime only");
   assert(!_roots.is_empty(), "must have loaded shared heap");
   oop result = roots()->obj_at(index);
   if (clear) {
@@ -263,7 +264,7 @@ void HeapShared::clear_root(int index) {
 }
 
 bool HeapShared::archive_object(oop obj) {
-  assert(DumpSharedSpaces, "dump-time only");
+  assert(CDSConfig::is_dumping_heap(), "dump-time only");
 
   assert(!obj->is_stackChunk(), "do not archive stack chunks");
   if (has_been_archived(obj)) {
@@ -599,7 +600,7 @@ HeapShared::RunTimeKlassSubGraphInfoTable   HeapShared::_run_time_subgraph_info_
 // there is no existing one for k. The subgraph_info records the "buffered"
 // address of the class.
 KlassSubGraphInfo* HeapShared::init_subgraph_info(Klass* k, bool is_full_module_graph) {
-  assert(DumpSharedSpaces, "dump time only");
+  assert(CDSConfig::is_dumping_heap(), "dump time only");
   bool created;
   Klass* buffered_k = ArchiveBuilder::get_buffered_klass(k);
   KlassSubGraphInfo* info =
@@ -610,7 +611,7 @@ KlassSubGraphInfo* HeapShared::init_subgraph_info(Klass* k, bool is_full_module_
 }
 
 KlassSubGraphInfo* HeapShared::get_subgraph_info(Klass* k) {
-  assert(DumpSharedSpaces, "dump time only");
+  assert(CDSConfig::is_dumping_heap(), "dump time only");
   KlassSubGraphInfo* info = _dump_time_subgraph_info_table->get(k);
   assert(info != nullptr, "must have been initialized");
   return info;
@@ -618,7 +619,7 @@ KlassSubGraphInfo* HeapShared::get_subgraph_info(Klass* k) {
 
 // Add an entry field to the current KlassSubGraphInfo.
 void KlassSubGraphInfo::add_subgraph_entry_field(int static_field_offset, oop v) {
-  assert(DumpSharedSpaces, "dump time only");
+  assert(CDSConfig::is_dumping_heap(), "dump time only");
   if (_subgraph_entry_fields == nullptr) {
     _subgraph_entry_fields =
       new (mtClass) GrowableArray(10, mtClass);
@@ -630,7 +631,7 @@ void KlassSubGraphInfo::add_subgraph_entry_field(int static_field_offset, oop v)
 // Add the Klass* for an object in the current KlassSubGraphInfo's subgraphs.
 // Only objects of boot classes can be included in sub-graph.
 void KlassSubGraphInfo::add_subgraph_object_klass(Klass* orig_k) {
-  assert(DumpSharedSpaces, "dump time only");
+  assert(CDSConfig::is_dumping_heap(), "dump time only");
   Klass* buffered_k = ArchiveBuilder::get_buffered_klass(orig_k);
 
   if (_subgraph_object_klasses == nullptr) {
@@ -946,7 +947,7 @@ void HeapShared::initialize_from_archived_subgraph(JavaThread* current, Klass* k
 
 const ArchivedKlassSubGraphInfoRecord*
 HeapShared::resolve_or_init_classes_for_subgraph_of(Klass* k, bool do_init, TRAPS) {
-  assert(!DumpSharedSpaces, "Should not be called with DumpSharedSpaces");
+  assert(!CDSConfig::is_dumping_heap(), "Should not be called when dumping heap");
 
   if (!k->is_shared()) {
     return nullptr;
@@ -1243,7 +1244,7 @@ void HeapShared::archive_reachable_objects_from_static_field(InstanceKlass *k,
                                                              const char* klass_name,
                                                              int field_offset,
                                                              const char* field_name) {
-  assert(DumpSharedSpaces, "dump time only");
+  assert(CDSConfig::is_dumping_heap(), "dump time only");
   assert(k->is_shared_boot_class(), "must be boot class");
 
   oop m = k->java_mirror();
@@ -1294,7 +1295,7 @@ class VerifySharedOopClosure: public BasicOopIterateClosure {
 };
 
 void HeapShared::verify_subgraph_from_static_field(InstanceKlass* k, int field_offset) {
-  assert(DumpSharedSpaces, "dump time only");
+  assert(CDSConfig::is_dumping_heap(), "dump time only");
   assert(k->is_shared_boot_class(), "must be boot class");
 
   oop m = k->java_mirror();
diff --git a/src/hotspot/share/cds/metaspaceShared.cpp b/src/hotspot/share/cds/metaspaceShared.cpp
index c4ec39f65db..0713212c100 100644
--- a/src/hotspot/share/cds/metaspaceShared.cpp
+++ b/src/hotspot/share/cds/metaspaceShared.cpp
@@ -27,6 +27,7 @@
 #include "cds/archiveHeapLoader.hpp"
 #include "cds/archiveHeapWriter.hpp"
 #include "cds/cds_globals.hpp"
+#include "cds/cdsConfig.hpp"
 #include "cds/cdsProtectionDomain.hpp"
 #include "cds/classListWriter.hpp"
 #include "cds/classListParser.hpp"
@@ -640,7 +641,7 @@ void MetaspaceShared::link_shared_classes(bool jcmd_request, TRAPS) {
 }
 
 void MetaspaceShared::prepare_for_dumping() {
-  Arguments::assert_is_dumping_archive();
+  assert(CDSConfig::is_dumping_archive(), "sanity");
   Arguments::check_unsupported_dumping_properties();
 
   ClassLoader::initialize_shared_path(JavaThread::current());
@@ -667,7 +668,7 @@ void MetaspaceShared::preload_and_dump() {
 
 #if INCLUDE_CDS_JAVA_HEAP && defined(_LP64)
 void MetaspaceShared::adjust_heap_sizes_for_dumping() {
-  if (!DumpSharedSpaces || UseCompressedOops) {
+  if (!CDSConfig::is_dumping_heap() || UseCompressedOops) {
     return;
   }
   // CDS heap dumping requires all string oops to have an offset
@@ -774,10 +775,12 @@ void MetaspaceShared::preload_and_dump_impl(TRAPS) {
   log_info(cds)("Rewriting and linking classes: done");
 
 #if INCLUDE_CDS_JAVA_HEAP
-  StringTable::allocate_shared_strings_array(CHECK);
-  ArchiveHeapWriter::init();
-  if (use_full_module_graph()) {
-    HeapShared::reset_archived_object_states(CHECK);
+  if (CDSConfig::is_dumping_heap()) {
+    StringTable::allocate_shared_strings_array(CHECK);
+    ArchiveHeapWriter::init();
+    if (use_full_module_graph()) {
+      HeapShared::reset_archived_object_states(CHECK);
+    }
   }
 #endif
 
@@ -789,7 +792,7 @@ void MetaspaceShared::preload_and_dump_impl(TRAPS) {
 bool MetaspaceShared::try_link_class(JavaThread* current, InstanceKlass* ik) {
   ExceptionMark em(current);
   JavaThread* THREAD = current; // For exception macros.
-  Arguments::assert_is_dumping_archive();
+  assert(CDSConfig::is_dumping_archive(), "sanity");
   if (!ik->is_shared() && ik->is_loaded() && !ik->is_linked() && ik->can_be_verified_at_dumptime() &&
       !SystemDictionaryShared::has_class_failed_verification(ik)) {
     bool saved = BytecodeVerificationLocal;
diff --git a/src/hotspot/share/classfile/classFileParser.cpp b/src/hotspot/share/classfile/classFileParser.cpp
index 16b11ec4fcb..7e39cafa811 100644
--- a/src/hotspot/share/classfile/classFileParser.cpp
+++ b/src/hotspot/share/classfile/classFileParser.cpp
@@ -22,6 +22,7 @@
  *
  */
 #include "precompiled.hpp"
+#include "cds/cdsConfig.hpp"
 #include "classfile/classFileParser.hpp"
 #include "classfile/classFileStream.hpp"
 #include "classfile/classLoader.hpp"
@@ -2852,7 +2853,7 @@ static const intArray* sort_methods(Array* methods) {
   // We temporarily use the vtable_index field in the Method* to store the
   // class file index, so we can read in after calling qsort.
   // Put the method ordering in the shared archive.
-  if (JvmtiExport::can_maintain_original_method_order() || Arguments::is_dumping_archive()) {
+  if (JvmtiExport::can_maintain_original_method_order() || CDSConfig::is_dumping_archive()) {
     for (int index = 0; index < length; index++) {
       Method* const m = methods->at(index);
       assert(!m->valid_vtable_index(), "vtable index should not be set");
@@ -2866,7 +2867,7 @@ static const intArray* sort_methods(Array* methods) {
   intArray* method_ordering = nullptr;
   // If JVMTI original method ordering or sharing is enabled construct int
   // array remembering the original ordering
-  if (JvmtiExport::can_maintain_original_method_order() || Arguments::is_dumping_archive()) {
+  if (JvmtiExport::can_maintain_original_method_order() || CDSConfig::is_dumping_archive()) {
     method_ordering = new intArray(length, length, -1);
     for (int index = 0; index < length; index++) {
       Method* const m = methods->at(index);
diff --git a/src/hotspot/share/classfile/classLoader.cpp b/src/hotspot/share/classfile/classLoader.cpp
index 56fe33141a1..e3e85a150f0 100644
--- a/src/hotspot/share/classfile/classLoader.cpp
+++ b/src/hotspot/share/classfile/classLoader.cpp
@@ -24,6 +24,7 @@
 
 #include "precompiled.hpp"
 #include "cds/cds_globals.hpp"
+#include "cds/cdsConfig.hpp"
 #include "cds/filemap.hpp"
 #include "classfile/classFileStream.hpp"
 #include "classfile/classLoader.inline.hpp"
@@ -446,7 +447,7 @@ bool ClassPathImageEntry::is_modules_image() const {
 
 #if INCLUDE_CDS
 void ClassLoader::exit_with_path_failure(const char* error, const char* message) {
-  Arguments::assert_is_dumping_archive();
+  assert(CDSConfig::is_dumping_archive(), "sanity");
   tty->print_cr("Hint: enable -Xlog:class+path=info to diagnose the failure");
   vm_exit_during_initialization(error, message);
 }
@@ -516,7 +517,7 @@ void ClassLoader::setup_bootstrap_search_path(JavaThread* current) {
 
 #if INCLUDE_CDS
 void ClassLoader::setup_app_search_path(JavaThread* current, const char *class_path) {
-  Arguments::assert_is_dumping_archive();
+  assert(CDSConfig::is_dumping_archive(), "sanity");
 
   ResourceMark rm(current);
   ClasspathStream cp_stream(class_path);
@@ -531,7 +532,7 @@ void ClassLoader::setup_app_search_path(JavaThread* current, const char *class_p
 void ClassLoader::add_to_module_path_entries(const char* path,
                                              ClassPathEntry* entry) {
   assert(entry != nullptr, "ClassPathEntry should not be nullptr");
-  Arguments::assert_is_dumping_archive();
+  assert(CDSConfig::is_dumping_archive(), "sanity");
 
   // The entry does not exist, add to the list
   if (_module_path_entries == nullptr) {
@@ -545,7 +546,7 @@ void ClassLoader::add_to_module_path_entries(const char* path,
 
 // Add a module path to the _module_path_entries list.
 void ClassLoader::setup_module_search_path(JavaThread* current, const char* path) {
-  Arguments::assert_is_dumping_archive();
+  assert(CDSConfig::is_dumping_archive(), "sanity");
   struct stat st;
   if (os::stat(path, &st) != 0) {
     tty->print_cr("os::stat error %d (%s). CDS dump aborted (path was \"%s\").",
@@ -633,7 +634,7 @@ void ClassLoader::setup_bootstrap_search_path_impl(JavaThread* current, const ch
   bool set_base_piece = true;
 
 #if INCLUDE_CDS
-  if (Arguments::is_dumping_archive()) {
+  if (CDSConfig::is_dumping_archive()) {
     if (!Arguments::has_jimage()) {
       vm_exit_during_initialization("CDS is not supported in exploded JDK build", nullptr);
     }
@@ -1249,7 +1250,7 @@ char* ClassLoader::skip_uri_protocol(char* source) {
 // by the builtin loaders at dump time.
 void ClassLoader::record_result(JavaThread* current, InstanceKlass* ik,
                                 const ClassFileStream* stream, bool redefined) {
-  Arguments::assert_is_dumping_archive();
+  assert(CDSConfig::is_dumping_archive(), "sanity");
   assert(stream != nullptr, "sanity");
 
   if (ik->is_hidden()) {
@@ -1443,13 +1444,13 @@ bool ClassLoader::is_module_observable(const char* module_name) {
 
 #if INCLUDE_CDS
 void ClassLoader::initialize_shared_path(JavaThread* current) {
-  if (Arguments::is_dumping_archive()) {
+  if (CDSConfig::is_dumping_archive()) {
     ClassLoaderExt::setup_search_paths(current);
   }
 }
 
 void ClassLoader::initialize_module_path(TRAPS) {
-  if (Arguments::is_dumping_archive()) {
+  if (CDSConfig::is_dumping_archive()) {
     ClassLoaderExt::setup_module_paths(THREAD);
     FileMapInfo::allocate_shared_path_table(CHECK);
   }
@@ -1458,7 +1459,7 @@ void ClassLoader::initialize_module_path(TRAPS) {
 // Helper function used by CDS code to get the number of module path
 // entries during shared classpath setup time.
 int ClassLoader::num_module_path_entries() {
-  Arguments::assert_is_dumping_archive();
+  assert(CDSConfig::is_dumping_archive(), "sanity");
   int num_entries = 0;
   ClassPathEntry* e= ClassLoader::_module_path_entries;
   while (e != nullptr) {
diff --git a/src/hotspot/share/classfile/classLoader.inline.hpp b/src/hotspot/share/classfile/classLoader.inline.hpp
index fd22b67165b..e0a06880dd4 100644
--- a/src/hotspot/share/classfile/classLoader.inline.hpp
+++ b/src/hotspot/share/classfile/classLoader.inline.hpp
@@ -27,8 +27,8 @@
 
 #include "classfile/classLoader.hpp"
 
+#include "cds/cdsConfig.hpp"
 #include "runtime/atomic.hpp"
-#include "runtime/arguments.hpp"
 
 // Next entry in class path
 inline ClassPathEntry* ClassPathEntry::next() const { return Atomic::load_acquire(&_next); }
@@ -70,7 +70,7 @@ inline void ClassLoader::load_zip_library_if_needed() {
 // entries during shared classpath setup time.
 
 inline int ClassLoader::num_boot_classpath_entries() {
-  Arguments::assert_is_dumping_archive();
+  assert(CDSConfig::is_dumping_archive(), "sanity");
   assert(has_jrt_entry(), "must have a java runtime image");
   int num_entries = 1; // count the runtime image
   ClassPathEntry* e = first_append_entry();
@@ -92,7 +92,7 @@ inline ClassPathEntry* ClassLoader::get_next_boot_classpath_entry(ClassPathEntry
 // Helper function used by CDS code to get the number of app classpath
 // entries during shared classpath setup time.
 inline int ClassLoader::num_app_classpath_entries() {
-  Arguments::assert_is_dumping_archive();
+  assert(CDSConfig::is_dumping_archive(), "sanity");
   int num_entries = 0;
   ClassPathEntry* e= ClassLoader::_app_classpath_entries;
   while (e != nullptr) {
diff --git a/src/hotspot/share/classfile/classLoaderExt.cpp b/src/hotspot/share/classfile/classLoaderExt.cpp
index 25c63bfb921..92511d762fb 100644
--- a/src/hotspot/share/classfile/classLoaderExt.cpp
+++ b/src/hotspot/share/classfile/classLoaderExt.cpp
@@ -24,6 +24,7 @@
 
 #include "precompiled.hpp"
 #include "cds/cds_globals.hpp"
+#include "cds/cdsConfig.hpp"
 #include "cds/dynamicArchive.hpp"
 #include "cds/filemap.hpp"
 #include "cds/heapShared.hpp"
@@ -70,7 +71,7 @@ void ClassLoaderExt::append_boot_classpath(ClassPathEntry* new_entry) {
 }
 
 void ClassLoaderExt::setup_app_search_path(JavaThread* current) {
-  Arguments::assert_is_dumping_archive();
+  assert(CDSConfig::is_dumping_archive(), "sanity");
   int start_index = ClassLoader::num_boot_classpath_entries();
   _app_class_paths_start_index = checked_cast(start_index);
   char* app_class_path = os::strdup_check_oom(Arguments::get_appclasspath(), mtClass);
@@ -121,7 +122,7 @@ void ClassLoaderExt::process_module_table(JavaThread* current, ModuleEntryTable*
 }
 
 void ClassLoaderExt::setup_module_paths(JavaThread* current) {
-  Arguments::assert_is_dumping_archive();
+  assert(CDSConfig::is_dumping_archive(), "sanity");
   int start_index = ClassLoader::num_boot_classpath_entries() +
                     ClassLoader::num_app_classpath_entries();
   _app_module_paths_start_index = checked_cast(start_index);
@@ -257,7 +258,7 @@ void ClassLoaderExt::setup_search_paths(JavaThread* current) {
 }
 
 void ClassLoaderExt::record_result(const s2 classpath_index, InstanceKlass* result, bool redefined) {
-  Arguments::assert_is_dumping_archive();
+  assert(CDSConfig::is_dumping_archive(), "sanity");
 
   // We need to remember where the class comes from during dumping.
   oop loader = result->class_loader();
diff --git a/src/hotspot/share/classfile/compactHashtable.cpp b/src/hotspot/share/classfile/compactHashtable.cpp
index 04562f4ae38..d4657e35a84 100644
--- a/src/hotspot/share/classfile/compactHashtable.cpp
+++ b/src/hotspot/share/classfile/compactHashtable.cpp
@@ -25,13 +25,14 @@
 #include "precompiled.hpp"
 #include "cds/archiveBuilder.hpp"
 #include "cds/cds_globals.hpp"
+#include "cds/cdsConfig.hpp"
 #include "classfile/compactHashtable.hpp"
 #include "classfile/javaClasses.hpp"
 #include "jvm.h"
 #include "logging/logMessage.hpp"
 #include "memory/metadataFactory.hpp"
-#include "runtime/arguments.hpp"
 #include "runtime/globals.hpp"
+#include "runtime/java.hpp"
 #include "runtime/vmThread.hpp"
 #include "utilities/numberSeq.hpp"
 
@@ -44,7 +45,7 @@
 //
 CompactHashtableWriter::CompactHashtableWriter(int num_entries,
                                                CompactHashtableStats* stats) {
-  Arguments::assert_is_dumping_archive();
+  assert(CDSConfig::is_dumping_archive(), "sanity");
   assert(num_entries >= 0, "sanity");
   _num_buckets = calculate_num_buckets(num_entries);
   assert(_num_buckets > 0, "no buckets");
diff --git a/src/hotspot/share/classfile/defaultMethods.cpp b/src/hotspot/share/classfile/defaultMethods.cpp
index d02f89a2ccc..60c75a44007 100644
--- a/src/hotspot/share/classfile/defaultMethods.cpp
+++ b/src/hotspot/share/classfile/defaultMethods.cpp
@@ -23,6 +23,7 @@
  */
 
 #include "precompiled.hpp"
+#include "cds/cdsConfig.hpp"
 #include "classfile/bytecodeAssembler.hpp"
 #include "classfile/defaultMethods.hpp"
 #include "classfile/symbolTable.hpp"
@@ -36,7 +37,6 @@
 #include "memory/resourceArea.hpp"
 #include "memory/universe.hpp"
 #include "prims/jvmtiExport.hpp"
-#include "runtime/arguments.hpp"
 #include "runtime/handles.inline.hpp"
 #include "runtime/javaThread.hpp"
 #include "runtime/signature.hpp"
@@ -1069,7 +1069,7 @@ static void merge_in_new_methods(InstanceKlass* klass,
       klass->class_loader_data(), new_size, nullptr, CHECK);
 
   // original_ordering might be empty if this class has no methods of its own
-  if (JvmtiExport::can_maintain_original_method_order() || Arguments::is_dumping_archive()) {
+  if (JvmtiExport::can_maintain_original_method_order() || CDSConfig::is_dumping_archive()) {
     merged_ordering = MetadataFactory::new_array(
         klass->class_loader_data(), new_size, CHECK);
   }
diff --git a/src/hotspot/share/classfile/dictionary.cpp b/src/hotspot/share/classfile/dictionary.cpp
index f1f02e11d81..01f324eb27e 100644
--- a/src/hotspot/share/classfile/dictionary.cpp
+++ b/src/hotspot/share/classfile/dictionary.cpp
@@ -23,6 +23,7 @@
  */
 
 #include "precompiled.hpp"
+#include "cds/cdsConfig.hpp"
 #include "classfile/classLoaderData.inline.hpp"
 #include "classfile/dictionary.hpp"
 #include "classfile/javaClasses.hpp"
@@ -39,7 +40,6 @@
 #include "oops/method.hpp"
 #include "oops/oop.inline.hpp"
 #include "oops/oopHandle.inline.hpp"
-#include "runtime/arguments.hpp"
 #include "runtime/handles.inline.hpp"
 #include "runtime/javaCalls.hpp"
 #include "runtime/mutexLocker.hpp"
@@ -211,7 +211,7 @@ void Dictionary::all_entries_do(KlassClosure* closure) {
 
 // Used to scan and relocate the classes during CDS archive dump.
 void Dictionary::classes_do(MetaspaceClosure* it) {
-  Arguments::assert_is_dumping_archive();
+  assert(CDSConfig::is_dumping_archive(), "sanity");
 
   auto push = [&] (DictionaryEntry** value) {
     InstanceKlass** k = (*value)->instance_klass_addr();
diff --git a/src/hotspot/share/classfile/javaClasses.cpp b/src/hotspot/share/classfile/javaClasses.cpp
index badab7aa6ef..c78bdd73a5d 100644
--- a/src/hotspot/share/classfile/javaClasses.cpp
+++ b/src/hotspot/share/classfile/javaClasses.cpp
@@ -25,6 +25,7 @@
 #include "precompiled.hpp"
 #include "cds/archiveBuilder.hpp"
 #include "cds/archiveHeapLoader.hpp"
+#include "cds/cdsConfig.hpp"
 #include "cds/heapShared.hpp"
 #include "cds/metaspaceShared.hpp"
 #include "classfile/altHashing.hpp"
@@ -1064,7 +1065,7 @@ void java_lang_Class::create_mirror(Klass* k, Handle class_loader,
       // concurrently doesn't expect a k to have a null java_mirror.
       release_set_array_klass(comp_mirror(), k);
     }
-    if (DumpSharedSpaces) {
+    if (CDSConfig::is_dumping_heap()) {
       create_scratch_mirror(k, CHECK);
     }
   } else {
@@ -1366,7 +1367,7 @@ BasicType java_lang_Class::primitive_type(oop java_class) {
     assert(java_class == Universe::void_mirror(), "only valid non-array primitive");
   }
 #ifdef ASSERT
-  if (DumpSharedSpaces) {
+  if (CDSConfig::is_dumping_heap()) {
     oop mirror = Universe::java_mirror(type);
     oop scratch_mirror = HeapShared::scratch_java_mirror(type);
     assert(java_class == mirror || java_class == scratch_mirror, "must be consistent");
diff --git a/src/hotspot/share/classfile/klassFactory.cpp b/src/hotspot/share/classfile/klassFactory.cpp
index 3e0f866fbd6..a53cbdf61cb 100644
--- a/src/hotspot/share/classfile/klassFactory.cpp
+++ b/src/hotspot/share/classfile/klassFactory.cpp
@@ -23,6 +23,7 @@
 */
 
 #include "precompiled.hpp"
+#include "cds/cdsConfig.hpp"
 #include "cds/filemap.hpp"
 #include "classfile/classFileParser.hpp"
 #include "classfile/classFileStream.hpp"
@@ -34,7 +35,6 @@
 #include "memory/resourceArea.hpp"
 #include "prims/jvmtiEnvBase.hpp"
 #include "prims/jvmtiRedefineClasses.hpp"
-#include "runtime/arguments.hpp"
 #include "runtime/handles.inline.hpp"
 #include "utilities/macros.hpp"
 #if INCLUDE_JFR
@@ -212,7 +212,7 @@ InstanceKlass* KlassFactory::create_from_stream(ClassFileStream* stream,
   JFR_ONLY(ON_KLASS_CREATION(result, parser, THREAD);)
 
 #if INCLUDE_CDS
-  if (Arguments::is_dumping_archive()) {
+  if (CDSConfig::is_dumping_archive()) {
     ClassLoader::record_result(THREAD, result, stream, old_stream != stream);
   }
 #endif // INCLUDE_CDS
diff --git a/src/hotspot/share/classfile/stringTable.cpp b/src/hotspot/share/classfile/stringTable.cpp
index e92b0e5eee3..506eef46241 100644
--- a/src/hotspot/share/classfile/stringTable.cpp
+++ b/src/hotspot/share/classfile/stringTable.cpp
@@ -26,6 +26,7 @@
 #include "cds/archiveBuilder.hpp"
 #include "cds/archiveHeapLoader.inline.hpp"
 #include "cds/archiveHeapWriter.hpp"
+#include "cds/cdsConfig.hpp"
 #include "cds/filemap.hpp"
 #include "cds/heapShared.hpp"
 #include "classfile/altHashing.hpp"
@@ -805,7 +806,7 @@ oop StringTable::lookup_shared(const jchar* name, int len) {
 // This should be called when we know no more strings will be added (which will be easy
 // to guarantee because CDS runs with a single Java thread. See JDK-8253495.)
 void StringTable::allocate_shared_strings_array(TRAPS) {
-  assert(DumpSharedSpaces, "must be");
+  assert(CDSConfig::is_dumping_heap(), "must be");
   if (_items_count > (size_t)max_jint) {
     fatal("Too many strings to be archived: %zu", _items_count);
   }
diff --git a/src/hotspot/share/classfile/systemDictionary.cpp b/src/hotspot/share/classfile/systemDictionary.cpp
index b5a41138aa3..3d1674bca99 100644
--- a/src/hotspot/share/classfile/systemDictionary.cpp
+++ b/src/hotspot/share/classfile/systemDictionary.cpp
@@ -23,6 +23,7 @@
  */
 
 #include "precompiled.hpp"
+#include "cds/cdsConfig.hpp"
 #include "cds/heapShared.hpp"
 #include "classfile/classFileParser.hpp"
 #include "classfile/classFileStream.hpp"
@@ -1782,7 +1783,7 @@ bool SystemDictionary::add_loader_constraint(Symbol* class_name,
     bool result = LoaderConstraintTable::add_entry(constraint_name, klass1, loader_data1,
                                                    klass2, loader_data2);
 #if INCLUDE_CDS
-    if (Arguments::is_dumping_archive() && klass_being_linked != nullptr &&
+    if (CDSConfig::is_dumping_archive() && klass_being_linked != nullptr &&
         !klass_being_linked->is_shared()) {
          SystemDictionaryShared::record_linking_constraint(constraint_name,
                                      InstanceKlass::cast(klass_being_linked),
diff --git a/src/hotspot/share/classfile/systemDictionaryShared.cpp b/src/hotspot/share/classfile/systemDictionaryShared.cpp
index 7750081ec8a..5c6aa989267 100644
--- a/src/hotspot/share/classfile/systemDictionaryShared.cpp
+++ b/src/hotspot/share/classfile/systemDictionaryShared.cpp
@@ -26,6 +26,7 @@
 #include "cds/archiveBuilder.hpp"
 #include "cds/archiveHeapLoader.hpp"
 #include "cds/archiveUtils.hpp"
+#include "cds/cdsConfig.hpp"
 #include "cds/classListParser.hpp"
 #include "cds/classListWriter.hpp"
 #include "cds/dynamicArchive.hpp"
@@ -196,7 +197,7 @@ bool SystemDictionaryShared::check_for_exclusion(InstanceKlass* k, DumpTimeClass
   if (MetaspaceShared::is_in_shared_metaspace(k)) {
     // We have reached a super type that's already in the base archive. Treat it
     // as "not excluded".
-    assert(DynamicDumpSharedSpaces, "must be");
+    assert(CDSConfig::is_dumping_dynamic_archive(), "must be");
     return false;
   }
 
@@ -435,7 +436,7 @@ bool SystemDictionaryShared::add_unregistered_class(Thread* current, InstanceKla
   // We don't allow duplicated unregistered classes with the same name.
   // We only archive the first class with that name that succeeds putting
   // itself into the table.
-  assert(Arguments::is_dumping_archive() || ClassListWriter::is_enabled(), "sanity");
+  assert(CDSConfig::is_dumping_archive() || ClassListWriter::is_enabled(), "sanity");
   MutexLocker ml(current, UnregisteredClassesTable_lock, Mutex::_no_safepoint_check_flag);
   Symbol* name = klass->name();
   if (_unregistered_classes_table == nullptr) {
@@ -489,7 +490,7 @@ InstanceKlass* SystemDictionaryShared::lookup_super_for_unregistered_class(
 }
 
 void SystemDictionaryShared::set_shared_class_misc_info(InstanceKlass* k, ClassFileStream* cfs) {
-  Arguments::assert_is_dumping_archive();
+  assert(CDSConfig::is_dumping_archive(), "sanity");
   assert(!is_builtin(k), "must be unregistered class");
   DumpTimeClassInfo* info = get_info(k);
   info->_clsfile_size  = cfs->length();
@@ -497,7 +498,7 @@ void SystemDictionaryShared::set_shared_class_misc_info(InstanceKlass* k, ClassF
 }
 
 void SystemDictionaryShared::initialize() {
-  if (Arguments::is_dumping_archive()) {
+  if (CDSConfig::is_dumping_archive()) {
     _dumptime_table = new (mtClass) DumpTimeSharedClassTable;
     _dumptime_lambda_proxy_class_dictionary =
                       new (mtClass) DumpTimeLambdaProxyClassDictionary;
@@ -516,11 +517,11 @@ void SystemDictionaryShared::remove_dumptime_info(InstanceKlass* k) {
 }
 
 void SystemDictionaryShared::handle_class_unloading(InstanceKlass* klass) {
-  if (Arguments::is_dumping_archive()) {
+  if (CDSConfig::is_dumping_archive()) {
     remove_dumptime_info(klass);
   }
 
-  if (Arguments::is_dumping_archive() || ClassListWriter::is_enabled()) {
+  if (CDSConfig::is_dumping_archive() || ClassListWriter::is_enabled()) {
     MutexLocker ml(Thread::current(), UnregisteredClassesTable_lock, Mutex::_no_safepoint_check_flag);
     if (_unregistered_classes_table != nullptr) {
       // Remove the class from _unregistered_classes_table: keep the entry but
@@ -625,7 +626,7 @@ void SystemDictionaryShared::check_excluded_classes() {
   assert(!class_loading_may_happen(), "class loading must be disabled");
   assert_lock_strong(DumpTimeTable_lock);
 
-  if (DynamicDumpSharedSpaces) {
+  if (CDSConfig::is_dumping_dynamic_archive()) {
     // Do this first -- if a base class is excluded due to duplication,
     // all of its subclasses will also be excluded.
     ResourceMark rm;
@@ -646,32 +647,32 @@ void SystemDictionaryShared::check_excluded_classes() {
 bool SystemDictionaryShared::is_excluded_class(InstanceKlass* k) {
   assert(!class_loading_may_happen(), "class loading must be disabled");
   assert_lock_strong(DumpTimeTable_lock);
-  Arguments::assert_is_dumping_archive();
+  assert(CDSConfig::is_dumping_archive(), "sanity");
   DumpTimeClassInfo* p = get_info_locked(k);
   return p->is_excluded();
 }
 
 void SystemDictionaryShared::set_excluded_locked(InstanceKlass* k) {
   assert_lock_strong(DumpTimeTable_lock);
-  Arguments::assert_is_dumping_archive();
+  assert(CDSConfig::is_dumping_archive(), "sanity");
   DumpTimeClassInfo* info = get_info_locked(k);
   info->set_excluded();
 }
 
 void SystemDictionaryShared::set_excluded(InstanceKlass* k) {
-  Arguments::assert_is_dumping_archive();
+  assert(CDSConfig::is_dumping_archive(), "sanity");
   DumpTimeClassInfo* info = get_info(k);
   info->set_excluded();
 }
 
 void SystemDictionaryShared::set_class_has_failed_verification(InstanceKlass* ik) {
-  Arguments::assert_is_dumping_archive();
+  assert(CDSConfig::is_dumping_archive(), "sanity");
   DumpTimeClassInfo* p = get_info(ik);
   p->set_failed_verification();
 }
 
 bool SystemDictionaryShared::has_class_failed_verification(InstanceKlass* ik) {
-  Arguments::assert_is_dumping_archive();
+  assert(CDSConfig::is_dumping_archive(), "sanity");
   DumpTimeClassInfo* p = _dumptime_table->get(ik);
   return (p == nullptr) ? false : p->failed_verification();
 }
@@ -697,12 +698,12 @@ void SystemDictionaryShared::dumptime_classes_do(class MetaspaceClosure* it) {
 
 bool SystemDictionaryShared::add_verification_constraint(InstanceKlass* k, Symbol* name,
          Symbol* from_name, bool from_field_is_protected, bool from_is_array, bool from_is_object) {
-  Arguments::assert_is_dumping_archive();
+  assert(CDSConfig::is_dumping_archive(), "sanity");
   DumpTimeClassInfo* info = get_info(k);
   info->add_verification_constraint(k, name, from_name, from_field_is_protected,
                                     from_is_array, from_is_object);
 
-  if (DynamicDumpSharedSpaces) {
+  if (CDSConfig::is_dumping_dynamic_archive()) {
     // For dynamic dumping, we can resolve all the constraint classes for all class loaders during
     // the initial run prior to creating the archive before vm exit. We will also perform verification
     // check when running with the archive.
@@ -993,7 +994,7 @@ void SystemDictionaryShared::record_linking_constraint(Symbol* name, InstanceKla
   }
   assert(!Thread::current()->is_VM_thread(), "must be");
 
-  Arguments::assert_is_dumping_archive();
+  assert(CDSConfig::is_dumping_archive(), "sanity");
   DumpTimeClassInfo* info = get_info(klass);
   info->record_linking_constraint(name, loader1, loader2);
 }
diff --git a/src/hotspot/share/classfile/verificationType.cpp b/src/hotspot/share/classfile/verificationType.cpp
index a310b638e86..bd66cf43b5c 100644
--- a/src/hotspot/share/classfile/verificationType.cpp
+++ b/src/hotspot/share/classfile/verificationType.cpp
@@ -23,6 +23,7 @@
  */
 
 #include "precompiled.hpp"
+#include "cds/cdsConfig.hpp"
 #include "classfile/symbolTable.hpp"
 #include "classfile/systemDictionary.hpp"
 #include "classfile/systemDictionaryShared.hpp"
@@ -32,7 +33,6 @@
 #include "classfile/vmSymbols.hpp"
 #include "logging/log.hpp"
 #include "oops/klass.inline.hpp"
-#include "runtime/arguments.hpp"
 #include "runtime/handles.inline.hpp"
 
 VerificationType VerificationType::from_tag(u1 tag) {
@@ -109,7 +109,7 @@ bool VerificationType::is_reference_assignable_from(
       return true;
     }
 
-    if (Arguments::is_dumping_archive()) {
+    if (CDSConfig::is_dumping_archive()) {
       if (SystemDictionaryShared::add_verification_constraint(klass,
               name(), from.name(), from_field_is_protected, from.is_array(),
               from.is_object())) {
diff --git a/src/hotspot/share/gc/shared/collectedHeap.cpp b/src/hotspot/share/gc/shared/collectedHeap.cpp
index 95fe3b1737c..422fef24318 100644
--- a/src/hotspot/share/gc/shared/collectedHeap.cpp
+++ b/src/hotspot/share/gc/shared/collectedHeap.cpp
@@ -23,6 +23,7 @@
  */
 
 #include "precompiled.hpp"
+#include "cds/cdsConfig.hpp"
 #include "classfile/classLoaderData.hpp"
 #include "classfile/vmClasses.hpp"
 #include "gc/shared/allocTracer.hpp"
@@ -455,7 +456,7 @@ CollectedHeap::fill_with_array(HeapWord* start, size_t words, bool zap)
 
   ObjArrayAllocator allocator(Universe::fillerArrayKlassObj(), words, (int)len, /* do_zero */ false);
   allocator.initialize(start);
-  if (DumpSharedSpaces) {
+  if (CDSConfig::is_dumping_heap()) {
     // This array is written into the CDS archive. Make sure it
     // has deterministic contents.
     zap_filler_array_with(start, words, 0);
diff --git a/src/hotspot/share/interpreter/rewriter.cpp b/src/hotspot/share/interpreter/rewriter.cpp
index 1de0a1be366..9d8f602a4fe 100644
--- a/src/hotspot/share/interpreter/rewriter.cpp
+++ b/src/hotspot/share/interpreter/rewriter.cpp
@@ -23,6 +23,7 @@
  */
 
 #include "precompiled.hpp"
+#include "cds/cdsConfig.hpp"
 #include "cds/metaspaceShared.hpp"
 #include "classfile/vmClasses.hpp"
 #include "interpreter/bytecodes.hpp"
@@ -35,7 +36,6 @@
 #include "oops/resolvedFieldEntry.hpp"
 #include "oops/resolvedIndyEntry.hpp"
 #include "prims/methodHandles.hpp"
-#include "runtime/arguments.hpp"
 #include "runtime/fieldDescriptor.inline.hpp"
 #include "runtime/handles.inline.hpp"
 #include "utilities/checkedCast.hpp"
@@ -118,7 +118,7 @@ void Rewriter::make_constant_pool_cache(TRAPS) {
                                         _resolved_reference_limit,
                                         THREAD);
 #if INCLUDE_CDS
-  if (!HAS_PENDING_EXCEPTION && Arguments::is_dumping_archive()) {
+  if (!HAS_PENDING_EXCEPTION && CDSConfig::is_dumping_archive()) {
     if (_pool->pool_holder()->is_shared()) {
       assert(DynamicDumpSharedSpaces, "must be");
       // We are linking a shared class from the base archive. This
diff --git a/src/hotspot/share/interpreter/zero/bytecodeInterpreter.cpp b/src/hotspot/share/interpreter/zero/bytecodeInterpreter.cpp
index 356bb7c940b..9ff83c7e140 100644
--- a/src/hotspot/share/interpreter/zero/bytecodeInterpreter.cpp
+++ b/src/hotspot/share/interpreter/zero/bytecodeInterpreter.cpp
@@ -23,6 +23,7 @@
  */
 
 // no precompiled headers
+#include "cds/cdsConfig.hpp"
 #include "classfile/javaClasses.hpp"
 #include "classfile/vmSymbols.hpp"
 #include "gc/shared/collectedHeap.hpp"
@@ -50,7 +51,6 @@
 #include "oops/typeArrayOop.inline.hpp"
 #include "prims/jvmtiExport.hpp"
 #include "prims/jvmtiThreadState.hpp"
-#include "runtime/arguments.hpp"
 #include "runtime/atomic.hpp"
 #include "runtime/frame.inline.hpp"
 #include "runtime/handles.inline.hpp"
@@ -2445,7 +2445,7 @@ void BytecodeInterpreter::run(interpreterState istate) {
             CHECK_NULL(STACK_OBJECT(-(cache->parameter_size())));
             if (cache->is_vfinal()) {
               callee = cache->f2_as_vfinal_method();
-              if (REWRITE_BYTECODES && !UseSharedSpaces && !Arguments::is_dumping_archive()) {
+              if (REWRITE_BYTECODES && !UseSharedSpaces && !CDSConfig::is_dumping_archive()) {
                 // Rewrite to _fast_invokevfinal.
                 REWRITE_AT_PC(Bytecodes::_fast_invokevfinal);
               }
diff --git a/src/hotspot/share/jfr/recorder/jfrRecorder.cpp b/src/hotspot/share/jfr/recorder/jfrRecorder.cpp
index 1faf1230068..f3b88e850dc 100644
--- a/src/hotspot/share/jfr/recorder/jfrRecorder.cpp
+++ b/src/hotspot/share/jfr/recorder/jfrRecorder.cpp
@@ -23,6 +23,7 @@
  */
 
 #include "precompiled.hpp"
+#include "cds/cdsConfig.hpp"
 #include "classfile/javaClasses.hpp"
 #include "jfr/dcmd/jfrDcmds.hpp"
 #include "jfr/instrumentation/jfrJvmtiAgent.hpp"
@@ -185,7 +186,7 @@ static void log_jdk_jfr_module_resolution_error(TRAPS) {
 
 static bool is_cds_dump_requested() {
   // we will not be able to launch recordings on startup if a cds dump is being requested
-  if (Arguments::is_dumping_archive() && JfrOptionSet::start_flight_recording_options() != nullptr) {
+  if (CDSConfig::is_dumping_archive() && JfrOptionSet::start_flight_recording_options() != nullptr) {
     warning("JFR will be disabled during CDS dumping");
     teardown_startup_support();
     return true;
@@ -227,7 +228,7 @@ bool JfrRecorder::on_create_vm_2() {
 
 bool JfrRecorder::on_create_vm_3() {
   assert(JvmtiEnvBase::get_phase() == JVMTI_PHASE_LIVE, "invalid init sequence");
-  return Arguments::is_dumping_archive() || launch_command_line_recordings(JavaThread::current());
+  return CDSConfig::is_dumping_archive() || launch_command_line_recordings(JavaThread::current());
 }
 
 static bool _created = false;
diff --git a/src/hotspot/share/memory/universe.cpp b/src/hotspot/share/memory/universe.cpp
index 8dcdb6a5f92..1c0a5461ffe 100644
--- a/src/hotspot/share/memory/universe.cpp
+++ b/src/hotspot/share/memory/universe.cpp
@@ -24,6 +24,7 @@
 
 #include "precompiled.hpp"
 #include "cds/archiveHeapLoader.hpp"
+#include "cds/cdsConfig.hpp"
 #include "cds/dynamicArchive.hpp"
 #include "cds/heapShared.hpp"
 #include "cds/metaspaceShared.hpp"
@@ -822,7 +823,7 @@ jint universe_init() {
     // system dictionary, symbol table, etc.)
     MetaspaceShared::initialize_shared_spaces();
   }
-  if (Arguments::is_dumping_archive()) {
+  if (CDSConfig::is_dumping_archive()) {
     MetaspaceShared::prepare_for_dumping();
   }
 #endif
diff --git a/src/hotspot/share/oops/constantPool.cpp b/src/hotspot/share/oops/constantPool.cpp
index 94908fb36b2..4b56bc3f536 100644
--- a/src/hotspot/share/oops/constantPool.cpp
+++ b/src/hotspot/share/oops/constantPool.cpp
@@ -26,6 +26,7 @@
 #include "cds/archiveHeapWriter.hpp"
 #include "cds/archiveHeapLoader.hpp"
 #include "cds/archiveBuilder.hpp"
+#include "cds/cdsConfig.hpp"
 #include "cds/classPrelinker.hpp"
 #include "cds/heapShared.hpp"
 #include "classfile/classLoaderData.hpp"
@@ -219,7 +220,7 @@ void ConstantPool::initialize_resolved_references(ClassLoaderData* loader_data,
     set_resolved_references(loader_data->add_handle(refs_handle));
 
     // Create a "scratch" copy of the resolved references array to archive
-    if (DumpSharedSpaces) {
+    if (CDSConfig::is_dumping_heap()) {
       objArrayOop scratch_references = oopFactory::new_objArray(vmClasses::Object_klass(), map_length, CHECK);
       HeapShared::add_scratch_resolved_references(this, scratch_references);
     }
diff --git a/src/hotspot/share/oops/cpCache.cpp b/src/hotspot/share/oops/cpCache.cpp
index 9a9d147632d..9bc19477efd 100644
--- a/src/hotspot/share/oops/cpCache.cpp
+++ b/src/hotspot/share/oops/cpCache.cpp
@@ -24,6 +24,7 @@
 
 #include "precompiled.hpp"
 #include "cds/archiveBuilder.hpp"
+#include "cds/cdsConfig.hpp"
 #include "cds/heapShared.hpp"
 #include "classfile/resolutionErrors.hpp"
 #include "classfile/systemDictionary.hpp"
@@ -704,7 +705,7 @@ void ConstantPoolCache::save_for_archive(TRAPS) {
 }
 
 void ConstantPoolCache::remove_unshareable_info() {
-  Arguments::assert_is_dumping_archive();
+  assert(CDSConfig::is_dumping_archive(), "sanity");
   //  is the copy to be written into the archive. It's in the ArchiveBuilder's "buffer space".
   // However, this->_initial_entries was not copied/relocated by the ArchiveBuilder, so it's
   // still pointing to the array allocated inside save_for_archive().
@@ -738,7 +739,7 @@ void ConstantPoolCache::deallocate_contents(ClassLoaderData* data) {
   set_reference_map(nullptr);
 #if INCLUDE_CDS
   if (_initial_entries != nullptr) {
-    Arguments::assert_is_dumping_archive();
+    assert(CDSConfig::is_dumping_archive(), "sanity");
     MetadataFactory::free_array(data, _initial_entries);
     if (_resolved_indy_entries) {
       MetadataFactory::free_array(data, _resolved_indy_entries);
diff --git a/src/hotspot/share/oops/instanceKlass.cpp b/src/hotspot/share/oops/instanceKlass.cpp
index ee8adc48958..f1050f5b315 100644
--- a/src/hotspot/share/oops/instanceKlass.cpp
+++ b/src/hotspot/share/oops/instanceKlass.cpp
@@ -24,6 +24,7 @@
 
 #include "precompiled.hpp"
 #include "cds/archiveUtils.hpp"
+#include "cds/cdsConfig.hpp"
 #include "cds/classListWriter.hpp"
 #include "cds/heapShared.hpp"
 #include "cds/metaspaceShared.hpp"
@@ -702,7 +703,7 @@ void InstanceKlass::deallocate_contents(ClassLoaderData* loader_data) {
   SystemDictionaryShared::handle_class_unloading(this);
 
 #if INCLUDE_CDS_JAVA_HEAP
-  if (DumpSharedSpaces) {
+  if (CDSConfig::is_dumping_heap()) {
     HeapShared::remove_scratch_objects(this);
   }
 #endif
@@ -4087,7 +4088,7 @@ void InstanceKlass::verify_on(outputStream* st) {
     Array* method_ordering = this->method_ordering();
     int length = method_ordering->length();
     if (JvmtiExport::can_maintain_original_method_order() ||
-        ((UseSharedSpaces || Arguments::is_dumping_archive()) && length != 0)) {
+        ((UseSharedSpaces || CDSConfig::is_dumping_archive()) && length != 0)) {
       guarantee(length == methods()->length(), "invalid method ordering length");
       jlong sum = 0;
       for (int j = 0; j < length; j++) {
diff --git a/src/hotspot/share/oops/klass.cpp b/src/hotspot/share/oops/klass.cpp
index 036386e7e3e..3af4bffaeaa 100644
--- a/src/hotspot/share/oops/klass.cpp
+++ b/src/hotspot/share/oops/klass.cpp
@@ -24,6 +24,7 @@
 
 #include "precompiled.hpp"
 #include "cds/archiveHeapLoader.hpp"
+#include "cds/cdsConfig.hpp"
 #include "cds/heapShared.hpp"
 #include "classfile/classLoaderData.inline.hpp"
 #include "classfile/classLoaderDataGraph.inline.hpp"
@@ -48,7 +49,6 @@
 #include "oops/oop.inline.hpp"
 #include "oops/oopHandle.inline.hpp"
 #include "prims/jvmtiExport.hpp"
-#include "runtime/arguments.hpp"
 #include "runtime/atomic.hpp"
 #include "runtime/handles.inline.hpp"
 #include "utilities/macros.hpp"
@@ -85,7 +85,7 @@ void Klass::set_name(Symbol* n) {
   _name = n;
   if (_name != nullptr) _name->increment_refcount();
 
-  if (Arguments::is_dumping_archive() && is_instance_klass()) {
+  if (CDSConfig::is_dumping_archive() && is_instance_klass()) {
     SystemDictionaryShared::init_dumptime_info(InstanceKlass::cast(this));
   }
 }
@@ -520,7 +520,7 @@ void Klass::metaspace_pointers_do(MetaspaceClosure* it) {
     it->push(&_primary_supers[i]);
   }
   it->push(&_super);
-  if (!Arguments::is_dumping_archive()) {
+  if (!CDSConfig::is_dumping_archive()) {
     // If dumping archive, these may point to excluded classes. There's no need
     // to follow these pointers anyway, as they will be set to null in
     // remove_unshareable_info().
@@ -537,7 +537,7 @@ void Klass::metaspace_pointers_do(MetaspaceClosure* it) {
 
 #if INCLUDE_CDS
 void Klass::remove_unshareable_info() {
-  assert (Arguments::is_dumping_archive(),
+  assert(CDSConfig::is_dumping_archive(),
           "only called during CDS dump time");
   JFR_ONLY(REMOVE_ID(this);)
   if (log_is_enabled(Trace, cds, unshareable)) {
@@ -555,7 +555,7 @@ void Klass::remove_unshareable_info() {
 }
 
 void Klass::remove_java_mirror() {
-  Arguments::assert_is_dumping_archive();
+  assert(CDSConfig::is_dumping_archive(), "sanity");
   if (log_is_enabled(Trace, cds, unshareable)) {
     ResourceMark rm;
     log_trace(cds, unshareable)("remove java_mirror: %s", external_name());
@@ -645,7 +645,7 @@ void Klass::clear_archived_mirror_index() {
 
 // No GC barrier
 void Klass::set_archived_java_mirror(int mirror_index) {
-  assert(DumpSharedSpaces, "called only during dumptime");
+  assert(CDSConfig::is_dumping_heap(), "sanity");
   _archived_mirror_index = mirror_index;
 }
 #endif // INCLUDE_CDS_JAVA_HEAP
diff --git a/src/hotspot/share/oops/method.cpp b/src/hotspot/share/oops/method.cpp
index a94698c5605..003f47b1e9c 100644
--- a/src/hotspot/share/oops/method.cpp
+++ b/src/hotspot/share/oops/method.cpp
@@ -23,6 +23,7 @@
  */
 
 #include "precompiled.hpp"
+#include "cds/cdsConfig.hpp"
 #include "cds/cppVtables.hpp"
 #include "cds/metaspaceShared.hpp"
 #include "classfile/classLoaderDataGraph.hpp"
@@ -59,12 +60,12 @@
 #include "oops/symbol.hpp"
 #include "prims/jvmtiExport.hpp"
 #include "prims/methodHandles.hpp"
-#include "runtime/arguments.hpp"
 #include "runtime/atomic.hpp"
 #include "runtime/continuationEntry.hpp"
 #include "runtime/frame.inline.hpp"
 #include "runtime/handles.inline.hpp"
 #include "runtime/init.hpp"
+#include "runtime/java.hpp"
 #include "runtime/orderAccess.hpp"
 #include "runtime/relocator.hpp"
 #include "runtime/safepointVerifiers.hpp"
@@ -1166,7 +1167,7 @@ void Method::unlink_code() {
 #if INCLUDE_CDS
 // Called by class data sharing to remove any entry points (which are not shared)
 void Method::unlink_method() {
-  Arguments::assert_is_dumping_archive();
+  assert(CDSConfig::is_dumping_archive(), "sanity");
   _code = nullptr;
   _adapter = nullptr;
   _i2i_entry = nullptr;
diff --git a/src/hotspot/share/oops/oop.cpp b/src/hotspot/share/oops/oop.cpp
index c2c78ce581e..17a9bf9c412 100644
--- a/src/hotspot/share/oops/oop.cpp
+++ b/src/hotspot/share/oops/oop.cpp
@@ -23,6 +23,7 @@
  */
 
 #include "precompiled.hpp"
+#include "cds/cdsConfig.hpp"
 #include "classfile/altHashing.hpp"
 #include "classfile/javaClasses.inline.hpp"
 #include "gc/shared/collectedHeap.inline.hpp"
@@ -162,7 +163,7 @@ bool oopDesc::has_klass_gap() {
 
 #if INCLUDE_CDS_JAVA_HEAP
 void oopDesc::set_narrow_klass(narrowKlass nk) {
-  assert(DumpSharedSpaces, "Used by CDS only. Do not abuse!");
+  assert(CDSConfig::is_dumping_heap(), "Used by CDS only. Do not abuse!");
   assert(UseCompressedClassPointers, "must be");
   _metadata._compressed_klass = nk;
 }
diff --git a/src/hotspot/share/prims/jvm.cpp b/src/hotspot/share/prims/jvm.cpp
index e8c97351a5f..582eab9dc5b 100644
--- a/src/hotspot/share/prims/jvm.cpp
+++ b/src/hotspot/share/prims/jvm.cpp
@@ -23,6 +23,7 @@
  */
 
 #include "precompiled.hpp"
+#include "cds/cdsConfig.hpp"
 #include "cds/classListParser.hpp"
 #include "cds/classListWriter.hpp"
 #include "cds/dynamicArchive.hpp"
@@ -3606,7 +3607,7 @@ JVM_ENTRY(void, JVM_RegisterLambdaProxyClassForArchiving(JNIEnv* env,
                                               jobject dynamicMethodType,
                                               jclass lambdaProxyClass))
 #if INCLUDE_CDS
-  if (!Arguments::is_dumping_archive()) {
+  if (!CDSConfig::is_dumping_archive()) {
     return;
   }
 
@@ -3694,7 +3695,7 @@ JVM_ENTRY(jclass, JVM_LookupLambdaProxyClassFromArchive(JNIEnv* env,
 JVM_END
 
 JVM_LEAF(jboolean, JVM_IsCDSDumpingEnabled(JNIEnv* env))
-  return Arguments::is_dumping_archive();
+  return CDSConfig::is_dumping_archive();
 JVM_END
 
 JVM_LEAF(jboolean, JVM_IsSharingEnabled(JNIEnv* env))
diff --git a/src/hotspot/share/prims/jvmtiAgent.cpp b/src/hotspot/share/prims/jvmtiAgent.cpp
index 86c5a32a1df..7e2f14ead3c 100644
--- a/src/hotspot/share/prims/jvmtiAgent.cpp
+++ b/src/hotspot/share/prims/jvmtiAgent.cpp
@@ -25,6 +25,7 @@
 #include "prims/jvmtiAgent.hpp"
 
 #include "cds/cds_globals.hpp"
+#include "cds/cdsConfig.hpp"
 #include "jni.h"
 #include "jvm_io.h"
 #include "jvmtifiles/jvmtiEnv.hpp"
@@ -623,7 +624,7 @@ static bool invoke_Agent_OnAttach(JvmtiAgent* agent, outputStream* st) {
 // CDS dumping supports Java agent if the AllowArchivingWithJavaAgent diagnostic option is specified.
 static void check_cds_dump(JvmtiAgent* agent) {
   assert(agent != nullptr, "invariant");
-  assert(Arguments::is_dumping_archive(), "invariant");
+  assert(CDSConfig::is_dumping_archive(), "invariant");
   if (!agent->is_instrument_lib()) {
     vm_exit_during_cds_dumping("CDS dumping does not support native JVMTI agent, name", agent->name());
   }
@@ -639,7 +640,7 @@ static bool invoke_Agent_OnLoad(JvmtiAgent* agent) {
   assert(!agent->is_xrun(), "invariant");
   assert(!agent->is_dynamic(), "invariant");
   assert(JvmtiEnvBase::get_phase() == JVMTI_PHASE_ONLOAD, "invariant");
-  if (Arguments::is_dumping_archive()) {
+  if (CDSConfig::is_dumping_archive()) {
     check_cds_dump(agent);
   }
   OnLoadEntry_t on_load_entry = lookup_Agent_OnLoad_entry_point(agent);
diff --git a/src/hotspot/share/runtime/arguments.cpp b/src/hotspot/share/runtime/arguments.cpp
index bcc0ab944f0..df55639d814 100644
--- a/src/hotspot/share/runtime/arguments.cpp
+++ b/src/hotspot/share/runtime/arguments.cpp
@@ -24,6 +24,7 @@
 
 #include "precompiled.hpp"
 #include "cds/cds_globals.hpp"
+#include "cds/cdsConfig.hpp"
 #include "cds/filemap.hpp"
 #include "classfile/classLoader.hpp"
 #include "classfile/javaAssertions.hpp"
@@ -1332,7 +1333,7 @@ const char* unsupported_options[] = { "--limit-modules",
                                       "--patch-module"
                                     };
 void Arguments::check_unsupported_dumping_properties() {
-  assert(is_dumping_archive(),
+  assert(CDSConfig::is_dumping_archive(),
          "this function is only used with CDS dump time");
   assert(ARRAY_SIZE(unsupported_properties) == ARRAY_SIZE(unsupported_options), "must be");
   // If a vm option is found in the unsupported_options array, vm will exit with an error message.
@@ -3451,7 +3452,7 @@ void Arguments::init_shared_archive_paths() {
     int archives = num_archives(SharedArchiveFile);
     assert(archives > 0, "must be");
 
-    if (is_dumping_archive() && archives > 1) {
+    if (CDSConfig::is_dumping_archive() && archives > 1) {
       vm_exit_during_initialization(
         "Cannot have more than 1 archive file specified in -XX:SharedArchiveFile during CDS dumping");
     }
diff --git a/src/hotspot/share/runtime/arguments.hpp b/src/hotspot/share/runtime/arguments.hpp
index f7b513d4e12..2b871fdc0c9 100644
--- a/src/hotspot/share/runtime/arguments.hpp
+++ b/src/hotspot/share/runtime/arguments.hpp
@@ -525,12 +525,6 @@ class Arguments : AllStatic {
 
   static bool has_jfr_option() NOT_JFR_RETURN_(false);
 
-  static bool is_dumping_archive() { return DumpSharedSpaces || DynamicDumpSharedSpaces; }
-
-  static void assert_is_dumping_archive() {
-    assert(Arguments::is_dumping_archive(), "dump time only");
-  }
-
   DEBUG_ONLY(static bool verify_special_jvm_flags(bool check_globals);)
 };
 

From ffadd635759d0898cd108f5fe5fe3a4a3de91763 Mon Sep 17 00:00:00 2001
From: Per Minborg 
Date: Mon, 23 Oct 2023 06:16:27 +0000
Subject: [PATCH 058/124] 8317868: Add @sealedGraph to MethodHandleDesc and
 descendants

Reviewed-by: jvernee, mli
---
 .../share/classes/java/lang/constant/MethodHandleDesc.java       | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/java.base/share/classes/java/lang/constant/MethodHandleDesc.java b/src/java.base/share/classes/java/lang/constant/MethodHandleDesc.java
index 9e8633d26e0..91d6951153e 100644
--- a/src/java.base/share/classes/java/lang/constant/MethodHandleDesc.java
+++ b/src/java.base/share/classes/java/lang/constant/MethodHandleDesc.java
@@ -35,6 +35,7 @@
  * A nominal descriptor for a
  * {@link MethodHandle} constant.
  *
+ * @sealedGraph
  * @since 12
  */
 public sealed interface MethodHandleDesc

From 4eab39d9415b2ec5c2984d0d3c110e9364090835 Mon Sep 17 00:00:00 2001
From: Thomas Schatzl 
Date: Mon, 23 Oct 2023 07:35:11 +0000
Subject: [PATCH 059/124] 8318585: Rename CodeCache::UnloadingScope to
 UnlinkingScope

Reviewed-by: ayang, iwalulya, mli
---
 src/hotspot/share/code/codeCache.cpp                |  4 ++--
 src/hotspot/share/code/codeCache.hpp                | 11 +++++++----
 src/hotspot/share/gc/g1/g1ConcurrentMark.cpp        |  2 +-
 src/hotspot/share/gc/g1/g1FullCollector.cpp         |  2 +-
 src/hotspot/share/gc/parallel/psParallelCompact.cpp |  2 +-
 src/hotspot/share/gc/serial/genMarkSweep.cpp        |  2 +-
 src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp  |  2 +-
 7 files changed, 14 insertions(+), 11 deletions(-)

diff --git a/src/hotspot/share/code/codeCache.cpp b/src/hotspot/share/code/codeCache.cpp
index 85ab194eba4..99539ed80cc 100644
--- a/src/hotspot/share/code/codeCache.cpp
+++ b/src/hotspot/share/code/codeCache.cpp
@@ -1016,7 +1016,7 @@ void CodeCache::increment_unloading_cycle() {
   }
 }
 
-CodeCache::UnloadingScope::UnloadingScope(BoolObjectClosure* is_alive)
+CodeCache::UnlinkingScope::UnlinkingScope(BoolObjectClosure* is_alive)
   : _is_unloading_behaviour(is_alive)
 {
   _saved_behaviour = IsUnloadingBehaviour::current();
@@ -1025,7 +1025,7 @@ CodeCache::UnloadingScope::UnloadingScope(BoolObjectClosure* is_alive)
   DependencyContext::cleaning_start();
 }
 
-CodeCache::UnloadingScope::~UnloadingScope() {
+CodeCache::UnlinkingScope::~UnlinkingScope() {
   IsUnloadingBehaviour::set_current(_saved_behaviour);
   DependencyContext::cleaning_end();
 }
diff --git a/src/hotspot/share/code/codeCache.hpp b/src/hotspot/share/code/codeCache.hpp
index 0300179942f..1b65fb3596e 100644
--- a/src/hotspot/share/code/codeCache.hpp
+++ b/src/hotspot/share/code/codeCache.hpp
@@ -177,14 +177,17 @@ class CodeCache : AllStatic {
 
   // GC support
   static void verify_oops();
-  // Scope object managing code cache unloading behavior.
-  class UnloadingScope: StackObj {
+
+  // Helper scope object managing code cache unlinking behavior, i.e. sets and
+  // restores the closure that determines which nmethods are going to be removed
+  // during the unlinking part of code cache unloading.
+  class UnlinkingScope : StackObj {
     ClosureIsUnloadingBehaviour _is_unloading_behaviour;
     IsUnloadingBehaviour*       _saved_behaviour;
 
   public:
-    UnloadingScope(BoolObjectClosure* is_alive);
-    ~UnloadingScope();
+    UnlinkingScope(BoolObjectClosure* is_alive);
+    ~UnlinkingScope();
   };
 
   // Code cache unloading heuristics
diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp
index da0e058cc32..f46ac31ceeb 100644
--- a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp
+++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp
@@ -1695,7 +1695,7 @@ void G1ConcurrentMark::weak_refs_work() {
   if (ClassUnloadingWithConcurrentMark) {
     GCTraceTime(Debug, gc, phases) debug("Class Unloading", _gc_timer_cm);
     {
-      CodeCache::UnloadingScope scope(&g1_is_alive);
+      CodeCache::UnlinkingScope scope(&g1_is_alive);
       bool unloading_occurred = SystemDictionary::do_unloading(_gc_timer_cm);
       _g1h->complete_cleaning(unloading_occurred);
     }
diff --git a/src/hotspot/share/gc/g1/g1FullCollector.cpp b/src/hotspot/share/gc/g1/g1FullCollector.cpp
index f225937a49f..039f13019ab 100644
--- a/src/hotspot/share/gc/g1/g1FullCollector.cpp
+++ b/src/hotspot/share/gc/g1/g1FullCollector.cpp
@@ -320,7 +320,7 @@ void G1FullCollector::phase1_mark_live_objects() {
   if (ClassUnloading) {
     GCTraceTime(Debug, gc, phases) debug("Phase 1: Class Unloading and Cleanup", scope()->timer());
     {
-      CodeCache::UnloadingScope unloading_scope(&_is_alive);
+      CodeCache::UnlinkingScope unloading_scope(&_is_alive);
       // Unload classes and purge the SystemDictionary.
       bool unloading_occurred = SystemDictionary::do_unloading(scope()->timer());
       _heap->complete_cleaning(unloading_occurred);
diff --git a/src/hotspot/share/gc/parallel/psParallelCompact.cpp b/src/hotspot/share/gc/parallel/psParallelCompact.cpp
index 637a7d3955c..b8ee8ef6163 100644
--- a/src/hotspot/share/gc/parallel/psParallelCompact.cpp
+++ b/src/hotspot/share/gc/parallel/psParallelCompact.cpp
@@ -2055,7 +2055,7 @@ void PSParallelCompact::marking_phase(ParallelOldTracer *gc_tracer) {
 
     bool unloading_occurred;
     {
-      CodeCache::UnloadingScope scope(is_alive_closure());
+      CodeCache::UnlinkingScope scope(is_alive_closure());
 
       // Follow system dictionary roots and unload classes.
       unloading_occurred = SystemDictionary::do_unloading(&_gc_timer);
diff --git a/src/hotspot/share/gc/serial/genMarkSweep.cpp b/src/hotspot/share/gc/serial/genMarkSweep.cpp
index 3228493b848..6eb3da6892d 100644
--- a/src/hotspot/share/gc/serial/genMarkSweep.cpp
+++ b/src/hotspot/share/gc/serial/genMarkSweep.cpp
@@ -202,7 +202,7 @@ void GenMarkSweep::mark_sweep_phase1(bool clear_all_softrefs) {
 
     bool unloading_occurred;
     {
-      CodeCache::UnloadingScope scope(&is_alive);
+      CodeCache::UnlinkingScope scope(&is_alive);
 
       // Unload classes and purge the SystemDictionary.
       unloading_occurred = SystemDictionary::do_unloading(gc_timer());
diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp
index 3e266cd9b4d..b6d77d1147e 100644
--- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp
+++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp
@@ -1812,7 +1812,7 @@ void ShenandoahHeap::stw_unload_classes(bool full_gc) {
                                           ShenandoahPhaseTimings::degen_gc_purge_class_unload;
     ShenandoahIsAliveSelector is_alive;
     {
-      CodeCache::UnloadingScope scope(is_alive.is_alive_closure());
+      CodeCache::UnlinkingScope scope(is_alive.is_alive_closure());
       ShenandoahGCPhase gc_phase(phase);
       ShenandoahGCWorkerPhase worker_phase(phase);
       bool unloading_occurred = SystemDictionary::do_unloading(gc_timer());

From 729f4c5d141cdc272249c4c69efd05f96a654137 Mon Sep 17 00:00:00 2001
From: Thomas Schatzl 
Date: Mon, 23 Oct 2023 08:19:50 +0000
Subject: [PATCH 060/124] 8318507: G1: Improve remset clearing for humongous
 candidates

Reviewed-by: iwalulya, ayang, mli
---
 src/hotspot/share/gc/g1/g1RemSet.cpp | 16 +++++-----------
 1 file changed, 5 insertions(+), 11 deletions(-)

diff --git a/src/hotspot/share/gc/g1/g1RemSet.cpp b/src/hotspot/share/gc/g1/g1RemSet.cpp
index f620b9778a4..0bc34d1e558 100644
--- a/src/hotspot/share/gc/g1/g1RemSet.cpp
+++ b/src/hotspot/share/gc/g1/g1RemSet.cpp
@@ -1186,23 +1186,17 @@ class G1MergeHeapRootsTask : public WorkerTask {
       guarantee(r->rem_set()->occupancy_less_or_equal_than(G1EagerReclaimRemSetThreshold),
                 "Found a not-small remembered set here. This is inconsistent with previous assumptions.");
 
-
       _cl.merge_card_set_for_region(r);
 
       // We should only clear the card based remembered set here as we will not
       // implicitly rebuild anything else during eager reclaim. Note that at the moment
       // (and probably never) we do not enter this path if there are other kind of
       // remembered sets for this region.
-      r->rem_set()->clear(true /* only_cardset */);
-      // Clear_locked() above sets the state to Empty. However we want to continue
-      // collecting remembered set entries for humongous regions that were not
-      // reclaimed.
-      r->rem_set()->set_state_complete();
-#ifdef ASSERT
-      G1HeapRegionAttr region_attr = g1h->region_attr(region_index);
-      assert(region_attr.remset_is_tracked(), "must be");
-#endif
-      assert(r->rem_set()->is_empty(), "At this point any humongous candidate remembered set must be empty.");
+      // We want to continue collecting remembered set entries for humongous regions
+      // that were not reclaimed.
+      r->rem_set()->clear(true /* only_cardset */, true /* keep_tracked */);
+
+      assert(r->rem_set()->is_empty() && r->rem_set()->is_complete(), "must be for eager reclaim candidates");
 
       return false;
     }

From fc29a2e152310ed81bd1bb23e6f17d02f055a454 Mon Sep 17 00:00:00 2001
From: Pavel Rappo 
Date: Mon, 23 Oct 2023 09:24:51 +0000
Subject: [PATCH 061/124] 8318082: ConcurrentModificationException from
 IndexWriter

Reviewed-by: jjg
---
 .../html/AbstractOverviewIndexWriter.java     |   7 +-
 .../doclets/formats/html/ClassWriter.java     |   5 +
 .../doclets/formats/html/DocFilesHandler.java |   7 +-
 .../formats/html/HtmlDocletWriter.java        |  17 +-
 .../doclets/formats/html/ModuleWriter.java    |   5 +
 .../doclets/formats/html/PackageWriter.java   |   5 +
 .../formats/html/taglets/TagletWriter.java    |   5 +-
 .../doclet/testIndex/TestSelfIndexing.java    | 164 ++++++++++++++++++
 .../javadoc/doclet/testSearch/TestSearch.java |  34 +---
 9 files changed, 214 insertions(+), 35 deletions(-)
 create mode 100644 test/langtools/jdk/javadoc/doclet/testIndex/TestSelfIndexing.java

diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractOverviewIndexWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractOverviewIndexWriter.java
index d46b4c69d82..2d7fb6e9b11 100644
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractOverviewIndexWriter.java
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AbstractOverviewIndexWriter.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2019, 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
@@ -113,6 +113,11 @@ public void buildPage() throws DocFileIOException {
                 getDescription(), body);
     }
 
+    @Override
+    public boolean isIndexable() {
+        return true;
+    }
+
     /**
      * Adds the index to the documentation.
      *
diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassWriter.java
index 364619065a5..dcbc78f7107 100644
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassWriter.java
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ClassWriter.java
@@ -769,4 +769,9 @@ protected Content getMemberDetails(Content content) {
         }
         return section;
     }
+
+    @Override
+    public boolean isIndexable() {
+        return true;
+    }
 }
diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/DocFilesHandler.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/DocFilesHandler.java
index 5330b20dcab..5849599a113 100644
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/DocFilesHandler.java
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/DocFilesHandler.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved.
+ * 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
@@ -301,6 +301,11 @@ private List getLocalHeaderTags(List dtree
             }
             return localTags;
         }
+
+        @Override
+        public boolean isIndexable() {
+            return true;
+        }
     }
 
 }
diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java
index 492743a704b..c1f2f8d7a63 100644
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java
@@ -411,6 +411,20 @@ public TagletWriter getTagletWriterInstance(TagletWriter.Context context) {
         return new TagletWriter(this, context);
     }
 
+    /**
+     * {@return true if the page written by this writer should be indexed,
+     * false otherwise}
+     *
+     * Some pages merely aggregate filtered information available on other pages
+     * and, thus, have no indexing value. In fact, if indexed, they would
+     * clutter the index and mislead the reader.
+     *
+     * @implSpec The default implementation returns {@code false}.
+     */
+    public boolean isIndexable() {
+        return false;
+    }
+
     /**
      * Generates the HTML document tree and prints it out.
      *
@@ -1369,7 +1383,8 @@ public Boolean visitInheritDoc(InheritDocTree node, Content content) {
                 @Override
                 public Boolean visitStartElement(StartElementTree node, Content content) {
                     Content attrs = new ContentBuilder();
-                    if (node.getName().toString().matches("(?i)h[1-6]")) {
+                    if (node.getName().toString().matches("(?i)h[1-6]")
+                            && isIndexable()) {
                         createSectionIdAndIndex(node, trees, attrs, element, context);
                     }
                     for (DocTree dt : node.getAttributes()) {
diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ModuleWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ModuleWriter.java
index d37e1334eb4..c9e1f4afaaf 100644
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ModuleWriter.java
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ModuleWriter.java
@@ -923,4 +923,9 @@ public void addPackageDeprecationInfo(Content li, PackageElement pkg) {
             li.add(deprDiv);
         }
     }
+
+    @Override
+    public boolean isIndexable() {
+        return true;
+    }
 }
diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageWriter.java
index e960b2e59ba..55be119f350 100644
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageWriter.java
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/PackageWriter.java
@@ -455,4 +455,9 @@ private List filterPackages(Predicate fi
                 .filter(p -> p != packageElement && filter.test(p))
                 .collect(Collectors.toList());
     }
+
+    @Override
+    public boolean isIndexable() {
+        return true;
+    }
 }
diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/TagletWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/TagletWriter.java
index 2288369d45b..b977951f2fa 100644
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/TagletWriter.java
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/taglets/TagletWriter.java
@@ -49,6 +49,8 @@
 import jdk.javadoc.internal.doclets.formats.html.HtmlDocletWriter;
 import jdk.javadoc.internal.doclets.formats.html.HtmlIds;
 import jdk.javadoc.internal.doclets.formats.html.HtmlOptions;
+import jdk.javadoc.internal.doclets.formats.html.IndexWriter;
+import jdk.javadoc.internal.doclets.formats.html.SummaryListWriter;
 import jdk.javadoc.internal.doclets.formats.html.markup.ContentBuilder;
 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlId;
 import jdk.javadoc.internal.doclets.formats.html.markup.HtmlStyle;
@@ -370,7 +372,8 @@ public Content createAnchorAndSearchIndex(Element element, String tagText, Strin
     @SuppressWarnings("preview")
     Content createAnchorAndSearchIndex(Element element, String tagText, Content tagContent, String desc, DocTree tree) {
         Content result;
-        if (context.isFirstSentence && context.inSummary || context.inTags.contains(DocTree.Kind.INDEX)) {
+        if (context.isFirstSentence && context.inSummary || context.inTags.contains(DocTree.Kind.INDEX)
+                || !htmlWriter.isIndexable()) {
             result = tagContent;
         } else {
             HtmlId id = HtmlIds.forText(tagText, htmlWriter.indexAnchorTable);
diff --git a/test/langtools/jdk/javadoc/doclet/testIndex/TestSelfIndexing.java b/test/langtools/jdk/javadoc/doclet/testIndex/TestSelfIndexing.java
new file mode 100644
index 00000000000..9d1d146d54d
--- /dev/null
+++ b/test/langtools/jdk/javadoc/doclet/testIndex/TestSelfIndexing.java
@@ -0,0 +1,164 @@
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.List;
+import java.util.Optional;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.regex.Pattern;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
+
+import javadoc.tester.JavadocTester;
+import toolbox.ToolBox;
+
+/*
+ * @test
+ * @bug 8318082
+ * @library /tools/lib ../../lib
+ * @modules jdk.javadoc/jdk.javadoc.internal.tool
+ * @build toolbox.ToolBox javadoc.tester.*
+ * @run main TestSelfIndexing
+ */
+public class TestSelfIndexing extends JavadocTester {
+
+    public static void main(String... args) throws Exception {
+        new TestSelfIndexing().runTests();
+    }
+
+    private final ToolBox tb = new ToolBox();
+
+    /*
+     * Pages derived from other pages must not be indexed and may not
+     * cross-reference each other except for navigation ergonomics.
+     *
+     * For example, it's okay for all-index.html to reference deprecated-list.html;
+     * but it is not okay, for all-index.html to reference an anchor, such as
+     * deprecated-list.html#java.lang.Object.finalize()
+     */
+    @Test
+    public void test(Path base) throws Exception {
+        Path src = base.resolve("src");
+        int i = 0;
+        // try to start a search tag (i) with the same letter, H,
+        // as the class, Hello, and (ii) with some other letter, P
+        for (var l : List.of("H", "P")) {
+            // try all markup constructs that cause indexing
+            for (var t : List.of("

%s

", "{@index %s}", "{@systemProperty %s}")) { + tb.writeJavaFiles(src, """ + package pkg; + + /** @deprecated %s */ + public class Hello { } + """.formatted(t.formatted(l))); + + Path out = base.resolve("out-" + i); + checking(t.formatted(l) + "; results in: " + out); + setAutomaticCheckNoStacktrace(true); // no exceptions + javadoc("-d", out.toString(), + "--source-path", src.toString(), + "pkg"); + // check that index pages do not refer to derived pages + try (var s = findIndexFiles(out)) { + record PathAndString(Path path, String str) { } + Optional r = s.map(p -> { + try { + return new PathAndString(p, Files.readString(p)); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + }) + .flatMap(pac -> findLinksToDerivedPages(pac.str) + .map(link -> new PathAndString(pac.path, link))) + .findAny(); + r.ifPresentOrElse(p -> failed(p.toString()), () -> passed(t.formatted(l))); + } + i++; + } + } + } + + // ----------- support and infrastructure ----------- + + private static Stream findIndexFiles(Path start) throws IOException { + return Files.find(start, Integer.MAX_VALUE, (path, attr) -> { + if (attr.isDirectory()) + return false; + var fileName = path.getFileName().toString(); + if (!fileName.endsWith(".html") && !fileName.endsWith(".js")) + return false; + if (!fileName.contains("-index") && !fileName.contains("index-")) + return false; + var underDocFiles = StreamSupport.stream(Spliterators.spliterator(path.iterator(), + Integer.MAX_VALUE, Spliterator.ORDERED), false) + .anyMatch(p -> p.equals(DOC_FILES)); + return !underDocFiles; + }); + } + + private static final Path DOC_FILES = Path.of("doc-files"); + + // good enough to capture relevant parts of URLs that javadoc uses, + // from html and js files alike + private static final Pattern URL = Pattern.compile( + "(?([a-zA-Z.%0-9-]+/)*+)(?[a-zA-Z.%0-9-]+\\.html)#[a-zA-Z.%0-9-]+"); + + static { + assert findLinksToDerivedPages("module-summary.html#a").findAny().isEmpty(); + assert findLinksToDerivedPages("package-summary.html#a").findAny().isEmpty(); + assert findLinksToDerivedPages("Exception.html#a").findAny().isEmpty(); + assert findLinksToDerivedPages("util/doc-files/coll-index.html#a").findAny().isEmpty(); + assert findLinksToDerivedPages("util/doc-files/index-all.html#a").findAny().isEmpty(); // tricky + + + assert findLinksToDerivedPages("index-all.html#a").findAny().isPresent(); + assert findLinksToDerivedPages("index-17.html#a").findAny().isPresent(); + } + + // NOTE: this will not find self-links that are allowed on some index pages. + // For example, the quick-jump first-character links, such as #I:A, + // #I:B, etc., on the top and at the bottom of index-all.html + private static Stream findLinksToDerivedPages(String content) { + return URL.matcher(content).results() + .filter(r -> { + String f = r.group("file"); + if (!f.contains("-")) + return false; + return switch (f) { + case "package-summary.html", + "module-summary.html", + "overview-summary.html", + "help-doc.html" -> false; + default -> { + String p = r.group("path"); + yield !p.contains("/doc-files/") && !p.startsWith("doc-files/"); + } + }; + }) + .map(r -> r.group(0)); + } +} diff --git a/test/langtools/jdk/javadoc/doclet/testSearch/TestSearch.java b/test/langtools/jdk/javadoc/doclet/testSearch/TestSearch.java index 08edce2031e..c2b1515d472 100644 --- a/test/langtools/jdk/javadoc/doclet/testSearch/TestSearch.java +++ b/test/langtools/jdk/javadoc/doclet/testSearch/TestSearch.java @@ -26,7 +26,7 @@ * @bug 8141492 8071982 8141636 8147890 8166175 8168965 8176794 8175218 8147881 * 8181622 8182263 8074407 8187521 8198522 8182765 8199278 8196201 8196202 * 8184205 8214468 8222548 8223378 8234746 8241219 8254627 8247994 8263528 - * 8266808 8248863 8305710 + * 8266808 8248863 8305710 8318082 * @summary Test the search feature of javadoc. * @library ../../lib * @modules jdk.javadoc/jdk.javadoc.internal.tool @@ -503,14 +503,6 @@ constant in enum class pkg2.TWO - Enum con\ stant in enum class pkg2.TestEnum"""); - checkOutput("index-all.html", true, - """ -
class_test1 passes. Search tag SearchTagDeprecatedClass""", - """ -
error_test3 passes. Search tag for - method SearchTagDeprecatedMethod
"""); } void checkSplitIndex() { @@ -621,13 +613,7 @@ ion interface pkg2.TestAnnotationType""", k">SearchTagDeprecatedClass - Search tag in class pkg2.TestClass""", """
Single\ - Word - Search tag in package pkg
""", - """ -
class_test1 passes. Search tag SearchTagDeprecatedClass
""", - """ -
error_test3 passes. Search tag for - method SearchTagDeprecatedMethod
"""); + Word - Search tag in package pkg"""); checkOutput("index-all.html", true, """
\ @@ -665,13 +651,7 @@ ion interface pkg2.TestAnnotationType
""", search phrase deprecated - Search tag in pkg2.TestEnum.ONE""", """
SearchTagDeprecatedMethod - Search tag in pkg2.TestError.TestError()
""", - """ -
class_test1 passes. Search tag SearchTagDeprecatedClass
""", - """ -
error_test3 passes. Search tag for - method SearchTagDeprecatedMethod
"""); + nk">SearchTagDeprecatedMethod - Search tag in pkg2.TestError.TestError()"""); } void checkJavaFXOutput() { @@ -839,20 +819,12 @@ void checkSearchTagIndex() { {"l":"r","h":"package pkg","u":"pkg/package-summary.html#r"}""", """ {"l":"search phrase","h":"class pkg1.RegClass","d":"with description","u":"pkg1/RegClass.html#searchphrase"}""", - """ - {"l":"search phrase deprecated","h":"pkg2.TestEnum.ONE","u":"deprecated-list.html#searchphrasedeprecated"}""", """ {"l":"search phrase deprecated","h":"pkg2.TestEnum.ONE","u":"pkg2/TestEnum.html#searchphrasedeprecated"}""", - """ - {"l":"search phrase with desc deprecated","h":"annotation interface pkg2.TestAnnotationType","d":"description for phrase deprecated","u":"deprecated-list.html#searchphrasewithdescdeprecated"}""", """ {"l":"search phrase with desc deprecated","h":"annotation interface pkg2.TestAnnotationType","d":"description for phrase deprecated","u":"pkg2/TestAnnotationType.html#searchphrasewithdescdeprecated"}""", - """ - {"l":"SearchTagDeprecatedClass","h":"class pkg2.TestClass","u":"deprecated-list.html#SearchTagDeprecatedClass"}""", """ {"l":"SearchTagDeprecatedClass","h":"class pkg2.TestClass","u":"pkg2/TestClass.html#SearchTagDeprecatedClass"}""", - """ - {"l":"SearchTagDeprecatedMethod","h":"pkg2.TestError.TestError()","d":"with description","u":"deprecated-list.html#SearchTagDeprecatedMethod"}""", """ {"l":"SearchTagDeprecatedMethod","h":"pkg2.TestError.TestError()","d":"with description","u":"pkg2/TestError.html#SearchTagDeprecatedMethod"}""", """ From ff5c5b6541b43a1323ba08f7a086e64de197edda Mon Sep 17 00:00:00 2001 From: Thomas Stuefe Date: Mon, 23 Oct 2023 09:59:43 +0000 Subject: [PATCH 062/124] 8318643: +UseTransparentHugePages must enable +UseLargePages Reviewed-by: sjohanss --- src/hotspot/os/linux/os_linux.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp index 40a576c09ae..685fa174ac9 100644 --- a/src/hotspot/os/linux/os_linux.cpp +++ b/src/hotspot/os/linux/os_linux.cpp @@ -3775,6 +3775,8 @@ void os::large_page_init() { _large_page_size = HugePages::thp_pagesize(); _page_sizes.add(_large_page_size); _page_sizes.add(os::vm_page_size()); + // +UseTransparentHugePages implies +UseLargePages + UseLargePages = true; } else { From 7c0a8288b23c11d455472762b56d5b20ac5b9f03 Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Mon, 23 Oct 2023 11:04:29 +0000 Subject: [PATCH 063/124] 8318649: G1: Remove unimplemented HeapRegionRemSet::add_code_root_locked Reviewed-by: tschatzl --- src/hotspot/share/gc/g1/heapRegionRemSet.hpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/hotspot/share/gc/g1/heapRegionRemSet.hpp b/src/hotspot/share/gc/g1/heapRegionRemSet.hpp index 960d0864a50..d75f52baa95 100644 --- a/src/hotspot/share/gc/g1/heapRegionRemSet.hpp +++ b/src/hotspot/share/gc/g1/heapRegionRemSet.hpp @@ -149,7 +149,6 @@ class HeapRegionRemSet : public CHeapObj { // Routines for managing the list of code roots that point into // the heap region that owns this RSet. void add_code_root(nmethod* nm); - void add_code_root_locked(nmethod* nm); void remove_code_root(nmethod* nm); // Applies blk->do_code_blob() to each of the entries in _code_roots From 704c6ea16cabc217588f430fd3c302d6df5e9c19 Mon Sep 17 00:00:00 2001 From: Matthew Donovan Date: Mon, 23 Oct 2023 11:15:32 +0000 Subject: [PATCH 064/124] 8303525: Refactor/cleanup open/test/jdk/javax/rmi/ssl/SSLSocketParametersTest.java Reviewed-by: smarks, msheppar --- .../rmi/ssl/SSLSocketParametersTest.java | 156 +++++------------- test/lib/jdk/test/lib/Asserts.java | 40 +++++ 2 files changed, 81 insertions(+), 115 deletions(-) diff --git a/test/jdk/javax/rmi/ssl/SSLSocketParametersTest.java b/test/jdk/javax/rmi/ssl/SSLSocketParametersTest.java index 63d9332f353..6da32894587 100644 --- a/test/jdk/javax/rmi/ssl/SSLSocketParametersTest.java +++ b/test/jdk/javax/rmi/ssl/SSLSocketParametersTest.java @@ -24,6 +24,7 @@ /* * @test * @bug 5016500 + * @library /test/lib/ * @summary Test SslRmi[Client|Server]SocketFactory SSL socket parameters. * @run main/othervm SSLSocketParametersTest 1 * @run main/othervm SSLSocketParametersTest 2 @@ -33,14 +34,15 @@ * @run main/othervm SSLSocketParametersTest 6 * @run main/othervm SSLSocketParametersTest 7 */ +import jdk.test.lib.Asserts; + import java.io.IOException; import java.io.File; import java.io.Serializable; -import java.net.ServerSocket; -import java.net.Socket; +import java.lang.ref.Reference; +import java.rmi.ConnectIOException; import java.rmi.Remote; import java.rmi.RemoteException; -import java.rmi.server.RMIClientSocketFactory; import java.rmi.server.RMIServerSocketFactory; import java.rmi.server.UnicastRemoteObject; import javax.net.ssl.SSLContext; @@ -50,121 +52,30 @@ public class SSLSocketParametersTest implements Serializable { public interface Hello extends Remote { - public String sayHello() throws RemoteException; + String sayHello() throws RemoteException; } - public class HelloImpl extends UnicastRemoteObject implements Hello { - - public HelloImpl(int port, - RMIClientSocketFactory csf, - RMIServerSocketFactory ssf) - throws RemoteException { - super(port, csf, ssf); - } - + public class HelloImpl implements Hello { public String sayHello() { return "Hello World!"; } - - public Remote runServer() throws IOException { - System.out.println("Inside HelloImpl::runServer"); - // Get a remote stub for this RMI object - // - Remote stub = toStub(this); - System.out.println("Stub = " + stub); - return stub; - } - } - - public class HelloClient { - - public void runClient(Remote stub) throws IOException { - System.out.println("Inside HelloClient::runClient"); - // "obj" is the identifier that we'll use to refer - // to the remote object that implements the "Hello" - // interface - Hello obj = (Hello) stub; - String message = obj.sayHello(); - System.out.println(message); - } - } - - public static class ClientFactory extends SslRMIClientSocketFactory { - - public ClientFactory() { - super(); - } - - public Socket createSocket(String host, int port) throws IOException { - System.out.println("ClientFactory::Calling createSocket(" + - host + "," + port + ")"); - return super.createSocket(host, port); - } - } - - public static class ServerFactory extends SslRMIServerSocketFactory { - - public ServerFactory() { - super(); - } - - public ServerFactory(String[] ciphers, - String[] protocols, - boolean need) { - super(ciphers, protocols, need); - } - - public ServerFactory(SSLContext context, - String[] ciphers, - String[] protocols, - boolean need) { - super(context, ciphers, protocols, need); - } - - public ServerSocket createServerSocket(int port) throws IOException { - System.out.println("ServerFactory::Calling createServerSocket(" + - port + ")"); - return super.createServerSocket(port); - } } - public void testRmiCommunication(RMIServerSocketFactory serverFactory, boolean expectException) { - - HelloImpl server = null; + public void testRmiCommunication(RMIServerSocketFactory serverSocketFactory) throws Exception { + HelloImpl server = new HelloImpl(); + Hello stub = (Hello)UnicastRemoteObject.exportObject(server, + 0, new SslRMIClientSocketFactory(), serverSocketFactory); try { - server = new HelloImpl(0, - new ClientFactory(), - serverFactory); - Remote stub = server.runServer(); - HelloClient client = new HelloClient(); - client.runClient(stub); - if (expectException) { - throw new RuntimeException("Test completed without throwing an expected exception."); - } - - } catch (IOException exc) { - if (!expectException) { - throw new RuntimeException("An error occurred during test execution", exc); - } else { - System.out.println("Caught expected exception: " + exc); - } - + String msg = stub.sayHello(); + Asserts.assertEquals("Hello World!", msg); + } finally { + Reference.reachabilityFence(server); } } - private static void testServerFactory(String[] cipherSuites, String[] protocol, String expectedMessage) throws Exception { - try { - new ServerFactory(SSLContext.getDefault(), + private static void testSslServerSocketFactory(String[] cipherSuites, String[] protocol) throws Exception { + new SslRMIServerSocketFactory(SSLContext.getDefault(), cipherSuites, protocol, false); - throw new RuntimeException( - "The expected exception for "+ expectedMessage + " was not thrown."); - } catch (IllegalArgumentException exc) { - // expecting an exception with a specific message - // anything else is an error - if (!exc.getMessage().toLowerCase().contains(expectedMessage)) { - throw exc; - } - } } public void runTest(int testNumber) throws Exception { @@ -172,34 +83,49 @@ public void runTest(int testNumber) throws Exception { switch (testNumber) { /* default constructor - default config */ - case 1 -> testRmiCommunication(new ServerFactory(), false); + case 1 -> + testRmiCommunication(new SslRMIServerSocketFactory()); /* non-default constructor - default config */ - case 2 -> testRmiCommunication(new ServerFactory(null, null, false), false); + case 2 -> + testRmiCommunication(new SslRMIServerSocketFactory(null, null, false)); /* needClientAuth=true */ - case 3 -> testRmiCommunication(new ServerFactory(null, null, null, true), false); + case 3 -> + testRmiCommunication(new SslRMIServerSocketFactory(null, null, null, true)); /* server side dummy_ciphersuite */ - case 4 -> - testServerFactory(new String[]{"dummy_ciphersuite"}, null, "unsupported ciphersuite"); + case 4 -> { + Exception exc = Asserts.assertThrows(IllegalArgumentException.class, + () -> testSslServerSocketFactory(new String[]{"dummy_ciphersuite"}, null)); + if (!exc.getMessage().toLowerCase().contains("unsupported ciphersuite")) { + throw exc; + } + } /* server side dummy_protocol */ - case 5 -> - testServerFactory(null, new String[]{"dummy_protocol"}, "unsupported protocol"); + case 5 -> { + Exception thrown = Asserts.assertThrows(IllegalArgumentException.class, + () -> testSslServerSocketFactory(null, new String[]{"dummy_protocol"})); + if (!thrown.getMessage().toLowerCase().contains("unsupported protocol")) { + throw thrown; + } + } /* client side dummy_ciphersuite */ case 6 -> { System.setProperty("javax.rmi.ssl.client.enabledCipherSuites", "dummy_ciphersuite"); - testRmiCommunication(new ServerFactory(), true); + Asserts.assertThrows(ConnectIOException.class, + () -> testRmiCommunication(new SslRMIServerSocketFactory())); } /* client side dummy_protocol */ case 7 -> { System.setProperty("javax.rmi.ssl.client.enabledProtocols", "dummy_protocol"); - testRmiCommunication(new ServerFactory(), true); + Asserts.assertThrows(ConnectIOException.class, + () -> testRmiCommunication(new SslRMIServerSocketFactory())); } default -> diff --git a/test/lib/jdk/test/lib/Asserts.java b/test/lib/jdk/test/lib/Asserts.java index 5abe03d6c47..d503ea8e544 100644 --- a/test/lib/jdk/test/lib/Asserts.java +++ b/test/lib/jdk/test/lib/Asserts.java @@ -552,6 +552,46 @@ public static void assertStringsEqual(String str1, String str2, } } + /** + * A functional interface for executing tests in assertThrownException + */ + @FunctionalInterface + public interface TestMethod { + void execute() throws Throwable; + } + + + public static T assertThrows(Class expected, TestMethod testMethod) { + return assertThrows(expected, testMethod, "An unexpected exception was thrown."); + } + + /** + * Asserts that the given exception (or a subclass of it) is thrown when + * executing the test method. + * + * If the test method throws the correct exception, the exception is returned + * to the caller for additional validation e.g., comparing the exception + * message. + * + * @param expected The expected exception + * @param testMethod The code to execute that should throw the exception + * @param msg A description of the assumption + * @return The thrown exception. + */ + public static T assertThrows(Class expected, TestMethod testMethod, String msg) { + try { + testMethod.execute(); + } catch (Throwable exc) { + if (expected.isInstance(exc)) { + return (T) exc; + } else { + fail(Objects.toString(msg, "An unexpected exception was thrown.") + + " Expected " + expected.getName(), exc); + } + } + throw new RuntimeException("No exception was thrown. Expected: " + expected.getName()); + } + /** * Returns a string formatted with a message and expected and actual values. * @param lhs the actual value From 99de9bb83ff70fe81c89751516a86a94c8f552be Mon Sep 17 00:00:00 2001 From: Magnus Ihse Bursie Date: Mon, 23 Oct 2023 11:26:39 +0000 Subject: [PATCH 065/124] 8317807: JAVA_FLAGS removed from jtreg running in JDK-8317039 Reviewed-by: erikj --- make/RunTestsPrebuilt.gmk | 4 ++-- make/RunTestsPrebuiltSpec.gmk | 2 ++ make/autoconf/lib-tests.m4 | 9 ++++----- make/autoconf/spec.gmk.in | 5 +++-- 4 files changed, 11 insertions(+), 9 deletions(-) diff --git a/make/RunTestsPrebuilt.gmk b/make/RunTestsPrebuilt.gmk index 363644ecf0a..ae14b1e5336 100644 --- a/make/RunTestsPrebuilt.gmk +++ b/make/RunTestsPrebuilt.gmk @@ -122,7 +122,7 @@ $(eval $(call SetupVariable,JT_HOME)) $(eval $(call SetupVariable,JDK_IMAGE_DIR,$(OUTPUTDIR)/images/jdk)) $(eval $(call SetupVariable,TEST_IMAGE_DIR,$(OUTPUTDIR)/images/test)) $(eval $(call SetupVariable,SYMBOLS_IMAGE_DIR,$(OUTPUTDIR)/images/symbols,NO_CHECK)) -$(eval $(call SetupVariable,JTREG_JAVA,$(BOOT_JDK)/bin/java)) +$(eval $(call SetupVariable,JTREG_JDK,$(BOOT_JDK))) # Provide default values for tools that we need $(eval $(call SetupVariable,MAKE,make,NO_CHECK)) @@ -249,7 +249,7 @@ $(call CreateNewSpec, $(NEW_SPEC), \ TOPDIR := $(TOPDIR), \ OUTPUTDIR := $(OUTPUTDIR), \ BOOT_JDK := $(BOOT_JDK), \ - JTREG_JAVA := $(FIXPATH) $(JTREG_JAVA), \ + JTREG_JDK := $(JTREG_JDK), \ JT_HOME := $(JT_HOME), \ JDK_IMAGE_DIR := $(JDK_IMAGE_DIR), \ JCOV_IMAGE_DIR := $(JCOV_IMAGE_DIR), \ diff --git a/make/RunTestsPrebuiltSpec.gmk b/make/RunTestsPrebuiltSpec.gmk index 585fd24fda3..7fcaf56ff52 100644 --- a/make/RunTestsPrebuiltSpec.gmk +++ b/make/RunTestsPrebuiltSpec.gmk @@ -124,6 +124,8 @@ JAR := $(FIXPATH) $(JAR_CMD) JLINK := $(FIXPATH) $(JLINK_CMD) JMOD := $(FIXPATH) $(JMOD_CMD) +JTREG_JAVA := $(FIXPATH) $(JTREG_JDK)/bin/java $(JAVA_FLAGS_BIG) $(JAVA_FLAGS) + BUILD_JAVA := $(JDK_IMAGE_DIR)/bin/JAVA ################################################################################ # Some common tools. Assume most common name and no path. diff --git a/make/autoconf/lib-tests.m4 b/make/autoconf/lib-tests.m4 index 5c03d433c38..be099e50a04 100644 --- a/make/autoconf/lib-tests.m4 +++ b/make/autoconf/lib-tests.m4 @@ -251,11 +251,10 @@ AC_DEFUN_ONCE([LIB_TESTS_SETUP_JTREG], AC_MSG_RESULT([no, using BOOT_JDK]) fi - JTREG_JAVA="$JTREG_JDK/bin/java" - UTIL_FIXUP_PATH(JTREG_JAVA) - JTREG_JAVA="$FIXPATH $JTREG_JAVA" - AC_SUBST([JTREG_JAVA]) - + UTIL_FIXUP_PATH(JTREG_JDK) + AC_SUBST([JTREG_JDK]) + # For use in the configure script + JTREG_JAVA="$FIXPATH $JTREG_JDK/bin/java" # Verify jtreg version if test "x$JT_HOME" != x; then diff --git a/make/autoconf/spec.gmk.in b/make/autoconf/spec.gmk.in index 1f2accf3a67..2b7a7b8d1af 100644 --- a/make/autoconf/spec.gmk.in +++ b/make/autoconf/spec.gmk.in @@ -666,8 +666,6 @@ JAVA_FLAGS_SMALL:=@JAVA_FLAGS_SMALL@ BUILDJDK_JAVA_FLAGS_SMALL:=@BUILDJDK_JAVA_FLAGS_SMALL@ JAVA_TOOL_FLAGS_SMALL:=@JAVA_TOOL_FLAGS_SMALL@ -JTREG_JAVA:=@JTREG_JAVA@ - # The *_CMD variables are defined separately to be easily overridden in bootcycle-spec.gmk # for bootcycle-images build. Make sure to keep them in sync. Do not use the *_CMD # versions of the variables directly. @@ -687,6 +685,9 @@ JAR = $(JAR_CMD) JLINK = $(JLINK_CMD) JMOD = $(JMOD_CMD) +JTREG_JDK := @JTREG_JDK@ +JTREG_JAVA = @FIXPATH@ $(JTREG_JDK)/bin/java $(JAVA_FLAGS_BIG) $(JAVA_FLAGS) + BUILD_JAVA_FLAGS := @BOOTCYCLE_JVM_ARGS_BIG@ BUILD_JAVA=@FIXPATH@ $(BUILD_JDK)/bin/java $(BUILD_JAVA_FLAGS) BUILD_JAVAC=@FIXPATH@ $(BUILD_JDK)/bin/javac From c2efd7741202a5e3c209de62b8b5e6bd8ae7611a Mon Sep 17 00:00:00 2001 From: Robbin Ehn Date: Mon, 23 Oct 2023 13:12:52 +0000 Subject: [PATCH 066/124] 8295795: hsdis does not build with binutils 2.39+ Reviewed-by: ihse, djelinski --- make/autoconf/lib-hsdis.m4 | 87 ++++++++++++++--------- src/utils/hsdis/binutils/hsdis-binutils.c | 32 +++++++-- 2 files changed, 83 insertions(+), 36 deletions(-) diff --git a/make/autoconf/lib-hsdis.m4 b/make/autoconf/lib-hsdis.m4 index 974d0e8b793..987658bc411 100644 --- a/make/autoconf/lib-hsdis.m4 +++ b/make/autoconf/lib-hsdis.m4 @@ -134,7 +134,8 @@ AC_DEFUN([LIB_BUILD_BINUTILS], BINUTILS_SRC="$with_binutils_src" UTIL_FIXUP_PATH(BINUTILS_SRC) - BINUTILS_DIR="$CONFIGURESUPPORT_OUTPUTDIR/binutils" + BINUTILS_BUILD_DIR="$CONFIGURESUPPORT_OUTPUTDIR/binutils" + BINUTILS_INSTALL_DIR="$CONFIGURESUPPORT_OUTPUTDIR/binutils-install" if ! test -d $BINUTILS_SRC; then AC_MSG_ERROR([--with-binutils-src is not pointing to a directory]) @@ -143,15 +144,15 @@ AC_DEFUN([LIB_BUILD_BINUTILS], AC_MSG_ERROR([--with-binutils-src does not look like a binutils source directory]) fi - if ! test -d $BINUTILS_DIR; then - $MKDIR -p $BINUTILS_DIR + if ! test -d $BINUTILS_BUILD_DIR; then + $MKDIR -p $BINUTILS_BUILD_DIR fi - if test -e $BINUTILS_DIR/bfd/libbfd.a && \ - test -e $BINUTILS_DIR/opcodes/libopcodes.a && \ - test -e $BINUTILS_DIR/libiberty/libiberty.a && \ - test -e $BINUTILS_DIR/zlib/libz.a; then - AC_MSG_NOTICE([Found binutils binaries in binutils source directory -- not building]) + # We don't know the version, not checking for libsframe.a + if test -e $BINUTILS_INSTALL_DIR/lib/libbfd.a && \ + test -e $BINUTILS_INSTALL_DIR/lib/libopcodes.a && \ + test -e $BINUTILS_INSTALL_DIR/lib/libiberty.a; then + AC_MSG_NOTICE([Found binutils binaries in binutils install directory -- not building]) else # On Windows, we cannot build with the normal Microsoft CL, but must instead use # a separate mingw toolchain. @@ -190,20 +191,26 @@ AC_DEFUN([LIB_BUILD_BINUTILS], binutils_cflags="$binutils_cflags $MACHINE_FLAG $JVM_PICFLAG $C_O_FLAG_NORM" AC_MSG_NOTICE([Running binutils configure]) - AC_MSG_NOTICE([configure command line: cd $BINUTILS_DIR && $BINUTILS_SRC/configure --disable-nls CFLAGS="$binutils_cflags" CC="$binutils_cc" AR="$AR" $binutils_target]) + AC_MSG_NOTICE([configure command line: cd $BINUTILS_BUILD_DIR && $BINUTILS_SRC/configure --disable-werror --prefix=$BINUTILS_INSTALL_DIR --enable-install-libiberty --with-system-zlib --without-zstd --disable-nls CFLAGS="$binutils_cflags" CC="$binutils_cc" AR="$AR" $binutils_target]) saved_dir=`pwd` - cd "$BINUTILS_DIR" - $BINUTILS_SRC/configure --disable-nls CFLAGS="$binutils_cflags" CC="$binutils_cc" AR="$AR" $binutils_target - if test $? -ne 0 || ! test -e $BINUTILS_DIR/Makefile; then + cd "$BINUTILS_BUILD_DIR" + $BINUTILS_SRC/configure --disable-werror --prefix=$BINUTILS_INSTALL_DIR --enable-install-libiberty --with-system-zlib --without-zstd --disable-nls CFLAGS="$binutils_cflags" CC="$binutils_cc" AR="$AR" $binutils_target + if test $? -ne 0 || ! test -e $BINUTILS_BUILD_DIR/Makefile; then AC_MSG_NOTICE([Automatic building of binutils failed on configure. Try building it manually]) AC_MSG_ERROR([Cannot continue]) fi AC_MSG_NOTICE([Running binutils make]) - $MAKE all-opcodes + $MAKE all-opcodes all-libiberty if test $? -ne 0; then AC_MSG_NOTICE([Automatic building of binutils failed on make. Try building it manually]) AC_MSG_ERROR([Cannot continue]) fi + AC_MSG_NOTICE([Running binutils make install]) + $MAKE install-opcodes install-libiberty + if test $? -ne 0; then + AC_MSG_NOTICE([Automatic building, install step, of binutils failed on make. Try building it manually]) + AC_MSG_ERROR([Cannot continue]) + fi cd $saved_dir AC_MSG_NOTICE([Building of binutils done]) fi @@ -223,41 +230,57 @@ AC_DEFUN([LIB_SETUP_HSDIS_BINUTILS], # We need the binutils static libs and includes. if test "x$with_binutils_src" != x; then - # Try building the source first. If it succeeds, it sets $BINUTILS_DIR. + # Try building the source first. If it succeeds, it sets $BINUTILS_INSTALL_DIR. LIB_BUILD_BINUTILS fi if test "x$with_binutils" != x; then - BINUTILS_DIR="$with_binutils" + BINUTILS_INSTALL_DIR="$with_binutils" fi binutils_system_error="" + HSDIS_LDFLAGS="" HSDIS_LIBS="" - if test "x$BINUTILS_DIR" = xsystem; then + disasm_header="" + + if test "x$BINUTILS_INSTALL_DIR" = xsystem; then AC_CHECK_LIB(bfd, bfd_openr, [ HSDIS_LIBS="-lbfd" ], [ binutils_system_error="libbfd not found" ]) AC_CHECK_LIB(opcodes, disassembler, [ HSDIS_LIBS="$HSDIS_LIBS -lopcodes" ], [ binutils_system_error="libopcodes not found" ]) + AC_CHECK_LIB(z, deflate, [ HSDIS_LIBS="$HSDIS_LIBS -lz" ], [ binutils_system_error="libz not found" ]) # libiberty is not required on Ubuntu AC_CHECK_LIB(iberty, xmalloc, [ HSDIS_LIBS="$HSDIS_LIBS -liberty" ]) - AC_CHECK_LIB(z, deflate, [ HSDIS_LIBS="$HSDIS_LIBS -lz" ], [ binutils_system_error="libz not found" ]) + AC_CHECK_LIB(sframe, frame, [ HSDIS_LIBS="$HSDIS_LIBS -lsframe" ], ) HSDIS_CFLAGS="-DLIBARCH_$OPENJDK_TARGET_CPU_LEGACY_LIB" - elif test "x$BINUTILS_DIR" != x; then - if test -e $BINUTILS_DIR/bfd/libbfd.a && \ - test -e $BINUTILS_DIR/opcodes/libopcodes.a && \ - test -e $BINUTILS_DIR/libiberty/libiberty.a && \ - test -e $BINUTILS_DIR/zlib/libz.a; then - HSDIS_CFLAGS="-DLIBARCH_$OPENJDK_TARGET_CPU_LEGACY_LIB" - if test -n "$BINUTILS_SRC"; then - HSDIS_CFLAGS="$HSDIS_CFLAGS -I$BINUTILS_SRC/include -I$BINUTILS_DIR/bfd" - else - HSDIS_CFLAGS="$HSDIS_CFLAGS -I$BINUTILS_DIR/include -I$BINUTILS_DIR/bfd" + elif test "x$BINUTILS_INSTALL_DIR" != x; then + disasm_header="\"$BINUTILS_INSTALL_DIR/include/dis-asm.h\"" + if test -e $BINUTILS_INSTALL_DIR/lib/libbfd.a && \ + test -e $BINUTILS_INSTALL_DIR/lib/libopcodes.a && \ + test -e $BINUTILS_INSTALL_DIR/lib/libiberty.a; then + HSDIS_CFLAGS="-DLIBARCH_$OPENJDK_TARGET_CPU_LEGACY_LIB -I$BINUTILS_INSTALL_DIR/include" + HSDIS_LIBS="$BINUTILS_INSTALL_DIR/lib/libbfd.a $BINUTILS_INSTALL_DIR/lib/libopcodes.a $BINUTILS_INSTALL_DIR/lib/libiberty.a" + # If we have libsframe add it. + if test -e $BINUTILS_INSTALL_DIR/lib/libsframe.a; then + HSDIS_LIBS="$HSDIS_LIBS $BINUTILS_INSTALL_DIR/lib/libsframe.a" fi - HSDIS_LDFLAGS="" - HSDIS_LIBS="$BINUTILS_DIR/bfd/libbfd.a $BINUTILS_DIR/opcodes/libopcodes.a $BINUTILS_DIR/libiberty/libiberty.a $BINUTILS_DIR/zlib/libz.a" + AC_CHECK_LIB(z, deflate, [ HSDIS_LIBS="$HSDIS_LIBS -lz" ], AC_MSG_ERROR([libz not found])) + else + AC_MSG_ERROR(["$BINUTILS_INSTALL_DIR/libs/ must contain libbfd.a, libopcodes.a, libiberty.a"]) fi fi + AC_MSG_CHECKING([Checking binutils API]) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([#include $disasm_header],[[void foo() {init_disassemble_info(0, 0, 0, 0);}]])], + [ + AC_MSG_RESULT([New API]) + HSDIS_CFLAGS="$HSDIS_CFLAGS -DBINUTILS_NEW_API" + ], + [ + AC_MSG_RESULT([Old API]) + ] + ) + AC_MSG_CHECKING([for binutils to use with hsdis]) - case "x$BINUTILS_DIR" in + case "x$BINUTILS_INSTALL_DIR" in xsystem) if test "x$OPENJDK_TARGET_OS" != xlinux; then AC_MSG_RESULT([invalid]) @@ -280,10 +303,10 @@ AC_DEFUN([LIB_SETUP_HSDIS_BINUTILS], ;; *) if test "x$HSDIS_LIBS" != x; then - AC_MSG_RESULT([$BINUTILS_DIR]) + AC_MSG_RESULT([$BINUTILS_INSTALL_DIR]) else AC_MSG_RESULT([invalid]) - AC_MSG_ERROR([$BINUTILS_DIR does not contain a proper binutils installation]) + AC_MSG_ERROR([$BINUTILS_INSTALL_DIR does not contain a proper binutils installation]) fi ;; esac diff --git a/src/utils/hsdis/binutils/hsdis-binutils.c b/src/utils/hsdis/binutils/hsdis-binutils.c index 28e374e05fc..86d49964f90 100644 --- a/src/utils/hsdis/binutils/hsdis-binutils.c +++ b/src/utils/hsdis/binutils/hsdis-binutils.c @@ -49,14 +49,16 @@ HotSpot PrintAssembly option. */ -#ifndef SYSTEM_BINUTILS -#include /* required by bfd.h */ -#endif - #include #include #include +#ifndef SYSTEM_BINUTILS +/* defines for bfd.h */ +#define PACKAGE "hsdis" +#define PACKAGE_VERSION 1 +#endif + #include #include @@ -555,12 +557,34 @@ static void parse_fake_insn(disassembler_ftype dfn, dinfo->fprintf_func = fprintf_func; } +static fprintf_ftype target_fprintf_func = NULL; + +#ifdef BINUTILS_NEW_API +static int wrapper_fprintf_styled_ftype(void *v, enum disassembler_style style_unused, const char* fmt, ...) { + char buffer[1024] = {}; + va_list args; + int r; + va_start(args, fmt); + r = vsnprintf(buffer, sizeof(buffer), fmt, args); + va_end(args); + if (target_fprintf_func != NULL) { + return target_fprintf_func(v, "%s", buffer); + } + return r; +} +#endif + static void init_disassemble_info_from_bfd(struct disassemble_info* dinfo, void *stream, fprintf_ftype fprintf_func, bfd* abfd, char* disassembler_options) { + target_fprintf_func = fprintf_func; +#ifdef BINUTILS_NEW_API + init_disassemble_info(dinfo, stream, fprintf_func, wrapper_fprintf_styled_ftype); +#else init_disassemble_info(dinfo, stream, fprintf_func); +#endif dinfo->flavour = bfd_get_flavour(abfd); dinfo->arch = bfd_get_arch(abfd); From bd22d2381fa3f21b113d5b8ef95fe15cec50b066 Mon Sep 17 00:00:00 2001 From: Doug Simon Date: Mon, 23 Oct 2023 13:15:31 +0000 Subject: [PATCH 067/124] 8318027: Support alternative name to jdk.internal.vm.compiler Reviewed-by: erikj, ihse, kvn, alanb, mli --- make/common/Modules.gmk | 4 ++-- make/conf/module-loader-map.conf | 4 ++-- src/java.base/share/lib/security/default.policy | 14 +------------- .../share/classes/module-info.java | 6 +++--- .../share/classes/module-info.java | 6 +++--- .../share/classes/module-info.java | 14 +++++++------- .../jvmci/compilerToVM/IsCompilableTest.java | 1 - .../getDeclaredField/FieldSetAccessibleTest.java | 9 ++++----- test/jdk/jdk/modules/etc/UpgradeableModules.java | 4 ++-- test/jdk/tools/jimage/VerifyJimage.java | 4 ++-- 10 files changed, 26 insertions(+), 40 deletions(-) rename src/{jdk.internal.vm.compiler.management => jdk.graal.compiler.management}/share/classes/module-info.java (92%) rename src/{jdk.internal.vm.compiler => jdk.graal.compiler}/share/classes/module-info.java (93%) diff --git a/make/common/Modules.gmk b/make/common/Modules.gmk index 0eb0fb2ddc1..bcbb6d1bab1 100644 --- a/make/common/Modules.gmk +++ b/make/common/Modules.gmk @@ -62,8 +62,8 @@ endif # Filter out jvmci specific modules if jvmci is disabled ifeq ($(INCLUDE_JVMCI), false) MODULES_FILTER += jdk.internal.vm.ci - MODULES_FILTER += jdk.internal.vm.compiler - MODULES_FILTER += jdk.internal.vm.compiler.management + MODULES_FILTER += jdk.graal.compiler + MODULES_FILTER += jdk.graal.compiler.management endif # jpackage is only on windows, macosx, and linux diff --git a/make/conf/module-loader-map.conf b/make/conf/module-loader-map.conf index cc7e7d5a652..ca09d23b02b 100644 --- a/make/conf/module-loader-map.conf +++ b/make/conf/module-loader-map.conf @@ -60,8 +60,8 @@ BOOT_MODULES= \ # should carefully be considered if it should be upgradeable or not. UPGRADEABLE_PLATFORM_MODULES= \ java.compiler \ - jdk.internal.vm.compiler \ - jdk.internal.vm.compiler.management \ + jdk.graal.compiler \ + jdk.graal.compiler.management \ # PLATFORM_MODULES= \ diff --git a/src/java.base/share/lib/security/default.policy b/src/java.base/share/lib/security/default.policy index 33774adce08..aa67bd6b53e 100644 --- a/src/java.base/share/lib/security/default.policy +++ b/src/java.base/share/lib/security/default.policy @@ -163,22 +163,10 @@ grant codeBase "jrt:/jdk.internal.le" { permission java.security.AllPermission; }; -grant codeBase "jrt:/jdk.internal.vm.compiler" { +grant codeBase "jrt:/jdk.graal.compiler" { permission java.security.AllPermission; }; -grant codeBase "jrt:/jdk.internal.vm.compiler.management" { - permission java.lang.RuntimePermission "accessClassInPackage.jdk.internal.vm.compiler.collections"; - permission java.lang.RuntimePermission "accessClassInPackage.jdk.vm.ci.runtime"; - permission java.lang.RuntimePermission "accessClassInPackage.jdk.vm.ci.services"; - permission java.lang.RuntimePermission "accessClassInPackage.org.graalvm.compiler.core.common"; - permission java.lang.RuntimePermission "accessClassInPackage.org.graalvm.compiler.debug"; - permission java.lang.RuntimePermission "accessClassInPackage.org.graalvm.compiler.hotspot"; - permission java.lang.RuntimePermission "accessClassInPackage.org.graalvm.compiler.options"; - permission java.lang.RuntimePermission "accessClassInPackage.org.graalvm.compiler.phases.common.jmx"; - permission java.lang.RuntimePermission "accessClassInPackage.org.graalvm.compiler.serviceprovider"; -}; - grant codeBase "jrt:/jdk.jsobject" { permission java.security.AllPermission; }; diff --git a/src/jdk.internal.vm.compiler.management/share/classes/module-info.java b/src/jdk.graal.compiler.management/share/classes/module-info.java similarity index 92% rename from src/jdk.internal.vm.compiler.management/share/classes/module-info.java rename to src/jdk.graal.compiler.management/share/classes/module-info.java index 88a5d933fca..976bf369819 100644 --- a/src/jdk.internal.vm.compiler.management/share/classes/module-info.java +++ b/src/jdk.graal.compiler.management/share/classes/module-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -33,9 +33,9 @@ * module descriptor. * * @moduleGraph - * @since 10 + * @since 22 */ -module jdk.internal.vm.compiler.management { +module jdk.graal.compiler.management { requires jdk.internal.vm.ci; } diff --git a/src/jdk.internal.vm.compiler/share/classes/module-info.java b/src/jdk.graal.compiler/share/classes/module-info.java similarity index 93% rename from src/jdk.internal.vm.compiler/share/classes/module-info.java rename to src/jdk.graal.compiler/share/classes/module-info.java index 7284f2f225d..bc8987ee919 100644 --- a/src/jdk.internal.vm.compiler/share/classes/module-info.java +++ b/src/jdk.graal.compiler/share/classes/module-info.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2021, 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 @@ -33,9 +33,9 @@ * module descriptor. * * @moduleGraph - * @since 9 + * @since 22 */ -module jdk.internal.vm.compiler { +module jdk.graal.compiler { requires jdk.internal.vm.ci; } diff --git a/src/jdk.internal.vm.ci/share/classes/module-info.java b/src/jdk.internal.vm.ci/share/classes/module-info.java index b4b93f6a747..14f97412b3d 100644 --- a/src/jdk.internal.vm.ci/share/classes/module-info.java +++ b/src/jdk.internal.vm.ci/share/classes/module-info.java @@ -25,14 +25,14 @@ module jdk.internal.vm.ci { exports jdk.vm.ci.services to - jdk.internal.vm.compiler, - jdk.internal.vm.compiler.management; + jdk.graal.compiler, + jdk.graal.compiler.management; exports jdk.vm.ci.runtime to - jdk.internal.vm.compiler, - jdk.internal.vm.compiler.management; - exports jdk.vm.ci.meta to jdk.internal.vm.compiler; - exports jdk.vm.ci.code to jdk.internal.vm.compiler; - exports jdk.vm.ci.hotspot to jdk.internal.vm.compiler; + jdk.graal.compiler, + jdk.graal.compiler.management; + exports jdk.vm.ci.meta to jdk.graal.compiler; + exports jdk.vm.ci.code to jdk.graal.compiler; + exports jdk.vm.ci.hotspot to jdk.graal.compiler; uses jdk.vm.ci.services.JVMCIServiceLocator; uses jdk.vm.ci.hotspot.HotSpotJVMCIBackendFactory; diff --git a/test/hotspot/jtreg/compiler/jvmci/compilerToVM/IsCompilableTest.java b/test/hotspot/jtreg/compiler/jvmci/compilerToVM/IsCompilableTest.java index 8f645f6ed97..fdcf72f6548 100644 --- a/test/hotspot/jtreg/compiler/jvmci/compilerToVM/IsCompilableTest.java +++ b/test/hotspot/jtreg/compiler/jvmci/compilerToVM/IsCompilableTest.java @@ -27,7 +27,6 @@ * @requires vm.graal.enabled & vm.compMode == "Xmixed" * @library /test/lib / * @library ../common/patches - * @modules jdk.internal.vm.compiler * @modules java.base/jdk.internal.misc * @modules java.base/jdk.internal.org.objectweb.asm * java.base/jdk.internal.org.objectweb.asm.tree diff --git a/test/jdk/java/lang/Class/getDeclaredField/FieldSetAccessibleTest.java b/test/jdk/java/lang/Class/getDeclaredField/FieldSetAccessibleTest.java index 624b287b0bf..ede0bfcb9e1 100644 --- a/test/jdk/java/lang/Class/getDeclaredField/FieldSetAccessibleTest.java +++ b/test/jdk/java/lang/Class/getDeclaredField/FieldSetAccessibleTest.java @@ -311,12 +311,11 @@ static Set systemModules() { Set mods = Set.of( // All JVMCI packages other than jdk.vm.ci.services are dynamically - // exported to jdk.internal.vm.compiler - "jdk.internal.vm.compiler", "jdk.internal.vm.compiler.management" + // exported to Graal + "jdk.graal.compiler", "jdk.graal.compiler.management" ); - // Filters all modules that directly or indirectly require jdk.internal.vm.compiler - // and jdk.internal.vm.compiler.management, as these are upgradeable and - // also provide APIs to add qualified exports dynamically + // Filters all modules that directly or indirectly require Graal modules + // as these are upgradeable and also provide APIs to add qualified exports dynamically Set filters = mods.stream().flatMap(mn -> findDeps(mn, inverseDeps).stream()) .collect(Collectors.toSet()); System.out.println("Filtered modules: " + filters); diff --git a/test/jdk/jdk/modules/etc/UpgradeableModules.java b/test/jdk/jdk/modules/etc/UpgradeableModules.java index 59ff5aa6b23..3616c6b6d4d 100644 --- a/test/jdk/jdk/modules/etc/UpgradeableModules.java +++ b/test/jdk/jdk/modules/etc/UpgradeableModules.java @@ -44,8 +44,8 @@ public class UpgradeableModules { private static final List UPGRADEABLE_MODULES = List.of("java.compiler", - "jdk.internal.vm.compiler", - "jdk.internal.vm.compiler.management"); + "jdk.graal.compiler", + "jdk.graal.compiler.management"); public static void main(String... args) { diff --git a/test/jdk/tools/jimage/VerifyJimage.java b/test/jdk/tools/jimage/VerifyJimage.java index 59d0a5cecf4..6da0e719950 100644 --- a/test/jdk/tools/jimage/VerifyJimage.java +++ b/test/jdk/tools/jimage/VerifyJimage.java @@ -196,8 +196,8 @@ private String toClassName(String entry) { } // All JVMCI packages other than jdk.vm.ci.services are dynamically - // exported to jdk.internal.vm.compiler - private static Set EXCLUDED_MODULES = Set.of("jdk.internal.vm.compiler"); + // exported to jdk.graal.compiler + private static Set EXCLUDED_MODULES = Set.of("jdk.graal.compiler"); private boolean accept(String entry) { int index = entry.indexOf('/', 1); From 9f767aa44b4699ed5404b934ac751f2cdd0ba824 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Mon, 23 Oct 2023 14:00:07 +0000 Subject: [PATCH 068/124] 8318109: Writing JFR records while a CHT has taken its lock asserts in rank checking Reviewed-by: iwalulya, mli --- src/hotspot/share/runtime/mutexLocker.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/share/runtime/mutexLocker.cpp b/src/hotspot/share/runtime/mutexLocker.cpp index cdbeea9a269..4a3444d9cae 100644 --- a/src/hotspot/share/runtime/mutexLocker.cpp +++ b/src/hotspot/share/runtime/mutexLocker.cpp @@ -295,7 +295,7 @@ void mutex_init() { #if INCLUDE_JFR MUTEX_DEFN(JfrBuffer_lock , PaddedMutex , event); MUTEX_DEFN(JfrMsg_lock , PaddedMonitor, event); - MUTEX_DEFN(JfrStacktrace_lock , PaddedMutex , stackwatermark-1); + MUTEX_DEFN(JfrStacktrace_lock , PaddedMutex , event); MUTEX_DEFN(JfrThreadSampler_lock , PaddedMonitor, nosafepoint); #endif From bea2d48696ee2c213e475ca3aa3aa9c412b91089 Mon Sep 17 00:00:00 2001 From: Michal Sobierski Date: Mon, 23 Oct 2023 14:31:12 +0000 Subject: [PATCH 069/124] 8312475: org.jline.util.PumpReader signed byte problem Reviewed-by: shade, jlahoda --- .../share/classes/jdk/internal/org/jline/utils/PumpReader.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/PumpReader.java b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/PumpReader.java index a6894e7672c..e80a18b6f3c 100644 --- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/PumpReader.java +++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/utils/PumpReader.java @@ -414,7 +414,7 @@ public int read() throws IOException { return EOF; } - return buffer.get(); + return buffer.get() & 0xFF; } private boolean readUsingBuffer() throws IOException { From d888b26783cbe9b2bf0a23ae728176f2eda6b90b Mon Sep 17 00:00:00 2001 From: Ramkumar Sunderbabu Date: Mon, 23 Oct 2023 15:10:22 +0000 Subject: [PATCH 070/124] 8318071: IgnoreUnrecognizedVMOptions flag still causes failure in ArchiveHeapTestClass Reviewed-by: dholmes, shade --- .../cacheObject/ArchiveHeapTestClass.java | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/test/hotspot/jtreg/runtime/cds/appcds/cacheObject/ArchiveHeapTestClass.java b/test/hotspot/jtreg/runtime/cds/appcds/cacheObject/ArchiveHeapTestClass.java index f82f1a02b59..f5975569447 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/cacheObject/ArchiveHeapTestClass.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/cacheObject/ArchiveHeapTestClass.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 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 @@ -26,7 +26,7 @@ * @test * @bug 8214781 8293187 * @summary Test for the -XX:ArchiveHeapTestClass flag - * @requires vm.cds.write.archived.java.heap + * @requires vm.debug == true & vm.cds.write.archived.java.heap * @modules java.base/sun.invoke.util java.logging * @library /test/jdk/lib/testlibrary /test/lib * /test/hotspot/jtreg/runtime/cds/appcds @@ -61,11 +61,7 @@ public class ArchiveHeapTestClass { static final String ARCHIVE_TEST_FIELD_NAME = "archivedObjects"; public static void main(String[] args) throws Exception { - if (Platform.isDebugBuild()) { - testDebugBuild(); - } else { - testProductBuild(); - } + testDebugBuild(); } static OutputAnalyzer dumpHelloOnly(String... extraOpts) throws Exception { @@ -169,13 +165,6 @@ static void testDebugBuild() throws Exception { mustSucceed(output); } } - - static void testProductBuild() throws Exception { - OutputAnalyzer output; - - output = dumpHelloOnly("-XX:-IgnoreUnrecognizedVMOptions", "-XX:ArchiveHeapTestClass=NoSuchClass"); - mustFail(output, "VM option 'ArchiveHeapTestClass' is develop and is available only in debug version of VM."); - } } class CDSTestClassA { From c1aeac79ba4c5b100f05ccd4f014326e46e9520a Mon Sep 17 00:00:00 2001 From: Thomas Stuefe Date: Mon, 23 Oct 2023 15:54:04 +0000 Subject: [PATCH 071/124] 8318445: More broken bailout chains in C2 Reviewed-by: kvn, epeter --- src/hotspot/share/opto/compile.cpp | 10 +++++++++- src/hotspot/share/opto/loopTransform.cpp | 10 +++++++--- src/hotspot/share/opto/loopopts.cpp | 1 + src/hotspot/share/opto/matcher.cpp | 1 + 4 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/hotspot/share/opto/compile.cpp b/src/hotspot/share/opto/compile.cpp index 1e353a90c97..c66c32fe973 100644 --- a/src/hotspot/share/opto/compile.cpp +++ b/src/hotspot/share/opto/compile.cpp @@ -1854,6 +1854,7 @@ void Compile::process_for_post_loop_opts_igvn(PhaseIterGVN& igvn) { igvn._worklist.push(n); } igvn.optimize(); + if (failing()) return; assert(_for_post_loop_igvn.length() == 0, "no more delayed nodes allowed"); assert(C->parse_predicate_count() == 0, "all parse predicates should have been removed now"); @@ -2069,6 +2070,7 @@ void Compile::inline_incrementally_cleanup(PhaseIterGVN& igvn) { TracePhase tp("incrementalInline_igvn", &timers[_t_incrInline_igvn]); igvn.reset_from_gvn(initial_gvn()); igvn.optimize(); + if (failing()) return; } print_method(PHASE_INCREMENTAL_INLINE_CLEANUP, 3); } @@ -2301,6 +2303,7 @@ void Compile::Optimize() { } igvn.reset_from_gvn(initial_gvn()); igvn.optimize(); + if (failing()) return; } // Now that all inlining is over and no PhaseRemoveUseless will run, cut edge from root to loop @@ -2330,7 +2333,7 @@ void Compile::Optimize() { igvn.optimize(); print_method(PHASE_ITER_GVN_AFTER_EA, 2); - if (failing()) return; + if (failing()) return; if (congraph() != nullptr && macro_count() > 0) { TracePhase tp("macroEliminate", &timers[_t_macroEliminate]); @@ -2340,6 +2343,8 @@ void Compile::Optimize() { igvn.set_delay_transform(false); igvn.optimize(); + if (failing()) return; + print_method(PHASE_ITER_GVN_AFTER_ELIMINATION, 2); } @@ -2449,6 +2454,7 @@ void Compile::Optimize() { if (C->max_vector_size() > 0) { C->optimize_logic_cones(igvn); igvn.optimize(); + if (failing()) return; } DEBUG_ONLY( _modified_nodes = nullptr; ) @@ -4366,6 +4372,7 @@ Compile::TracePhase::TracePhase(const char* name, elapsedTimer* accumulator) } Compile::TracePhase::~TracePhase() { + if (_compile->failing()) return; #ifdef ASSERT if (PrintIdealNodeCount) { tty->print_cr("phase name='%s' nodes='%d' live='%d' live_graph_walk='%d'", @@ -5083,6 +5090,7 @@ void Compile::sort_macro_nodes() { } void Compile::print_method(CompilerPhaseType cpt, int level, Node* n) { + if (failing()) { return; } EventCompilerPhase event; if (event.should_commit()) { CompilerEvent::PhaseEvent::post(event, C->_latest_stage_start_counter, cpt, C->_compile_id, level); diff --git a/src/hotspot/share/opto/loopTransform.cpp b/src/hotspot/share/opto/loopTransform.cpp index d299e159537..22386b144c2 100644 --- a/src/hotspot/share/opto/loopTransform.cpp +++ b/src/hotspot/share/opto/loopTransform.cpp @@ -3605,9 +3605,13 @@ bool IdealLoopTree::iteration_split_impl(PhaseIdealLoop *phase, Node_List &old_n // Non-counted loops may be peeled; exactly 1 iteration is peeled. // This removes loop-invariant tests (usually null checks). if (!_head->is_CountedLoop()) { // Non-counted loop - if (PartialPeelLoop && phase->partial_peel(this, old_new)) { - // Partial peel succeeded so terminate this round of loop opts - return false; + if (PartialPeelLoop) { + bool rc = phase->partial_peel(this, old_new); + if (Compile::current()->failing()) { return false; } + if (rc) { + // Partial peel succeeded so terminate this round of loop opts + return false; + } } if (policy_peeling(phase)) { // Should we peel? if (PrintOpto) { tty->print_cr("should_peel"); } diff --git a/src/hotspot/share/opto/loopopts.cpp b/src/hotspot/share/opto/loopopts.cpp index fa2f5d84201..0a197dd413b 100644 --- a/src/hotspot/share/opto/loopopts.cpp +++ b/src/hotspot/share/opto/loopopts.cpp @@ -3685,6 +3685,7 @@ bool PhaseIdealLoop::partial_peel( IdealLoopTree *loop, Node_List &old_new ) { // and not a CMove (Matcher expects only bool->cmove). if (n->in(0) == nullptr && !n->is_Load() && !n->is_CMove()) { int new_clones = clone_for_use_outside_loop(loop, n, worklist); + if (C->failing()) return false; if (new_clones == -1) { too_many_clones = true; break; diff --git a/src/hotspot/share/opto/matcher.cpp b/src/hotspot/share/opto/matcher.cpp index b527a7657b2..9ed0ca62410 100644 --- a/src/hotspot/share/opto/matcher.cpp +++ b/src/hotspot/share/opto/matcher.cpp @@ -361,6 +361,7 @@ void Matcher::match( ) { C->set_cached_top_node(n); if (!C->failing()) { Node* xroot = xform( C->root(), 1 ); + if (C->failing()) return; if (xroot == nullptr) { Matcher::soft_match_failure(); // recursive matching process failed assert(false, "instruction match failed"); From 69c0ae23a323dd547f53234848f32ed9ba41792b Mon Sep 17 00:00:00 2001 From: Erik Gahlin Date: Mon, 23 Oct 2023 16:00:14 +0000 Subject: [PATCH 072/124] 8318124: JFR: Rewrite instrumentation to use Class-File API Reviewed-by: mgronlun --- src/java.base/share/classes/module-info.java | 5 + .../jdk/jfr/consumer/RecordedEvent.java | 8 +- .../classes/jdk/jfr/internal/ASMToolkit.java | 102 -- .../jdk/jfr/internal/EventClassBuilder.java | 147 ++- .../jfr/internal/EventInstrumentation.java | 1011 ++++++++--------- .../jdk/jfr/internal/EventWriterMethod.java | 58 +- .../classes/jdk/jfr/internal/JVMUpcalls.java | 6 +- .../classes/jdk/jfr/internal/TypeLibrary.java | 14 +- .../jfr/internal/consumer/EventParser.java | 2 +- .../jdk/jfr/internal/util/Bytecode.java | 166 +++ .../classes/jdk/jfr/internal/util/Utils.java | 5 + test/jdk/jdk/jfr/jvm/TestEventWriterLog.java | 4 +- 12 files changed, 779 insertions(+), 749 deletions(-) delete mode 100644 src/jdk.jfr/share/classes/jdk/jfr/internal/ASMToolkit.java create mode 100644 src/jdk.jfr/share/classes/jdk/jfr/internal/util/Bytecode.java diff --git a/src/java.base/share/classes/module-info.java b/src/java.base/share/classes/module-info.java index bcf7daf8189..161cbe380cf 100644 --- a/src/java.base/share/classes/module-info.java +++ b/src/java.base/share/classes/module-info.java @@ -187,15 +187,20 @@ exports jdk.internal.classfile to jdk.jartool, jdk.jdeps, + jdk.jfr, jdk.jlink, jdk.jshell; exports jdk.internal.classfile.attribute to jdk.jartool, jdk.jdeps, + jdk.jfr, jdk.jlink; + exports jdk.internal.classfile.components to + jdk.jfr; exports jdk.internal.classfile.constantpool to jdk.jartool, jdk.jdeps, + jdk.jfr, jdk.jlink; exports jdk.internal.classfile.instruction to jdk.jdeps, diff --git a/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordedEvent.java b/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordedEvent.java index b0ffe88b9c7..9ec117ffc88 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordedEvent.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordedEvent.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2022, 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 @@ -31,7 +31,7 @@ import jdk.jfr.EventType; import jdk.jfr.ValueDescriptor; -import jdk.jfr.internal.EventInstrumentation; +import jdk.jfr.internal.util.Utils; import jdk.jfr.internal.consumer.ObjectContext; /** @@ -57,7 +57,7 @@ public final class RecordedEvent extends RecordedObject { * @return stack trace, or {@code null} if doesn't exist for the event */ public RecordedStackTrace getStackTrace() { - return getTyped(EventInstrumentation.FIELD_STACK_TRACE, RecordedStackTrace.class, null); + return getTyped(Utils.FIELD_STACK_TRACE, RecordedStackTrace.class, null); } /** @@ -67,7 +67,7 @@ public RecordedStackTrace getStackTrace() { * @return thread, or {@code null} if doesn't exist for the event */ public RecordedThread getThread() { - return getTyped(EventInstrumentation.FIELD_EVENT_THREAD, RecordedThread.class, null); + return getTyped(Utils.FIELD_EVENT_THREAD, RecordedThread.class, null); } /** diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/ASMToolkit.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/ASMToolkit.java deleted file mode 100644 index f9e088c8fdf..00000000000 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/ASMToolkit.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright (c) 2016, 2022, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package jdk.jfr.internal; - -import java.io.ByteArrayOutputStream; -import java.io.PrintWriter; - -import jdk.internal.org.objectweb.asm.ClassReader; -import jdk.internal.org.objectweb.asm.Type; -import jdk.internal.org.objectweb.asm.util.TraceClassVisitor; -import jdk.jfr.ValueDescriptor; - -final class ASMToolkit { - public static final Type TYPE_STRING = Type.getType(String.class); - private static final Type TYPE_THREAD = Type.getType(Thread.class); - private static final Type TYPE_CLASS = Type.getType(Class.class); - - public static Type toType(ValueDescriptor v) { - return switch (v.getTypeName()) { - case "byte" -> Type.BYTE_TYPE; - case "short" -> Type.SHORT_TYPE; - case "int" -> Type.INT_TYPE; - case "long" ->Type.LONG_TYPE; - case "double" -> Type.DOUBLE_TYPE; - case "float" -> Type.FLOAT_TYPE; - case "char" -> Type.CHAR_TYPE; - case "boolean" -> Type.BOOLEAN_TYPE; - case "java.lang.String" -> TYPE_STRING; - case "java.lang.Thread" -> TYPE_THREAD; - case "java.lang.Class" -> TYPE_CLASS; - default -> throw new Error("Not a valid type " + v.getTypeName()); - }; - } - - /** - * Converts "int" into "I" and "java.lang.String" into "Ljava/lang/String;" - * - * @param typeName - * type - * - * @return descriptor - */ - public static String getDescriptor(String typeName) { - return switch (typeName) { - case "int" -> "I"; - case "long" -> "J"; - case "boolean" -> "Z"; - case "float" -> "F"; - case "double" -> "D"; - case "short" -> "S"; - case "char" -> "C"; - case "byte" -> "B"; - default -> Type.getObjectType(getInternalName(typeName)).getDescriptor(); - }; - } - - /** - * Converts java.lang.String into java/lang/String - * - * @param className - * - * @return internal name - */ - public static String getInternalName(String className) { - return className.replace(".", "/"); - } - - public static void logASM(String className, byte[] bytes) { - Logger.log(LogTag.JFR_SYSTEM_BYTECODE, LogLevel.INFO, "Generated bytecode for class " + className); - if (Logger.shouldLog(LogTag.JFR_SYSTEM_BYTECODE, LogLevel.TRACE)) { - ClassReader cr = new ClassReader(bytes); - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - PrintWriter w = new PrintWriter(baos); - w.println("Bytecode:"); - cr.accept(new TraceClassVisitor(w), 0); - Logger.log(LogTag.JFR_SYSTEM_BYTECODE, LogLevel.TRACE, baos.toString()); - }; - } -} diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/EventClassBuilder.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/EventClassBuilder.java index 70bd3eef1f4..3d661f725e8 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/EventClassBuilder.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/EventClassBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2022, 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 @@ -25,117 +25,112 @@ package jdk.jfr.internal; +import static jdk.jfr.internal.util.Bytecode.invokespecial; + +import java.lang.constant.ClassDesc; +import java.lang.constant.ConstantDescs; +import java.lang.reflect.AccessFlag; +import java.util.ArrayList; import java.util.List; import java.util.concurrent.atomic.AtomicLong; -import jdk.internal.org.objectweb.asm.AnnotationVisitor; -import jdk.internal.org.objectweb.asm.ClassWriter; -import jdk.internal.org.objectweb.asm.Label; -import jdk.internal.org.objectweb.asm.MethodVisitor; -import jdk.internal.org.objectweb.asm.Opcodes; -import jdk.internal.org.objectweb.asm.Type; -import jdk.internal.org.objectweb.asm.commons.GeneratorAdapter; -import jdk.internal.org.objectweb.asm.commons.Method; +import jdk.internal.classfile.AnnotationValue; +import jdk.internal.classfile.ClassBuilder; +import jdk.internal.classfile.Classfile; +import jdk.internal.classfile.Label; +import jdk.internal.classfile.attribute.RuntimeVisibleAnnotationsAttribute; import jdk.jfr.AnnotationElement; import jdk.jfr.Event; import jdk.jfr.ValueDescriptor; - +import jdk.jfr.internal.util.Bytecode; +import jdk.jfr.internal.util.Bytecode.MethodDesc; // Helper class for building dynamic events public final class EventClassBuilder { - - private static final Type TYPE_EVENT = Type.getType(Event.class); - private static final Type TYPE_IOBE = Type.getType(IndexOutOfBoundsException.class); - private static final Method DEFAULT_CONSTRUCTOR = Method.getMethod("void ()"); - private static final Method SET_METHOD = Method.getMethod("void set (int, java.lang.Object)"); + private static final ClassDesc TYPE_EVENT = Bytecode.classDesc(Event.class); + private static final ClassDesc TYPE_IOBE = Bytecode.classDesc(IndexOutOfBoundsException.class); + private static final MethodDesc DEFAULT_CONSTRUCTOR = MethodDesc.of("", "()V"); + private static final MethodDesc SET_METHOD = MethodDesc.of("set", "(ILjava/lang/Object;)V"); private static final AtomicLong idCounter = new AtomicLong(); - private final ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES); + private final String fullClassName; - private final Type type; + private final ClassDesc type; private final List fields; private final List annotationElements; public EventClassBuilder(List annotationElements, List fields) { this.fullClassName = "jdk.jfr.DynamicEvent" + idCounter.incrementAndGet(); - this.type = Type.getType("L" + fullClassName.replace(".", "/") + ";"); + this.type = ClassDesc.of(fullClassName); this.fields = fields; this.annotationElements = annotationElements; } public Class build() { - buildClassInfo(); - buildConstructor(); - buildFields(); - buildSetMethod(); - endClass(); - byte[] bytes = classWriter.toByteArray(); - ASMToolkit.logASM(fullClassName, bytes); + byte[] bytes = Classfile.of().build(ClassDesc.of(fullClassName), cb -> build(cb)); + Bytecode.log(fullClassName, bytes); return SecuritySupport.defineClass(Event.class, bytes).asSubclass(Event.class); } - private void endClass() { - classWriter.visitEnd(); + void build(ClassBuilder builder) { + buildClassInfo(builder); + buildConstructor(builder); + buildFields(builder); + buildSetMethod(builder); } - private void buildSetMethod() { - GeneratorAdapter ga = new GeneratorAdapter(Opcodes.ACC_PUBLIC, SET_METHOD, null, null, classWriter); - int index = 0; - for (ValueDescriptor v : fields) { - ga.loadArg(0); - ga.visitLdcInsn(index); - Label notEqual = new Label(); - ga.ifICmp(GeneratorAdapter.NE, notEqual); - ga.loadThis(); - ga.loadArg(1); - Type fieldType = ASMToolkit.toType(v); - ga.unbox(ASMToolkit.toType(v)); - ga.putField(type, v.getName(), fieldType); - ga.visitInsn(Opcodes.RETURN); - ga.visitLabel(notEqual); - index++; - } - ga.throwException(TYPE_IOBE, "Index must between 0 and " + fields.size()); - ga.endMethod(); + private void buildSetMethod(ClassBuilder builder) { + // void Event::set(int index, Object value); + builder.withMethod(SET_METHOD.name(), SET_METHOD.descriptor(), Classfile.ACC_PUBLIC, methodBuilder -> methodBuilder.withCode(codeBuilder -> { + int index = 0; + for (ValueDescriptor v : fields) { + codeBuilder.iload(1); + codeBuilder.ldc(index); + Label notEqual = codeBuilder.newLabel(); + codeBuilder.if_icmpne(notEqual); + codeBuilder.aload(0); // this + codeBuilder.aload(2); // value + ClassDesc cd = Bytecode.classDesc(v); + Bytecode.unbox(codeBuilder, cd); + codeBuilder.putfield(type, v.getName(), cd); + codeBuilder.return_(); + codeBuilder.labelBinding(notEqual); + index++; + } + Bytecode.throwException(codeBuilder, TYPE_IOBE, "Index must between 0 and " + fields.size()); + })); } - private void buildConstructor() { - MethodVisitor mv = classWriter.visitMethod(Opcodes.ACC_PUBLIC, DEFAULT_CONSTRUCTOR.getName(), DEFAULT_CONSTRUCTOR.getDescriptor(), null, null); - mv.visitIntInsn(Opcodes.ALOAD, 0); - mv.visitMethodInsn(Opcodes.INVOKESPECIAL, TYPE_EVENT.getInternalName(), DEFAULT_CONSTRUCTOR.getName(), DEFAULT_CONSTRUCTOR.getDescriptor(), false); - mv.visitInsn(Opcodes.RETURN); - mv.visitMaxs(0, 0); + private void buildConstructor(ClassBuilder builder) { + builder.withMethod(ConstantDescs.INIT_NAME, ConstantDescs.MTD_void, Classfile.ACC_PUBLIC, methodBuilder -> methodBuilder.withCode(codeBuilder -> { + codeBuilder.aload(0); + invokespecial(codeBuilder, TYPE_EVENT, DEFAULT_CONSTRUCTOR); + codeBuilder.return_(); + })); } - private void buildClassInfo() { - String internalSuperName = ASMToolkit.getInternalName(Event.class.getName()); - String internalClassName = type.getInternalName(); - classWriter.visit(52, Opcodes.ACC_PUBLIC + Opcodes.ACC_FINAL + Opcodes.ACC_SUPER, internalClassName, null, internalSuperName, null); - - for (AnnotationElement a : annotationElements) { - String descriptor = ASMToolkit.getDescriptor(a.getTypeName()); - AnnotationVisitor av = classWriter.visitAnnotation(descriptor, true); + private void buildClassInfo(ClassBuilder builder) { + builder.withSuperclass(Bytecode.classDesc(Event.class)); + builder.withFlags(AccessFlag.FINAL, AccessFlag.PUBLIC, AccessFlag.SUPER); + List annotations = new ArrayList<>(); + for (jdk.jfr.AnnotationElement a : annotationElements) { + List list = new ArrayList<>(); for (ValueDescriptor v : a.getValueDescriptors()) { - Object value = a.getValue(v.getName()); - String name = v.getName(); - if (v.isArray()) { - AnnotationVisitor arrayVisitor = av.visitArray(name); - Object[] array = (Object[]) value; - for (int i = 0; i < array.length; i++) { - arrayVisitor.visit(null, array[i]); - } - arrayVisitor.visitEnd(); - } else { - av.visit(name, value); - } + // ValueDescriptor can only hold primitive + // No need to care about classes/enums + var value = a.getValue(v.getName()); + var av = AnnotationValue.of(value); + var ae = jdk.internal.classfile.AnnotationElement.of(v.getName(), av); + list.add(ae); } - av.visitEnd(); + ClassDesc cd = ClassDesc.of(a.getTypeName()); + annotations.add(jdk.internal.classfile.Annotation.of(cd, list)); } + builder.with(RuntimeVisibleAnnotationsAttribute.of(annotations)); } - private void buildFields() { + private void buildFields(ClassBuilder builder) { for (ValueDescriptor v : fields) { - String internal = ASMToolkit.getDescriptor(v.getTypeName()); - classWriter.visitField(Opcodes.ACC_PRIVATE, v.getName(), internal, null, null); + builder.withField(v.getName(), Bytecode.classDesc(v), Classfile.ACC_PRIVATE); // No need to store annotations on field since they will be replaced anyway. } } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/EventInstrumentation.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/EventInstrumentation.java index 9c3770c8fad..fcf00a7db9b 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/EventInstrumentation.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/EventInstrumentation.java @@ -25,117 +25,125 @@ package jdk.jfr.internal; +import java.lang.constant.ClassDesc; +import java.lang.constant.MethodTypeDesc; import java.lang.reflect.Field; import java.lang.reflect.Modifier; -import java.lang.reflect.Parameter; import java.util.ArrayList; import java.util.HashSet; +import java.util.LinkedHashMap; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.function.Consumer; -import jdk.internal.org.objectweb.asm.ClassReader; -import jdk.internal.org.objectweb.asm.ClassWriter; -import jdk.internal.org.objectweb.asm.Label; -import jdk.internal.org.objectweb.asm.MethodVisitor; -import jdk.internal.org.objectweb.asm.Opcodes; -import jdk.internal.org.objectweb.asm.Type; -import jdk.internal.org.objectweb.asm.commons.Method; -import jdk.internal.org.objectweb.asm.tree.AnnotationNode; -import jdk.internal.org.objectweb.asm.tree.ClassNode; -import jdk.internal.org.objectweb.asm.tree.FieldNode; -import jdk.internal.org.objectweb.asm.tree.MethodNode; +import jdk.internal.classfile.Annotation; +import jdk.internal.classfile.AnnotationElement; +import jdk.internal.classfile.AnnotationValue; +import jdk.internal.classfile.ClassElement; +import jdk.internal.classfile.ClassModel; +import jdk.internal.classfile.Classfile; +import jdk.internal.classfile.CodeBuilder; +import jdk.internal.classfile.CodeBuilder.BlockCodeBuilder; +import jdk.internal.classfile.FieldModel; +import jdk.internal.classfile.Label; +import jdk.internal.classfile.MethodModel; +import jdk.internal.classfile.Opcode; +import jdk.internal.classfile.TypeKind; +import jdk.internal.classfile.attribute.RuntimeVisibleAnnotationsAttribute; +import jdk.jfr.internal.event.EventConfiguration; +import jdk.jfr.internal.event.EventWriter; import jdk.jfr.Enabled; -import jdk.jfr.Event; import jdk.jfr.Name; import jdk.jfr.Registered; import jdk.jfr.SettingControl; import jdk.jfr.SettingDefinition; -import jdk.jfr.internal.event.EventConfiguration; -import jdk.jfr.internal.event.EventWriter; import jdk.jfr.internal.util.Utils; +import jdk.jfr.internal.util.Bytecode; +import jdk.jfr.internal.util.Bytecode.FieldDesc; +import jdk.jfr.internal.util.Bytecode.MethodDesc; +import static jdk.jfr.internal.util.Bytecode.invokevirtual; +import static jdk.jfr.internal.util.Bytecode.invokestatic; +import static jdk.jfr.internal.util.Bytecode.getfield; +import static jdk.jfr.internal.util.Bytecode.putfield; +import static jdk.jfr.internal.util.Bytecode.classDesc; /** * Class responsible for adding instrumentation to a subclass of {@link Event}. * */ -public final class EventInstrumentation { - - record SettingInfo(Type paramType, String methodName) { - } - - record FieldInfo(String name, String descriptor) { - } - - public static final String FIELD_EVENT_THREAD = "eventThread"; - public static final String FIELD_STACK_TRACE = "stackTrace"; - public static final String FIELD_DURATION = "duration"; - - static final String FIELD_EVENT_CONFIGURATION = "eventConfiguration"; - static final String FIELD_START_TIME = "startTime"; - - private static final String ANNOTATION_NAME_DESCRIPTOR = Type.getDescriptor(Name.class); - private static final String ANNOTATION_REGISTERED_DESCRIPTOR = Type.getDescriptor(Registered.class); - private static final String ANNOTATION_ENABLED_DESCRIPTOR = Type.getDescriptor(Enabled.class); - private static final Type TYPE_EVENT_CONFIGURATION = Type.getType(EventConfiguration.class); - private static final Type TYPE_EVENT_WRITER = Type.getType(EventWriter.class); - private static final Type TYPE_EVENT_WRITER_FACTORY = Type.getType("Ljdk/jfr/internal/event/EventWriterFactory;"); - private static final Type TYPE_SETTING_CONTROL = Type.getType(SettingControl.class); - private static final String TYPE_OBJECT_DESCRIPTOR = Type.getDescriptor(Object.class); - private static final String TYPE_EVENT_CONFIGURATION_DESCRIPTOR = TYPE_EVENT_CONFIGURATION.getDescriptor(); - private static final String TYPE_SETTING_DEFINITION_DESCRIPTOR = Type.getDescriptor(SettingDefinition.class); - private static final Method METHOD_COMMIT = new Method("commit", Type.VOID_TYPE, new Type[0]); - private static final Method METHOD_BEGIN = new Method("begin", Type.VOID_TYPE, new Type[0]); - private static final Method METHOD_END = new Method("end", Type.VOID_TYPE, new Type[0]); - private static final Method METHOD_IS_ENABLED = new Method("isEnabled", Type.BOOLEAN_TYPE, new Type[0]); - private static final Method METHOD_TIME_STAMP = new Method("timestamp", Type.LONG_TYPE, new Type[0]); - private static final Method METHOD_GET_EVENT_WRITER_KEY = new Method("getEventWriter", TYPE_EVENT_WRITER, new Type[] { Type.LONG_TYPE }); - private static final Method METHOD_EVENT_SHOULD_COMMIT = new Method("shouldCommit", Type.BOOLEAN_TYPE, new Type[0]); - private static final Method METHOD_EVENT_CONFIGURATION_SHOULD_COMMIT = new Method("shouldCommit", Type.BOOLEAN_TYPE, new Type[] { Type.LONG_TYPE }); - private static final Method METHOD_EVENT_CONFIGURATION_GET_SETTING = new Method("getSetting", TYPE_SETTING_CONTROL, new Type[] { Type.INT_TYPE }); - private static final Method METHOD_DURATION = new Method("duration", Type.LONG_TYPE, new Type[] { Type.LONG_TYPE }); - private static final Method METHOD_RESET = new Method("reset", "()V"); - private static final Method METHOD_ENABLED = new Method("enabled", Type.BOOLEAN_TYPE, new Type[0]); - private static final Method METHOD_SHOULD_COMMIT_LONG = new Method("shouldCommit", Type.BOOLEAN_TYPE, new Type[] { Type.LONG_TYPE }); - - private final ClassNode classNode; - private final List settingInfos; - private final List fieldInfos;; +final class EventInstrumentation { + + private record SettingDesc(ClassDesc paramType, String methodName) { + } + + private static final FieldDesc FIELD_DURATION = FieldDesc.of(long.class, Utils.FIELD_DURATION); + private static final FieldDesc FIELD_EVENT_CONFIGURATION = FieldDesc.of(Object.class, "eventConfiguration");; + private static final FieldDesc FIELD_START_TIME = FieldDesc.of(long.class, Utils.FIELD_START_TIME); + private static final ClassDesc ANNOTATION_ENABLED = classDesc(Enabled.class); + private static final ClassDesc ANNOTATION_NAME = classDesc(Name.class); + private static final ClassDesc ANNOTATION_REGISTERED = classDesc(Registered.class); + private static final ClassDesc TYPE_EVENT_CONFIGURATION = classDesc(EventConfiguration.class); + private static final ClassDesc TYPE_EVENT_WRITER = classDesc(EventWriter.class); + private static final ClassDesc TYPE_EVENT_WRITER_FACTORY = ClassDesc.of("jdk.jfr.internal.event.EventWriterFactory"); + private static final ClassDesc TYPE_OBJECT = Bytecode.classDesc(Object.class); + private static final ClassDesc TYPE_SETTING_DEFINITION = Bytecode.classDesc(SettingDefinition.class); + private static final MethodDesc METHOD_BEGIN = MethodDesc.of("begin", "()V"); + private static final MethodDesc METHOD_COMMIT = MethodDesc.of("commit", "()V"); + private static final MethodDesc METHOD_DURATION = MethodDesc.of("duration", "(J)J"); + private static final MethodDesc METHOD_ENABLED = MethodDesc.of("enabled", "()Z"); + private static final MethodDesc METHOD_END = MethodDesc.of("end", "()V"); + private static final MethodDesc METHOD_EVENT_CONFIGURATION_SHOULD_COMMIT = MethodDesc.of("shouldCommit", "(J)Z"); + private static final MethodDesc METHOD_EVENT_CONFIGURATION_GET_SETTING = MethodDesc.of("getSetting", SettingControl.class, int.class); + private static final MethodDesc METHOD_EVENT_SHOULD_COMMIT = MethodDesc.of("shouldCommit", "()Z"); + private static final MethodDesc METHOD_GET_EVENT_WRITER_KEY = MethodDesc.of("getEventWriter", "(J)" + TYPE_EVENT_WRITER.descriptorString()); + private static final MethodDesc METHOD_IS_ENABLED = MethodDesc.of("isEnabled", "()Z"); + private static final MethodDesc METHOD_RESET = MethodDesc.of("reset", "()V"); + private static final MethodDesc METHOD_SHOULD_COMMIT_LONG = MethodDesc.of("shouldCommit", "(J)Z"); + private static final MethodDesc METHOD_TIME_STAMP = MethodDesc.of("timestamp", "()J"); + + private final ClassModel classModel; + private final List settingDescs; + private final List fieldDescs;; private final String eventName; private final Class superClass; private final boolean untypedEventConfiguration; - private final Method staticCommitMethod; + private final MethodDesc staticCommitMethod; private final long eventTypeId; private final boolean guardEventConfiguration; private final boolean isJDK; + private final Map> methodUpdates = new LinkedHashMap<>(); EventInstrumentation(Class superClass, byte[] bytes, long id, boolean isJDK, boolean guardEventConfiguration) { this.eventTypeId = id; this.superClass = superClass; - this.classNode = createClassNode(bytes); - this.settingInfos = buildSettingInfos(superClass, classNode); - this.fieldInfos = buildFieldInfos(superClass, classNode); - String n = annotationValue(classNode, ANNOTATION_NAME_DESCRIPTOR, String.class); - this.eventName = n == null ? classNode.name.replace("/", ".") : n; - this.staticCommitMethod = isJDK ? findStaticCommitMethod(classNode, fieldInfos) : null; + this.classModel = createClassModel(bytes); + this.settingDescs = buildSettingDescs(superClass, classModel); + this.fieldDescs = buildFieldDescs(superClass, classModel); + String n = annotationValue(classModel, ANNOTATION_NAME, String.class); + this.eventName = n == null ? classModel.thisClass().asInternalName().replace("/", ".") : n; + this.staticCommitMethod = isJDK ? findStaticCommitMethod(classModel, fieldDescs) : null; this.untypedEventConfiguration = hasUntypedConfiguration(); - // Corner case when we are forced to generate bytecode (bytesForEagerInstrumentation) - // We can't reference EventConfiguration::isEnabled() before event class has been registered, + // Corner case when we are forced to generate bytecode + // (bytesForEagerInstrumentation) + // We can't reference EventConfiguration::isEnabled() before event class has + // been registered, // so we add a guard against a null reference. this.guardEventConfiguration = guardEventConfiguration; this.isJDK = isJDK; } - public static Method findStaticCommitMethod(ClassNode classNode, List fields) { + static MethodDesc findStaticCommitMethod(ClassModel classModel, List fields) { StringBuilder sb = new StringBuilder(); sb.append("("); - for (FieldInfo field : fields) { - sb.append(field.descriptor); + for (FieldDesc field : fields) { + sb.append(field.type().descriptorString()); } sb.append(")V"); - Method m = new Method("commit", sb.toString()); - for (MethodNode method : classNode.methods) { - if ("commit".equals(method.name) && m.getDescriptor().equals(method.desc)) { + MethodDesc m = MethodDesc.of("commit", sb.toString()); + for (MethodModel method : classModel.methods()) { + String d = method.methodTypeSymbol().descriptorString(); + if (method.methodName().equalsString("commit") && m.descriptor().descriptorString().equals(d)) { return m; } } @@ -143,27 +151,24 @@ public static Method findStaticCommitMethod(ClassNode classNode, List } private boolean hasUntypedConfiguration() { - for (FieldNode field : classNode.fields) { - if (FIELD_EVENT_CONFIGURATION.equals(field.name)) { - return field.desc.equals(TYPE_OBJECT_DESCRIPTOR); + for (FieldModel f : classModel.fields()) { + if (f.fieldName().equalsString(FIELD_EVENT_CONFIGURATION.name())) { + return f.fieldType().equalsString(TYPE_OBJECT.descriptorString()); } } throw new InternalError("Class missing configuration field"); } public String getClassName() { - return classNode.name.replace("/", "."); + return classModel.thisClass().asInternalName().replace("/", "."); } - private ClassNode createClassNode(byte[] bytes) { - ClassNode classNode = new ClassNode(); - ClassReader classReader = new ClassReader(bytes); - classReader.accept(classNode, 0); - return classNode; + private ClassModel createClassModel(byte[] bytes) { + return Classfile.of().parse(bytes); } boolean isRegistered() { - Boolean result = annotationValue(classNode, ANNOTATION_REGISTERED_DESCRIPTOR, Boolean.class); + Boolean result = annotationValue(classModel, ANNOTATION_REGISTERED, Boolean.class); if (result != null) { return result.booleanValue(); } @@ -177,7 +182,7 @@ boolean isRegistered() { } boolean isEnabled() { - Boolean result = annotationValue(classNode, ANNOTATION_ENABLED_DESCRIPTOR, Boolean.class); + Boolean result = annotationValue(classModel, ANNOTATION_ENABLED, Boolean.class); if (result != null) { return result.booleanValue(); } @@ -191,18 +196,23 @@ boolean isEnabled() { } @SuppressWarnings("unchecked") - private static T annotationValue(ClassNode classNode, String typeDescriptor, Class type) { - if (classNode.visibleAnnotations != null) { - for (AnnotationNode a : classNode.visibleAnnotations) { - if (typeDescriptor.equals(a.desc)) { - List values = a.values; - if (values != null && values.size() == 2) { - Object key = values.get(0); - Object value = values.get(1); - if (key instanceof String keyName && value != null) { - if (type == value.getClass()) { - if ("value".equals(keyName)) { - return (T) value; + // Only supports String and Boolean values + private static T annotationValue(ClassModel classModel, ClassDesc classDesc, Class type) { + String typeDescriptor = classDesc.descriptorString(); + for (ClassElement ce : classModel.elements()) { + if (ce instanceof RuntimeVisibleAnnotationsAttribute rvaa) { + for (Annotation a : rvaa.annotations()) { + if (a.className().equalsString(typeDescriptor)) { + if (a.elements().size() == 1) { + AnnotationElement ae = a.elements().getFirst(); + if (ae.name().equalsString("value")) { + if (ae.value() instanceof AnnotationValue.OfBoolean ofb && type.equals(Boolean.class)) { + Boolean b = ofb.booleanValue(); + return (T)b; + } + if (ae.value() instanceof AnnotationValue.OfString ofs && type.equals(String.class)) { + String s = ofs.stringValue(); + return (T)s; } } } @@ -213,99 +223,119 @@ private static T annotationValue(ClassNode classNode, String typeDescriptor, return null; } - private static List buildSettingInfos(Class superClass, ClassNode classNode) { + private static List buildSettingDescs(Class superClass, ClassModel classModel) { Set methodSet = new HashSet<>(); - List settingInfos = new ArrayList<>(); - for (MethodNode m : classNode.methods) { - if (m.visibleAnnotations != null) { - for (AnnotationNode an : m.visibleAnnotations) { - // We can't really validate the method at this - // stage. We would need to check that the parameter - // is an instance of SettingControl. - if (TYPE_SETTING_DEFINITION_DESCRIPTOR.equals(an.desc)) { - String name = m.name; - for (AnnotationNode nameCandidate : m.visibleAnnotations) { - if (ANNOTATION_NAME_DESCRIPTOR.equals(nameCandidate.desc)) { - List values = nameCandidate.values; - if (values.size() == 1 && values.getFirst() instanceof String s) { - name = Utils.validJavaIdentifier(s, name); + List settingDescs = new ArrayList<>(); + for (MethodModel m : classModel.methods()) { + for (var me : m.elements()) { + if (me instanceof RuntimeVisibleAnnotationsAttribute rvaa) { + for (Annotation a : rvaa.annotations()) { + // We can't really validate the method at this + // stage. We would need to check that the parameter + // is an instance of SettingControl. + if (a.className().equalsString(TYPE_SETTING_DEFINITION.descriptorString())) { + String name = m.methodName().stringValue(); + // Use @Name if it exists + for (Annotation nameCandidate : rvaa.annotations()) { + if (nameCandidate.className().equalsString(ANNOTATION_NAME.descriptorString())) { + if (nameCandidate.elements().size() == 1) { + AnnotationElement ae = nameCandidate.elements().getFirst(); + if (ae.name().equalsString("value")) { + if (ae.value() instanceof AnnotationValue.OfString s) { + name = Utils.validJavaIdentifier(s.stringValue(), name); + } + } + } } } - } - Type returnType = Type.getReturnType(m.desc); - if (returnType.equals(Type.getType(Boolean.TYPE))) { - Type[] args = Type.getArgumentTypes(m.desc); - if (args.length == 1) { - Type paramType = args[0]; - methodSet.add(m.name); - settingInfos.add(new SettingInfo(paramType, m.name)); + // Add setting if method returns boolean and has one parameter + MethodTypeDesc mtd = m.methodTypeSymbol(); + if ("Z".equals(mtd.returnType().descriptorString())) { + if (mtd.parameterList().size() == 1) { + ClassDesc type = mtd.parameterList().getFirst(); + if (type.isClassOrInterface()) { + String methodName = m.methodName().stringValue(); + methodSet.add(methodName); + settingDescs.add(new SettingDesc(type, methodName)); + } + } } } } } } } - for (Class c = superClass; c != jdk.internal.event.Event.class; c = c.getSuperclass()) { + for (Class c = superClass; jdk.internal.event.Event.class != c; c = c.getSuperclass()) { for (java.lang.reflect.Method method : c.getDeclaredMethods()) { if (!methodSet.contains(method.getName())) { // skip private method in base classes if (!Modifier.isPrivate(method.getModifiers())) { if (method.getReturnType().equals(Boolean.TYPE)) { if (method.getParameterCount() == 1) { - Parameter param = method.getParameters()[0]; - Type paramType = Type.getType(param.getType()); - methodSet.add(method.getName()); - settingInfos.add(new SettingInfo(paramType, method.getName())); + Class type = method.getParameters()[0].getType(); + if (SettingControl.class.isAssignableFrom(type)) { + ClassDesc paramType = Bytecode.classDesc(type); + methodSet.add(method.getName()); + settingDescs.add(new SettingDesc(paramType, method.getName())); + } } } } } } } - return settingInfos; + return settingDescs; } - private static List buildFieldInfos(Class superClass, ClassNode classNode) { + private static List buildFieldDescs(Class superClass, ClassModel classModel) { Set fieldSet = new HashSet<>(); - List fieldInfos = new ArrayList<>(classNode.fields.size()); + List fieldDescs = new ArrayList<>(classModel.fields().size()); // These two fields are added by native as 'transient' so they will be // ignored by the loop below. // The benefit of adding them manually is that we can // control in which order they occur and we can add @Name, @Description // in Java, instead of in native. It also means code for adding implicit // fields for native can be reused by Java. - fieldInfos.add(new FieldInfo("startTime", Type.LONG_TYPE.getDescriptor())); - fieldInfos.add(new FieldInfo("duration", Type.LONG_TYPE.getDescriptor())); - for (FieldNode field : classNode.fields) { - if (!fieldSet.contains(field.name) && isValidField(field.access, Type.getType(field.desc).getClassName())) { - FieldInfo fi = new FieldInfo(field.name, field.desc); - fieldInfos.add(fi); - fieldSet.add(field.name); + fieldDescs.add(FIELD_START_TIME); + fieldDescs.add(FIELD_DURATION); + for (FieldModel field : classModel.fields()) { + if (!fieldSet.contains(field.fieldName().stringValue()) && isValidField(field.flags().flagsMask(), field.fieldTypeSymbol())) { + FieldDesc fi = FieldDesc.of(field.fieldTypeSymbol(), field.fieldName().stringValue()); + fieldDescs.add(fi); + fieldSet.add(field.fieldName().stringValue()); } } - for (Class c = superClass; c != jdk.internal.event.Event.class; c = c.getSuperclass()) { + for (Class c = superClass; jdk.internal.event.Event.class != c; c = c.getSuperclass()) { for (Field field : c.getDeclaredFields()) { // skip private field in base classes if (!Modifier.isPrivate(field.getModifiers())) { if (isValidField(field.getModifiers(), field.getType().getName())) { String fieldName = field.getName(); if (!fieldSet.contains(fieldName)) { - Type fieldType = Type.getType(field.getType()); - fieldInfos.add(new FieldInfo(fieldName, fieldType.getDescriptor())); + fieldDescs.add(FieldDesc.of(field.getType(), fieldName)); fieldSet.add(fieldName); } } } } } - return fieldInfos; + return fieldDescs; + } + + public static boolean isValidField(int access, ClassDesc classDesc) { + String className = classDesc.packageName(); + if (!className.isEmpty()) { + className = className + "."; + } + className += classDesc.displayName(); + return isValidField(access, className); } public static boolean isValidField(int access, String className) { if (Modifier.isTransient(access) || Modifier.isStatic(access)) { return false; } - return jdk.jfr.internal.Type.isValidJavaFieldType(className); + return Type.isValidJavaFieldType(className); } public byte[] buildInstrumented() { @@ -313,11 +343,24 @@ public byte[] buildInstrumented() { return toByteArray(); } - private byte[] toByteArray() { - ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); - classNode.accept(cw); - cw.visitEnd(); - return cw.toByteArray(); + byte[] toByteArray() { + return Classfile.of().build(classModel.thisClass().asSymbol(), classBuilder -> { + for (ClassElement ce : classModel) { + boolean updated = false; + if (ce instanceof MethodModel method) { + Consumer methodUpdate = findMethodUpdate(method); + if (methodUpdate != null) { + classBuilder.withMethod(method.methodName().stringValue(), method.methodTypeSymbol(), method.flags().flagsMask(), methodBuilder -> { + methodBuilder.withCode(methodUpdate); + }); + updated = true; + } + } + if (!updated) { + classBuilder.with(ce); + } + } + }); } public byte[] buildUninstrumented() { @@ -330,416 +373,347 @@ private void makeInstrumented() { updateEnabledMethod(METHOD_IS_ENABLED); // MyEvent#begin() - updateMethod(METHOD_BEGIN, methodVisitor -> { - methodVisitor.visitIntInsn(Opcodes.ALOAD, 0); - invokeStatic(methodVisitor, TYPE_EVENT_CONFIGURATION.getInternalName(), METHOD_TIME_STAMP); - methodVisitor.visitFieldInsn(Opcodes.PUTFIELD, getInternalClassName(), FIELD_START_TIME, "J"); - methodVisitor.visitInsn(Opcodes.RETURN); + updateMethod(METHOD_BEGIN, codeBuilder -> { + codeBuilder.aload(0); + invokestatic(codeBuilder, TYPE_EVENT_CONFIGURATION, METHOD_TIME_STAMP); + putfield(codeBuilder, getEventClassDesc(), FIELD_START_TIME); + codeBuilder.return_(); }); // MyEvent#end() - updateMethod(METHOD_END, methodVisitor -> { - methodVisitor.visitIntInsn(Opcodes.ALOAD, 0); - methodVisitor.visitIntInsn(Opcodes.ALOAD, 0); - methodVisitor.visitFieldInsn(Opcodes.GETFIELD, getInternalClassName(), FIELD_START_TIME, "J"); - invokeStatic(methodVisitor, TYPE_EVENT_CONFIGURATION.getInternalName(), METHOD_DURATION); - methodVisitor.visitFieldInsn(Opcodes.PUTFIELD, getInternalClassName(), FIELD_DURATION, "J"); - methodVisitor.visitInsn(Opcodes.RETURN); - methodVisitor.visitMaxs(0, 0); + updateMethod(METHOD_END, codeBuilder -> { + codeBuilder.aload(0); + codeBuilder.aload(0); + getfield(codeBuilder, getEventClassDesc(), FIELD_START_TIME); + invokestatic(codeBuilder, TYPE_EVENT_CONFIGURATION, METHOD_DURATION); + putfield(codeBuilder, getEventClassDesc(), FIELD_DURATION); + codeBuilder.return_(); }); // MyEvent#commit() or static MyEvent#commit(...) - if (staticCommitMethod != null) { - updateExistingWithEmptyVoidMethod(METHOD_COMMIT); - updateMethod(staticCommitMethod, mv -> { - // indexes the argument type array, the argument type array does not include - // 'this' - int argIndex = 0; - // indexes the proper slot in the local variable table, takes type size into - // account, therefore sometimes argIndex != slotIndex - int slotIndex = 0; - int fieldIndex = 0; - Type[] argumentTypes = Type.getArgumentTypes(staticCommitMethod.getDescriptor()); - mv.visitCode(); - Label start = new Label(); - Label endTryBlock = new Label(); - Label exceptionHandler = new Label(); - mv.visitTryCatchBlock(start, endTryBlock, exceptionHandler, "java/lang/Throwable"); - mv.visitLabel(start); - getEventWriter(mv); - // stack: [EW] - mv.visitInsn(Opcodes.DUP); - // stack: [EW], [EW] - // write begin event - getEventConfiguration(mv); - // stack: [EW], [EW], [EventConfiguration] - mv.visitLdcInsn(eventTypeId); - // stack: [EW], [EW], [EventConfiguration] [long] - visitMethod(mv, Opcodes.INVOKEVIRTUAL, TYPE_EVENT_WRITER, EventWriterMethod.BEGIN_EVENT.asASM()); - // stack: [EW], [integer] - Label excluded = new Label(); - mv.visitJumpInsn(Opcodes.IFEQ, excluded); - // stack: [EW] - // write startTime - mv.visitInsn(Opcodes.DUP); - // stack: [EW], [EW] - mv.visitVarInsn(argumentTypes[argIndex].getOpcode(Opcodes.ILOAD), slotIndex); - // stack: [EW], [EW], [long] - slotIndex += argumentTypes[argIndex++].getSize(); - visitMethod(mv, Opcodes.INVOKEVIRTUAL, TYPE_EVENT_WRITER, EventWriterMethod.PUT_LONG.asASM()); - // stack: [EW] - fieldIndex++; - // write duration - mv.visitInsn(Opcodes.DUP); - // stack: [EW], [EW] - mv.visitVarInsn(argumentTypes[argIndex].getOpcode(Opcodes.ILOAD), slotIndex); - // stack: [EW], [EW], [long] - slotIndex += argumentTypes[argIndex++].getSize(); - visitMethod(mv, Opcodes.INVOKEVIRTUAL, TYPE_EVENT_WRITER, EventWriterMethod.PUT_LONG.asASM()); - // stack: [EW] - fieldIndex++; - // write eventThread - mv.visitInsn(Opcodes.DUP); - // stack: [EW], [EW] - visitMethod(mv, Opcodes.INVOKEVIRTUAL, TYPE_EVENT_WRITER, EventWriterMethod.PUT_EVENT_THREAD.asASM()); - // stack: [EW] - // write stackTrace - mv.visitInsn(Opcodes.DUP); - // stack: [EW], [EW] - visitMethod(mv, Opcodes.INVOKEVIRTUAL, TYPE_EVENT_WRITER, EventWriterMethod.PUT_STACK_TRACE.asASM()); - // stack: [EW] - // write custom fields - while (fieldIndex < fieldInfos.size()) { - mv.visitInsn(Opcodes.DUP); - // stack: [EW], [EW] - mv.visitVarInsn(argumentTypes[argIndex].getOpcode(Opcodes.ILOAD), slotIndex); - // stack:[EW], [EW], [field] - slotIndex += argumentTypes[argIndex++].getSize(); - FieldInfo field = fieldInfos.get(fieldIndex); - EventWriterMethod eventMethod = EventWriterMethod.lookupMethod(field); - visitMethod(mv, Opcodes.INVOKEVIRTUAL, TYPE_EVENT_WRITER, eventMethod.asASM()); - // stack: [EW] - fieldIndex++; - } - // stack: [EW] - // write end event (writer already on stack) - visitMethod(mv, Opcodes.INVOKEVIRTUAL, TYPE_EVENT_WRITER, EventWriterMethod.END_EVENT.asASM()); - // stack [integer] - // notified -> restart event write attempt - mv.visitJumpInsn(Opcodes.IFEQ, start); - // stack: - mv.visitLabel(endTryBlock); - Label end = new Label(); - mv.visitJumpInsn(Opcodes.GOTO, end); - mv.visitLabel(exceptionHandler); - // stack: [ex] - mv.visitFrame(Opcodes.F_SAME1, 0, null, 1, new Object[] { "java/lang/Throwable" }); - getEventWriter(mv); - // stack: [ex] [EW] - mv.visitInsn(Opcodes.DUP); - // stack: [ex] [EW] [EW] - Label rethrow = new Label(); - mv.visitJumpInsn(Opcodes.IFNULL, rethrow); - // stack: [ex] [EW] - mv.visitInsn(Opcodes.DUP); - // stack: [ex] [EW] [EW] - visitMethod(mv, Opcodes.INVOKEVIRTUAL, TYPE_EVENT_WRITER, METHOD_RESET); - mv.visitLabel(rethrow); - // stack:[ex] [EW] - mv.visitFrame(Opcodes.F_SAME, 0, null, 2, new Object[] { "java/lang/Throwable", TYPE_EVENT_WRITER.getInternalName() }); - mv.visitInsn(Opcodes.POP); - // stack:[ex] - mv.visitInsn(Opcodes.ATHROW); - mv.visitLabel(excluded); - // stack: [EW] - mv.visitFrame(Opcodes.F_SAME, 0, null, 1, new Object[] { TYPE_EVENT_WRITER.getInternalName() }); - mv.visitInsn(Opcodes.POP); - mv.visitLabel(end); - // stack: - mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - mv.visitInsn(Opcodes.RETURN); - mv.visitMaxs(0, 0); - mv.visitEnd(); - }); - } else { - updateMethod(METHOD_COMMIT, methodVisitor -> { - // if (!isEnable()) { - // return; - // } - methodVisitor.visitCode(); - Label start = new Label(); - Label endTryBlock = new Label(); - Label exceptionHandler = new Label(); - methodVisitor.visitTryCatchBlock(start, endTryBlock, exceptionHandler, "java/lang/Throwable"); - methodVisitor.visitLabel(start); - methodVisitor.visitVarInsn(Opcodes.ALOAD, 0); - methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, getInternalClassName(), METHOD_IS_ENABLED.getName(), METHOD_IS_ENABLED.getDescriptor(), false); - Label l0 = new Label(); - methodVisitor.visitJumpInsn(Opcodes.IFNE, l0); - methodVisitor.visitInsn(Opcodes.RETURN); - methodVisitor.visitLabel(l0); - methodVisitor.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - // long startTime = this.startTime - methodVisitor.visitVarInsn(Opcodes.ALOAD, 0); - methodVisitor.visitFieldInsn(Opcodes.GETFIELD, getInternalClassName(), FIELD_START_TIME, "J"); - methodVisitor.visitVarInsn(Opcodes.LSTORE, 1); - // if (startTime == 0) { - // startTime = EventWriter.timestamp(); - // } else { - methodVisitor.visitVarInsn(Opcodes.LLOAD, 1); - methodVisitor.visitInsn(Opcodes.LCONST_0); - methodVisitor.visitInsn(Opcodes.LCMP); - Label durationalEvent = new Label(); - methodVisitor.visitJumpInsn(Opcodes.IFNE, durationalEvent); - methodVisitor.visitMethodInsn(Opcodes.INVOKESTATIC, TYPE_EVENT_CONFIGURATION.getInternalName(), METHOD_TIME_STAMP.getName(), METHOD_TIME_STAMP.getDescriptor(), false); - methodVisitor.visitVarInsn(Opcodes.LSTORE, 1); - Label commit = new Label(); - methodVisitor.visitJumpInsn(Opcodes.GOTO, commit); - // if (duration == 0) { - // duration = EventWriter.timestamp() - startTime; - // } - // } - methodVisitor.visitLabel(durationalEvent); - methodVisitor.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - methodVisitor.visitVarInsn(Opcodes.ALOAD, 0); - methodVisitor.visitFieldInsn(Opcodes.GETFIELD, getInternalClassName(), FIELD_DURATION, "J"); - methodVisitor.visitInsn(Opcodes.LCONST_0); - methodVisitor.visitInsn(Opcodes.LCMP); - methodVisitor.visitJumpInsn(Opcodes.IFNE, commit); - methodVisitor.visitVarInsn(Opcodes.ALOAD, 0); - methodVisitor.visitMethodInsn(Opcodes.INVOKESTATIC, TYPE_EVENT_CONFIGURATION.getInternalName(), METHOD_TIME_STAMP.getName(), METHOD_TIME_STAMP.getDescriptor(), false); - methodVisitor.visitVarInsn(Opcodes.LLOAD, 1); - methodVisitor.visitInsn(Opcodes.LSUB); - methodVisitor.visitFieldInsn(Opcodes.PUTFIELD, getInternalClassName(), FIELD_DURATION, "J"); - methodVisitor.visitLabel(commit); - // if (shouldCommit()) { - methodVisitor.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - methodVisitor.visitVarInsn(Opcodes.ALOAD, 0); - invokeVirtual(methodVisitor, getInternalClassName(), METHOD_EVENT_SHOULD_COMMIT); - Label end = new Label(); - methodVisitor.visitJumpInsn(Opcodes.IFEQ, end); - getEventWriter(methodVisitor); - // stack: [EW] - methodVisitor.visitInsn(Opcodes.DUP); - // stack: [EW] [EW] - getEventConfiguration(methodVisitor); - // stack: [EW] [EW] [EC] - methodVisitor.visitLdcInsn(eventTypeId); - invokeVirtual(methodVisitor, TYPE_EVENT_WRITER, EventWriterMethod.BEGIN_EVENT.asmMethod); - Label excluded = new Label(); - // stack: [EW] [int] - methodVisitor.visitJumpInsn(Opcodes.IFEQ, excluded); - // stack: [EW] - int fieldIndex = 0; - methodVisitor.visitInsn(Opcodes.DUP); - // stack: [EW] [EW] - methodVisitor.visitVarInsn(Opcodes.LLOAD, 1); - // stack: [EW] [EW] [long] - invokeVirtual(methodVisitor, TYPE_EVENT_WRITER, EventWriterMethod.PUT_LONG.asmMethod); - // stack: [EW] - fieldIndex++; - methodVisitor.visitInsn(Opcodes.DUP); - // stack: [EW] [EW] - methodVisitor.visitVarInsn(Opcodes.ALOAD, 0); - // stack: [EW] [EW] [this] - methodVisitor.visitFieldInsn(Opcodes.GETFIELD, getInternalClassName(), FIELD_DURATION, "J"); - // stack: [EW] [EW] [long] - invokeVirtual(methodVisitor, TYPE_EVENT_WRITER, EventWriterMethod.PUT_LONG.asmMethod); - // stack: [EW] - fieldIndex++; - methodVisitor.visitInsn(Opcodes.DUP); - // stack: [EW] [EW] - invokeVirtual(methodVisitor, TYPE_EVENT_WRITER, EventWriterMethod.PUT_EVENT_THREAD.asASM()); - // stack: [EW] - methodVisitor.visitInsn(Opcodes.DUP); - // stack: [EW] [EW] - invokeVirtual(methodVisitor, TYPE_EVENT_WRITER, EventWriterMethod.PUT_STACK_TRACE.asASM()); - // stack: [EW] - while (fieldIndex < fieldInfos.size()) { - FieldInfo field = fieldInfos.get(fieldIndex); - methodVisitor.visitInsn(Opcodes.DUP); - // stack: [EW] [EW] - methodVisitor.visitVarInsn(Opcodes.ALOAD, 0); - // stack: [EW] [EW] [this] - methodVisitor.visitFieldInsn(Opcodes.GETFIELD, getInternalClassName(), field.name, field.descriptor); - // stack: [EW] [EW] - EventWriterMethod eventMethod = EventWriterMethod.lookupMethod(field); - invokeVirtual(methodVisitor, TYPE_EVENT_WRITER, eventMethod.asmMethod); - // stack: [EW] - fieldIndex++; + MethodDesc m = staticCommitMethod == null ? METHOD_COMMIT : staticCommitMethod; + updateMethod(m, codeBuilder -> { + Label excluded = codeBuilder.newLabel(); + Label end = codeBuilder.newLabel(); + codeBuilder.trying(blockCodeBuilder -> { + if (staticCommitMethod != null) { + updateStaticCommit(blockCodeBuilder, excluded); + } else { + updateInstanceCommit(blockCodeBuilder, end, excluded); } - // stack:[EW] - invokeVirtual(methodVisitor, TYPE_EVENT_WRITER, EventWriterMethod.END_EVENT.asASM()); - // stack [int] + // stack: [integer] // notified -> restart event write attempt - methodVisitor.visitJumpInsn(Opcodes.IFEQ, start); - methodVisitor.visitLabel(endTryBlock); - methodVisitor.visitJumpInsn(Opcodes.GOTO, end); - methodVisitor.visitLabel(exceptionHandler); - // stack: [ex] - methodVisitor.visitFrame(Opcodes.F_SAME1, 0, null, 1, new Object[] { "java/lang/Throwable" }); - getEventWriter(methodVisitor); - // stack: [ex] [EW] - methodVisitor.visitInsn(Opcodes.DUP); - // stack: [ex] [EW] [EW] - Label rethrow = new Label(); - methodVisitor.visitJumpInsn(Opcodes.IFNULL, rethrow); - // stack: [ex] [EW] - methodVisitor.visitInsn(Opcodes.DUP); - // stack: [ex] [EW] [EW] - visitMethod(methodVisitor, Opcodes.INVOKEVIRTUAL, TYPE_EVENT_WRITER, METHOD_RESET); - methodVisitor.visitLabel(rethrow); - // stack:[ex] [EW] - methodVisitor.visitFrame(Opcodes.F_SAME, 0, null, 2, new Object[] { "java/lang/Throwable", TYPE_EVENT_WRITER.getInternalName() }); - methodVisitor.visitInsn(Opcodes.POP); - // stack:[ex] - methodVisitor.visitInsn(Opcodes.ATHROW); - methodVisitor.visitLabel(excluded); - // stack: [EW] - methodVisitor.visitFrame(Opcodes.F_SAME, 0, null, 1, new Object[] { TYPE_EVENT_WRITER.getInternalName() }); - methodVisitor.visitInsn(Opcodes.POP); - methodVisitor.visitLabel(end); - // stack: - methodVisitor.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - methodVisitor.visitInsn(Opcodes.RETURN); - methodVisitor.visitMaxs(0, 0); - methodVisitor.visitEnd(); + blockCodeBuilder.ifeq(blockCodeBuilder.startLabel()); + // stack: [] + blockCodeBuilder.goto_(end); + }, catchBuilder -> { + catchBuilder.catchingAll(catchAllHandler -> { + getEventWriter(catchAllHandler); + // stack: [ex] [EW] + catchAllHandler.dup(); + // stack: [ex] [EW] [EW] + Label rethrow = catchAllHandler.newLabel(); + catchAllHandler.if_null(rethrow); + // stack: [ex] [EW] + catchAllHandler.dup(); + // stack: [ex] [EW] [EW] + invokevirtual(catchAllHandler, TYPE_EVENT_WRITER, METHOD_RESET); + catchAllHandler.labelBinding(rethrow); + // stack:[ex] [EW] + catchAllHandler.pop(); + // stack:[ex] + catchAllHandler.throwInstruction(); + }); }); - } + codeBuilder.labelBinding(excluded); + // stack: [EW] + codeBuilder.pop(); + codeBuilder.labelBinding(end); + // stack: [] + codeBuilder.return_(); + }); // MyEvent#shouldCommit() - updateMethod(METHOD_EVENT_SHOULD_COMMIT, methodVisitor -> { - Label fail = new Label(); + updateMethod(METHOD_EVENT_SHOULD_COMMIT, codeBuilder -> { + Label fail = codeBuilder.newLabel(); if (guardEventConfiguration) { - getEventConfiguration(methodVisitor); - methodVisitor.visitJumpInsn(Opcodes.IFNULL, fail); + getEventConfiguration(codeBuilder); + codeBuilder.if_null(fail); } // if (!eventConfiguration.shouldCommit(duration) goto fail; - getEventConfiguration(methodVisitor); - methodVisitor.visitVarInsn(Opcodes.ALOAD, 0); - methodVisitor.visitFieldInsn(Opcodes.GETFIELD, getInternalClassName(), FIELD_DURATION, "J"); - invokeVirtual(methodVisitor, TYPE_EVENT_CONFIGURATION, METHOD_EVENT_CONFIGURATION_SHOULD_COMMIT); - methodVisitor.visitJumpInsn(Opcodes.IFEQ, fail); - for (int index = 0; index < settingInfos.size(); index++) { - SettingInfo si = settingInfos.get(index); + getEventConfiguration(codeBuilder); + codeBuilder.aload(0); + getfield(codeBuilder, getEventClassDesc(), FIELD_DURATION); + invokevirtual(codeBuilder, TYPE_EVENT_CONFIGURATION, METHOD_EVENT_CONFIGURATION_SHOULD_COMMIT); + codeBuilder.ifeq(fail); + for (int index = 0; index < settingDescs.size(); index++) { + SettingDesc sd = settingDescs.get(index); // if (!settingsMethod(eventConfiguration.settingX)) goto fail; - methodVisitor.visitIntInsn(Opcodes.ALOAD, 0); - if (untypedEventConfiguration) { - methodVisitor.visitFieldInsn(Opcodes.GETSTATIC, getInternalClassName(), FIELD_EVENT_CONFIGURATION, TYPE_OBJECT_DESCRIPTOR); - } else { - methodVisitor.visitFieldInsn(Opcodes.GETSTATIC, getInternalClassName(), FIELD_EVENT_CONFIGURATION, TYPE_EVENT_CONFIGURATION_DESCRIPTOR); - } - methodVisitor.visitTypeInsn(Opcodes.CHECKCAST, TYPE_EVENT_CONFIGURATION.getInternalName()); - methodVisitor.visitLdcInsn(index); - invokeVirtual(methodVisitor, TYPE_EVENT_CONFIGURATION, METHOD_EVENT_CONFIGURATION_GET_SETTING); - methodVisitor.visitTypeInsn(Opcodes.CHECKCAST, si.paramType().getInternalName()); - methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, getInternalClassName(), si.methodName, "(" + si.paramType().getDescriptor() + ")Z", false); - methodVisitor.visitJumpInsn(Opcodes.IFEQ, fail); + codeBuilder.aload(0); + getEventConfiguration(codeBuilder); + codeBuilder.checkcast(TYPE_EVENT_CONFIGURATION); + codeBuilder.ldc(index); + invokevirtual(codeBuilder, TYPE_EVENT_CONFIGURATION, METHOD_EVENT_CONFIGURATION_GET_SETTING); + MethodTypeDesc mdesc = MethodTypeDesc.ofDescriptor("(" + sd.paramType().descriptorString() + ")Z"); + codeBuilder.checkcast(sd.paramType()); + codeBuilder.invokevirtual(getEventClassDesc(), sd.methodName(), mdesc); + codeBuilder.ifeq(fail); } // return true - methodVisitor.visitInsn(Opcodes.ICONST_1); - methodVisitor.visitInsn(Opcodes.IRETURN); + codeBuilder.iconst_1(); + codeBuilder.ireturn(); // return false - methodVisitor.visitLabel(fail); - methodVisitor.visitInsn(Opcodes.ICONST_0); - methodVisitor.visitInsn(Opcodes.IRETURN); + codeBuilder.labelBinding(fail); + codeBuilder.iconst_0(); + codeBuilder.ireturn(); }); if (isJDK) { if (hasStaticMethod(METHOD_ENABLED)) { updateEnabledMethod(METHOD_ENABLED); - }; - updateIfStaticMethodExists(METHOD_SHOULD_COMMIT_LONG, methodVisitor -> { - Label fail = new Label(); + } + + updateIfStaticMethodExists(METHOD_SHOULD_COMMIT_LONG, codeBuilder -> { + Label fail = codeBuilder.newLabel(); if (guardEventConfiguration) { // if (eventConfiguration == null) goto fail; - getEventConfiguration(methodVisitor); - methodVisitor.visitJumpInsn(Opcodes.IFNULL, fail); + getEventConfiguration(codeBuilder); + codeBuilder.if_null(fail); } // return eventConfiguration.shouldCommit(duration); - getEventConfiguration(methodVisitor); - methodVisitor.visitVarInsn(Opcodes.LLOAD, 0); - invokeVirtual(methodVisitor, TYPE_EVENT_CONFIGURATION, METHOD_EVENT_CONFIGURATION_SHOULD_COMMIT); - methodVisitor.visitInsn(Opcodes.IRETURN); + getEventConfiguration(codeBuilder); + codeBuilder.lload(0); + codeBuilder.invokevirtual(TYPE_EVENT_CONFIGURATION, METHOD_EVENT_CONFIGURATION_SHOULD_COMMIT.name(), METHOD_EVENT_CONFIGURATION_SHOULD_COMMIT.descriptor()); + codeBuilder.ireturn(); // fail: - methodVisitor.visitLabel(fail); + codeBuilder.labelBinding(fail); // return false - methodVisitor.visitInsn(Opcodes.ICONST_0); - methodVisitor.visitInsn(Opcodes.IRETURN); - methodVisitor.visitMaxs(0, 0); - methodVisitor.visitEnd(); + codeBuilder.iconst_0(); + codeBuilder.ireturn(); }); - updateIfStaticMethodExists(METHOD_TIME_STAMP, methodVisitor -> { - invokeStatic(methodVisitor, TYPE_EVENT_CONFIGURATION.getInternalName(), METHOD_TIME_STAMP); - methodVisitor.visitInsn(Opcodes.LRETURN); - methodVisitor.visitMaxs(0, 0); - methodVisitor.visitEnd(); + updateIfStaticMethodExists(METHOD_TIME_STAMP, codeBuilder -> { + invokestatic(codeBuilder, TYPE_EVENT_CONFIGURATION, METHOD_TIME_STAMP); + codeBuilder.lreturn(); }); } } - private void updateEnabledMethod(Method method) { - updateMethod(method, methodVisitor -> { - Label nullLabel = new Label(); + void updateStaticCommit(BlockCodeBuilder blockCodeBuilder, Label excluded) { + // indexes the argument type array, the argument type array does not include + // 'this' + int argIndex = 0; + // indexes the proper slot in the local variable table, takes type size into + // account, therefore sometimes argIndex != slotIndex + int slotIndex = 0; + int fieldIndex = 0; + ClassDesc[] argumentTypes = staticCommitMethod.descriptor().parameterArray(); + TypeKind tk = null; + getEventWriter(blockCodeBuilder); + // stack: [EW], + blockCodeBuilder.dup(); + // stack: [EW], [EW] + // write begin event + getEventConfiguration(blockCodeBuilder); + // stack: [EW], [EW], [EventConfiguration] + blockCodeBuilder.constantInstruction(Opcode.LDC2_W, eventTypeId); + // stack: [EW], [EW], [EventConfiguration] [long] + invokevirtual(blockCodeBuilder, TYPE_EVENT_WRITER, EventWriterMethod.BEGIN_EVENT.method()); + // stack: [EW], [integer] + blockCodeBuilder.ifeq(excluded); + // stack: [EW] + // write startTime + blockCodeBuilder.dup(); + // stack: [EW], [EW] + tk = TypeKind.from(argumentTypes[argIndex++]); + blockCodeBuilder.loadInstruction(tk, slotIndex); + // stack: [EW], [EW], [long] + slotIndex += tk.slotSize(); + invokevirtual(blockCodeBuilder, TYPE_EVENT_WRITER, EventWriterMethod.PUT_LONG.method()); + // stack: [EW] + fieldIndex++; + // write duration + blockCodeBuilder.dup(); + // stack: [EW], [EW] + tk = TypeKind.from(argumentTypes[argIndex++]); + blockCodeBuilder.loadInstruction(tk, slotIndex); + // stack: [EW], [EW], [long] + slotIndex += tk.slotSize(); + invokevirtual(blockCodeBuilder, TYPE_EVENT_WRITER, EventWriterMethod.PUT_LONG.method()); + // stack: [EW] + fieldIndex++; + // write eventThread + blockCodeBuilder.dup(); + // stack: [EW], [EW] + invokevirtual(blockCodeBuilder, TYPE_EVENT_WRITER, EventWriterMethod.PUT_EVENT_THREAD.method()); + // stack: [EW] + // write stackTrace + blockCodeBuilder.dup(); + // stack: [EW], [EW] + invokevirtual(blockCodeBuilder, TYPE_EVENT_WRITER, EventWriterMethod.PUT_STACK_TRACE.method()); + // stack: [EW] + // write custom fields + while (fieldIndex < fieldDescs.size()) { + blockCodeBuilder.dup(); + // stack: [EW], [EW] + tk = TypeKind.from(argumentTypes[argIndex++]); + blockCodeBuilder.loadInstruction(tk, slotIndex); + // stack:[EW], [EW], [field] + slotIndex += tk.slotSize(); + FieldDesc field = fieldDescs.get(fieldIndex); + EventWriterMethod eventMethod = EventWriterMethod.lookupMethod(field); + invokevirtual(blockCodeBuilder, TYPE_EVENT_WRITER, eventMethod.method()); + // stack: [EW] + fieldIndex++; + } + // stack: [EW] + // write end event (writer already on stack) + invokevirtual(blockCodeBuilder, TYPE_EVENT_WRITER, EventWriterMethod.END_EVENT.method()); + // stack: [int] + } + + void updateInstanceCommit(BlockCodeBuilder blockCodeBuilder, Label end, Label excluded) { + // if (!isEnable()) { + // return; + // } + blockCodeBuilder.aload(0); + invokevirtual(blockCodeBuilder, getEventClassDesc(), METHOD_IS_ENABLED); + Label l0 = blockCodeBuilder.newLabel(); + blockCodeBuilder.ifne(l0); + blockCodeBuilder.return_(); + blockCodeBuilder.labelBinding(l0); + // long startTime = this.startTime + blockCodeBuilder.aload(0); + getfield(blockCodeBuilder, getEventClassDesc(), FIELD_START_TIME); + blockCodeBuilder.lstore(1); + // if (startTime == 0) { + // startTime = EventWriter.timestamp(); + // } else { + blockCodeBuilder.lload(1); + blockCodeBuilder.lconst_0(); + blockCodeBuilder.lcmp(); + Label durationEvent = blockCodeBuilder.newLabel(); + blockCodeBuilder.ifne(durationEvent); + invokestatic(blockCodeBuilder, TYPE_EVENT_CONFIGURATION, METHOD_TIME_STAMP); + blockCodeBuilder.lstore(1); + Label commit = blockCodeBuilder.newLabel(); + blockCodeBuilder.goto_(commit); + // if (duration == 0) { + // duration = EventWriter.timestamp() - startTime; + // } + // } + blockCodeBuilder.labelBinding(durationEvent); + blockCodeBuilder.aload(0); + getfield(blockCodeBuilder, getEventClassDesc(), FIELD_DURATION); + blockCodeBuilder.lconst_0(); + blockCodeBuilder.lcmp(); + blockCodeBuilder.ifne(commit); + blockCodeBuilder.aload(0); + invokestatic(blockCodeBuilder, TYPE_EVENT_CONFIGURATION, METHOD_TIME_STAMP); + blockCodeBuilder.lload(1); + blockCodeBuilder.lsub(); + putfield(blockCodeBuilder, getEventClassDesc(), FIELD_DURATION); + blockCodeBuilder.labelBinding(commit); + // if (shouldCommit()) { + blockCodeBuilder.aload(0); + invokevirtual(blockCodeBuilder, getEventClassDesc(), METHOD_EVENT_SHOULD_COMMIT); + blockCodeBuilder.ifeq(end); + getEventWriter(blockCodeBuilder); + // stack: [EW] + blockCodeBuilder.dup(); + // stack: [EW] [EW] + getEventConfiguration(blockCodeBuilder); + // stack: [EW] [EW] [EC] + blockCodeBuilder.constantInstruction(Opcode.LDC2_W, eventTypeId); + invokevirtual(blockCodeBuilder, TYPE_EVENT_WRITER, EventWriterMethod.BEGIN_EVENT.method()); + // stack: [EW] [int] + blockCodeBuilder.ifeq(excluded); + // stack: [EW] + int fieldIndex = 0; + blockCodeBuilder.dup(); + // stack: [EW] [EW] + blockCodeBuilder.lload(1); + // stack: [EW] [EW] [long] + invokevirtual(blockCodeBuilder, TYPE_EVENT_WRITER, EventWriterMethod.PUT_LONG.method()); + // stack: [EW] + fieldIndex++; + blockCodeBuilder.dup(); + // stack: [EW] [EW] + blockCodeBuilder.aload(0); + // stack: [EW] [EW] [this] + getfield(blockCodeBuilder, getEventClassDesc(), FIELD_DURATION); + // stack: [EW] [EW] [long] + invokevirtual(blockCodeBuilder, TYPE_EVENT_WRITER, EventWriterMethod.PUT_LONG.method()); + // stack: [EW] + fieldIndex++; + blockCodeBuilder.dup(); + // stack: [EW] [EW] + invokevirtual(blockCodeBuilder, TYPE_EVENT_WRITER, EventWriterMethod.PUT_EVENT_THREAD.method()); + // stack: [EW] + blockCodeBuilder.dup(); + // stack: [EW] [EW] + invokevirtual(blockCodeBuilder, TYPE_EVENT_WRITER, EventWriterMethod.PUT_STACK_TRACE.method()); + // stack: [EW] + while (fieldIndex < fieldDescs.size()) { + FieldDesc field = fieldDescs.get(fieldIndex); + blockCodeBuilder.dup(); + // stack: [EW] [EW] + blockCodeBuilder.aload(0); + // stack: [EW] [EW] [this] + getfield(blockCodeBuilder, getEventClassDesc(), field); + // stack: [EW] [EW] + EventWriterMethod eventMethod = EventWriterMethod.lookupMethod(field); + invokevirtual(blockCodeBuilder, TYPE_EVENT_WRITER, eventMethod.method()); + // stack: [EW] + fieldIndex++; + } + // stack:[EW] + invokevirtual(blockCodeBuilder, TYPE_EVENT_WRITER, EventWriterMethod.END_EVENT.method()); + // stack:[int] + } + + private void updateEnabledMethod(MethodDesc method) { + updateMethod(method, codeBuilder -> { + Label nullLabel = codeBuilder.newLabel(); if (guardEventConfiguration) { - getEventConfiguration(methodVisitor); - methodVisitor.visitJumpInsn(Opcodes.IFNULL, nullLabel); + getEventConfiguration(codeBuilder); + codeBuilder.branchInstruction(Opcode.IFNULL, nullLabel); } - getEventConfiguration(methodVisitor); - invokeVirtual(methodVisitor, TYPE_EVENT_CONFIGURATION, METHOD_IS_ENABLED); - methodVisitor.visitInsn(Opcodes.IRETURN); + getEventConfiguration(codeBuilder); + invokevirtual(codeBuilder, TYPE_EVENT_CONFIGURATION, METHOD_IS_ENABLED); + codeBuilder.ireturn(); if (guardEventConfiguration) { - methodVisitor.visitLabel(nullLabel); - methodVisitor.visitFrame(Opcodes.F_SAME, 0, null, 0, null); - methodVisitor.visitInsn(Opcodes.ICONST_0); - methodVisitor.visitInsn(Opcodes.IRETURN); + codeBuilder.labelBinding(nullLabel); + codeBuilder.iconst_0(); + codeBuilder.ireturn(); } - methodVisitor.visitMaxs(0, 0); - methodVisitor.visitEnd(); }); } - private void updateIfStaticMethodExists(Method method, Consumer code) { + private void updateIfStaticMethodExists(MethodDesc method, Consumer code) { if (hasStaticMethod(method)) { updateMethod(method, code); } } - private boolean hasStaticMethod(Method method) { - for (MethodNode m : classNode.methods) { - if (m.name.equals(method.getName()) && m.desc.equals(method.getDescriptor())) { - return Modifier.isStatic(m.access); + private boolean hasStaticMethod(MethodDesc method) { + for (MethodModel m : classModel.methods()) { + if (m.methodName().equalsString(method.name()) && m.methodTypeSymbol().equals(method.descriptor())) { + return Modifier.isStatic(m.flags().flagsMask()); } } return false; } - private void getEventWriter(MethodVisitor mv) { - mv.visitLdcInsn(EventWriterKey.getKey()); - visitMethod(mv, Opcodes.INVOKESTATIC, TYPE_EVENT_WRITER_FACTORY, METHOD_GET_EVENT_WRITER_KEY); + private void getEventWriter(CodeBuilder codeBuilder) { + codeBuilder.ldc(EventWriterKey.getKey()); + invokestatic(codeBuilder, TYPE_EVENT_WRITER_FACTORY, METHOD_GET_EVENT_WRITER_KEY); } - private void visitMethod(final MethodVisitor mv, final int opcode, final Type type, final Method method) { - mv.visitMethodInsn(opcode, type.getInternalName(), method.getName(), method.getDescriptor(), false); - } - - private static void invokeStatic(MethodVisitor methodVisitor, String className, Method m) { - methodVisitor.visitMethodInsn(Opcodes.INVOKESTATIC, className, m.getName(), m.getDescriptor(), false); - } - - private static void invokeVirtual(MethodVisitor methodVisitor, String className, Method m) { - methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, className, m.getName(), m.getDescriptor(), false); - } - - private void invokeVirtual(MethodVisitor methodVisitor, Type type, Method method) { - methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL, type.getInternalName(), method.getName(), method.getDescriptor(), false); - } - - private void getEventConfiguration(MethodVisitor methodVisitor) { + private void getEventConfiguration(CodeBuilder codeBuilder) { if (untypedEventConfiguration) { - methodVisitor.visitFieldInsn(Opcodes.GETSTATIC, getInternalClassName(), FIELD_EVENT_CONFIGURATION, TYPE_OBJECT_DESCRIPTOR); + codeBuilder.getstatic(getEventClassDesc(), FIELD_EVENT_CONFIGURATION.name(), TYPE_OBJECT); } else { - methodVisitor.visitFieldInsn(Opcodes.GETSTATIC, getInternalClassName(), FIELD_EVENT_CONFIGURATION, TYPE_EVENT_CONFIGURATION_DESCRIPTOR); + codeBuilder.getstatic(getEventClassDesc(), FIELD_EVENT_CONFIGURATION.name(), TYPE_EVENT_CONFIGURATION); } } @@ -754,43 +728,30 @@ private void makeUninstrumented() { updateExistingWithEmptyVoidMethod(METHOD_END); } - private final void updateExistingWithEmptyVoidMethod(Method voidMethod) { - updateMethod(voidMethod, methodVisitor -> { - methodVisitor.visitInsn(Opcodes.RETURN); + private final void updateExistingWithEmptyVoidMethod(MethodDesc voidMethod) { + updateMethod(voidMethod, codeBuilder -> { + codeBuilder.return_(); }); } - private final void updateExistingWithReturnFalse(Method voidMethod) { - updateMethod(voidMethod, methodVisitor -> { - methodVisitor.visitInsn(Opcodes.ICONST_0); - methodVisitor.visitInsn(Opcodes.IRETURN); + private final void updateExistingWithReturnFalse(MethodDesc voidMethod) { + updateMethod(voidMethod, codeBuilder -> { + codeBuilder.iconst_0(); + codeBuilder.ireturn(); }); } - private MethodNode getMethodNode(Method method) { - for (MethodNode m : classNode.methods) { - if (m.name.equals(method.getName()) && m.desc.equals(method.getDescriptor())) { - return m; - } - } - return null; + private Consumer findMethodUpdate(MethodModel mm) { + MethodDesc m = MethodDesc.of(mm.methodName().stringValue(), mm.methodType().stringValue()); + return methodUpdates.get(m); } - private final void updateMethod(Method method, Consumer code) { - MethodNode old = getMethodNode(method); - int index = classNode.methods.indexOf(old); - classNode.methods.remove(old); - MethodVisitor mv = classNode.visitMethod(old.access, old.name, old.desc, null, null); - mv.visitCode(); - code.accept(mv); - mv.visitMaxs(0, 0); - MethodNode newMethod = getMethodNode(method); - classNode.methods.remove(newMethod); - classNode.methods.add(index, newMethod); + private void updateMethod(MethodDesc method, Consumer codeBuilder) { + methodUpdates.put(method, codeBuilder); } - private String getInternalClassName() { - return classNode.name; + private ClassDesc getEventClassDesc() { + return classModel.thisClass().asSymbol(); } public String getEventName() { diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/EventWriterMethod.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/EventWriterMethod.java index 5497aa19455..e1cbbb99d56 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/EventWriterMethod.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/EventWriterMethod.java @@ -25,38 +25,38 @@ package jdk.jfr.internal; -import jdk.internal.org.objectweb.asm.commons.Method; -import jdk.jfr.internal.EventInstrumentation.FieldInfo; -import jdk.jfr.internal.event.EventConfiguration; +import jdk.jfr.internal.util.Bytecode.FieldDesc; +import jdk.jfr.internal.util.Bytecode.MethodDesc; +import jdk.jfr.internal.util.Utils; public enum EventWriterMethod { - BEGIN_EVENT("(" + jdk.internal.org.objectweb.asm.Type.getType(EventConfiguration.class).getDescriptor() + "J)Z", "???", "beginEvent"), - END_EVENT("()Z", "???", "endEvent"), - PUT_BYTE("(B)V", "byte", "putByte"), - PUT_SHORT("(S)V", "short", "putShort"), - PUT_INT("(I)V", "int", "putInt"), - PUT_LONG("(J)V", "long", "putLong"), - PUT_FLOAT("(F)V", "float", "putFloat"), - PUT_DOUBLE("(D)V", "double", "putDouble"), - PUT_CHAR("(C)V", "char", "putChar"), - PUT_BOOLEAN("(Z)V", "boolean", "putBoolean"), - PUT_THREAD("(Ljava/lang/Thread;)V", Type.THREAD.getName(), "putThread"), - PUT_CLASS("(Ljava/lang/Class;)V", Type.CLASS.getName(), "putClass"), - PUT_STRING("(Ljava/lang/String;)V", Type.STRING.getName(), "putString"), - PUT_EVENT_THREAD("()V", Type.THREAD.getName(), "putEventThread"), - PUT_STACK_TRACE("()V", Type.TYPES_PREFIX + "StackTrace", "putStackTrace"); + BEGIN_EVENT("beginEvent", "(Ljdk/jfr/internal/event/EventConfiguration;J)Z", "???"), + END_EVENT("endEvent", "()Z", "???"), + PUT_BYTE("putByte", "(B)V", "B"), + PUT_SHORT("putShort", "(S)V", "S"), + PUT_INT("putInt", "(I)V", "I"), + PUT_LONG("putLong", "(J)V", "J"), + PUT_FLOAT("putFloat", "(F)V", "F"), + PUT_DOUBLE("putDouble", "(D)V", "D"), + PUT_CHAR("putChar", "(C)V", "C"), + PUT_BOOLEAN("putBoolean", "(Z)V", "Z"), + PUT_THREAD("putThread", "(Ljava/lang/Thread;)V", "Ljava/lang/Thread;"), + PUT_CLASS("putClass", "(Ljava/lang/Class;)V", "Ljava/lang/Class;"), + PUT_STRING("putString", "(Ljava/lang/String;)V", "Ljava/lang/String;"), + PUT_EVENT_THREAD("putEventThread", "()V", "???"), + PUT_STACK_TRACE("putStackTrace", "()V", "???"); - final Method asmMethod; - final String typeDescriptor; + final MethodDesc method; + final String fieldType; - EventWriterMethod(String paramSignature, String typeName, String methodName) { - this.typeDescriptor = ASMToolkit.getDescriptor(typeName); - this.asmMethod = new Method(methodName, paramSignature); + EventWriterMethod(String methodName, String paramType, String fieldType) { + this.fieldType = fieldType; + this.method = MethodDesc.of(methodName, paramType); } - public Method asASM() { - return asmMethod; + public MethodDesc method() { + return method; } /** @@ -67,16 +67,16 @@ public Method asASM() { * * @return the method */ - public static EventWriterMethod lookupMethod(FieldInfo field) { + public static EventWriterMethod lookupMethod(FieldDesc field) { // event thread - if (field.name().equals(EventInstrumentation.FIELD_EVENT_THREAD)) { + if (field.name().equals(Utils.FIELD_EVENT_THREAD)) { return EventWriterMethod.PUT_EVENT_THREAD; } for (EventWriterMethod m : EventWriterMethod.values()) { - if (field.descriptor().equals(m.typeDescriptor)) { + if (field.type().descriptorString().equals(m.fieldType)) { return m; } } - throw new Error("Unknown type " + field.descriptor()); + throw new Error("Unknown field type " + field.type()); } } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/JVMUpcalls.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/JVMUpcalls.java index 91f2e3980c2..38ac6a680bf 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/JVMUpcalls.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/JVMUpcalls.java @@ -28,7 +28,7 @@ import jdk.jfr.internal.event.EventConfiguration; import jdk.jfr.internal.instrument.JDKEvents; -import jdk.jfr.internal.util.Utils; +import jdk.jfr.internal.util.Bytecode; /** * All upcalls from the JVM should go through this class. * @@ -75,7 +75,7 @@ static byte[] onRetransform(long traceId, boolean dummy1, boolean dummy2, Class< Logger.log(LogTag.JFR_SYSTEM, LogLevel.INFO, "Adding instrumentation to event class " + clazz.getName() + " using retransform"); EventInstrumentation ei = new EventInstrumentation(clazz.getSuperclass(), oldBytes, traceId, bootClassLoader, false); byte[] bytes = ei.buildInstrumented(); - ASMToolkit.logASM(clazz.getName(), bytes); + Bytecode.log(clazz.getName(), bytes); return bytes; } return JDKEvents.retransformCallback(clazz, oldBytes); @@ -126,7 +126,7 @@ static byte[] bytesForEagerInstrumentation(long traceId, boolean forceInstrument EventWriterKey.ensureEventWriterFactory(); Logger.log(LogTag.JFR_SYSTEM, LogLevel.INFO, "Adding " + (forceInstrumentation ? "forced " : "") + "instrumentation for event type " + eventName + " during initial class load"); byte[] bytes = ei.buildInstrumented(); - ASMToolkit.logASM(ei.getClassName() + "(" + traceId + ")", bytes); + Bytecode.log(ei.getClassName() + "(" + traceId + ")", bytes); return bytes; } catch (Throwable t) { Logger.log(LogTag.JFR_SYSTEM, LogLevel.WARN, "Unexpected error when adding instrumentation for event type " + eventName); diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/TypeLibrary.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/TypeLibrary.java index 42c74ee64c9..d858c56354e 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/TypeLibrary.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/TypeLibrary.java @@ -76,26 +76,26 @@ private TypeLibrary() { private static ValueDescriptor createStartTimeField() { var annos = createStandardAnnotations("Start Time", null); annos.add(new jdk.jfr.AnnotationElement(Timestamp.class, Timestamp.TICKS)); - return PrivateAccess.getInstance().newValueDescriptor(EventInstrumentation.FIELD_START_TIME, Type.LONG, annos, 0, false, - EventInstrumentation.FIELD_START_TIME); + return PrivateAccess.getInstance().newValueDescriptor(Utils.FIELD_START_TIME, Type.LONG, annos, 0, false, + Utils.FIELD_START_TIME); } private static ValueDescriptor createStackTraceField() { var annos = createStandardAnnotations("Stack Trace", "Stack Trace starting from the method the event was committed in"); - return PrivateAccess.getInstance().newValueDescriptor(EventInstrumentation.FIELD_STACK_TRACE, Type.STACK_TRACE, annos, 0, true, - EventInstrumentation.FIELD_STACK_TRACE); + return PrivateAccess.getInstance().newValueDescriptor(Utils.FIELD_STACK_TRACE, Type.STACK_TRACE, annos, 0, true, + Utils.FIELD_STACK_TRACE); } private static ValueDescriptor createThreadField() { var annos = createStandardAnnotations("Event Thread", "Thread in which event was committed in"); - return PrivateAccess.getInstance().newValueDescriptor(EventInstrumentation.FIELD_EVENT_THREAD, Type.THREAD, annos, 0, true, - EventInstrumentation.FIELD_EVENT_THREAD); + return PrivateAccess.getInstance().newValueDescriptor(Utils.FIELD_EVENT_THREAD, Type.THREAD, annos, 0, true, + Utils.FIELD_EVENT_THREAD); } private static ValueDescriptor createDurationField() { var annos = createStandardAnnotations("Duration", null); annos.add(new jdk.jfr.AnnotationElement(Timespan.class, Timespan.TICKS)); - return PrivateAccess.getInstance().newValueDescriptor(EventInstrumentation.FIELD_DURATION, Type.LONG, annos, 0, false, EventInstrumentation.FIELD_DURATION); + return PrivateAccess.getInstance().newValueDescriptor(Utils.FIELD_DURATION, Type.LONG, annos, 0, false, Utils.FIELD_DURATION); } public static synchronized void initialize() { diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/EventParser.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/EventParser.java index c77c30eb622..451dd426368 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/EventParser.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/EventParser.java @@ -25,7 +25,7 @@ package jdk.jfr.internal.consumer; -import static jdk.jfr.internal.EventInstrumentation.FIELD_DURATION; +import static jdk.jfr.internal.util.Utils.FIELD_DURATION; import java.io.IOException; import java.util.List; diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/util/Bytecode.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/util/Bytecode.java new file mode 100644 index 00000000000..76dd8850a29 --- /dev/null +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/util/Bytecode.java @@ -0,0 +1,166 @@ +/* + * 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. + */ +package jdk.jfr.internal.util; + +import jdk.jfr.ValueDescriptor; +import java.lang.constant.ClassDesc; +import java.lang.constant.ConstantDescs; +import java.lang.constant.MethodTypeDesc; +import java.util.Objects; +import jdk.jfr.internal.Logger; +import jdk.jfr.internal.LogLevel; +import jdk.jfr.internal.LogTag; +import jdk.internal.classfile.CodeBuilder; +import jdk.internal.classfile.ClassModel; +import jdk.internal.classfile.Classfile; +import jdk.internal.classfile.components.ClassPrinter; + +/** + * Helper class when working with bytecode. + */ +public final class Bytecode { + + private static final ClassDesc CD_Thread = classDesc(Thread.class); + + public record ClassMethodDesc(ClassDesc type, MethodDesc method) { + public static ClassMethodDesc of(Class clazz, String method, String desrciptor) { + return new ClassMethodDesc(classDesc(clazz), MethodDesc.of(method, desrciptor)); + } + } + + public record FieldDesc(ClassDesc type, String name) { + public static FieldDesc of(ClassDesc type, String name) { + return new FieldDesc(type, name); + } + + public static FieldDesc of(Class type, String name) { + return of(classDesc(type), name); + } + } + + public record MethodDesc(String name, MethodTypeDesc descriptor) { + public static MethodDesc of(String methodName, String descriptor) { + return new MethodDesc(methodName, MethodTypeDesc.ofDescriptor(descriptor)); + } + + public static MethodDesc of(String methodName, Class returnType, Class... parameters) { + ClassDesc[] parameterDesc = new ClassDesc[parameters.length]; + for (int i = 0; i < parameterDesc.length; i++) { + parameterDesc[i] = classDesc(parameters[i]); + } + ClassDesc returnDesc = classDesc(returnType); + MethodTypeDesc mtd = MethodTypeDesc.of(returnDesc, parameterDesc); + return new MethodDesc(methodName, mtd); + } + } + + public static ClassDesc classDesc(ValueDescriptor v) { + String typeName = v.getTypeName(); + return switch (typeName) { + case "boolean" -> ConstantDescs.CD_boolean; + case "byte" -> ConstantDescs.CD_byte; + case "short" -> ConstantDescs.CD_short; + case "char" -> ConstantDescs.CD_char; + case "int" -> ConstantDescs.CD_int; + case "long" -> ConstantDescs.CD_long; + case "double" -> ConstantDescs.CD_double; + case "float" -> ConstantDescs.CD_float; + case "java.lang.String" -> ConstantDescs.CD_String; + case "java.lang.Class" -> ConstantDescs.CD_Class; + case "java.lang.Thread" -> CD_Thread; + default -> throw new InternalError("Unsupported JFR type " + v.getTypeName()); + }; + } + + public static ClassDesc classDesc(Class clazz) { + return ClassDesc.ofDescriptor(clazz.descriptorString()); + } + + public static void getfield(CodeBuilder codeBuilder, ClassDesc owner, FieldDesc field) { + codeBuilder.getfield(owner, field.name(), field.type()); + } + + public static void putfield(CodeBuilder codeBuilder, ClassDesc owner, FieldDesc field) { + codeBuilder.putfield(owner, field.name(), field.type()); + } + + public static void invokestatic(CodeBuilder codeBuilder, ClassDesc owner, MethodDesc method) { + codeBuilder.invokestatic(owner, method.name(), method.descriptor()); + } + + public static void invokespecial(CodeBuilder codeBuilder, ClassDesc owner, MethodDesc method) { + codeBuilder.invokespecial(owner, method.name(), method.descriptor()); + } + + public static void invokevirtual(CodeBuilder codeBuilder, ClassDesc owner, MethodDesc method) { + codeBuilder.invokevirtual(owner, method.name(), method.descriptor()); + } + + public static void invokevirtual(CodeBuilder codeBuilder, ClassMethodDesc cmd) { + invokevirtual(codeBuilder, cmd.type(), cmd.method()); + } + + public static void unbox(CodeBuilder codeBuilder, ClassDesc type) { + if (!type.isPrimitive()) { + codeBuilder.checkcast(type); + return; + } + ClassMethodDesc unboxer = switch (type.descriptorString()) { + case "B" -> ClassMethodDesc.of(Byte.class, "byteValue", "()B"); + case "S" -> ClassMethodDesc.of(Short.class, "shortValue", "()S"); + case "C" -> ClassMethodDesc.of(Character.class, "charValue", "()C"); + case "I" -> ClassMethodDesc.of(Integer.class, "intValue", "()I"); + case "J" -> ClassMethodDesc.of(Long.class, "longValue", "()J"); + case "F" -> ClassMethodDesc.of(Float.class, "floatValue", "()F"); + case "D" -> ClassMethodDesc.of(Double.class, "doubleValue", "()D"); + case "Z" -> ClassMethodDesc.of(Boolean.class, "booleanValue", "()Z"); + default -> throw new InternalError("Unsupported JFR type " + type.descriptorString()); + }; + codeBuilder.checkcast(unboxer.type()); + invokevirtual(codeBuilder, unboxer); + } + + public static void throwException(CodeBuilder cb, ClassDesc type, String message) { + Objects.requireNonNull(message); + cb.new_(type); + cb.dup(); + cb.ldc(message); + MethodDesc md = MethodDesc.of("", void.class, String.class); + invokespecial(cb, type, md); + cb.athrow(); + } + + public static void log(String className, byte[] bytes) { + Logger.log(LogTag.JFR_SYSTEM_BYTECODE, LogLevel.INFO, "Generated bytecode for class " + className); + if (Logger.shouldLog(LogTag.JFR_SYSTEM_BYTECODE, LogLevel.TRACE)) { + StringBuilder out = new StringBuilder(); + out.append("Bytecode:"); + out.append(System.lineSeparator()); + ClassModel classModel = Classfile.of().parse(bytes); + ClassPrinter.toYaml(classModel, ClassPrinter.Verbosity.TRACE_ALL, out::append); + Logger.log(LogTag.JFR_SYSTEM_BYTECODE, LogLevel.TRACE, out.toString()); + } + } +} diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/util/Utils.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/util/Utils.java index 1b739712985..4be05abca08 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/util/Utils.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/util/Utils.java @@ -56,6 +56,11 @@ import jdk.jfr.internal.settings.ThresholdSetting; public final class Utils { + public static final String FIELD_DURATION = "duration"; + public static final String FIELD_STACK_TRACE = "stackTrace"; + public static final String FIELD_START_TIME = "startTime"; + public static final String FIELD_EVENT_THREAD = "eventThread"; + private static final Object flushObject = new Object(); private static final String LEGACY_EVENT_NAME_PREFIX = "com.oracle.jdk."; diff --git a/test/jdk/jdk/jfr/jvm/TestEventWriterLog.java b/test/jdk/jdk/jfr/jvm/TestEventWriterLog.java index a242eede559..9f11ee04863 100644 --- a/test/jdk/jdk/jfr/jvm/TestEventWriterLog.java +++ b/test/jdk/jdk/jfr/jvm/TestEventWriterLog.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 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 @@ -37,6 +37,6 @@ public class TestEventWriterLog { public static void main(String[] args) throws Exception { ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-Xlog:jfr+system+bytecode=trace", "-XX:StartFlightRecording", "-version"); OutputAnalyzer output = new OutputAnalyzer(pb.start()); - output.shouldContain("extends jdk/jfr/events/AbstractJDKEvent"); + output.shouldContain("superclass: jdk/jfr/events/AbstractJDKEvent"); } } From 8d9a4b43f4fff30fd217dab2c224e641cb913c18 Mon Sep 17 00:00:00 2001 From: Sean Coffey Date: Mon, 23 Oct 2023 17:12:41 +0000 Subject: [PATCH 073/124] 8317678: Fix up hashCode() for ZipFile.Source.Key Reviewed-by: lancea, alanb, jpai --- .../share/classes/java/util/zip/ZipFile.java | 11 +- .../java/util/zip/ZipFile/ZipSourceCache.java | 162 ++++++++++++++++++ .../bench/java/util/zip/ZipFileOpen.java | 17 ++ 3 files changed, 189 insertions(+), 1 deletion(-) create mode 100644 test/jdk/java/util/zip/ZipFile/ZipSourceCache.java diff --git a/src/java.base/share/classes/java/util/zip/ZipFile.java b/src/java.base/share/classes/java/util/zip/ZipFile.java index cb9070fc885..bbcd3cdd712 100644 --- a/src/java.base/share/classes/java/util/zip/ZipFile.java +++ b/src/java.base/share/classes/java/util/zip/ZipFile.java @@ -1395,6 +1395,13 @@ private static boolean isZip64ExtBlockSizeValid(int blockSize) { private int[] table; // Hash chain heads: indexes into entries private int tablelen; // number of hash heads + /** + * A class representing a key to a zip file. A key is based + * on the file key if available, or the path value if the + * file key is not available. The key is also based on the + * file's last modified time to allow for cases where a zip + * file is re-opened after it has been modified. + */ private static class Key { final BasicFileAttributes attrs; File file; @@ -1409,7 +1416,9 @@ public Key(File file, BasicFileAttributes attrs, ZipCoder zc) { public int hashCode() { long t = utf8 ? 0 : Long.MAX_VALUE; t += attrs.lastModifiedTime().toMillis(); - return ((int)(t ^ (t >>> 32))) + file.hashCode(); + Object fk = attrs.fileKey(); + return Long.hashCode(t) + + (fk != null ? fk.hashCode() : file.hashCode()); } public boolean equals(Object obj) { diff --git a/test/jdk/java/util/zip/ZipFile/ZipSourceCache.java b/test/jdk/java/util/zip/ZipFile/ZipSourceCache.java new file mode 100644 index 00000000000..8cb1051a87c --- /dev/null +++ b/test/jdk/java/util/zip/ZipFile/ZipSourceCache.java @@ -0,0 +1,162 @@ +/* + * 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 8317678 + * @modules java.base/java.util.zip:open + * @summary Fix up hashCode() for ZipFile.Source.Key + * @run junit/othervm ZipSourceCache + */ + +import java.io.*; +import java.lang.reflect.*; +import java.nio.file.*; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.*; +import java.util.zip.*; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.AfterAll; +import static org.junit.jupiter.api.Assertions.*; + +public class ZipSourceCache { + + private static final String ZIPFILE_NAME = + System.currentTimeMillis() + "-bug8317678.zip"; + private static final String ZIPENTRY_NAME = "random.txt"; + private static final String INVALID_LOC_EXCEPTION = + "ZipFile invalid LOC header (bad signature)"; + private static final boolean DEBUG = false; + + private static File relativeFile = new File(ZIPFILE_NAME); + private static File absoluteFile = new File(ZIPFILE_NAME).getAbsoluteFile(); + private static boolean hasfileKeySupport; + + @BeforeAll + public static void setup() throws Exception { + createZipFile("test1"); + var attrs = Files.readAttributes(relativeFile.toPath(), BasicFileAttributes.class); + hasfileKeySupport = (attrs.fileKey() != null); + } + + @AfterAll + public static void cleanup() throws IOException { + Files.deleteIfExists(Path.of(ZIPFILE_NAME)); + } + + /* + * Monitor the internal "files" HashMap to ensure that we only + * create one mapping per unique zip file. + * + * This test also ensures that a new mapping is created + * if an update to an existing zip file is detected. + */ + @Test + public void testKeySourceMapping() throws Exception { + ZipFile absoluteZipFile; + HashMap internalMap; + int numSources; + try (ZipFile zipFile = new ZipFile(relativeFile)) { + Class source = Class.forName("java.util.zip.ZipFile$Source"); + Field filesMap = source.getDeclaredField("files"); + filesMap.setAccessible(true); + internalMap = (HashMap) filesMap.get(zipFile); + numSources = internalMap.size(); + // opening of same zip file shouldn't cause new Source + // to be constructed on filesystems which support fileKey() + absoluteZipFile = new ZipFile(absoluteFile); + if (hasfileKeySupport) { + assertEquals(numSources, internalMap.size()); + } else { + assertEquals(++numSources, internalMap.size()); + } + + // update the zip file, should expect a new Source Object + // ignore this part of test if file can't be updated (can't overwrite) + if (createZipFile("differentContent")) { + ZipFile z = new ZipFile(relativeFile); + // update of file should trigger new mapping + assertEquals(++numSources, internalMap.size()); + // new Source created, CEN structure should map fine + readZipFileContents(z); + // the old Source in use for old file, should no longer map correctly + IOException ioe = assertThrows(IOException.class, () -> readZipFileContents(absoluteZipFile)); + assertEquals(INVALID_LOC_EXCEPTION, ioe.getMessage()); + z.close(); + assertEquals(--numSources, internalMap.size()); + } + } + // with fileKey() support, the close() call shouldn't remove the + // Source entry just yet since we still have one reference to the file + if (hasfileKeySupport) { + assertEquals(numSources, internalMap.size()); + } else { + assertEquals(--numSources, internalMap.size()); + } + if (absoluteZipFile != null) { + absoluteZipFile.close(); + } + // now, the Source entry key should be removed + assertEquals(--numSources, internalMap.size()); + } + + private static void readZipFileContents(ZipFile zf) throws IOException { + var e = zf.entries(); + while (e.hasMoreElements()) { + InputStream is = zf.getInputStream(e.nextElement()); + String s = new String(is.readAllBytes()); + if (DEBUG) System.err.println(s); + } + } + + private static boolean createZipFile(String content) { + CRC32 crc32 = new CRC32(); + long t = System.currentTimeMillis(); + // let's have at least 2 entries created to ensure + // that a bad zip structure is detected if file is updated + int numEntries = new Random().nextInt(10) + 2; + File zipFile = new File(ZIPFILE_NAME); + try (FileOutputStream fos = new FileOutputStream(zipFile); + BufferedOutputStream bos = new BufferedOutputStream(fos); + ZipOutputStream zos = new ZipOutputStream(bos)) { + for (int i = 0; i < numEntries; i++) { + ZipEntry e = new ZipEntry(ZIPENTRY_NAME + i); + e.setMethod(ZipEntry.STORED); + byte[] toWrite = content.repeat(i+1).getBytes(); + e.setTime(t); + e.setSize(toWrite.length); + crc32.reset(); + crc32.update(toWrite); + e.setCrc(crc32.getValue()); + zos.putNextEntry(e); + zos.write(toWrite); + } + } catch (IOException e) { + // some systems mightn't allow file to be updated while open + System.err.println("error updating file. " + e); + return false; + } + return true; + } +} diff --git a/test/micro/org/openjdk/bench/java/util/zip/ZipFileOpen.java b/test/micro/org/openjdk/bench/java/util/zip/ZipFileOpen.java index ffbbc3d245f..e450fcfe9a0 100644 --- a/test/micro/org/openjdk/bench/java/util/zip/ZipFileOpen.java +++ b/test/micro/org/openjdk/bench/java/util/zip/ZipFileOpen.java @@ -29,6 +29,7 @@ import java.io.FileOutputStream; import java.io.IOException; import java.nio.file.Files; +import java.nio.file.Path; import java.util.concurrent.TimeUnit; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; @@ -50,6 +51,7 @@ public class ZipFileOpen { private int size; public File zipFile; + public File relativePathFile; @Setup(Level.Trial) public void beforeRun() throws IOException { @@ -74,6 +76,8 @@ public void beforeRun() throws IOException { } } zipFile = tempFile; + relativePathFile = Path.of(System.getProperty("user.dir")) + .relativize(zipFile.toPath()).toFile(); } @Benchmark @@ -90,4 +94,17 @@ public ZipFile openCloseZipFile() throws Exception { zf.close(); return zf; } + + @Benchmark + public void openCloseZipFilex2() throws Exception { + // A follow on from the openCloseZipFile benchmark. + // The initCEN logic should be called once per file, if + // opened multiple times and not closed, for the ZipFile + // under test if that file is identified by a unique value + // returned via attrs.fileKey() + ZipFile zf = new ZipFile(zipFile); + ZipFile zf2 = new ZipFile(relativePathFile); + zf.close(); + zf2.close(); + } } From 5ba9705d60fb3e3bab832aadd989b738471fcaf5 Mon Sep 17 00:00:00 2001 From: Thomas Stuefe Date: Mon, 23 Oct 2023 21:10:52 +0000 Subject: [PATCH 074/124] 8318485: Narrow klass shift should be zero if encoding range extends to 0x1_0000_0000 Reviewed-by: ccheung, iklam --- src/hotspot/os/linux/os_linux.cpp | 1 - src/hotspot/share/memory/metaspace.cpp | 5 ++ src/hotspot/share/oops/compressedKlass.cpp | 2 +- test/hotspot/gtest/runtime/test_os.cpp | 2 +- ...CompressedClassPointersEncodingScheme.java | 81 +++++++++++++++++++ .../jdk/test/lib/process/OutputAnalyzer.java | 21 +++++ 6 files changed, 109 insertions(+), 3 deletions(-) create mode 100644 test/hotspot/jtreg/runtime/CompressedOops/CompressedClassPointersEncodingScheme.java diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp index 685fa174ac9..db942feabcf 100644 --- a/src/hotspot/os/linux/os_linux.cpp +++ b/src/hotspot/os/linux/os_linux.cpp @@ -5300,7 +5300,6 @@ void os::print_memory_mappings(char* addr, size_t bytes, outputStream* st) { if (num_found == 0) { st->print_cr("nothing."); } - st->cr(); } } diff --git a/src/hotspot/share/memory/metaspace.cpp b/src/hotspot/share/memory/metaspace.cpp index 2145bb68b33..b0d47dcce0d 100644 --- a/src/hotspot/share/memory/metaspace.cpp +++ b/src/hotspot/share/memory/metaspace.cpp @@ -778,6 +778,11 @@ void Metaspace::global_initialize() { if (rs.is_reserved()) { log_info(metaspace)("Successfully forced class space address to " PTR_FORMAT, p2i(base)); } else { + LogTarget(Debug, metaspace) lt; + if (lt.is_enabled()) { + LogStream ls(lt); + os::print_memory_mappings((char*)base, size, &ls); + } vm_exit_during_initialization( err_msg("CompressedClassSpaceBaseAddress=" PTR_FORMAT " given, but reserving class space failed.", CompressedClassSpaceBaseAddress)); diff --git a/src/hotspot/share/oops/compressedKlass.cpp b/src/hotspot/share/oops/compressedKlass.cpp index f9750c1b7c0..947085b02e3 100644 --- a/src/hotspot/share/oops/compressedKlass.cpp +++ b/src/hotspot/share/oops/compressedKlass.cpp @@ -80,7 +80,7 @@ void CompressedKlassPointers::initialize(address addr, size_t len) { // We may not even need a shift if the range fits into 32bit: const uint64_t UnscaledClassSpaceMax = (uint64_t(max_juint) + 1); - if (range < UnscaledClassSpaceMax) { + if (range <= UnscaledClassSpaceMax) { shift = 0; } else { shift = LogKlassAlignmentInBytes; diff --git a/test/hotspot/gtest/runtime/test_os.cpp b/test/hotspot/gtest/runtime/test_os.cpp index be6e22f5f4e..035210218c4 100644 --- a/test/hotspot/gtest/runtime/test_os.cpp +++ b/test/hotspot/gtest/runtime/test_os.cpp @@ -377,7 +377,7 @@ static inline bool can_reserve_executable_memory(void) { #endif // Test that os::release_memory() can deal with areas containing multiple mappings. -#define PRINT_MAPPINGS(s) { tty->print_cr("%s", s); os::print_memory_mappings((char*)p, total_range_len, tty); } +#define PRINT_MAPPINGS(s) { tty->print_cr("%s", s); os::print_memory_mappings((char*)p, total_range_len, tty); tty->cr(); } //#define PRINT_MAPPINGS // Release a range allocated with reserve_multiple carefully, to not trip mapping diff --git a/test/hotspot/jtreg/runtime/CompressedOops/CompressedClassPointersEncodingScheme.java b/test/hotspot/jtreg/runtime/CompressedOops/CompressedClassPointersEncodingScheme.java new file mode 100644 index 00000000000..d67b6534049 --- /dev/null +++ b/test/hotspot/jtreg/runtime/CompressedOops/CompressedClassPointersEncodingScheme.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2013, 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 + * @summary Testing that, faced with a given (possibly odd) mapping address of class space, the encoding + * scheme fits the address + * @requires vm.bits == 64 & !vm.graal.enabled + * @requires vm.flagless + * @library /test/lib + * @modules java.base/jdk.internal.misc + * java.management + * @run driver CompressedClassPointersEncodingScheme + */ + +import jdk.test.lib.Platform; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; +import jtreg.SkippedException; + +import java.io.IOException; + +public class CompressedClassPointersEncodingScheme { + + private static void test(long forceAddress, long classSpaceSize, long expectedEncodingBase, int expectedEncodingShift) throws IOException { + String forceAddressString = String.format("0x%016X", forceAddress).toLowerCase(); + String expectedEncodingBaseString = String.format("0x%016X", expectedEncodingBase).toLowerCase(); + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-Xshare:off", // to make CompressedClassSpaceBaseAddress work + "-XX:+UnlockDiagnosticVMOptions", + "-XX:-UseCompressedOops", // keep VM from optimizing heap location + "-XX:CompressedClassSpaceBaseAddress=" + forceAddress, + "-XX:CompressedClassSpaceSize=" + classSpaceSize, + "-Xmx128m", + "-Xlog:metaspace*", + "-version"); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + + output.reportDiagnosticSummary(); + + // We ignore cases where we were not able to map at the force address + if (output.contains("reserving class space failed")) { + throw new SkippedException("Skipping because we cannot force ccs to " + forceAddressString); + } + + output.shouldHaveExitValue(0); + output.shouldContain("Narrow klass base: " + expectedEncodingBaseString + ", Narrow klass shift: " + expectedEncodingShift); + } + + final static long K = 1024; + final static long M = K * 1024; + final static long G = M * 1024; + public static void main(String[] args) throws Exception { + // Test ccs nestling right at the end of the 4G range + // Expecting base=0, shift=0 + test(4 * G - 128 * M, 128 * M, 0, 0); + + // add more... + + } +} diff --git a/test/lib/jdk/test/lib/process/OutputAnalyzer.java b/test/lib/jdk/test/lib/process/OutputAnalyzer.java index 41b240b9e48..fab7b99196d 100644 --- a/test/lib/jdk/test/lib/process/OutputAnalyzer.java +++ b/test/lib/jdk/test/lib/process/OutputAnalyzer.java @@ -207,6 +207,27 @@ public OutputAnalyzer stderrShouldNotBeEmpty() { return this; } + /** + * Returns true if stdout contains the given string + */ + public boolean stdoutContains(String expectedString) { + return getStdout().contains(expectedString); + } + + /** + * Returns true if stderr contains the given string + */ + public boolean stderrContains(String expectedString) { + return getStderr().contains(expectedString); + } + + /** + * Returns true if either stdout or stderr contains the given string + */ + public boolean contains(String expectedString) { + return stdoutContains(expectedString) || stderrContains(expectedString); + } + /** * Verify that the stdout and stderr contents of output buffer contains the string * From 1b150117fd9ccb7ff8adc012b74d7d95e5219b94 Mon Sep 17 00:00:00 2001 From: Joe Darcy Date: Mon, 23 Oct 2023 22:08:12 +0000 Subject: [PATCH 075/124] 8318476: Add resource consumption note to BigInteger and BigDecimal Reviewed-by: alanb, bpb --- .../share/classes/java/math/BigDecimal.java | 23 ++++++++++- .../share/classes/java/math/BigInteger.java | 38 ++++++++++++++++++- 2 files changed, 59 insertions(+), 2 deletions(-) diff --git a/src/java.base/share/classes/java/math/BigDecimal.java b/src/java.base/share/classes/java/math/BigDecimal.java index 094c48bc02f..dd34ad24571 100644 --- a/src/java.base/share/classes/java/math/BigDecimal.java +++ b/src/java.base/share/classes/java/math/BigDecimal.java @@ -279,7 +279,7 @@ * operations indicated by {@linkplain RoundingMode rounding modes} * are a proper superset of the IEEE 754 rounding-direction * attributes. - + * *

{@code BigDecimal} arithmetic will most resemble IEEE 754 * decimal arithmetic if a {@code MathContext} corresponding to an * IEEE 754 decimal format, such as {@linkplain MathContext#DECIMAL64 @@ -292,6 +292,27 @@ * such as dividing by zero, throw an {@code ArithmeticException} in * {@code BigDecimal} arithmetic. * + *

Algorithmic Complexity

+ * + * Operations on {@code BigDecimal} values have a range of algorithmic + * complexities; in general, those complexities are a function of both + * the size of the unscaled value as well as the size of the + * scale. For example, an {@linkplain BigDecimal#multiply(BigDecimal) + * exact multiply} of two {@code BigDecimal} values is subject to the + * same {@linkplain BigInteger##algorithmicComplexity complexity + * constraints} as {@code BigInteger} multiply of the unscaled + * values. In contrast, a {@code BigDecimal} value with a compact + * representation like {@code new BigDecimal(1E-1000000000)} has a + * {@link toPlainString} result with over one billion characters. + * + *

Operations may also allocate and compute on intermediate + * results, potentially those allocations may be as large as in + * proportion to the running time of the algorithm. + * + *

Users of {@code BigDecimal} concerned with bounding the running + * time or space of operations can screen out {@code BigDecimal} + * values with unscaled values or scales above a chosen magnitude. + * * @see BigInteger * @see MathContext * @see RoundingMode diff --git a/src/java.base/share/classes/java/math/BigInteger.java b/src/java.base/share/classes/java/math/BigInteger.java index d678a0f76a6..3b751c85c55 100644 --- a/src/java.base/share/classes/java/math/BigInteger.java +++ b/src/java.base/share/classes/java/math/BigInteger.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 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 @@ -118,6 +118,42 @@ * the full supported positive range of {@code BigInteger}. * The range must be at least 1 to 2500000000. * + * @apiNote + * As {@code BigInteger} values are + * arbitrary precision integers, the algorithmic complexity of the + * methods of this class varies and may be superlinear in the size of + * the input. For example, a method like {@link intValue()} would be + * expected to run in O(1), that is constant time, since with + * the current internal representation only a fixed-size component of + * the {@code BigInteger} needs to be accessed to perform the + * conversion to {@code int}. In contrast, a method like {@link not()} + * would be expected to run in O(n) time where n + * is the size of the {@code BigInteger} in bits, that is, to run in + * time proportional to the size of the input. For multiplying two + * {@code BigInteger} values of size n, a naive multiplication + * algorithm would run in time O(n2) and + * theoretical results indicate a multiplication algorithm for numbers + * using this category of representation must run in at least + * O(n log n). Common multiplication + * algorithms between the bounds of the naive and theoretical cases + * include the Karatsuba multiplication + * (O(n1.585)) and 3-way Toom-Cook + * multiplication (O(n1.465)). + * + *

A particular implementation of {@link multiply(BigInteger) + * multiply} is free to switch between different algorithms for + * different inputs, such as to improve actual running time to produce + * the product by using simpler algorithms for smaller inputs even if + * the simpler algorithm has a larger asymptotic complexity. + * + *

Operations may also allocate and compute on intermediate + * results, potentially those allocations may be as large as in + * proportion to the running time of the algorithm. + * + *

Users of {@code BigInteger} concerned with bounding the running + * time or space of operations can screen out {@code BigInteger} + * values above a chosen magnitude. + * * @implNote * In the reference implementation, BigInteger constructors and * operations throw {@code ArithmeticException} when the result is out From eb5916729defd37002f4096d4910849938e0fe3b Mon Sep 17 00:00:00 2001 From: Jie Fu Date: Tue, 24 Oct 2023 02:57:47 +0000 Subject: [PATCH 076/124] 8318691: runtime/CompressedOops/CompressedClassPointersEncodingScheme.java fails with release VMs Reviewed-by: ccheung --- .../CompressedOops/CompressedClassPointersEncodingScheme.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/hotspot/jtreg/runtime/CompressedOops/CompressedClassPointersEncodingScheme.java b/test/hotspot/jtreg/runtime/CompressedOops/CompressedClassPointersEncodingScheme.java index d67b6534049..c1ef73d836c 100644 --- a/test/hotspot/jtreg/runtime/CompressedOops/CompressedClassPointersEncodingScheme.java +++ b/test/hotspot/jtreg/runtime/CompressedOops/CompressedClassPointersEncodingScheme.java @@ -25,7 +25,7 @@ * @test * @summary Testing that, faced with a given (possibly odd) mapping address of class space, the encoding * scheme fits the address - * @requires vm.bits == 64 & !vm.graal.enabled + * @requires vm.bits == 64 & !vm.graal.enabled & vm.debug == true * @requires vm.flagless * @library /test/lib * @modules java.base/jdk.internal.misc From 728b858c787567fa4eed6dd44730dfdb8b30be0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Jeli=C5=84ski?= Date: Tue, 24 Oct 2023 05:36:43 +0000 Subject: [PATCH 077/124] 8318130: SocksSocketImpl needlessly encodes hostname for IPv6 addresses Reviewed-by: dfuchs, jpai, aefimov, michaelm --- .../classes/java/net/SocksSocketImpl.java | 16 +- .../Socks/SocksSocketProxySelectorTest.java | 195 ++++++++++++++++++ 2 files changed, 203 insertions(+), 8 deletions(-) create mode 100644 test/jdk/java/net/Socks/SocksSocketProxySelectorTest.java diff --git a/src/java.base/share/classes/java/net/SocksSocketImpl.java b/src/java.base/share/classes/java/net/SocksSocketImpl.java index 9353452efeb..e6efddae65c 100644 --- a/src/java.base/share/classes/java/net/SocksSocketImpl.java +++ b/src/java.base/share/classes/java/net/SocksSocketImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -37,6 +37,8 @@ import sun.net.spi.DefaultProxySelector; import sun.net.www.ParseUtil; +import static sun.net.util.IPAddressUtil.isIPv6LiteralAddress; + /** * SOCKS (V4 & V5) TCP socket implementation (RFC 1928). */ @@ -297,17 +299,15 @@ public ProxySelector run() { URI uri; // Use getHostString() to avoid reverse lookups String host = epoint.getHostString(); - // IPv6 literal? - if (epoint.getAddress() instanceof Inet6Address && - (!host.startsWith("[")) && (host.indexOf(':') >= 0)) { + if (isIPv6LiteralAddress(host)) { host = "[" + host + "]"; + } else { + host = ParseUtil.encodePath(host); } try { - uri = new URI("socket://" + ParseUtil.encodePath(host) + ":"+ epoint.getPort()); + uri = new URI("socket://" + host + ":"+ epoint.getPort()); } catch (URISyntaxException e) { - // This shouldn't happen - assert false : e; - uri = null; + throw new IOException("Failed to select a proxy", e); } Proxy p = null; IOException savedExc = null; diff --git a/test/jdk/java/net/Socks/SocksSocketProxySelectorTest.java b/test/jdk/java/net/Socks/SocksSocketProxySelectorTest.java new file mode 100644 index 00000000000..e43edb4f6f7 --- /dev/null +++ b/test/jdk/java/net/Socks/SocksSocketProxySelectorTest.java @@ -0,0 +1,195 @@ +/* + * 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. + */ + +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.net.Proxy; +import java.net.ProxySelector; +import java.net.Socket; +import java.net.SocketAddress; +import java.net.SocketException; +import java.net.URI; +import java.net.UnknownHostException; +import java.util.List; +import java.util.stream.Stream; + +import static org.junit.jupiter.api.Assertions.*; + +/** + * @test + * @bug 8318130 + * @summary Tests that java.net.SocksSocketImpl produces correct arguments + * for proxy selector + * @run junit/othervm SocksSocketProxySelectorTest + */ +public class SocksSocketProxySelectorTest { + + public static final String SHORTEN_IPV6 = "((?<=\\[)0)?:(0:)+"; + + @BeforeAll + public static void beforeTest() { + ProxySelector.setDefault(new LoggingProxySelector()); + } + + // should match the host name + public static Stream ipLiterals() { + return Stream.of("127.0.0.1", + "[::1]", + "[fe80::1%1234567890]"); + } + + // should be wrapped in [ ] + public static Stream shortIpv6Literals() { + return Stream.of("::1", + "fe80::1%1234567890"); + } + + // with real interface names in scope + // should be wrapped in [ ], repeated 0's not trimmed + public static Stream linkLocalIpv6Literals() throws SocketException { + return NetworkInterface.networkInterfaces() + .flatMap(NetworkInterface::inetAddresses) + .filter(InetAddress::isLinkLocalAddress) + .map(InetAddress::getHostAddress); + } + + public static Stream hostNames() throws UnknownHostException { + return Stream.of( + InetAddress.getByAddress("localhost", new byte[] {127,0,0,1}), + InetAddress.getByAddress("bugs.openjdk.org", new byte[] {127,0,0,1}), + InetAddress.getByAddress("xn--kda4b0koi.com", new byte[] {127,0,0,1}) + ); + } + + /** + * Creates a socket connection, which internally triggers proxy selection for the target + * address. The test has been configured to use a {@link LoggingProxySelector ProxySelector} + * which throws an {@link IllegalArgumentException} with hostname in exception message. + * The test then verifies that the hostname matches the expected one. + * + * @throws Exception + */ + @ParameterizedTest + @MethodSource("ipLiterals") + public void testIpLiterals(String host) throws Exception { + try (Socket s1 = new Socket(host, 80)) { + fail("IOException was expected to be thrown, but wasn't"); + } catch (IOException ioe) { + // expected + // now verify the IOE was thrown for the correct expected reason + if (!(ioe.getCause() instanceof IllegalArgumentException iae)) { + // rethrow this so that the test output failure will capture the entire/real + // cause in its stacktrace + throw ioe; + } + assertNotNull(iae.getMessage(), "Host not found"); + assertEquals(host, + iae.getMessage().replaceFirst(SHORTEN_IPV6, "::"), + "Found unexpected host"); + } + } + + @ParameterizedTest + @MethodSource("shortIpv6Literals") + public void testShortIpv6Literals(String host) throws Exception { + try (Socket s1 = new Socket(host, 80)) { + fail("IOException was expected to be thrown, but wasn't"); + } catch (IOException ioe) { + // expected + // now verify the IOE was thrown for the correct expected reason + if (!(ioe.getCause() instanceof IllegalArgumentException iae)) { + // rethrow this so that the test output failure will capture the entire/real + // cause in its stacktrace + throw ioe; + } + assertNotNull(iae.getMessage(), "Host not found"); + assertEquals('[' + host + ']', + iae.getMessage().replaceFirst(SHORTEN_IPV6, "::"), + "Found unexpected host"); + } + } + + @ParameterizedTest + @MethodSource("linkLocalIpv6Literals") + public void testLinkLocalIpv6Literals(String host) throws Exception { + try (Socket s1 = new Socket(host, 80)) { + fail("IOException was expected to be thrown, but wasn't"); + } catch (IOException ioe) { + // expected + // now verify the IOE was thrown for the correct expected reason + if (!(ioe.getCause() instanceof IllegalArgumentException iae)) { + // rethrow this so that the test output failure will capture the entire/real + // cause in its stacktrace + throw ioe; + } + assertNotNull(iae.getMessage(), "Host not found"); + assertEquals('[' + host + ']', + iae.getMessage(), + "Found unexpected host"); + } + } + + @ParameterizedTest + @MethodSource("hostNames") + public void testHostNames(InetAddress host) throws Exception { + try (Socket s1 = new Socket(host, 80)) { + fail("IOException was expected to be thrown, but wasn't"); + } catch (IOException ioe) { + // expected + // now verify the IOE was thrown for the correct expected reason + if (!(ioe.getCause() instanceof IllegalArgumentException iae)) { + // rethrow this so that the test output failure will capture the entire/real + // cause in its stacktrace + throw ioe; + } + assertNotNull(iae.getMessage(), "Host not found"); + assertEquals(host.getHostName(), + iae.getMessage(), + "Found unexpected host"); + } + } + + /** + * A {@link ProxySelector} which throws an IllegalArgumentException + * with the given hostname in exception message + */ + private static final class LoggingProxySelector extends + ProxySelector { + + @Override + public List select(final URI uri) { + throw new IllegalArgumentException(uri.getHost()); + } + + @Override + public void connectFailed(URI uri, SocketAddress sa, IOException ioe) { + + } + } +} From 08f79148c6607bf2fce3710f112313e29c05ea90 Mon Sep 17 00:00:00 2001 From: Ioi Lam Date: Tue, 24 Oct 2023 06:34:50 +0000 Subject: [PATCH 078/124] 8305753: Allow JIT compilation for -Xshare:dump Reviewed-by: dholmes, matsaave, ccheung --- src/hotspot/share/runtime/arguments.cpp | 26 +++++++++++++------ src/java.base/share/man/java.1 | 12 +++++++++ .../jtreg/runtime/cds/DeterministicDump.java | 1 + .../cds/appcds/CommandLineFlagCombo.java | 7 +++-- 4 files changed, 36 insertions(+), 10 deletions(-) diff --git a/src/hotspot/share/runtime/arguments.cpp b/src/hotspot/share/runtime/arguments.cpp index df55639d814..33686a3b6e9 100644 --- a/src/hotspot/share/runtime/arguments.cpp +++ b/src/hotspot/share/runtime/arguments.cpp @@ -131,6 +131,9 @@ char* Arguments::_ext_dirs = nullptr; // True if -Xshare:auto option was specified. static bool xshare_auto_cmd_line = false; +// True if -Xint/-Xmixed/-Xcomp were specified +static bool mode_flag_cmd_line = false; + bool PathString::set_value(const char *value, AllocFailType alloc_failmode) { char* new_value = AllocateHeap(strlen(value)+1, mtArguments, alloc_failmode); if (new_value == nullptr) { @@ -2600,13 +2603,16 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, bool* patch_m // -Xint } else if (match_option(option, "-Xint")) { set_mode_flags(_int); + mode_flag_cmd_line = true; // -Xmixed } else if (match_option(option, "-Xmixed")) { set_mode_flags(_mixed); + mode_flag_cmd_line = true; // -Xcomp } else if (match_option(option, "-Xcomp")) { // for testing the compiler; turn off all flags that inhibit compilation set_mode_flags(_comp); + mode_flag_cmd_line = true; // -Xshare:dump } else if (match_option(option, "-Xshare:dump")) { DumpSharedSpaces = true; @@ -3031,14 +3037,18 @@ jint Arguments::finalize_vm_init_args(bool patch_mod_javabase) { #if INCLUDE_CDS if (DumpSharedSpaces) { - // Compiler threads may concurrently update the class metadata (such as method entries), so it's - // unsafe with -Xshare:dump (which modifies the class metadata in place). Let's disable - // compiler just to be safe. - // - // Note: this is not a concern for dynamically dumping shared spaces, which makes a copy of the - // class metadata instead of modifying them in place. The copy is inaccessible to the compiler. - // TODO: revisit the following for the static archive case. - set_mode_flags(_int); + if (!mode_flag_cmd_line) { + // By default, -Xshare:dump runs in interpreter-only mode, which is required for deterministic archive. + // + // If your classlist is large and you don't care about deterministic dumping, you can use + // -Xshare:dump -Xmixed to improve dumping speed. + set_mode_flags(_int); + } else if (_mode == _comp) { + // -Xcomp may use excessive CPU for the test tiers. Also, -Xshare:dump runs a small and fixed set of + // Java code, so there's not much benefit in running -Xcomp. + log_info(cds)("reduced -Xcomp to -Xmixed for static dumping"); + set_mode_flags(_mixed); + } // String deduplication may cause CDS to iterate the strings in different order from one // run to another which resulting in non-determinstic CDS archives. diff --git a/src/java.base/share/man/java.1 b/src/java.base/share/man/java.1 index a72da6d7c11..ece26077424 100644 --- a/src/java.base/share/man/java.1 +++ b/src/java.base/share/man/java.1 @@ -5069,6 +5069,18 @@ The output of this command should contain the following text: \f[V][info][class,load] test.Hello source: shared objects file\f[R] .RE .RE +.PP +By default, when the \f[V]-Xshare:dump\f[R] option is used, the JVM runs +in interpreter-only mode (as if the \f[V]-Xint\f[R] option were +specified). +This is required for generating deterministic output in the shared +archive file. +I.e., the exact same archive will be generated, bit-for-bit, every time +you dump it. +However, if deterministic output is not needed, and you have a large +classlist, you can explicitly add \f[V]-Xmixed\f[R] to the command-line +to enable the JIT compiler. +This will speed up the archive creation. .SS Creating a Dynamic CDS Archive File with -XX:ArchiveClassesAtExit .PP Advantages of dynamic CDS archives are: diff --git a/test/hotspot/jtreg/runtime/cds/DeterministicDump.java b/test/hotspot/jtreg/runtime/cds/DeterministicDump.java index 57e4000fe7a..8f9bb4a5829 100644 --- a/test/hotspot/jtreg/runtime/cds/DeterministicDump.java +++ b/test/hotspot/jtreg/runtime/cds/DeterministicDump.java @@ -79,6 +79,7 @@ static String dump(ArrayList args, String... more) throws Exception { String archiveName = logName + ".jsa"; String mapName = logName + ".map"; CDSOptions opts = (new CDSOptions()) + .addPrefix("-Xint") // Override any -Xmixed/-Xcomp flags from jtreg -vmoptions .addPrefix("-Xlog:cds=debug") .addPrefix("-Xlog:cds+map*=trace:file=" + mapName + ":none:filesize=0") .setArchiveName(archiveName) diff --git a/test/hotspot/jtreg/runtime/cds/appcds/CommandLineFlagCombo.java b/test/hotspot/jtreg/runtime/cds/appcds/CommandLineFlagCombo.java index baf59d02fed..7b4a03850b8 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/CommandLineFlagCombo.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/CommandLineFlagCombo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 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 @@ -59,7 +59,10 @@ public class CommandLineFlagCombo { "-XX:+UseCompressedOops", "-XX:ObjectAlignmentInBytes=16", "-XX:ObjectAlignmentInBytes=32", - "-XX:ObjectAlignmentInBytes=64" + "-XX:ObjectAlignmentInBytes=64", + "-Xint", + "-Xmixed", + "-Xcomp", }; public static void main(String[] args) throws Exception { From 4bfe226870a15306b1e015c38fe3835f26b41fe6 Mon Sep 17 00:00:00 2001 From: Richard Reingruber Date: Tue, 24 Oct 2023 07:05:56 +0000 Subject: [PATCH 079/124] 8310031: Parallel: Implement better work distribution for large object arrays in old gen Co-authored-by: Albert Mingkun Yang Reviewed-by: tschatzl, ayang --- src/hotspot/share/gc/parallel/psCardTable.cpp | 351 +++++++++++------- src/hotspot/share/gc/parallel/psCardTable.hpp | 55 ++- .../share/gc/parallel/psPromotionManager.hpp | 1 + .../gc/parallel/psPromotionManager.inline.hpp | 5 + src/hotspot/share/gc/parallel/psScavenge.cpp | 9 +- 5 files changed, 264 insertions(+), 157 deletions(-) diff --git a/src/hotspot/share/gc/parallel/psCardTable.cpp b/src/hotspot/share/gc/parallel/psCardTable.cpp index d08ad157261..4d63cdb9a3f 100644 --- a/src/hotspot/share/gc/parallel/psCardTable.cpp +++ b/src/hotspot/share/gc/parallel/psCardTable.cpp @@ -33,6 +33,7 @@ #include "oops/access.inline.hpp" #include "oops/oop.inline.hpp" #include "runtime/prefetch.inline.hpp" +#include "utilities/spinYield.hpp" #include "utilities/align.hpp" // Checks an individual oop for missing precise marks. Mark @@ -123,70 +124,184 @@ static void prefetch_write(void *p) { } } -// postcondition: ret is a dirty card or end_card -CardTable::CardValue* PSCardTable::find_first_dirty_card(CardValue* const start_card, - CardValue* const end_card) { - for (CardValue* i_card = start_card; i_card < end_card; ++i_card) { - if (*i_card != PSCardTable::clean_card_val()) { - return i_card; - } +void PSCardTable::scan_obj_with_limit(PSPromotionManager* pm, + oop obj, + HeapWord* start, + HeapWord* end) { + if (!obj->is_typeArray()) { + prefetch_write(start); + pm->push_contents_bounded(obj, start, end); } - return end_card; } -// postcondition: ret is a clean card or end_card -// Note: if a part of an object is on a dirty card, all cards this object -// resides on are considered dirty. -CardTable::CardValue* PSCardTable::find_first_clean_card(ObjectStartArray* const start_array, - CardValue* const start_card, - CardValue* const end_card) { - assert(start_card == end_card || - *start_card != PSCardTable::clean_card_val(), "precondition"); - // Skip the first dirty card. - CardValue* i_card = start_card + 1; - while (i_card < end_card) { - if (*i_card != PSCardTable::clean_card_val()) { - i_card++; - continue; - } - assert(i_card - 1 >= start_card, "inv"); - assert(*(i_card - 1) != PSCardTable::clean_card_val(), "prev card must be dirty"); - // Find the final obj on the prev dirty card. - HeapWord* obj_addr = start_array->object_start(addr_for(i_card)-1); - HeapWord* obj_end_addr = obj_addr + cast_to_oop(obj_addr)->size(); - CardValue* final_card_by_obj = byte_for(obj_end_addr - 1); - assert(final_card_by_obj < end_card, "inv"); - if (final_card_by_obj <= i_card) { - return i_card; +void PSCardTable::pre_scavenge(HeapWord* old_gen_bottom, uint active_workers) { + _preprocessing_active_workers = active_workers; +} + +// The "shadow" table is a copy of the card table entries of the current stripe. +// It is used to separate card reading, clearing and redirtying which reduces +// complexity significantly. +class PSStripeShadowCardTable { + typedef CardTable::CardValue CardValue; + + const uint _card_shift; + const uint _card_size; + CardValue _table[PSCardTable::num_cards_in_stripe]; + const CardValue* _table_base; + +public: + PSStripeShadowCardTable(PSCardTable* pst, HeapWord* const start, HeapWord* const end) : + _card_shift(CardTable::card_shift()), + _card_size(CardTable::card_size()), + _table_base(_table - (uintptr_t(start) >> _card_shift)) { + size_t stripe_byte_size = pointer_delta(end, start) * HeapWordSize; + size_t copy_length = align_up(stripe_byte_size, _card_size) >> _card_shift; + // The end of the last stripe may not be card aligned as it is equal to old + // gen top at scavenge start. We should not clear the card containing old gen + // top if not card aligned because there can be promoted objects on that + // same card. If it was marked dirty because of the promoted objects and we + // cleared it, we would loose a card mark. + size_t clear_length = align_down(stripe_byte_size, _card_size) >> _card_shift; + CardValue* stripe_start_card = pst->byte_for(start); + memcpy(_table, stripe_start_card, copy_length); + memset(stripe_start_card, CardTable::clean_card_val(), clear_length); + } + + HeapWord* addr_for(const CardValue* const card) { + assert(card >= _table && card <= &_table[PSCardTable::num_cards_in_stripe], "out of bounds"); + return (HeapWord*) ((card - _table_base) << _card_shift); + } + + const CardValue* card_for(HeapWord* addr) { + return &_table_base[uintptr_t(addr) >> _card_shift]; + } + + bool is_dirty(const CardValue* const card) { + return !is_clean(card); + } + + bool is_clean(const CardValue* const card) { + assert(card >= _table && card < &_table[PSCardTable::num_cards_in_stripe], "out of bounds"); + return *card == PSCardTable::clean_card_val(); + } + + const CardValue* find_first_dirty_card(const CardValue* const start, + const CardValue* const end) { + for (const CardValue* i = start; i < end; ++i) { + if (is_dirty(i)) { + return i; + } } - // This final obj extends beyond i_card, check if this new card is dirty. - if (*final_card_by_obj == PSCardTable::clean_card_val()) { - return final_card_by_obj; + return end; + } + + const CardValue* find_first_clean_card(const CardValue* const start, + const CardValue* const end) { + for (const CardValue* i = start; i < end; ++i) { + if (is_clean(i)) { + return i; + } } - // This new card is dirty, continuing the search... - i_card = final_card_by_obj + 1; + return end; } - return end_card; -} +}; + +template +void PSCardTable::process_range(Func&& object_start, + PSPromotionManager* pm, + HeapWord* const start, + HeapWord* const end) { + assert(start < end, "precondition"); + assert(is_card_aligned(start), "precondition"); + + PSStripeShadowCardTable sct(this, start, end); + + // end might not be card-aligned. + const CardValue* end_card = sct.card_for(end - 1) + 1; -void PSCardTable::clear_cards(CardValue* const start, CardValue* const end) { - for (CardValue* i_card = start; i_card < end; ++i_card) { - *i_card = clean_card; + for (HeapWord* i_addr = start; i_addr < end; /* empty */) { + const CardValue* dirty_l = sct.find_first_dirty_card(sct.card_for(i_addr), end_card); + const CardValue* dirty_r = sct.find_first_clean_card(dirty_l, end_card); + + assert(dirty_l <= dirty_r, "inv"); + + if (dirty_l == dirty_r) { + assert(dirty_r == end_card, "inv"); + break; + } + + // Located a non-empty dirty chunk [dirty_l, dirty_r). + HeapWord* addr_l = sct.addr_for(dirty_l); + HeapWord* addr_r = MIN2(sct.addr_for(dirty_r), end); + + // Scan objects overlapping [addr_l, addr_r) limited to [start, end). + HeapWord* obj_addr = object_start(addr_l); + + while (true) { + assert(obj_addr < addr_r, "inv"); + + oop obj = cast_to_oop(obj_addr); + const bool is_obj_array = obj->is_objArray(); + HeapWord* const obj_end_addr = obj_addr + obj->size(); + + if (is_obj_array) { + // Always scan obj arrays precisely (they are always marked precisely) + // to avoid unnecessary work. + scan_obj_with_limit(pm, obj, addr_l, addr_r); + } else { + if (obj_addr < i_addr && i_addr > start) { + // Already scanned this object. Has been one that spans multiple dirty chunks. + // The second condition makes sure objects reaching in the stripe are scanned once. + } else { + scan_obj_with_limit(pm, obj, addr_l, end); + } + } + + if (obj_end_addr >= addr_r) { + i_addr = is_obj_array ? addr_r : obj_end_addr; + break; + } + + // Move to next obj inside this dirty chunk. + obj_addr = obj_end_addr; + } + + // Finished a dirty chunk. + pm->drain_stacks_cond_depth(); } } -void PSCardTable::scan_objects_in_range(PSPromotionManager* pm, - HeapWord* start, - HeapWord* end) { - HeapWord* obj_addr = start; - while (obj_addr < end) { - oop obj = cast_to_oop(obj_addr); - assert(oopDesc::is_oop(obj), "inv"); - prefetch_write(obj_addr); - pm->push_contents(obj); - obj_addr += obj->size(); +template +void PSCardTable::preprocess_card_table_parallel(Func&& object_start, + HeapWord* old_gen_bottom, + HeapWord* old_gen_top, + uint stripe_index, + uint n_stripes) { + const size_t num_cards_in_slice = num_cards_in_stripe * n_stripes; + CardValue* cur_card = byte_for(old_gen_bottom) + stripe_index * num_cards_in_stripe; + CardValue* const end_card = byte_for(old_gen_top - 1) + 1; + + for (/* empty */; cur_card < end_card; cur_card += num_cards_in_slice) { + HeapWord* stripe_addr = addr_for(cur_card); + if (is_dirty(cur_card)) { + // The first card of this stripe is already dirty, no need to see if the + // reaching-in object is a potentially imprecisely marked non-array + // object. + continue; + } + HeapWord* first_obj_addr = object_start(stripe_addr); + if (first_obj_addr == stripe_addr) { + // No object reaching into this stripe. + continue; + } + oop first_obj = cast_to_oop(first_obj_addr); + if (!first_obj->is_array() && is_dirty(byte_for(first_obj_addr))) { + // Found a non-array object reaching into the stripe that has + // potentially been marked imprecisely. Mark first card of the stripe + // dirty so it will be processed later. + *cur_card = dirty_card_val(); + } } - pm->drain_stacks_cond_depth(); } // We get passed the space_top value to prevent us from traversing into @@ -227,103 +342,61 @@ void PSCardTable::scan_objects_in_range(PSPromotionManager* pm, // slice_size_in_words to the start of stripe 0 in slice 0 to get to the start // of stripe 0 in slice 1. +// Scavenging and accesses to the card table are strictly limited to the stripe. +// In particular scavenging of an object crossing stripe boundaries is shared +// among the threads assigned to the stripes it resides on. This reduces +// complexity and enables shared scanning of large objects. +// It requires preprocessing of the card table though where imprecise card marks of +// objects crossing stripe boundaries are propagated to the first card of +// each stripe covered by the individual object. + void PSCardTable::scavenge_contents_parallel(ObjectStartArray* start_array, - MutableSpace* sp, - HeapWord* space_top, + HeapWord* old_gen_bottom, + HeapWord* old_gen_top, PSPromotionManager* pm, uint stripe_index, uint n_stripes) { - const size_t num_cards_in_stripe = 128; - const size_t stripe_size_in_words = num_cards_in_stripe * _card_size_in_words; - const size_t slice_size_in_words = stripe_size_in_words * n_stripes; - - HeapWord* cur_stripe_addr = sp->bottom() + stripe_index * stripe_size_in_words; - - for (/* empty */; cur_stripe_addr < space_top; cur_stripe_addr += slice_size_in_words) { - // exclusive - HeapWord* const cur_stripe_end_addr = MIN2(cur_stripe_addr + stripe_size_in_words, - space_top); - - // Process a stripe iff it contains any obj-start - if (!start_array->object_starts_in_range(cur_stripe_addr, cur_stripe_end_addr)) { - continue; + // ObjectStartArray queries can be expensive for large objects. We cache known objects. + struct { + HeapWord* start_addr; + HeapWord* end_addr; + } cached_obj {nullptr, old_gen_bottom}; + + // Queries must be monotonic because we don't check addr >= cached_obj.start_addr. + auto object_start = [&] (HeapWord* addr) { + if (addr < cached_obj.end_addr) { + assert(cached_obj.start_addr != nullptr, "inv"); + return cached_obj.start_addr; } + HeapWord* result = start_array->object_start(addr); - // Constraints: - // 1. range of cards checked for being dirty or clean: [iter_limit_l, iter_limit_r) - // 2. range of cards can be cleared: [clear_limit_l, clear_limit_r) - // 3. range of objs (obj-start) can be scanned: [first_obj_addr, cur_stripe_end_addr) - - CardValue* iter_limit_l; - CardValue* iter_limit_r; - CardValue* clear_limit_l; - CardValue* clear_limit_r; - - // Identify left ends and the first obj-start inside this stripe. - HeapWord* first_obj_addr = start_array->object_start(cur_stripe_addr); - if (first_obj_addr < cur_stripe_addr) { - // this obj belongs to previous stripe; can't clear any cards it occupies - first_obj_addr += cast_to_oop(first_obj_addr)->size(); - clear_limit_l = byte_for(first_obj_addr - 1) + 1; - iter_limit_l = byte_for(first_obj_addr); - } else { - assert(first_obj_addr == cur_stripe_addr, "inv"); - iter_limit_l = clear_limit_l = byte_for(cur_stripe_addr); - } + cached_obj.start_addr = result; + cached_obj.end_addr = result + cast_to_oop(result)->size(); - assert(cur_stripe_addr <= first_obj_addr, "inside this stripe"); - assert(first_obj_addr <= cur_stripe_end_addr, "can be empty"); + return result; + }; - { - // Identify right ends. - HeapWord* obj_addr = start_array->object_start(cur_stripe_end_addr - 1); - HeapWord* obj_end_addr = obj_addr + cast_to_oop(obj_addr)->size(); - assert(obj_end_addr >= cur_stripe_end_addr, "inv"); - clear_limit_r = byte_for(obj_end_addr); - iter_limit_r = byte_for(obj_end_addr - 1) + 1; - } - - assert(iter_limit_l <= clear_limit_l && - clear_limit_r <= iter_limit_r, "clear cards only if we iterate over them"); - - // Process dirty chunks, i.e. consecutive dirty cards [dirty_l, dirty_r), - // chunk by chunk inside [iter_limit_l, iter_limit_r). - CardValue* dirty_l; - CardValue* dirty_r; - - for (CardValue* cur_card = iter_limit_l; cur_card < iter_limit_r; cur_card = dirty_r + 1) { - dirty_l = find_first_dirty_card(cur_card, iter_limit_r); - dirty_r = find_first_clean_card(start_array, dirty_l, iter_limit_r); - assert(dirty_l <= dirty_r, "inv"); - - // empty - if (dirty_l == dirty_r) { - assert(dirty_r == iter_limit_r, "no more dirty cards in this stripe"); - break; - } - - assert(*dirty_l != clean_card, "inv"); - assert(*dirty_r == clean_card || dirty_r >= clear_limit_r, - "clean card or belonging to next stripe"); + // Prepare scavenge. + preprocess_card_table_parallel(object_start, old_gen_bottom, old_gen_top, stripe_index, n_stripes); - // Process this non-empty dirty chunk in two steps: - { - // 1. Clear card in [dirty_l, dirty_r) subject to [clear_limit_l, clear_limit_r) constraint - clear_cards(MAX2(dirty_l, clear_limit_l), - MIN2(dirty_r, clear_limit_r)); - } - - { - // 2. Scan objs in [dirty_l, dirty_r) subject to [first_obj_addr, cur_stripe_end_addr) constraint - HeapWord* obj_l = MAX2(start_array->object_start(addr_for(dirty_l)), - first_obj_addr); + // Sync with other workers. + Atomic::dec(&_preprocessing_active_workers); + SpinYield spin_yield; + while (Atomic::load_acquire(&_preprocessing_active_workers) > 0) { + spin_yield.wait(); + } - HeapWord* obj_r = MIN2(addr_for(dirty_r), - cur_stripe_end_addr); + // Scavenge + cached_obj = {nullptr, old_gen_bottom}; + const size_t stripe_size_in_words = num_cards_in_stripe * _card_size_in_words; + const size_t slice_size_in_words = stripe_size_in_words * n_stripes; + HeapWord* cur_addr = old_gen_bottom + stripe_index * stripe_size_in_words; + for (/* empty */; cur_addr < old_gen_top; cur_addr += slice_size_in_words) { + HeapWord* const stripe_l = cur_addr; + HeapWord* const stripe_r = MIN2(cur_addr + stripe_size_in_words, + old_gen_top); - scan_objects_in_range(pm, obj_l, obj_r); - } - } + process_range(object_start, pm, stripe_l, stripe_r); } } diff --git a/src/hotspot/share/gc/parallel/psCardTable.hpp b/src/hotspot/share/gc/parallel/psCardTable.hpp index 6953c15d37c..b0634d5c0b0 100644 --- a/src/hotspot/share/gc/parallel/psCardTable.hpp +++ b/src/hotspot/share/gc/parallel/psCardTable.hpp @@ -33,7 +33,35 @@ class ObjectStartArray; class PSPromotionManager; class PSCardTable: public CardTable { - private: + friend class PSStripeShadowCardTable; + static constexpr size_t num_cards_in_stripe = 128; + static_assert(num_cards_in_stripe >= 1, "progress"); + + volatile int _preprocessing_active_workers; + + bool is_dirty(CardValue* card) { + return !is_clean(card); + } + + bool is_clean(CardValue* card) { + return *card == clean_card_val(); + } + + // Iterate the stripes with the given index and copy imprecise card marks of + // objects reaching into a stripe to its first card. + template + void preprocess_card_table_parallel(Func&& object_start, + HeapWord* old_gen_bottom, + HeapWord* old_gen_top, + uint stripe_index, + uint n_stripes); + + // Scavenge contents on dirty cards of the given stripe [start, end). + template + void process_range(Func&& object_start, + PSPromotionManager* pm, + HeapWord* const start, + HeapWord* const end); void verify_all_young_refs_precise_helper(MemRegion mr); @@ -42,29 +70,24 @@ class PSCardTable: public CardTable { verify_card = CT_MR_BS_last_reserved + 5 }; - CardValue* find_first_dirty_card(CardValue* const start_card, - CardValue* const end_card); - - CardValue* find_first_clean_card(ObjectStartArray* start_array, - CardValue* const start_card, - CardValue* const end_card); - - void clear_cards(CardValue* const start, CardValue* const end); - - void scan_objects_in_range(PSPromotionManager* pm, - HeapWord* start, - HeapWord* end); + void scan_obj_with_limit(PSPromotionManager* pm, + oop obj, + HeapWord* start, + HeapWord* end); public: - PSCardTable(MemRegion whole_heap) : CardTable(whole_heap) {} + PSCardTable(MemRegion whole_heap) : CardTable(whole_heap), + _preprocessing_active_workers(0) {} static CardValue youngergen_card_val() { return youngergen_card; } static CardValue verify_card_val() { return verify_card; } // Scavenge support + void pre_scavenge(HeapWord* old_gen_bottom, uint active_workers); + // Scavenge contents of stripes with the given index. void scavenge_contents_parallel(ObjectStartArray* start_array, - MutableSpace* sp, - HeapWord* space_top, + HeapWord* old_gen_bottom, + HeapWord* old_gen_top, PSPromotionManager* pm, uint stripe_index, uint n_stripes); diff --git a/src/hotspot/share/gc/parallel/psPromotionManager.hpp b/src/hotspot/share/gc/parallel/psPromotionManager.hpp index a1d2b38db31..d053ffb6cc9 100644 --- a/src/hotspot/share/gc/parallel/psPromotionManager.hpp +++ b/src/hotspot/share/gc/parallel/psPromotionManager.hpp @@ -177,6 +177,7 @@ class PSPromotionManager { TASKQUEUE_STATS_ONLY(inline void record_steal(ScannerTask task);) void push_contents(oop obj); + void push_contents_bounded(oop obj, HeapWord* left, HeapWord* right); }; #endif // SHARE_GC_PARALLEL_PSPROMOTIONMANAGER_HPP diff --git a/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp b/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp index f702bc48348..c1cbeb0f597 100644 --- a/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp +++ b/src/hotspot/share/gc/parallel/psPromotionManager.inline.hpp @@ -131,6 +131,11 @@ inline void PSPromotionManager::push_contents(oop obj) { } } +inline void PSPromotionManager::push_contents_bounded(oop obj, HeapWord* left, HeapWord* right) { + PSPushContentsClosure pcc(this); + obj->oop_iterate(&pcc, MemRegion(left, right)); +} + template inline oop PSPromotionManager::copy_to_survivor_space(oop o) { assert(should_scavenge(&o), "Sanity"); diff --git a/src/hotspot/share/gc/parallel/psScavenge.cpp b/src/hotspot/share/gc/parallel/psScavenge.cpp index 18e0edd88c9..5354d9257b9 100644 --- a/src/hotspot/share/gc/parallel/psScavenge.cpp +++ b/src/hotspot/share/gc/parallel/psScavenge.cpp @@ -87,7 +87,6 @@ static void scavenge_roots_work(ParallelRootType::Value root_type, uint worker_i assert(ParallelScavengeHeap::heap()->is_gc_active(), "called outside gc"); PSPromotionManager* pm = PSPromotionManager::gc_thread_promotion_manager(worker_id); - PSScavengeRootsClosure roots_closure(pm); PSPromoteRootsClosure roots_to_old_closure(pm); switch (root_type) { @@ -301,6 +300,11 @@ class ScavengeRootsTask : public WorkerTask { _is_old_gen_empty(old_gen->object_space()->is_empty()), _terminator(active_workers, PSPromotionManager::vm_thread_promotion_manager()->stack_array_depth()) { assert(_old_gen != nullptr, "Sanity"); + + if (!_is_old_gen_empty) { + PSCardTable* card_table = ParallelScavengeHeap::heap()->card_table(); + card_table->pre_scavenge(_old_gen->object_space()->bottom(), active_workers); + } } virtual void work(uint worker_id) { @@ -314,8 +318,9 @@ class ScavengeRootsTask : public WorkerTask { PSPromotionManager* pm = PSPromotionManager::gc_thread_promotion_manager(worker_id); PSCardTable* card_table = ParallelScavengeHeap::heap()->card_table(); + // The top of the old gen changes during scavenge when objects are promoted. card_table->scavenge_contents_parallel(_old_gen->start_array(), - _old_gen->object_space(), + _old_gen->object_space()->bottom(), _gen_top, pm, worker_id, From cb383c05b23ef4f6992796bdc5b27eb8386c65d5 Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Tue, 24 Oct 2023 07:09:44 +0000 Subject: [PATCH 080/124] 8318587: refresh libraries cache on AIX in print_vm_info Reviewed-by: mdoerr, lucy, stuefe --- src/hotspot/share/utilities/vmError.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/hotspot/share/utilities/vmError.cpp b/src/hotspot/share/utilities/vmError.cpp index df360335cc9..2f4aec97868 100644 --- a/src/hotspot/share/utilities/vmError.cpp +++ b/src/hotspot/share/utilities/vmError.cpp @@ -74,6 +74,10 @@ #include "jvmci/jvmci.hpp" #endif +#ifdef AIX +#include "loadlib_aix.hpp" +#endif + #ifndef PRODUCT #include #endif // PRODUCT @@ -1343,6 +1347,8 @@ void VMError::report(outputStream* st, bool _verbose) { void VMError::print_vm_info(outputStream* st) { char buf[O_BUFLEN]; + AIX_ONLY(LoadedLibraries::reload()); + report_vm_version(st, buf, sizeof(buf)); // STEP("printing summary") From 6d3cb459dc07ae6abfacd167d1d282457c2cd1b6 Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Tue, 24 Oct 2023 07:34:05 +0000 Subject: [PATCH 081/124] 8318591: avoid leaks in loadlib_aix.cpp reload_table() Reviewed-by: mdoerr, lucy --- src/hotspot/os/aix/loadlib_aix.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/hotspot/os/aix/loadlib_aix.cpp b/src/hotspot/os/aix/loadlib_aix.cpp index 3a71a78e45c..bc71ca2e310 100644 --- a/src/hotspot/os/aix/loadlib_aix.cpp +++ b/src/hotspot/os/aix/loadlib_aix.cpp @@ -225,6 +225,7 @@ static bool reload_table() { lm->path = g_stringlist.add(ldi->ldinfo_filename); if (!lm->path) { trcVerbose("OOM."); + free(lm); goto cleanup; } @@ -246,6 +247,7 @@ static bool reload_table() { lm->member = g_stringlist.add(p_mbr_name); if (!lm->member) { trcVerbose("OOM."); + free(lm); goto cleanup; } } else { From fd332da1c8a689e91b7124fc342f02b6e0d3dff5 Mon Sep 17 00:00:00 2001 From: Pavel Rappo Date: Tue, 24 Oct 2023 08:46:10 +0000 Subject: [PATCH 082/124] 8317289: javadoc fails with -sourcepath if module-info.java contains import statements Reviewed-by: jlahoda --- .../com/sun/tools/javac/tree/TreeInfo.java | 11 +--- .../javadoc/internal/tool/ElementsTable.java | 5 +- .../testModules/TestSourcePathModule.java | 56 +++++++++++++++++++ 3 files changed, 59 insertions(+), 13 deletions(-) create mode 100644 test/langtools/jdk/javadoc/doclet/testModules/TestSourcePathModule.java diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeInfo.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeInfo.java index b25c99d3b06..40dc8042a06 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeInfo.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/TreeInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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 @@ -1321,15 +1321,6 @@ public static boolean isModuleInfo(JCCompilationUnit tree) { && tree.getModuleDecl() != null; } - public static JCModuleDecl getModule(JCCompilationUnit t) { - if (t.defs.nonEmpty()) { - JCTree def = t.defs.head; - if (def.hasTag(MODULEDEF)) - return (JCModuleDecl) def; - } - return null; - } - public static boolean isPackageInfo(JCCompilationUnit tree) { return tree.sourcefile.isNameCompatible("package-info", JavaFileObject.Kind.SOURCE); } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/ElementsTable.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/ElementsTable.java index 3f642658deb..e915fc5f34c 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/ElementsTable.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/ElementsTable.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2022, 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 @@ -67,7 +67,6 @@ import com.sun.tools.javac.tree.JCTree.JCClassDecl; import com.sun.tools.javac.tree.JCTree.JCCompilationUnit; import com.sun.tools.javac.tree.JCTree.JCModuleDecl; -import com.sun.tools.javac.tree.TreeInfo; import com.sun.tools.javac.util.Context; import com.sun.tools.javac.util.ListBuffer; import com.sun.tools.javac.util.Name; @@ -391,7 +390,7 @@ private String getModuleName(Location location) throws ToolException { "module-info", JavaFileObject.Kind.SOURCE); if (jfo != null) { JCCompilationUnit jcu = compiler.parse(jfo); - JCModuleDecl module = TreeInfo.getModule(jcu); + JCModuleDecl module = jcu.getModule(); if (module != null) { return module.getName().toString(); } diff --git a/test/langtools/jdk/javadoc/doclet/testModules/TestSourcePathModule.java b/test/langtools/jdk/javadoc/doclet/testModules/TestSourcePathModule.java new file mode 100644 index 00000000000..eb80955d498 --- /dev/null +++ b/test/langtools/jdk/javadoc/doclet/testModules/TestSourcePathModule.java @@ -0,0 +1,56 @@ +/* + * 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. + */ + +import java.nio.file.Path; + +import javadoc.tester.JavadocTester; +import toolbox.ToolBox; + +/* + * @test + * @bug 8317289 + * @library /tools/lib ../../lib + * @modules jdk.javadoc/jdk.javadoc.internal.tool + * @build toolbox.ToolBox javadoc.tester.* + * @run main TestSourcePathModule + */ +public class TestSourcePathModule extends JavadocTester { + + public static void main(String... args) throws Exception { + new TestSourcePathModule().runTests(); + } + + @Test + public void testSourcePath(Path base) throws Exception { + Path src = base.resolve("src"); + new ToolBox().writeJavaFiles(src, """ + import java.lang.Object; + /** documentation */ + module m { } + """); + javadoc("-d", "out", + "-sourcepath", src.toString(), + "--module", "m"); + checkExit(Exit.OK); + } +} \ No newline at end of file From e6f23a90d4a53339a3c9c2b76fc5d317940e4472 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerg=C3=B6=20Barany?= Date: Tue, 24 Oct 2023 08:58:15 +0000 Subject: [PATCH 083/124] 8315024: Vector API FP reduction tests should not test for exact equality Reviewed-by: epeter, thartmann --- .../vector/Double128VectorTests.java | 47 +++++++++++---- .../vector/Double256VectorTests.java | 47 +++++++++++---- .../vector/Double512VectorTests.java | 47 +++++++++++---- .../incubator/vector/Double64VectorTests.java | 47 +++++++++++---- .../vector/DoubleMaxVectorTests.java | 47 +++++++++++---- .../incubator/vector/Float128VectorTests.java | 47 +++++++++++---- .../incubator/vector/Float256VectorTests.java | 47 +++++++++++---- .../incubator/vector/Float512VectorTests.java | 47 +++++++++++---- .../incubator/vector/Float64VectorTests.java | 47 +++++++++++---- .../incubator/vector/FloatMaxVectorTests.java | 47 +++++++++++---- .../Unit-Reduction-Masked-op.template | 4 ++ .../templates/Unit-Reduction-op.template | 4 ++ .../vector/templates/Unit-header.template | 57 +++++++++++++++++++ 13 files changed, 415 insertions(+), 120 deletions(-) diff --git a/test/jdk/jdk/incubator/vector/Double128VectorTests.java b/test/jdk/jdk/incubator/vector/Double128VectorTests.java index 8336b59accb..5e81cb946bc 100644 --- a/test/jdk/jdk/incubator/vector/Double128VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Double128VectorTests.java @@ -60,6 +60,8 @@ public class Double128VectorTests extends AbstractVectorTest { static final int INVOC_COUNT = Integer.getInteger("jdk.incubator.vector.test.loop-iterations", 100); + // for floating point reduction ops that may introduce rounding errors + private static final double RELATIVE_ROUNDING_ERROR = (double)0.000001; static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / 128); @@ -119,15 +121,21 @@ interface FReductionAllOp { static void assertReductionArraysEquals(double[] r, double rc, double[] a, FReductionOp f, FReductionAllOp fa) { + assertReductionArraysEquals(r, rc, a, f, fa, (double)0.0); + } + + static void assertReductionArraysEquals(double[] r, double rc, double[] a, + FReductionOp f, FReductionAllOp fa, + double relativeError) { int i = 0; try { - Assert.assertEquals(rc, fa.apply(a)); + Assert.assertEquals(rc, fa.apply(a), Math.abs(rc * relativeError)); for (; i < a.length; i += SPECIES.length()) { - Assert.assertEquals(r[i], f.apply(a, i)); + Assert.assertEquals(r[i], f.apply(a, i), Math.abs(r[i] * relativeError)); } } catch (AssertionError e) { - Assert.assertEquals(rc, fa.apply(a), "Final result is incorrect!"); - Assert.assertEquals(r[i], f.apply(a, i), "at index #" + i); + Assert.assertEquals(rc, fa.apply(a), Math.abs(rc * relativeError), "Final result is incorrect!"); + Assert.assertEquals(r[i], f.apply(a, i), Math.abs(r[i] * relativeError), "at index #" + i); } } @@ -141,15 +149,22 @@ interface FReductionAllMaskedOp { static void assertReductionArraysEqualsMasked(double[] r, double rc, double[] a, boolean[] mask, FReductionMaskedOp f, FReductionAllMaskedOp fa) { + assertReductionArraysEqualsMasked(r, rc, a, mask, f, fa, (double)0.0); + } + + static void assertReductionArraysEqualsMasked(double[] r, double rc, double[] a, boolean[] mask, + FReductionMaskedOp f, FReductionAllMaskedOp fa, + double relativeError) { int i = 0; try { - Assert.assertEquals(rc, fa.apply(a, mask)); + Assert.assertEquals(rc, fa.apply(a, mask), Math.abs(rc * relativeError)); for (; i < a.length; i += SPECIES.length()) { - Assert.assertEquals(r[i], f.apply(a, i, mask)); + Assert.assertEquals(r[i], f.apply(a, i, mask), Math.abs(r[i] * +relativeError)); } } catch (AssertionError e) { - Assert.assertEquals(rc, fa.apply(a, mask), "Final result is incorrect!"); - Assert.assertEquals(r[i], f.apply(a, i, mask), "at index #" + i); + Assert.assertEquals(rc, fa.apply(a, mask), Math.abs(rc * relativeError), "Final result is incorrect!"); + Assert.assertEquals(r[i], f.apply(a, i, mask), Math.abs(r[i] * relativeError), "at index #" + i); } } @@ -1078,6 +1093,14 @@ static long bits(double e) { return fill(s * BUFFER_REPS, i -> (((double)(i + 1) == 0) ? 1 : (double)(i + 1))); }), + withToString("double[0.01 + (i / (i + 1))]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (double)0.01 + ((double)i / (i + 1))); + }), + withToString("double[i -> i % 17 == 0 ? cornerCaseValue(i) : 0.01 + (i / (i + 1))]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> i % 17 == 0 ? cornerCaseValue(i) : (double)0.01 + ((double)i / (i + 1))); + }), withToString("double[cornerCaseValue(i)]", (int s) -> { return fill(s * BUFFER_REPS, i -> cornerCaseValue(i)); @@ -2168,7 +2191,7 @@ static void ADDReduceDouble128VectorTests(IntFunction fa) { } assertReductionArraysEquals(r, ra, a, - Double128VectorTests::ADDReduce, Double128VectorTests::ADDReduceAll); + Double128VectorTests::ADDReduce, Double128VectorTests::ADDReduceAll, RELATIVE_ROUNDING_ERROR); } static double ADDReduceMasked(double[] a, int idx, boolean[] mask) { @@ -2214,7 +2237,7 @@ static void ADDReduceDouble128VectorTestsMasked(IntFunction fa, IntFun } assertReductionArraysEqualsMasked(r, ra, a, mask, - Double128VectorTests::ADDReduceMasked, Double128VectorTests::ADDReduceAllMasked); + Double128VectorTests::ADDReduceMasked, Double128VectorTests::ADDReduceAllMasked, RELATIVE_ROUNDING_ERROR); } static double MULReduce(double[] a, int idx) { @@ -2257,7 +2280,7 @@ static void MULReduceDouble128VectorTests(IntFunction fa) { } assertReductionArraysEquals(r, ra, a, - Double128VectorTests::MULReduce, Double128VectorTests::MULReduceAll); + Double128VectorTests::MULReduce, Double128VectorTests::MULReduceAll, RELATIVE_ROUNDING_ERROR); } static double MULReduceMasked(double[] a, int idx, boolean[] mask) { @@ -2303,7 +2326,7 @@ static void MULReduceDouble128VectorTestsMasked(IntFunction fa, IntFun } assertReductionArraysEqualsMasked(r, ra, a, mask, - Double128VectorTests::MULReduceMasked, Double128VectorTests::MULReduceAllMasked); + Double128VectorTests::MULReduceMasked, Double128VectorTests::MULReduceAllMasked, RELATIVE_ROUNDING_ERROR); } static double MINReduce(double[] a, int idx) { diff --git a/test/jdk/jdk/incubator/vector/Double256VectorTests.java b/test/jdk/jdk/incubator/vector/Double256VectorTests.java index f170ccc406b..ef4f3f0f975 100644 --- a/test/jdk/jdk/incubator/vector/Double256VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Double256VectorTests.java @@ -60,6 +60,8 @@ public class Double256VectorTests extends AbstractVectorTest { static final int INVOC_COUNT = Integer.getInteger("jdk.incubator.vector.test.loop-iterations", 100); + // for floating point reduction ops that may introduce rounding errors + private static final double RELATIVE_ROUNDING_ERROR = (double)0.000001; static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / 256); @@ -119,15 +121,21 @@ interface FReductionAllOp { static void assertReductionArraysEquals(double[] r, double rc, double[] a, FReductionOp f, FReductionAllOp fa) { + assertReductionArraysEquals(r, rc, a, f, fa, (double)0.0); + } + + static void assertReductionArraysEquals(double[] r, double rc, double[] a, + FReductionOp f, FReductionAllOp fa, + double relativeError) { int i = 0; try { - Assert.assertEquals(rc, fa.apply(a)); + Assert.assertEquals(rc, fa.apply(a), Math.abs(rc * relativeError)); for (; i < a.length; i += SPECIES.length()) { - Assert.assertEquals(r[i], f.apply(a, i)); + Assert.assertEquals(r[i], f.apply(a, i), Math.abs(r[i] * relativeError)); } } catch (AssertionError e) { - Assert.assertEquals(rc, fa.apply(a), "Final result is incorrect!"); - Assert.assertEquals(r[i], f.apply(a, i), "at index #" + i); + Assert.assertEquals(rc, fa.apply(a), Math.abs(rc * relativeError), "Final result is incorrect!"); + Assert.assertEquals(r[i], f.apply(a, i), Math.abs(r[i] * relativeError), "at index #" + i); } } @@ -141,15 +149,22 @@ interface FReductionAllMaskedOp { static void assertReductionArraysEqualsMasked(double[] r, double rc, double[] a, boolean[] mask, FReductionMaskedOp f, FReductionAllMaskedOp fa) { + assertReductionArraysEqualsMasked(r, rc, a, mask, f, fa, (double)0.0); + } + + static void assertReductionArraysEqualsMasked(double[] r, double rc, double[] a, boolean[] mask, + FReductionMaskedOp f, FReductionAllMaskedOp fa, + double relativeError) { int i = 0; try { - Assert.assertEquals(rc, fa.apply(a, mask)); + Assert.assertEquals(rc, fa.apply(a, mask), Math.abs(rc * relativeError)); for (; i < a.length; i += SPECIES.length()) { - Assert.assertEquals(r[i], f.apply(a, i, mask)); + Assert.assertEquals(r[i], f.apply(a, i, mask), Math.abs(r[i] * +relativeError)); } } catch (AssertionError e) { - Assert.assertEquals(rc, fa.apply(a, mask), "Final result is incorrect!"); - Assert.assertEquals(r[i], f.apply(a, i, mask), "at index #" + i); + Assert.assertEquals(rc, fa.apply(a, mask), Math.abs(rc * relativeError), "Final result is incorrect!"); + Assert.assertEquals(r[i], f.apply(a, i, mask), Math.abs(r[i] * relativeError), "at index #" + i); } } @@ -1078,6 +1093,14 @@ static long bits(double e) { return fill(s * BUFFER_REPS, i -> (((double)(i + 1) == 0) ? 1 : (double)(i + 1))); }), + withToString("double[0.01 + (i / (i + 1))]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (double)0.01 + ((double)i / (i + 1))); + }), + withToString("double[i -> i % 17 == 0 ? cornerCaseValue(i) : 0.01 + (i / (i + 1))]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> i % 17 == 0 ? cornerCaseValue(i) : (double)0.01 + ((double)i / (i + 1))); + }), withToString("double[cornerCaseValue(i)]", (int s) -> { return fill(s * BUFFER_REPS, i -> cornerCaseValue(i)); @@ -2168,7 +2191,7 @@ static void ADDReduceDouble256VectorTests(IntFunction fa) { } assertReductionArraysEquals(r, ra, a, - Double256VectorTests::ADDReduce, Double256VectorTests::ADDReduceAll); + Double256VectorTests::ADDReduce, Double256VectorTests::ADDReduceAll, RELATIVE_ROUNDING_ERROR); } static double ADDReduceMasked(double[] a, int idx, boolean[] mask) { @@ -2214,7 +2237,7 @@ static void ADDReduceDouble256VectorTestsMasked(IntFunction fa, IntFun } assertReductionArraysEqualsMasked(r, ra, a, mask, - Double256VectorTests::ADDReduceMasked, Double256VectorTests::ADDReduceAllMasked); + Double256VectorTests::ADDReduceMasked, Double256VectorTests::ADDReduceAllMasked, RELATIVE_ROUNDING_ERROR); } static double MULReduce(double[] a, int idx) { @@ -2257,7 +2280,7 @@ static void MULReduceDouble256VectorTests(IntFunction fa) { } assertReductionArraysEquals(r, ra, a, - Double256VectorTests::MULReduce, Double256VectorTests::MULReduceAll); + Double256VectorTests::MULReduce, Double256VectorTests::MULReduceAll, RELATIVE_ROUNDING_ERROR); } static double MULReduceMasked(double[] a, int idx, boolean[] mask) { @@ -2303,7 +2326,7 @@ static void MULReduceDouble256VectorTestsMasked(IntFunction fa, IntFun } assertReductionArraysEqualsMasked(r, ra, a, mask, - Double256VectorTests::MULReduceMasked, Double256VectorTests::MULReduceAllMasked); + Double256VectorTests::MULReduceMasked, Double256VectorTests::MULReduceAllMasked, RELATIVE_ROUNDING_ERROR); } static double MINReduce(double[] a, int idx) { diff --git a/test/jdk/jdk/incubator/vector/Double512VectorTests.java b/test/jdk/jdk/incubator/vector/Double512VectorTests.java index 406636bed0e..21209c23ea1 100644 --- a/test/jdk/jdk/incubator/vector/Double512VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Double512VectorTests.java @@ -60,6 +60,8 @@ public class Double512VectorTests extends AbstractVectorTest { static final int INVOC_COUNT = Integer.getInteger("jdk.incubator.vector.test.loop-iterations", 100); + // for floating point reduction ops that may introduce rounding errors + private static final double RELATIVE_ROUNDING_ERROR = (double)0.000001; static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / 512); @@ -119,15 +121,21 @@ interface FReductionAllOp { static void assertReductionArraysEquals(double[] r, double rc, double[] a, FReductionOp f, FReductionAllOp fa) { + assertReductionArraysEquals(r, rc, a, f, fa, (double)0.0); + } + + static void assertReductionArraysEquals(double[] r, double rc, double[] a, + FReductionOp f, FReductionAllOp fa, + double relativeError) { int i = 0; try { - Assert.assertEquals(rc, fa.apply(a)); + Assert.assertEquals(rc, fa.apply(a), Math.abs(rc * relativeError)); for (; i < a.length; i += SPECIES.length()) { - Assert.assertEquals(r[i], f.apply(a, i)); + Assert.assertEquals(r[i], f.apply(a, i), Math.abs(r[i] * relativeError)); } } catch (AssertionError e) { - Assert.assertEquals(rc, fa.apply(a), "Final result is incorrect!"); - Assert.assertEquals(r[i], f.apply(a, i), "at index #" + i); + Assert.assertEquals(rc, fa.apply(a), Math.abs(rc * relativeError), "Final result is incorrect!"); + Assert.assertEquals(r[i], f.apply(a, i), Math.abs(r[i] * relativeError), "at index #" + i); } } @@ -141,15 +149,22 @@ interface FReductionAllMaskedOp { static void assertReductionArraysEqualsMasked(double[] r, double rc, double[] a, boolean[] mask, FReductionMaskedOp f, FReductionAllMaskedOp fa) { + assertReductionArraysEqualsMasked(r, rc, a, mask, f, fa, (double)0.0); + } + + static void assertReductionArraysEqualsMasked(double[] r, double rc, double[] a, boolean[] mask, + FReductionMaskedOp f, FReductionAllMaskedOp fa, + double relativeError) { int i = 0; try { - Assert.assertEquals(rc, fa.apply(a, mask)); + Assert.assertEquals(rc, fa.apply(a, mask), Math.abs(rc * relativeError)); for (; i < a.length; i += SPECIES.length()) { - Assert.assertEquals(r[i], f.apply(a, i, mask)); + Assert.assertEquals(r[i], f.apply(a, i, mask), Math.abs(r[i] * +relativeError)); } } catch (AssertionError e) { - Assert.assertEquals(rc, fa.apply(a, mask), "Final result is incorrect!"); - Assert.assertEquals(r[i], f.apply(a, i, mask), "at index #" + i); + Assert.assertEquals(rc, fa.apply(a, mask), Math.abs(rc * relativeError), "Final result is incorrect!"); + Assert.assertEquals(r[i], f.apply(a, i, mask), Math.abs(r[i] * relativeError), "at index #" + i); } } @@ -1078,6 +1093,14 @@ static long bits(double e) { return fill(s * BUFFER_REPS, i -> (((double)(i + 1) == 0) ? 1 : (double)(i + 1))); }), + withToString("double[0.01 + (i / (i + 1))]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (double)0.01 + ((double)i / (i + 1))); + }), + withToString("double[i -> i % 17 == 0 ? cornerCaseValue(i) : 0.01 + (i / (i + 1))]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> i % 17 == 0 ? cornerCaseValue(i) : (double)0.01 + ((double)i / (i + 1))); + }), withToString("double[cornerCaseValue(i)]", (int s) -> { return fill(s * BUFFER_REPS, i -> cornerCaseValue(i)); @@ -2168,7 +2191,7 @@ static void ADDReduceDouble512VectorTests(IntFunction fa) { } assertReductionArraysEquals(r, ra, a, - Double512VectorTests::ADDReduce, Double512VectorTests::ADDReduceAll); + Double512VectorTests::ADDReduce, Double512VectorTests::ADDReduceAll, RELATIVE_ROUNDING_ERROR); } static double ADDReduceMasked(double[] a, int idx, boolean[] mask) { @@ -2214,7 +2237,7 @@ static void ADDReduceDouble512VectorTestsMasked(IntFunction fa, IntFun } assertReductionArraysEqualsMasked(r, ra, a, mask, - Double512VectorTests::ADDReduceMasked, Double512VectorTests::ADDReduceAllMasked); + Double512VectorTests::ADDReduceMasked, Double512VectorTests::ADDReduceAllMasked, RELATIVE_ROUNDING_ERROR); } static double MULReduce(double[] a, int idx) { @@ -2257,7 +2280,7 @@ static void MULReduceDouble512VectorTests(IntFunction fa) { } assertReductionArraysEquals(r, ra, a, - Double512VectorTests::MULReduce, Double512VectorTests::MULReduceAll); + Double512VectorTests::MULReduce, Double512VectorTests::MULReduceAll, RELATIVE_ROUNDING_ERROR); } static double MULReduceMasked(double[] a, int idx, boolean[] mask) { @@ -2303,7 +2326,7 @@ static void MULReduceDouble512VectorTestsMasked(IntFunction fa, IntFun } assertReductionArraysEqualsMasked(r, ra, a, mask, - Double512VectorTests::MULReduceMasked, Double512VectorTests::MULReduceAllMasked); + Double512VectorTests::MULReduceMasked, Double512VectorTests::MULReduceAllMasked, RELATIVE_ROUNDING_ERROR); } static double MINReduce(double[] a, int idx) { diff --git a/test/jdk/jdk/incubator/vector/Double64VectorTests.java b/test/jdk/jdk/incubator/vector/Double64VectorTests.java index c86b0281072..360445a6b7f 100644 --- a/test/jdk/jdk/incubator/vector/Double64VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Double64VectorTests.java @@ -60,6 +60,8 @@ public class Double64VectorTests extends AbstractVectorTest { static final int INVOC_COUNT = Integer.getInteger("jdk.incubator.vector.test.loop-iterations", 100); + // for floating point reduction ops that may introduce rounding errors + private static final double RELATIVE_ROUNDING_ERROR = (double)0.000001; static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / 64); @@ -119,15 +121,21 @@ interface FReductionAllOp { static void assertReductionArraysEquals(double[] r, double rc, double[] a, FReductionOp f, FReductionAllOp fa) { + assertReductionArraysEquals(r, rc, a, f, fa, (double)0.0); + } + + static void assertReductionArraysEquals(double[] r, double rc, double[] a, + FReductionOp f, FReductionAllOp fa, + double relativeError) { int i = 0; try { - Assert.assertEquals(rc, fa.apply(a)); + Assert.assertEquals(rc, fa.apply(a), Math.abs(rc * relativeError)); for (; i < a.length; i += SPECIES.length()) { - Assert.assertEquals(r[i], f.apply(a, i)); + Assert.assertEquals(r[i], f.apply(a, i), Math.abs(r[i] * relativeError)); } } catch (AssertionError e) { - Assert.assertEquals(rc, fa.apply(a), "Final result is incorrect!"); - Assert.assertEquals(r[i], f.apply(a, i), "at index #" + i); + Assert.assertEquals(rc, fa.apply(a), Math.abs(rc * relativeError), "Final result is incorrect!"); + Assert.assertEquals(r[i], f.apply(a, i), Math.abs(r[i] * relativeError), "at index #" + i); } } @@ -141,15 +149,22 @@ interface FReductionAllMaskedOp { static void assertReductionArraysEqualsMasked(double[] r, double rc, double[] a, boolean[] mask, FReductionMaskedOp f, FReductionAllMaskedOp fa) { + assertReductionArraysEqualsMasked(r, rc, a, mask, f, fa, (double)0.0); + } + + static void assertReductionArraysEqualsMasked(double[] r, double rc, double[] a, boolean[] mask, + FReductionMaskedOp f, FReductionAllMaskedOp fa, + double relativeError) { int i = 0; try { - Assert.assertEquals(rc, fa.apply(a, mask)); + Assert.assertEquals(rc, fa.apply(a, mask), Math.abs(rc * relativeError)); for (; i < a.length; i += SPECIES.length()) { - Assert.assertEquals(r[i], f.apply(a, i, mask)); + Assert.assertEquals(r[i], f.apply(a, i, mask), Math.abs(r[i] * +relativeError)); } } catch (AssertionError e) { - Assert.assertEquals(rc, fa.apply(a, mask), "Final result is incorrect!"); - Assert.assertEquals(r[i], f.apply(a, i, mask), "at index #" + i); + Assert.assertEquals(rc, fa.apply(a, mask), Math.abs(rc * relativeError), "Final result is incorrect!"); + Assert.assertEquals(r[i], f.apply(a, i, mask), Math.abs(r[i] * relativeError), "at index #" + i); } } @@ -1078,6 +1093,14 @@ static long bits(double e) { return fill(s * BUFFER_REPS, i -> (((double)(i + 1) == 0) ? 1 : (double)(i + 1))); }), + withToString("double[0.01 + (i / (i + 1))]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (double)0.01 + ((double)i / (i + 1))); + }), + withToString("double[i -> i % 17 == 0 ? cornerCaseValue(i) : 0.01 + (i / (i + 1))]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> i % 17 == 0 ? cornerCaseValue(i) : (double)0.01 + ((double)i / (i + 1))); + }), withToString("double[cornerCaseValue(i)]", (int s) -> { return fill(s * BUFFER_REPS, i -> cornerCaseValue(i)); @@ -2168,7 +2191,7 @@ static void ADDReduceDouble64VectorTests(IntFunction fa) { } assertReductionArraysEquals(r, ra, a, - Double64VectorTests::ADDReduce, Double64VectorTests::ADDReduceAll); + Double64VectorTests::ADDReduce, Double64VectorTests::ADDReduceAll, RELATIVE_ROUNDING_ERROR); } static double ADDReduceMasked(double[] a, int idx, boolean[] mask) { @@ -2214,7 +2237,7 @@ static void ADDReduceDouble64VectorTestsMasked(IntFunction fa, IntFunc } assertReductionArraysEqualsMasked(r, ra, a, mask, - Double64VectorTests::ADDReduceMasked, Double64VectorTests::ADDReduceAllMasked); + Double64VectorTests::ADDReduceMasked, Double64VectorTests::ADDReduceAllMasked, RELATIVE_ROUNDING_ERROR); } static double MULReduce(double[] a, int idx) { @@ -2257,7 +2280,7 @@ static void MULReduceDouble64VectorTests(IntFunction fa) { } assertReductionArraysEquals(r, ra, a, - Double64VectorTests::MULReduce, Double64VectorTests::MULReduceAll); + Double64VectorTests::MULReduce, Double64VectorTests::MULReduceAll, RELATIVE_ROUNDING_ERROR); } static double MULReduceMasked(double[] a, int idx, boolean[] mask) { @@ -2303,7 +2326,7 @@ static void MULReduceDouble64VectorTestsMasked(IntFunction fa, IntFunc } assertReductionArraysEqualsMasked(r, ra, a, mask, - Double64VectorTests::MULReduceMasked, Double64VectorTests::MULReduceAllMasked); + Double64VectorTests::MULReduceMasked, Double64VectorTests::MULReduceAllMasked, RELATIVE_ROUNDING_ERROR); } static double MINReduce(double[] a, int idx) { diff --git a/test/jdk/jdk/incubator/vector/DoubleMaxVectorTests.java b/test/jdk/jdk/incubator/vector/DoubleMaxVectorTests.java index bcc7b6b0144..01d72b64d2d 100644 --- a/test/jdk/jdk/incubator/vector/DoubleMaxVectorTests.java +++ b/test/jdk/jdk/incubator/vector/DoubleMaxVectorTests.java @@ -65,6 +65,8 @@ static VectorShape getMaxBit() { private static final int Max = 256; // juts so we can do N/Max + // for floating point reduction ops that may introduce rounding errors + private static final double RELATIVE_ROUNDING_ERROR = (double)0.000001; static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / Max); @@ -124,15 +126,21 @@ interface FReductionAllOp { static void assertReductionArraysEquals(double[] r, double rc, double[] a, FReductionOp f, FReductionAllOp fa) { + assertReductionArraysEquals(r, rc, a, f, fa, (double)0.0); + } + + static void assertReductionArraysEquals(double[] r, double rc, double[] a, + FReductionOp f, FReductionAllOp fa, + double relativeError) { int i = 0; try { - Assert.assertEquals(rc, fa.apply(a)); + Assert.assertEquals(rc, fa.apply(a), Math.abs(rc * relativeError)); for (; i < a.length; i += SPECIES.length()) { - Assert.assertEquals(r[i], f.apply(a, i)); + Assert.assertEquals(r[i], f.apply(a, i), Math.abs(r[i] * relativeError)); } } catch (AssertionError e) { - Assert.assertEquals(rc, fa.apply(a), "Final result is incorrect!"); - Assert.assertEquals(r[i], f.apply(a, i), "at index #" + i); + Assert.assertEquals(rc, fa.apply(a), Math.abs(rc * relativeError), "Final result is incorrect!"); + Assert.assertEquals(r[i], f.apply(a, i), Math.abs(r[i] * relativeError), "at index #" + i); } } @@ -146,15 +154,22 @@ interface FReductionAllMaskedOp { static void assertReductionArraysEqualsMasked(double[] r, double rc, double[] a, boolean[] mask, FReductionMaskedOp f, FReductionAllMaskedOp fa) { + assertReductionArraysEqualsMasked(r, rc, a, mask, f, fa, (double)0.0); + } + + static void assertReductionArraysEqualsMasked(double[] r, double rc, double[] a, boolean[] mask, + FReductionMaskedOp f, FReductionAllMaskedOp fa, + double relativeError) { int i = 0; try { - Assert.assertEquals(rc, fa.apply(a, mask)); + Assert.assertEquals(rc, fa.apply(a, mask), Math.abs(rc * relativeError)); for (; i < a.length; i += SPECIES.length()) { - Assert.assertEquals(r[i], f.apply(a, i, mask)); + Assert.assertEquals(r[i], f.apply(a, i, mask), Math.abs(r[i] * +relativeError)); } } catch (AssertionError e) { - Assert.assertEquals(rc, fa.apply(a, mask), "Final result is incorrect!"); - Assert.assertEquals(r[i], f.apply(a, i, mask), "at index #" + i); + Assert.assertEquals(rc, fa.apply(a, mask), Math.abs(rc * relativeError), "Final result is incorrect!"); + Assert.assertEquals(r[i], f.apply(a, i, mask), Math.abs(r[i] * relativeError), "at index #" + i); } } @@ -1083,6 +1098,14 @@ static long bits(double e) { return fill(s * BUFFER_REPS, i -> (((double)(i + 1) == 0) ? 1 : (double)(i + 1))); }), + withToString("double[0.01 + (i / (i + 1))]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (double)0.01 + ((double)i / (i + 1))); + }), + withToString("double[i -> i % 17 == 0 ? cornerCaseValue(i) : 0.01 + (i / (i + 1))]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> i % 17 == 0 ? cornerCaseValue(i) : (double)0.01 + ((double)i / (i + 1))); + }), withToString("double[cornerCaseValue(i)]", (int s) -> { return fill(s * BUFFER_REPS, i -> cornerCaseValue(i)); @@ -2173,7 +2196,7 @@ static void ADDReduceDoubleMaxVectorTests(IntFunction fa) { } assertReductionArraysEquals(r, ra, a, - DoubleMaxVectorTests::ADDReduce, DoubleMaxVectorTests::ADDReduceAll); + DoubleMaxVectorTests::ADDReduce, DoubleMaxVectorTests::ADDReduceAll, RELATIVE_ROUNDING_ERROR); } static double ADDReduceMasked(double[] a, int idx, boolean[] mask) { @@ -2219,7 +2242,7 @@ static void ADDReduceDoubleMaxVectorTestsMasked(IntFunction fa, IntFun } assertReductionArraysEqualsMasked(r, ra, a, mask, - DoubleMaxVectorTests::ADDReduceMasked, DoubleMaxVectorTests::ADDReduceAllMasked); + DoubleMaxVectorTests::ADDReduceMasked, DoubleMaxVectorTests::ADDReduceAllMasked, RELATIVE_ROUNDING_ERROR); } static double MULReduce(double[] a, int idx) { @@ -2262,7 +2285,7 @@ static void MULReduceDoubleMaxVectorTests(IntFunction fa) { } assertReductionArraysEquals(r, ra, a, - DoubleMaxVectorTests::MULReduce, DoubleMaxVectorTests::MULReduceAll); + DoubleMaxVectorTests::MULReduce, DoubleMaxVectorTests::MULReduceAll, RELATIVE_ROUNDING_ERROR); } static double MULReduceMasked(double[] a, int idx, boolean[] mask) { @@ -2308,7 +2331,7 @@ static void MULReduceDoubleMaxVectorTestsMasked(IntFunction fa, IntFun } assertReductionArraysEqualsMasked(r, ra, a, mask, - DoubleMaxVectorTests::MULReduceMasked, DoubleMaxVectorTests::MULReduceAllMasked); + DoubleMaxVectorTests::MULReduceMasked, DoubleMaxVectorTests::MULReduceAllMasked, RELATIVE_ROUNDING_ERROR); } static double MINReduce(double[] a, int idx) { diff --git a/test/jdk/jdk/incubator/vector/Float128VectorTests.java b/test/jdk/jdk/incubator/vector/Float128VectorTests.java index 21de8e1bd96..9f1b28a80c6 100644 --- a/test/jdk/jdk/incubator/vector/Float128VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Float128VectorTests.java @@ -60,6 +60,8 @@ public class Float128VectorTests extends AbstractVectorTest { static final int INVOC_COUNT = Integer.getInteger("jdk.incubator.vector.test.loop-iterations", 100); + // for floating point reduction ops that may introduce rounding errors + private static final float RELATIVE_ROUNDING_ERROR = (float)0.000001; static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / 128); @@ -119,15 +121,21 @@ interface FReductionAllOp { static void assertReductionArraysEquals(float[] r, float rc, float[] a, FReductionOp f, FReductionAllOp fa) { + assertReductionArraysEquals(r, rc, a, f, fa, (float)0.0); + } + + static void assertReductionArraysEquals(float[] r, float rc, float[] a, + FReductionOp f, FReductionAllOp fa, + float relativeError) { int i = 0; try { - Assert.assertEquals(rc, fa.apply(a)); + Assert.assertEquals(rc, fa.apply(a), Math.abs(rc * relativeError)); for (; i < a.length; i += SPECIES.length()) { - Assert.assertEquals(r[i], f.apply(a, i)); + Assert.assertEquals(r[i], f.apply(a, i), Math.abs(r[i] * relativeError)); } } catch (AssertionError e) { - Assert.assertEquals(rc, fa.apply(a), "Final result is incorrect!"); - Assert.assertEquals(r[i], f.apply(a, i), "at index #" + i); + Assert.assertEquals(rc, fa.apply(a), Math.abs(rc * relativeError), "Final result is incorrect!"); + Assert.assertEquals(r[i], f.apply(a, i), Math.abs(r[i] * relativeError), "at index #" + i); } } @@ -141,15 +149,22 @@ interface FReductionAllMaskedOp { static void assertReductionArraysEqualsMasked(float[] r, float rc, float[] a, boolean[] mask, FReductionMaskedOp f, FReductionAllMaskedOp fa) { + assertReductionArraysEqualsMasked(r, rc, a, mask, f, fa, (float)0.0); + } + + static void assertReductionArraysEqualsMasked(float[] r, float rc, float[] a, boolean[] mask, + FReductionMaskedOp f, FReductionAllMaskedOp fa, + float relativeError) { int i = 0; try { - Assert.assertEquals(rc, fa.apply(a, mask)); + Assert.assertEquals(rc, fa.apply(a, mask), Math.abs(rc * relativeError)); for (; i < a.length; i += SPECIES.length()) { - Assert.assertEquals(r[i], f.apply(a, i, mask)); + Assert.assertEquals(r[i], f.apply(a, i, mask), Math.abs(r[i] * +relativeError)); } } catch (AssertionError e) { - Assert.assertEquals(rc, fa.apply(a, mask), "Final result is incorrect!"); - Assert.assertEquals(r[i], f.apply(a, i, mask), "at index #" + i); + Assert.assertEquals(rc, fa.apply(a, mask), Math.abs(rc * relativeError), "Final result is incorrect!"); + Assert.assertEquals(r[i], f.apply(a, i, mask), Math.abs(r[i] * relativeError), "at index #" + i); } } @@ -1089,6 +1104,14 @@ static int bits(float e) { return fill(s * BUFFER_REPS, i -> (((float)(i + 1) == 0) ? 1 : (float)(i + 1))); }), + withToString("float[0.01 + (i / (i + 1))]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (float)0.01 + ((float)i / (i + 1))); + }), + withToString("float[i -> i % 17 == 0 ? cornerCaseValue(i) : 0.01 + (i / (i + 1))]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> i % 17 == 0 ? cornerCaseValue(i) : (float)0.01 + ((float)i / (i + 1))); + }), withToString("float[cornerCaseValue(i)]", (int s) -> { return fill(s * BUFFER_REPS, i -> cornerCaseValue(i)); @@ -2179,7 +2202,7 @@ static void ADDReduceFloat128VectorTests(IntFunction fa) { } assertReductionArraysEquals(r, ra, a, - Float128VectorTests::ADDReduce, Float128VectorTests::ADDReduceAll); + Float128VectorTests::ADDReduce, Float128VectorTests::ADDReduceAll, RELATIVE_ROUNDING_ERROR); } static float ADDReduceMasked(float[] a, int idx, boolean[] mask) { @@ -2225,7 +2248,7 @@ static void ADDReduceFloat128VectorTestsMasked(IntFunction fa, IntFunct } assertReductionArraysEqualsMasked(r, ra, a, mask, - Float128VectorTests::ADDReduceMasked, Float128VectorTests::ADDReduceAllMasked); + Float128VectorTests::ADDReduceMasked, Float128VectorTests::ADDReduceAllMasked, RELATIVE_ROUNDING_ERROR); } static float MULReduce(float[] a, int idx) { @@ -2268,7 +2291,7 @@ static void MULReduceFloat128VectorTests(IntFunction fa) { } assertReductionArraysEquals(r, ra, a, - Float128VectorTests::MULReduce, Float128VectorTests::MULReduceAll); + Float128VectorTests::MULReduce, Float128VectorTests::MULReduceAll, RELATIVE_ROUNDING_ERROR); } static float MULReduceMasked(float[] a, int idx, boolean[] mask) { @@ -2314,7 +2337,7 @@ static void MULReduceFloat128VectorTestsMasked(IntFunction fa, IntFunct } assertReductionArraysEqualsMasked(r, ra, a, mask, - Float128VectorTests::MULReduceMasked, Float128VectorTests::MULReduceAllMasked); + Float128VectorTests::MULReduceMasked, Float128VectorTests::MULReduceAllMasked, RELATIVE_ROUNDING_ERROR); } static float MINReduce(float[] a, int idx) { diff --git a/test/jdk/jdk/incubator/vector/Float256VectorTests.java b/test/jdk/jdk/incubator/vector/Float256VectorTests.java index bd74e79d24b..649b06a007d 100644 --- a/test/jdk/jdk/incubator/vector/Float256VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Float256VectorTests.java @@ -60,6 +60,8 @@ public class Float256VectorTests extends AbstractVectorTest { static final int INVOC_COUNT = Integer.getInteger("jdk.incubator.vector.test.loop-iterations", 100); + // for floating point reduction ops that may introduce rounding errors + private static final float RELATIVE_ROUNDING_ERROR = (float)0.000001; static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / 256); @@ -119,15 +121,21 @@ interface FReductionAllOp { static void assertReductionArraysEquals(float[] r, float rc, float[] a, FReductionOp f, FReductionAllOp fa) { + assertReductionArraysEquals(r, rc, a, f, fa, (float)0.0); + } + + static void assertReductionArraysEquals(float[] r, float rc, float[] a, + FReductionOp f, FReductionAllOp fa, + float relativeError) { int i = 0; try { - Assert.assertEquals(rc, fa.apply(a)); + Assert.assertEquals(rc, fa.apply(a), Math.abs(rc * relativeError)); for (; i < a.length; i += SPECIES.length()) { - Assert.assertEquals(r[i], f.apply(a, i)); + Assert.assertEquals(r[i], f.apply(a, i), Math.abs(r[i] * relativeError)); } } catch (AssertionError e) { - Assert.assertEquals(rc, fa.apply(a), "Final result is incorrect!"); - Assert.assertEquals(r[i], f.apply(a, i), "at index #" + i); + Assert.assertEquals(rc, fa.apply(a), Math.abs(rc * relativeError), "Final result is incorrect!"); + Assert.assertEquals(r[i], f.apply(a, i), Math.abs(r[i] * relativeError), "at index #" + i); } } @@ -141,15 +149,22 @@ interface FReductionAllMaskedOp { static void assertReductionArraysEqualsMasked(float[] r, float rc, float[] a, boolean[] mask, FReductionMaskedOp f, FReductionAllMaskedOp fa) { + assertReductionArraysEqualsMasked(r, rc, a, mask, f, fa, (float)0.0); + } + + static void assertReductionArraysEqualsMasked(float[] r, float rc, float[] a, boolean[] mask, + FReductionMaskedOp f, FReductionAllMaskedOp fa, + float relativeError) { int i = 0; try { - Assert.assertEquals(rc, fa.apply(a, mask)); + Assert.assertEquals(rc, fa.apply(a, mask), Math.abs(rc * relativeError)); for (; i < a.length; i += SPECIES.length()) { - Assert.assertEquals(r[i], f.apply(a, i, mask)); + Assert.assertEquals(r[i], f.apply(a, i, mask), Math.abs(r[i] * +relativeError)); } } catch (AssertionError e) { - Assert.assertEquals(rc, fa.apply(a, mask), "Final result is incorrect!"); - Assert.assertEquals(r[i], f.apply(a, i, mask), "at index #" + i); + Assert.assertEquals(rc, fa.apply(a, mask), Math.abs(rc * relativeError), "Final result is incorrect!"); + Assert.assertEquals(r[i], f.apply(a, i, mask), Math.abs(r[i] * relativeError), "at index #" + i); } } @@ -1089,6 +1104,14 @@ static int bits(float e) { return fill(s * BUFFER_REPS, i -> (((float)(i + 1) == 0) ? 1 : (float)(i + 1))); }), + withToString("float[0.01 + (i / (i + 1))]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (float)0.01 + ((float)i / (i + 1))); + }), + withToString("float[i -> i % 17 == 0 ? cornerCaseValue(i) : 0.01 + (i / (i + 1))]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> i % 17 == 0 ? cornerCaseValue(i) : (float)0.01 + ((float)i / (i + 1))); + }), withToString("float[cornerCaseValue(i)]", (int s) -> { return fill(s * BUFFER_REPS, i -> cornerCaseValue(i)); @@ -2179,7 +2202,7 @@ static void ADDReduceFloat256VectorTests(IntFunction fa) { } assertReductionArraysEquals(r, ra, a, - Float256VectorTests::ADDReduce, Float256VectorTests::ADDReduceAll); + Float256VectorTests::ADDReduce, Float256VectorTests::ADDReduceAll, RELATIVE_ROUNDING_ERROR); } static float ADDReduceMasked(float[] a, int idx, boolean[] mask) { @@ -2225,7 +2248,7 @@ static void ADDReduceFloat256VectorTestsMasked(IntFunction fa, IntFunct } assertReductionArraysEqualsMasked(r, ra, a, mask, - Float256VectorTests::ADDReduceMasked, Float256VectorTests::ADDReduceAllMasked); + Float256VectorTests::ADDReduceMasked, Float256VectorTests::ADDReduceAllMasked, RELATIVE_ROUNDING_ERROR); } static float MULReduce(float[] a, int idx) { @@ -2268,7 +2291,7 @@ static void MULReduceFloat256VectorTests(IntFunction fa) { } assertReductionArraysEquals(r, ra, a, - Float256VectorTests::MULReduce, Float256VectorTests::MULReduceAll); + Float256VectorTests::MULReduce, Float256VectorTests::MULReduceAll, RELATIVE_ROUNDING_ERROR); } static float MULReduceMasked(float[] a, int idx, boolean[] mask) { @@ -2314,7 +2337,7 @@ static void MULReduceFloat256VectorTestsMasked(IntFunction fa, IntFunct } assertReductionArraysEqualsMasked(r, ra, a, mask, - Float256VectorTests::MULReduceMasked, Float256VectorTests::MULReduceAllMasked); + Float256VectorTests::MULReduceMasked, Float256VectorTests::MULReduceAllMasked, RELATIVE_ROUNDING_ERROR); } static float MINReduce(float[] a, int idx) { diff --git a/test/jdk/jdk/incubator/vector/Float512VectorTests.java b/test/jdk/jdk/incubator/vector/Float512VectorTests.java index 527900594f4..5bd3932cef1 100644 --- a/test/jdk/jdk/incubator/vector/Float512VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Float512VectorTests.java @@ -60,6 +60,8 @@ public class Float512VectorTests extends AbstractVectorTest { static final int INVOC_COUNT = Integer.getInteger("jdk.incubator.vector.test.loop-iterations", 100); + // for floating point reduction ops that may introduce rounding errors + private static final float RELATIVE_ROUNDING_ERROR = (float)0.000001; static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / 512); @@ -119,15 +121,21 @@ interface FReductionAllOp { static void assertReductionArraysEquals(float[] r, float rc, float[] a, FReductionOp f, FReductionAllOp fa) { + assertReductionArraysEquals(r, rc, a, f, fa, (float)0.0); + } + + static void assertReductionArraysEquals(float[] r, float rc, float[] a, + FReductionOp f, FReductionAllOp fa, + float relativeError) { int i = 0; try { - Assert.assertEquals(rc, fa.apply(a)); + Assert.assertEquals(rc, fa.apply(a), Math.abs(rc * relativeError)); for (; i < a.length; i += SPECIES.length()) { - Assert.assertEquals(r[i], f.apply(a, i)); + Assert.assertEquals(r[i], f.apply(a, i), Math.abs(r[i] * relativeError)); } } catch (AssertionError e) { - Assert.assertEquals(rc, fa.apply(a), "Final result is incorrect!"); - Assert.assertEquals(r[i], f.apply(a, i), "at index #" + i); + Assert.assertEquals(rc, fa.apply(a), Math.abs(rc * relativeError), "Final result is incorrect!"); + Assert.assertEquals(r[i], f.apply(a, i), Math.abs(r[i] * relativeError), "at index #" + i); } } @@ -141,15 +149,22 @@ interface FReductionAllMaskedOp { static void assertReductionArraysEqualsMasked(float[] r, float rc, float[] a, boolean[] mask, FReductionMaskedOp f, FReductionAllMaskedOp fa) { + assertReductionArraysEqualsMasked(r, rc, a, mask, f, fa, (float)0.0); + } + + static void assertReductionArraysEqualsMasked(float[] r, float rc, float[] a, boolean[] mask, + FReductionMaskedOp f, FReductionAllMaskedOp fa, + float relativeError) { int i = 0; try { - Assert.assertEquals(rc, fa.apply(a, mask)); + Assert.assertEquals(rc, fa.apply(a, mask), Math.abs(rc * relativeError)); for (; i < a.length; i += SPECIES.length()) { - Assert.assertEquals(r[i], f.apply(a, i, mask)); + Assert.assertEquals(r[i], f.apply(a, i, mask), Math.abs(r[i] * +relativeError)); } } catch (AssertionError e) { - Assert.assertEquals(rc, fa.apply(a, mask), "Final result is incorrect!"); - Assert.assertEquals(r[i], f.apply(a, i, mask), "at index #" + i); + Assert.assertEquals(rc, fa.apply(a, mask), Math.abs(rc * relativeError), "Final result is incorrect!"); + Assert.assertEquals(r[i], f.apply(a, i, mask), Math.abs(r[i] * relativeError), "at index #" + i); } } @@ -1089,6 +1104,14 @@ static int bits(float e) { return fill(s * BUFFER_REPS, i -> (((float)(i + 1) == 0) ? 1 : (float)(i + 1))); }), + withToString("float[0.01 + (i / (i + 1))]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (float)0.01 + ((float)i / (i + 1))); + }), + withToString("float[i -> i % 17 == 0 ? cornerCaseValue(i) : 0.01 + (i / (i + 1))]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> i % 17 == 0 ? cornerCaseValue(i) : (float)0.01 + ((float)i / (i + 1))); + }), withToString("float[cornerCaseValue(i)]", (int s) -> { return fill(s * BUFFER_REPS, i -> cornerCaseValue(i)); @@ -2179,7 +2202,7 @@ static void ADDReduceFloat512VectorTests(IntFunction fa) { } assertReductionArraysEquals(r, ra, a, - Float512VectorTests::ADDReduce, Float512VectorTests::ADDReduceAll); + Float512VectorTests::ADDReduce, Float512VectorTests::ADDReduceAll, RELATIVE_ROUNDING_ERROR); } static float ADDReduceMasked(float[] a, int idx, boolean[] mask) { @@ -2225,7 +2248,7 @@ static void ADDReduceFloat512VectorTestsMasked(IntFunction fa, IntFunct } assertReductionArraysEqualsMasked(r, ra, a, mask, - Float512VectorTests::ADDReduceMasked, Float512VectorTests::ADDReduceAllMasked); + Float512VectorTests::ADDReduceMasked, Float512VectorTests::ADDReduceAllMasked, RELATIVE_ROUNDING_ERROR); } static float MULReduce(float[] a, int idx) { @@ -2268,7 +2291,7 @@ static void MULReduceFloat512VectorTests(IntFunction fa) { } assertReductionArraysEquals(r, ra, a, - Float512VectorTests::MULReduce, Float512VectorTests::MULReduceAll); + Float512VectorTests::MULReduce, Float512VectorTests::MULReduceAll, RELATIVE_ROUNDING_ERROR); } static float MULReduceMasked(float[] a, int idx, boolean[] mask) { @@ -2314,7 +2337,7 @@ static void MULReduceFloat512VectorTestsMasked(IntFunction fa, IntFunct } assertReductionArraysEqualsMasked(r, ra, a, mask, - Float512VectorTests::MULReduceMasked, Float512VectorTests::MULReduceAllMasked); + Float512VectorTests::MULReduceMasked, Float512VectorTests::MULReduceAllMasked, RELATIVE_ROUNDING_ERROR); } static float MINReduce(float[] a, int idx) { diff --git a/test/jdk/jdk/incubator/vector/Float64VectorTests.java b/test/jdk/jdk/incubator/vector/Float64VectorTests.java index a07c4f19b13..1922be94f40 100644 --- a/test/jdk/jdk/incubator/vector/Float64VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Float64VectorTests.java @@ -60,6 +60,8 @@ public class Float64VectorTests extends AbstractVectorTest { static final int INVOC_COUNT = Integer.getInteger("jdk.incubator.vector.test.loop-iterations", 100); + // for floating point reduction ops that may introduce rounding errors + private static final float RELATIVE_ROUNDING_ERROR = (float)0.000001; static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / 64); @@ -119,15 +121,21 @@ interface FReductionAllOp { static void assertReductionArraysEquals(float[] r, float rc, float[] a, FReductionOp f, FReductionAllOp fa) { + assertReductionArraysEquals(r, rc, a, f, fa, (float)0.0); + } + + static void assertReductionArraysEquals(float[] r, float rc, float[] a, + FReductionOp f, FReductionAllOp fa, + float relativeError) { int i = 0; try { - Assert.assertEquals(rc, fa.apply(a)); + Assert.assertEquals(rc, fa.apply(a), Math.abs(rc * relativeError)); for (; i < a.length; i += SPECIES.length()) { - Assert.assertEquals(r[i], f.apply(a, i)); + Assert.assertEquals(r[i], f.apply(a, i), Math.abs(r[i] * relativeError)); } } catch (AssertionError e) { - Assert.assertEquals(rc, fa.apply(a), "Final result is incorrect!"); - Assert.assertEquals(r[i], f.apply(a, i), "at index #" + i); + Assert.assertEquals(rc, fa.apply(a), Math.abs(rc * relativeError), "Final result is incorrect!"); + Assert.assertEquals(r[i], f.apply(a, i), Math.abs(r[i] * relativeError), "at index #" + i); } } @@ -141,15 +149,22 @@ interface FReductionAllMaskedOp { static void assertReductionArraysEqualsMasked(float[] r, float rc, float[] a, boolean[] mask, FReductionMaskedOp f, FReductionAllMaskedOp fa) { + assertReductionArraysEqualsMasked(r, rc, a, mask, f, fa, (float)0.0); + } + + static void assertReductionArraysEqualsMasked(float[] r, float rc, float[] a, boolean[] mask, + FReductionMaskedOp f, FReductionAllMaskedOp fa, + float relativeError) { int i = 0; try { - Assert.assertEquals(rc, fa.apply(a, mask)); + Assert.assertEquals(rc, fa.apply(a, mask), Math.abs(rc * relativeError)); for (; i < a.length; i += SPECIES.length()) { - Assert.assertEquals(r[i], f.apply(a, i, mask)); + Assert.assertEquals(r[i], f.apply(a, i, mask), Math.abs(r[i] * +relativeError)); } } catch (AssertionError e) { - Assert.assertEquals(rc, fa.apply(a, mask), "Final result is incorrect!"); - Assert.assertEquals(r[i], f.apply(a, i, mask), "at index #" + i); + Assert.assertEquals(rc, fa.apply(a, mask), Math.abs(rc * relativeError), "Final result is incorrect!"); + Assert.assertEquals(r[i], f.apply(a, i, mask), Math.abs(r[i] * relativeError), "at index #" + i); } } @@ -1089,6 +1104,14 @@ static int bits(float e) { return fill(s * BUFFER_REPS, i -> (((float)(i + 1) == 0) ? 1 : (float)(i + 1))); }), + withToString("float[0.01 + (i / (i + 1))]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (float)0.01 + ((float)i / (i + 1))); + }), + withToString("float[i -> i % 17 == 0 ? cornerCaseValue(i) : 0.01 + (i / (i + 1))]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> i % 17 == 0 ? cornerCaseValue(i) : (float)0.01 + ((float)i / (i + 1))); + }), withToString("float[cornerCaseValue(i)]", (int s) -> { return fill(s * BUFFER_REPS, i -> cornerCaseValue(i)); @@ -2179,7 +2202,7 @@ static void ADDReduceFloat64VectorTests(IntFunction fa) { } assertReductionArraysEquals(r, ra, a, - Float64VectorTests::ADDReduce, Float64VectorTests::ADDReduceAll); + Float64VectorTests::ADDReduce, Float64VectorTests::ADDReduceAll, RELATIVE_ROUNDING_ERROR); } static float ADDReduceMasked(float[] a, int idx, boolean[] mask) { @@ -2225,7 +2248,7 @@ static void ADDReduceFloat64VectorTestsMasked(IntFunction fa, IntFuncti } assertReductionArraysEqualsMasked(r, ra, a, mask, - Float64VectorTests::ADDReduceMasked, Float64VectorTests::ADDReduceAllMasked); + Float64VectorTests::ADDReduceMasked, Float64VectorTests::ADDReduceAllMasked, RELATIVE_ROUNDING_ERROR); } static float MULReduce(float[] a, int idx) { @@ -2268,7 +2291,7 @@ static void MULReduceFloat64VectorTests(IntFunction fa) { } assertReductionArraysEquals(r, ra, a, - Float64VectorTests::MULReduce, Float64VectorTests::MULReduceAll); + Float64VectorTests::MULReduce, Float64VectorTests::MULReduceAll, RELATIVE_ROUNDING_ERROR); } static float MULReduceMasked(float[] a, int idx, boolean[] mask) { @@ -2314,7 +2337,7 @@ static void MULReduceFloat64VectorTestsMasked(IntFunction fa, IntFuncti } assertReductionArraysEqualsMasked(r, ra, a, mask, - Float64VectorTests::MULReduceMasked, Float64VectorTests::MULReduceAllMasked); + Float64VectorTests::MULReduceMasked, Float64VectorTests::MULReduceAllMasked, RELATIVE_ROUNDING_ERROR); } static float MINReduce(float[] a, int idx) { diff --git a/test/jdk/jdk/incubator/vector/FloatMaxVectorTests.java b/test/jdk/jdk/incubator/vector/FloatMaxVectorTests.java index 1c42c670b87..3e72f9077f6 100644 --- a/test/jdk/jdk/incubator/vector/FloatMaxVectorTests.java +++ b/test/jdk/jdk/incubator/vector/FloatMaxVectorTests.java @@ -65,6 +65,8 @@ static VectorShape getMaxBit() { private static final int Max = 256; // juts so we can do N/Max + // for floating point reduction ops that may introduce rounding errors + private static final float RELATIVE_ROUNDING_ERROR = (float)0.000001; static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / Max); @@ -124,15 +126,21 @@ interface FReductionAllOp { static void assertReductionArraysEquals(float[] r, float rc, float[] a, FReductionOp f, FReductionAllOp fa) { + assertReductionArraysEquals(r, rc, a, f, fa, (float)0.0); + } + + static void assertReductionArraysEquals(float[] r, float rc, float[] a, + FReductionOp f, FReductionAllOp fa, + float relativeError) { int i = 0; try { - Assert.assertEquals(rc, fa.apply(a)); + Assert.assertEquals(rc, fa.apply(a), Math.abs(rc * relativeError)); for (; i < a.length; i += SPECIES.length()) { - Assert.assertEquals(r[i], f.apply(a, i)); + Assert.assertEquals(r[i], f.apply(a, i), Math.abs(r[i] * relativeError)); } } catch (AssertionError e) { - Assert.assertEquals(rc, fa.apply(a), "Final result is incorrect!"); - Assert.assertEquals(r[i], f.apply(a, i), "at index #" + i); + Assert.assertEquals(rc, fa.apply(a), Math.abs(rc * relativeError), "Final result is incorrect!"); + Assert.assertEquals(r[i], f.apply(a, i), Math.abs(r[i] * relativeError), "at index #" + i); } } @@ -146,15 +154,22 @@ interface FReductionAllMaskedOp { static void assertReductionArraysEqualsMasked(float[] r, float rc, float[] a, boolean[] mask, FReductionMaskedOp f, FReductionAllMaskedOp fa) { + assertReductionArraysEqualsMasked(r, rc, a, mask, f, fa, (float)0.0); + } + + static void assertReductionArraysEqualsMasked(float[] r, float rc, float[] a, boolean[] mask, + FReductionMaskedOp f, FReductionAllMaskedOp fa, + float relativeError) { int i = 0; try { - Assert.assertEquals(rc, fa.apply(a, mask)); + Assert.assertEquals(rc, fa.apply(a, mask), Math.abs(rc * relativeError)); for (; i < a.length; i += SPECIES.length()) { - Assert.assertEquals(r[i], f.apply(a, i, mask)); + Assert.assertEquals(r[i], f.apply(a, i, mask), Math.abs(r[i] * +relativeError)); } } catch (AssertionError e) { - Assert.assertEquals(rc, fa.apply(a, mask), "Final result is incorrect!"); - Assert.assertEquals(r[i], f.apply(a, i, mask), "at index #" + i); + Assert.assertEquals(rc, fa.apply(a, mask), Math.abs(rc * relativeError), "Final result is incorrect!"); + Assert.assertEquals(r[i], f.apply(a, i, mask), Math.abs(r[i] * relativeError), "at index #" + i); } } @@ -1094,6 +1109,14 @@ static int bits(float e) { return fill(s * BUFFER_REPS, i -> (((float)(i + 1) == 0) ? 1 : (float)(i + 1))); }), + withToString("float[0.01 + (i / (i + 1))]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> (float)0.01 + ((float)i / (i + 1))); + }), + withToString("float[i -> i % 17 == 0 ? cornerCaseValue(i) : 0.01 + (i / (i + 1))]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> i % 17 == 0 ? cornerCaseValue(i) : (float)0.01 + ((float)i / (i + 1))); + }), withToString("float[cornerCaseValue(i)]", (int s) -> { return fill(s * BUFFER_REPS, i -> cornerCaseValue(i)); @@ -2184,7 +2207,7 @@ static void ADDReduceFloatMaxVectorTests(IntFunction fa) { } assertReductionArraysEquals(r, ra, a, - FloatMaxVectorTests::ADDReduce, FloatMaxVectorTests::ADDReduceAll); + FloatMaxVectorTests::ADDReduce, FloatMaxVectorTests::ADDReduceAll, RELATIVE_ROUNDING_ERROR); } static float ADDReduceMasked(float[] a, int idx, boolean[] mask) { @@ -2230,7 +2253,7 @@ static void ADDReduceFloatMaxVectorTestsMasked(IntFunction fa, IntFunct } assertReductionArraysEqualsMasked(r, ra, a, mask, - FloatMaxVectorTests::ADDReduceMasked, FloatMaxVectorTests::ADDReduceAllMasked); + FloatMaxVectorTests::ADDReduceMasked, FloatMaxVectorTests::ADDReduceAllMasked, RELATIVE_ROUNDING_ERROR); } static float MULReduce(float[] a, int idx) { @@ -2273,7 +2296,7 @@ static void MULReduceFloatMaxVectorTests(IntFunction fa) { } assertReductionArraysEquals(r, ra, a, - FloatMaxVectorTests::MULReduce, FloatMaxVectorTests::MULReduceAll); + FloatMaxVectorTests::MULReduce, FloatMaxVectorTests::MULReduceAll, RELATIVE_ROUNDING_ERROR); } static float MULReduceMasked(float[] a, int idx, boolean[] mask) { @@ -2319,7 +2342,7 @@ static void MULReduceFloatMaxVectorTestsMasked(IntFunction fa, IntFunct } assertReductionArraysEqualsMasked(r, ra, a, mask, - FloatMaxVectorTests::MULReduceMasked, FloatMaxVectorTests::MULReduceAllMasked); + FloatMaxVectorTests::MULReduceMasked, FloatMaxVectorTests::MULReduceAllMasked, RELATIVE_ROUNDING_ERROR); } static float MINReduce(float[] a, int idx) { diff --git a/test/jdk/jdk/incubator/vector/templates/Unit-Reduction-Masked-op.template b/test/jdk/jdk/incubator/vector/templates/Unit-Reduction-Masked-op.template index 8af236eb0e3..3b306ce387a 100644 --- a/test/jdk/jdk/incubator/vector/templates/Unit-Reduction-Masked-op.template +++ b/test/jdk/jdk/incubator/vector/templates/Unit-Reduction-Masked-op.template @@ -3,5 +3,9 @@ static void [[TEST]]Reduce$vectorteststype$Masked(IntFunction<$type$[]> fa, IntFunction fm) { [[KERNEL]] assertReductionArraysEqualsMasked(r, ra, a, mask, +#if[FP] + $vectorteststype$::[[TEST]]ReduceMasked, $vectorteststype$::[[TEST]]ReduceAllMasked, RELATIVE_ROUNDING_ERROR); +#else[FP] $vectorteststype$::[[TEST]]ReduceMasked, $vectorteststype$::[[TEST]]ReduceAllMasked); +#end[FP] } diff --git a/test/jdk/jdk/incubator/vector/templates/Unit-Reduction-op.template b/test/jdk/jdk/incubator/vector/templates/Unit-Reduction-op.template index e6bcdb83c2e..5c689688708 100644 --- a/test/jdk/jdk/incubator/vector/templates/Unit-Reduction-op.template +++ b/test/jdk/jdk/incubator/vector/templates/Unit-Reduction-op.template @@ -3,5 +3,9 @@ static void [[TEST]]Reduce$vectorteststype$(IntFunction<$type$[]> fa) { [[KERNEL]] assertReductionArraysEquals(r, ra, a, +#if[FP] + $vectorteststype$::[[TEST]]Reduce, $vectorteststype$::[[TEST]]ReduceAll, RELATIVE_ROUNDING_ERROR); +#else[FP] $vectorteststype$::[[TEST]]Reduce, $vectorteststype$::[[TEST]]ReduceAll); +#end[FP] } diff --git a/test/jdk/jdk/incubator/vector/templates/Unit-header.template b/test/jdk/jdk/incubator/vector/templates/Unit-header.template index 0f460c231dc..87364836f7c 100644 --- a/test/jdk/jdk/incubator/vector/templates/Unit-header.template +++ b/test/jdk/jdk/incubator/vector/templates/Unit-header.template @@ -92,6 +92,10 @@ public class $vectorteststype$ extends AbstractVectorTest { #if[BITWISE] private static final $type$ CONST_SHIFT = $Boxtype$.SIZE / 2; #end[BITWISE] +#if[FP] + // for floating point reduction ops that may introduce rounding errors + private static final $type$ RELATIVE_ROUNDING_ERROR = ($type$)0.000001; +#end[FP] static final int BUFFER_REPS = Integer.getInteger("jdk.incubator.vector.test.buffer-vectors", 25000 / $bits$); @@ -151,6 +155,9 @@ public class $vectorteststype$ extends AbstractVectorTest { static void assertReductionArraysEquals($type$[] r, $type$ rc, $type$[] a, FReductionOp f, FReductionAllOp fa) { +#if[FP] + assertReductionArraysEquals(r, rc, a, f, fa, ($type$)0.0); +#else[FP] int i = 0; try { Assert.assertEquals(rc, fa.apply(a)); @@ -161,7 +168,25 @@ public class $vectorteststype$ extends AbstractVectorTest { Assert.assertEquals(rc, fa.apply(a), "Final result is incorrect!"); Assert.assertEquals(r[i], f.apply(a, i), "at index #" + i); } +#end[FP] + } +#if[FP] + + static void assertReductionArraysEquals($type$[] r, $type$ rc, $type$[] a, + FReductionOp f, FReductionAllOp fa, + $type$ relativeError) { + int i = 0; + try { + Assert.assertEquals(rc, fa.apply(a), Math.abs(rc * relativeError)); + for (; i < a.length; i += SPECIES.length()) { + Assert.assertEquals(r[i], f.apply(a, i), Math.abs(r[i] * relativeError)); + } + } catch (AssertionError e) { + Assert.assertEquals(rc, fa.apply(a), Math.abs(rc * relativeError), "Final result is incorrect!"); + Assert.assertEquals(r[i], f.apply(a, i), Math.abs(r[i] * relativeError), "at index #" + i); + } } +#end[FP] interface FReductionMaskedOp { $type$ apply($type$[] a, int idx, boolean[] mask); @@ -173,6 +198,9 @@ public class $vectorteststype$ extends AbstractVectorTest { static void assertReductionArraysEqualsMasked($type$[] r, $type$ rc, $type$[] a, boolean[] mask, FReductionMaskedOp f, FReductionAllMaskedOp fa) { +#if[FP] + assertReductionArraysEqualsMasked(r, rc, a, mask, f, fa, ($type$)0.0); +#else[FP] int i = 0; try { Assert.assertEquals(rc, fa.apply(a, mask)); @@ -183,7 +211,26 @@ public class $vectorteststype$ extends AbstractVectorTest { Assert.assertEquals(rc, fa.apply(a, mask), "Final result is incorrect!"); Assert.assertEquals(r[i], f.apply(a, i, mask), "at index #" + i); } +#end[FP] + } +#if[FP] + + static void assertReductionArraysEqualsMasked($type$[] r, $type$ rc, $type$[] a, boolean[] mask, + FReductionMaskedOp f, FReductionAllMaskedOp fa, + $type$ relativeError) { + int i = 0; + try { + Assert.assertEquals(rc, fa.apply(a, mask), Math.abs(rc * relativeError)); + for (; i < a.length; i += SPECIES.length()) { + Assert.assertEquals(r[i], f.apply(a, i, mask), Math.abs(r[i] * +relativeError)); + } + } catch (AssertionError e) { + Assert.assertEquals(rc, fa.apply(a, mask), Math.abs(rc * relativeError), "Final result is incorrect!"); + Assert.assertEquals(r[i], f.apply(a, i, mask), Math.abs(r[i] * relativeError), "at index #" + i); + } } +#end[FP] #if[!Long] interface FReductionOpLong { @@ -1147,6 +1194,16 @@ public class $vectorteststype$ extends AbstractVectorTest { return fill(s * BUFFER_REPS, i -> ((($type$)(i + 1) == 0) ? 1 : ($type$)(i + 1))); }), +#if[FP] + withToString("$type$[0.01 + (i / (i + 1))]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> ($type$)0.01 + (($type$)i / (i + 1))); + }), + withToString("$type$[i -> i % 17 == 0 ? cornerCaseValue(i) : 0.01 + (i / (i + 1))]", (int s) -> { + return fill(s * BUFFER_REPS, + i -> i % 17 == 0 ? cornerCaseValue(i) : ($type$)0.01 + (($type$)i / (i + 1))); + }), +#end[FP] withToString("$type$[cornerCaseValue(i)]", (int s) -> { return fill(s * BUFFER_REPS, i -> cornerCaseValue(i)); From a644670cc6afc3bd6cedaa7f0d7bb75c1de90417 Mon Sep 17 00:00:00 2001 From: Martin Doerr Date: Tue, 24 Oct 2023 09:09:33 +0000 Subject: [PATCH 084/124] 8318609: Upcall stubs should be smaller Co-authored-by: Jorn Vernee Reviewed-by: rrich, jvernee --- .../cpu/aarch64/stubGenerator_aarch64.cpp | 18 +++++++++++++ .../cpu/aarch64/upcallLinker_aarch64.cpp | 19 ++----------- src/hotspot/cpu/ppc/stubGenerator_ppc.cpp | 17 ++++++++++++ src/hotspot/cpu/ppc/upcallLinker_ppc.cpp | 20 +++----------- src/hotspot/cpu/riscv/stubGenerator_riscv.cpp | 17 ++++++++++++ src/hotspot/cpu/riscv/upcallLinker_riscv.cpp | 19 +++---------- src/hotspot/cpu/s390/stubGenerator_s390.cpp | 17 ++++++++++++ src/hotspot/cpu/s390/upcallLinker_s390.cpp | 20 +++----------- src/hotspot/cpu/x86/stubGenerator_x86_64.cpp | 21 +++++++++++++++ src/hotspot/cpu/x86/stubGenerator_x86_64.hpp | 3 +++ src/hotspot/cpu/x86/upcallLinker_x86_64.cpp | 27 +++---------------- src/hotspot/share/code/codeBlob.cpp | 12 +++------ src/hotspot/share/code/codeBlob.hpp | 10 ++----- src/hotspot/share/prims/upcallLinker.cpp | 4 ++- src/hotspot/share/prims/upcallLinker.hpp | 6 +++-- src/hotspot/share/runtime/sharedRuntime.cpp | 2 +- src/hotspot/share/runtime/stubRoutines.cpp | 2 ++ src/hotspot/share/runtime/stubRoutines.hpp | 7 +++++ 18 files changed, 129 insertions(+), 112 deletions(-) diff --git a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp index 6d2e2628553..7b36f42986e 100644 --- a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp @@ -41,6 +41,7 @@ #include "oops/objArrayKlass.hpp" #include "oops/oop.inline.hpp" #include "prims/methodHandles.hpp" +#include "prims/upcallLinker.hpp" #include "runtime/atomic.hpp" #include "runtime/continuation.hpp" #include "runtime/continuationEntry.inline.hpp" @@ -7326,6 +7327,21 @@ class StubGenerator: public StubCodeGenerator { #endif // INCLUDE_JFR + // exception handler for upcall stubs + address generate_upcall_stub_exception_handler() { + StubCodeMark mark(this, "StubRoutines", "upcall stub exception handler"); + address start = __ pc(); + + // Native caller has no idea how to handle exceptions, + // so we just crash here. Up to callee to catch exceptions. + __ verify_oop(r0); + __ movptr(rscratch1, CAST_FROM_FN_PTR(uint64_t, UpcallLinker::handle_uncaught_exception)); + __ blr(rscratch1); + __ should_not_reach_here(); + + return start; + } + // Continuation point for throwing of implicit exceptions that are // not handled in the current activation. Fabricates an exception // oop and initiates normal exception dispatching in this @@ -8377,6 +8393,8 @@ class StubGenerator: public StubCodeGenerator { #endif // LINUX + StubRoutines::_upcall_stub_exception_handler = generate_upcall_stub_exception_handler(); + StubRoutines::aarch64::set_completed(); // Inidicate that arraycopy and zero_blocks stubs are generated } diff --git a/src/hotspot/cpu/aarch64/upcallLinker_aarch64.cpp b/src/hotspot/cpu/aarch64/upcallLinker_aarch64.cpp index 57cc9fe6274..fb2f52facaf 100644 --- a/src/hotspot/cpu/aarch64/upcallLinker_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/upcallLinker_aarch64.cpp @@ -217,6 +217,7 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry, __ block_comment("{ on_entry"); __ lea(c_rarg0, Address(sp, frame_data_offset)); + __ movptr(c_rarg1, (intptr_t)receiver); __ movptr(rscratch1, CAST_FROM_FN_PTR(uint64_t, UpcallLinker::on_entry)); __ blr(rscratch1); __ mov(rthread, r0); @@ -233,9 +234,7 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry, __ block_comment("} argument shuffle"); __ block_comment("{ receiver "); - __ movptr(shuffle_reg, (intptr_t)receiver); - __ resolve_jobject(shuffle_reg, rscratch1, rscratch2); - __ mov(j_rarg0, shuffle_reg); + __ get_vm_result(j_rarg0, rthread); __ block_comment("} receiver "); __ mov_metadata(rmethod, entry); @@ -306,19 +305,6 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry, ////////////////////////////////////////////////////////////////////////////// - __ block_comment("{ exception handler"); - - intptr_t exception_handler_offset = __ pc() - start; - - // Native caller has no idea how to handle exceptions, - // so we just crash here. Up to callee to catch exceptions. - __ verify_oop(r0); - __ movptr(rscratch1, CAST_FROM_FN_PTR(uint64_t, UpcallLinker::handle_uncaught_exception)); - __ blr(rscratch1); - __ should_not_reach_here(); - - __ block_comment("} exception handler"); - _masm->flush(); #ifndef PRODUCT @@ -334,7 +320,6 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry, UpcallStub* blob = UpcallStub::create(name, &buffer, - exception_handler_offset, receiver, in_ByteSize(frame_data_offset)); diff --git a/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp b/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp index c06f22e0fbb..efcc8c89721 100644 --- a/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp +++ b/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp @@ -36,6 +36,7 @@ #include "oops/objArrayKlass.hpp" #include "oops/oop.inline.hpp" #include "prims/methodHandles.hpp" +#include "prims/upcallLinker.hpp" #include "runtime/continuation.hpp" #include "runtime/continuationEntry.inline.hpp" #include "runtime/frame.inline.hpp" @@ -4717,6 +4718,20 @@ class StubGenerator: public StubCodeGenerator { #endif // INCLUDE_JFR + // exception handler for upcall stubs + address generate_upcall_stub_exception_handler() { + StubCodeMark mark(this, "StubRoutines", "upcall stub exception handler"); + address start = __ pc(); + + // Native caller has no idea how to handle exceptions, + // so we just crash here. Up to callee to catch exceptions. + __ verify_oop(R3_ARG1); + __ load_const_optimized(R12_scratch2, CAST_FROM_FN_PTR(uint64_t, UpcallLinker::handle_uncaught_exception), R0); + __ call_c(R12_scratch2); + __ should_not_reach_here(); + + return start; + } // Initialization void generate_initial_stubs() { @@ -4796,6 +4811,8 @@ class StubGenerator: public StubCodeGenerator { // arraycopy stubs used by compilers generate_arraycopy_stubs(); + + StubRoutines::_upcall_stub_exception_handler = generate_upcall_stub_exception_handler(); } void generate_compiler_stubs() { diff --git a/src/hotspot/cpu/ppc/upcallLinker_ppc.cpp b/src/hotspot/cpu/ppc/upcallLinker_ppc.cpp index 4cb86ad573c..aaa9952656c 100644 --- a/src/hotspot/cpu/ppc/upcallLinker_ppc.cpp +++ b/src/hotspot/cpu/ppc/upcallLinker_ppc.cpp @@ -115,7 +115,7 @@ static void restore_callee_saved_registers(MacroAssembler* _masm, const ABIDescr __ block_comment("} restore_callee_saved_regs "); } -static const int upcall_stub_code_base_size = 1536; // depends on GC (resolve_jobject) +static const int upcall_stub_code_base_size = 1024; static const int upcall_stub_size_per_arg = 16; // arg save & restore + move address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry, @@ -217,6 +217,7 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry, __ block_comment("{ on_entry"); __ load_const_optimized(call_target_address, CAST_FROM_FN_PTR(uint64_t, UpcallLinker::on_entry), R0); __ addi(R3_ARG1, R1_SP, frame_data_offset); + __ load_const_optimized(R4_ARG2, (intptr_t)receiver, R0); __ call_c(call_target_address); __ mr(R16_thread, R3_RET); __ block_comment("} on_entry"); @@ -232,8 +233,7 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry, __ block_comment("} argument shuffle"); __ block_comment("{ receiver "); - __ load_const_optimized(R3_ARG1, (intptr_t)receiver, R0); - __ resolve_jobject(R3_ARG1, tmp, R31, MacroAssembler::PRESERVATION_FRAME_LR_GP_FP_REGS); // kills R31 + __ get_vm_result(R3_ARG1); __ block_comment("} receiver "); __ load_const_optimized(R19_method, (intptr_t)entry); @@ -314,19 +314,6 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry, ////////////////////////////////////////////////////////////////////////////// - __ block_comment("{ exception handler"); - - intptr_t exception_handler_offset = __ pc() - start; - - // Native caller has no idea how to handle exceptions, - // so we just crash here. Up to callee to catch exceptions. - __ verify_oop(R3_ARG1); - __ load_const_optimized(call_target_address, CAST_FROM_FN_PTR(uint64_t, UpcallLinker::handle_uncaught_exception), R0); - __ call_c(call_target_address); - __ should_not_reach_here(); - - __ block_comment("} exception handler"); - _masm->flush(); #ifndef PRODUCT @@ -342,7 +329,6 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry, UpcallStub* blob = UpcallStub::create(name, &buffer, - exception_handler_offset, receiver, in_ByteSize(frame_data_offset)); #ifndef ABI_ELFv2 diff --git a/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp b/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp index 6f302f747bb..2431df1178d 100644 --- a/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp +++ b/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp @@ -38,6 +38,7 @@ #include "oops/objArrayKlass.hpp" #include "oops/oop.inline.hpp" #include "prims/methodHandles.hpp" +#include "prims/upcallLinker.hpp" #include "runtime/continuation.hpp" #include "runtime/continuationEntry.inline.hpp" #include "runtime/frame.inline.hpp" @@ -4504,6 +4505,20 @@ class StubGenerator: public StubCodeGenerator { #endif // INCLUDE_JFR + // exception handler for upcall stubs + address generate_upcall_stub_exception_handler() { + StubCodeMark mark(this, "StubRoutines", "upcall stub exception handler"); + address start = __ pc(); + + // Native caller has no idea how to handle exceptions, + // so we just crash here. Up to callee to catch exceptions. + __ verify_oop(x10); // return a exception oop in a0 + __ rt_call(CAST_FROM_FN_PTR(address, UpcallLinker::handle_uncaught_exception)); + __ should_not_reach_here(); + + return start; + } + #undef __ // Initialization @@ -4588,6 +4603,8 @@ class StubGenerator: public StubCodeGenerator { StubRoutines::riscv::_method_entry_barrier = generate_method_entry_barrier(); } + StubRoutines::_upcall_stub_exception_handler = generate_upcall_stub_exception_handler(); + StubRoutines::riscv::set_completed(); } diff --git a/src/hotspot/cpu/riscv/upcallLinker_riscv.cpp b/src/hotspot/cpu/riscv/upcallLinker_riscv.cpp index 6d605d716af..de90694945b 100644 --- a/src/hotspot/cpu/riscv/upcallLinker_riscv.cpp +++ b/src/hotspot/cpu/riscv/upcallLinker_riscv.cpp @@ -114,7 +114,7 @@ static void restore_callee_saved_registers(MacroAssembler* _masm, const ABIDescr __ block_comment("} restore_callee_saved_regs "); } -static const int upcall_stub_code_base_size = 2048; +static const int upcall_stub_code_base_size = 1024; static const int upcall_stub_size_per_arg = 16; address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry, @@ -218,6 +218,7 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry, __ block_comment("{ on_entry"); __ la(c_rarg0, Address(sp, frame_data_offset)); + __ movptr(c_rarg1, (intptr_t) receiver); __ rt_call(CAST_FROM_FN_PTR(address, UpcallLinker::on_entry)); __ mv(xthread, x10); __ reinit_heapbase(); @@ -255,9 +256,7 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry, __ block_comment("} argument shuffle"); __ block_comment("{ receiver "); - __ movptr(shuffle_reg, (intptr_t) receiver); - __ resolve_jobject(shuffle_reg, t0, t1); - __ mv(j_rarg0, shuffle_reg); + __ get_vm_result(j_rarg0, xthread); __ block_comment("} receiver "); __ mov_metadata(xmethod, entry); @@ -326,17 +325,6 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry, ////////////////////////////////////////////////////////////////////////////// - __ block_comment("{ exception handler"); - - intptr_t exception_handler_offset = __ pc() - start; - - // Native caller has no idea how to handle exceptions, - // so we just crash here. Up to callee to catch exceptions. - __ verify_oop(x10); // return a exception oop in a0 - __ rt_call(CAST_FROM_FN_PTR(address, UpcallLinker::handle_uncaught_exception)); - __ should_not_reach_here(); - - __ block_comment("} exception handler"); __ flush(); #ifndef PRODUCT @@ -352,7 +340,6 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry, UpcallStub* blob = UpcallStub::create(name, &buffer, - exception_handler_offset, receiver, in_ByteSize(frame_data_offset)); #ifndef PRODUCT diff --git a/src/hotspot/cpu/s390/stubGenerator_s390.cpp b/src/hotspot/cpu/s390/stubGenerator_s390.cpp index a26bcd04de2..64d8d9fa978 100644 --- a/src/hotspot/cpu/s390/stubGenerator_s390.cpp +++ b/src/hotspot/cpu/s390/stubGenerator_s390.cpp @@ -37,6 +37,7 @@ #include "oops/objArrayKlass.hpp" #include "oops/oop.inline.hpp" #include "prims/methodHandles.hpp" +#include "prims/upcallLinker.hpp" #include "runtime/frame.inline.hpp" #include "runtime/handles.inline.hpp" #include "runtime/javaThread.hpp" @@ -3094,6 +3095,21 @@ class StubGenerator: public StubCodeGenerator { #endif // INCLUDE_JFR + // exception handler for upcall stubs + address generate_upcall_stub_exception_handler() { + StubCodeMark mark(this, "StubRoutines", "upcall stub exception handler"); + address start = __ pc(); + + // Native caller has no idea how to handle exceptions, + // so we just crash here. Up to callee to catch exceptions. + __ verify_oop(Z_ARG1); + __ load_const_optimized(Z_R1_scratch, CAST_FROM_FN_PTR(uint64_t, UpcallLinker::handle_uncaught_exception)); + __ call_c(Z_R1_scratch); + __ should_not_reach_here(); + + return start; + } + void generate_initial_stubs() { // Generates all stubs and initializes the entry points. @@ -3174,6 +3190,7 @@ class StubGenerator: public StubCodeGenerator { StubRoutines::zarch::_nmethod_entry_barrier = generate_nmethod_entry_barrier(); } + StubRoutines::_upcall_stub_exception_handler = generate_upcall_stub_exception_handler(); } void generate_compiler_stubs() { diff --git a/src/hotspot/cpu/s390/upcallLinker_s390.cpp b/src/hotspot/cpu/s390/upcallLinker_s390.cpp index b748ec547cc..884f334c806 100644 --- a/src/hotspot/cpu/s390/upcallLinker_s390.cpp +++ b/src/hotspot/cpu/s390/upcallLinker_s390.cpp @@ -114,7 +114,7 @@ static void restore_callee_saved_registers(MacroAssembler* _masm, const ABIDescr __ block_comment("} restore_callee_saved_regs "); } -static const int upcall_stub_code_base_size = 1024; // depends on GC (resolve_jobject) +static const int upcall_stub_code_base_size = 1024; static const int upcall_stub_size_per_arg = 16; // arg save & restore + move address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry, BasicType* in_sig_bt, int total_in_args, @@ -202,6 +202,7 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry, __ block_comment("{ on_entry"); __ load_const_optimized(call_target_address, CAST_FROM_FN_PTR(uint64_t, UpcallLinker::on_entry)); __ z_aghik(Z_ARG1, Z_SP, frame_data_offset); + __ load_const_optimized(Z_ARG2, (intptr_t)receiver); __ call(call_target_address); __ z_lgr(Z_thread, Z_RET); __ block_comment("} on_entry"); @@ -212,8 +213,7 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry, __ block_comment("} argument shuffle"); __ block_comment("{ receiver "); - __ load_const_optimized(Z_ARG1, (intptr_t)receiver); - __ resolve_jobject(Z_ARG1, Z_tmp_1, Z_tmp_2); + __ get_vm_result(Z_ARG1); __ block_comment("} receiver "); __ load_const_optimized(Z_method, (intptr_t)entry); @@ -266,19 +266,6 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry, ////////////////////////////////////////////////////////////////////////////// - __ block_comment("{ exception handler"); - - intptr_t exception_handler_offset = __ pc() - start; - - // Native caller has no idea how to handle exceptions, - // so we just crash here. Up to callee to catch exceptions. - __ verify_oop(Z_ARG1); - __ load_const_optimized(call_target_address, CAST_FROM_FN_PTR(uint64_t, UpcallLinker::handle_uncaught_exception)); - __ call_c(call_target_address); - __ should_not_reach_here(); - - __ block_comment("} exception handler"); - _masm->flush(); #ifndef PRODUCT @@ -293,7 +280,6 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry, UpcallStub* blob = UpcallStub::create(name, &buffer, - exception_handler_offset, receiver, in_ByteSize(frame_data_offset)); #ifndef PRODUCT diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp index e071583b10b..15109a6af1b 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp @@ -32,6 +32,7 @@ #include "gc/shared/gc_globals.hpp" #include "memory/universe.hpp" #include "prims/jvmtiExport.hpp" +#include "prims/upcallLinker.hpp" #include "runtime/arguments.hpp" #include "runtime/javaThread.hpp" #include "runtime/sharedRuntime.hpp" @@ -3887,6 +3888,24 @@ address StubGenerator::generate_throw_exception(const char* name, return stub->entry_point(); } +// exception handler for upcall stubs +address StubGenerator::generate_upcall_stub_exception_handler() { + StubCodeMark mark(this, "StubRoutines", "upcall stub exception handler"); + address start = __ pc(); + + // native caller has no idea how to handle exceptions + // we just crash here. Up to callee to catch exceptions. + __ verify_oop(rax); + __ vzeroupper(); + __ mov(c_rarg0, rax); + __ andptr(rsp, -StackAlignmentInBytes); // align stack as required by ABI + __ subptr(rsp, frame::arg_reg_save_area_bytes); // windows + __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, UpcallLinker::handle_uncaught_exception))); + __ should_not_reach_here(); + + return start; +} + void StubGenerator::create_control_words() { // Round to nearest, 64-bit mode, exceptions masked StubRoutines::x86::_mxcsr_std = 0x1F80; @@ -4039,6 +4058,8 @@ void StubGenerator::generate_final_stubs() { if (UseVectorizedMismatchIntrinsic) { StubRoutines::_vectorizedMismatch = generate_vectorizedMismatch(); } + + StubRoutines::_upcall_stub_exception_handler = generate_upcall_stub_exception_handler(); } void StubGenerator::generate_compiler_stubs() { diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64.hpp b/src/hotspot/cpu/x86/stubGenerator_x86_64.hpp index 3b568ace836..109c98f83bd 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64.hpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64.hpp @@ -565,6 +565,9 @@ class StubGenerator: public StubCodeGenerator { Register arg1 = noreg, Register arg2 = noreg); + // shared exception handler for FFM upcall stubs + address generate_upcall_stub_exception_handler(); + void create_control_words(); // Initialization diff --git a/src/hotspot/cpu/x86/upcallLinker_x86_64.cpp b/src/hotspot/cpu/x86/upcallLinker_x86_64.cpp index dfce6aef52d..395877f1479 100644 --- a/src/hotspot/cpu/x86/upcallLinker_x86_64.cpp +++ b/src/hotspot/cpu/x86/upcallLinker_x86_64.cpp @@ -165,7 +165,7 @@ static void restore_callee_saved_registers(MacroAssembler* _masm, const ABIDescr __ block_comment("} restore_callee_saved_regs "); } -static const int upcall_stub_code_base_size = 2048; +static const int upcall_stub_code_base_size = 1024; static const int upcall_stub_size_per_arg = 16; address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry, @@ -272,6 +272,7 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry, __ block_comment("{ on_entry"); __ vzeroupper(); __ lea(c_rarg0, Address(rsp, frame_data_offset)); + __ movptr(c_rarg1, (intptr_t)receiver); // stack already aligned __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, UpcallLinker::on_entry))); __ movptr(r15_thread, rax); @@ -288,9 +289,7 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry, __ block_comment("} argument shuffle"); __ block_comment("{ receiver "); - __ movptr(rscratch1, (intptr_t)receiver); - __ resolve_jobject(rscratch1, r15_thread, rscratch2); - __ movptr(j_rarg0, rscratch1); + __ get_vm_result(j_rarg0, r15_thread); __ block_comment("} receiver "); __ mov_metadata(rbx, entry); @@ -361,27 +360,8 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry, ////////////////////////////////////////////////////////////////////////////// - __ block_comment("{ exception handler"); - - intptr_t exception_handler_offset = __ pc() - start; - - // TODO: this is always the same, can we bypass and call handle_uncaught_exception directly? - - // native caller has no idea how to handle exceptions - // we just crash here. Up to callee to catch exceptions. - __ verify_oop(rax); - __ vzeroupper(); - __ mov(c_rarg0, rax); - __ andptr(rsp, -StackAlignmentInBytes); // align stack as required by ABI - __ subptr(rsp, frame::arg_reg_save_area_bytes); // windows (not really needed) - __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, UpcallLinker::handle_uncaught_exception))); - __ should_not_reach_here(); - - __ block_comment("} exception handler"); - _masm->flush(); - #ifndef PRODUCT stringStream ss; ss.print("upcall_stub_%s", entry->signature()->as_C_string()); @@ -395,7 +375,6 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry, UpcallStub* blob = UpcallStub::create(name, &buffer, - exception_handler_offset, receiver, in_ByteSize(frame_data_offset)); diff --git a/src/hotspot/share/code/codeBlob.cpp b/src/hotspot/share/code/codeBlob.cpp index 9011bbfc1c2..c49fca717c9 100644 --- a/src/hotspot/share/code/codeBlob.cpp +++ b/src/hotspot/share/code/codeBlob.cpp @@ -738,12 +738,9 @@ void DeoptimizationBlob::print_value_on(outputStream* st) const { // Implementation of UpcallStub -UpcallStub::UpcallStub(const char* name, CodeBuffer* cb, int size, - intptr_t exception_handler_offset, - jobject receiver, ByteSize frame_data_offset) : +UpcallStub::UpcallStub(const char* name, CodeBuffer* cb, int size, jobject receiver, ByteSize frame_data_offset) : RuntimeBlob(name, cb, sizeof(UpcallStub), size, CodeOffsets::frame_never_safe, 0 /* no frame size */, /* oop maps = */ nullptr, /* caller must gc arguments = */ false), - _exception_handler_offset(exception_handler_offset), _receiver(receiver), _frame_data_offset(frame_data_offset) { CodeCache::commit(this); @@ -753,17 +750,14 @@ void* UpcallStub::operator new(size_t s, unsigned size) throw() { return CodeCache::allocate(size, CodeBlobType::NonNMethod); } -UpcallStub* UpcallStub::create(const char* name, CodeBuffer* cb, - intptr_t exception_handler_offset, - jobject receiver, ByteSize frame_data_offset) { +UpcallStub* UpcallStub::create(const char* name, CodeBuffer* cb, jobject receiver, ByteSize frame_data_offset) { ThreadInVMfromUnknown __tiv; // get to VM state in case we block on CodeCache_lock UpcallStub* blob = nullptr; unsigned int size = CodeBlob::allocation_size(cb, sizeof(UpcallStub)); { MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); - blob = new (size) UpcallStub(name, cb, size, - exception_handler_offset, receiver, frame_data_offset); + blob = new (size) UpcallStub(name, cb, size, receiver, frame_data_offset); } // Track memory usage statistic after releasing CodeCache_lock MemoryService::track_code_cache_memory_usage(); diff --git a/src/hotspot/share/code/codeBlob.hpp b/src/hotspot/share/code/codeBlob.hpp index d5618f86622..4e7093bed24 100644 --- a/src/hotspot/share/code/codeBlob.hpp +++ b/src/hotspot/share/code/codeBlob.hpp @@ -733,13 +733,10 @@ class UpcallLinker; class UpcallStub: public RuntimeBlob { friend class UpcallLinker; private: - intptr_t _exception_handler_offset; jobject _receiver; ByteSize _frame_data_offset; - UpcallStub(const char* name, CodeBuffer* cb, int size, - intptr_t exception_handler_offset, - jobject receiver, ByteSize frame_data_offset); + UpcallStub(const char* name, CodeBuffer* cb, int size, jobject receiver, ByteSize frame_data_offset); void* operator new(size_t s, unsigned size) throw(); @@ -754,13 +751,10 @@ class UpcallStub: public RuntimeBlob { FrameData* frame_data_for_frame(const frame& frame) const; public: // Creation - static UpcallStub* create(const char* name, CodeBuffer* cb, - intptr_t exception_handler_offset, - jobject receiver, ByteSize frame_data_offset); + static UpcallStub* create(const char* name, CodeBuffer* cb, jobject receiver, ByteSize frame_data_offset); static void free(UpcallStub* blob); - address exception_handler() { return code_begin() + _exception_handler_offset; } jobject receiver() { return _receiver; } JavaFrameAnchor* jfa_for_frame(const frame& frame) const; diff --git a/src/hotspot/share/prims/upcallLinker.cpp b/src/hotspot/share/prims/upcallLinker.cpp index 1576c011525..8358649ac95 100644 --- a/src/hotspot/share/prims/upcallLinker.cpp +++ b/src/hotspot/share/prims/upcallLinker.cpp @@ -74,7 +74,7 @@ JavaThread* UpcallLinker::maybe_attach_and_get_thread() { } // modelled after JavaCallWrapper::JavaCallWrapper -JavaThread* UpcallLinker::on_entry(UpcallStub::FrameData* context) { +JavaThread* UpcallLinker::on_entry(UpcallStub::FrameData* context, jobject receiver) { JavaThread* thread = maybe_attach_and_get_thread(); guarantee(thread->thread_state() == _thread_in_native, "wrong thread state for upcall"); context->thread = thread; @@ -109,6 +109,8 @@ JavaThread* UpcallLinker::on_entry(UpcallStub::FrameData* context) { debug_only(thread->inc_java_call_counter()); thread->set_active_handles(context->new_handles); // install new handle block and reset Java frame linkage + thread->set_vm_result(JNIHandles::resolve(receiver)); + return thread; } diff --git a/src/hotspot/share/prims/upcallLinker.hpp b/src/hotspot/share/prims/upcallLinker.hpp index 3f8c717e501..529cb7c3911 100644 --- a/src/hotspot/share/prims/upcallLinker.hpp +++ b/src/hotspot/share/prims/upcallLinker.hpp @@ -32,10 +32,9 @@ class JavaThread; class UpcallLinker { private: - static void handle_uncaught_exception(oop exception); static JavaThread* maybe_attach_and_get_thread(); - static JavaThread* on_entry(UpcallStub::FrameData* context); + static JavaThread* on_entry(UpcallStub::FrameData* context, jobject receiver); static void on_exit(UpcallStub::FrameData* context); public: static address make_upcall_stub(jobject mh, Method* entry, @@ -44,6 +43,9 @@ class UpcallLinker { BasicType ret_type, jobject jabi, jobject jconv, bool needs_return_buffer, int ret_buf_size); + + // public for stubGenerator + static void handle_uncaught_exception(oop exception); }; #endif // SHARE_VM_PRIMS_UPCALLLINKER_HPP diff --git a/src/hotspot/share/runtime/sharedRuntime.cpp b/src/hotspot/share/runtime/sharedRuntime.cpp index 31a38443672..536944a61dc 100644 --- a/src/hotspot/share/runtime/sharedRuntime.cpp +++ b/src/hotspot/share/runtime/sharedRuntime.cpp @@ -520,7 +520,7 @@ address SharedRuntime::raw_exception_handler_for_return_address(JavaThread* curr return StubRoutines::catch_exception_entry(); } if (blob != nullptr && blob->is_upcall_stub()) { - return ((UpcallStub*)blob)->exception_handler(); + return StubRoutines::upcall_stub_exception_handler(); } // Interpreted code if (Interpreter::contains(return_address)) { diff --git a/src/hotspot/share/runtime/stubRoutines.cpp b/src/hotspot/share/runtime/stubRoutines.cpp index bea2a934bc6..faeaedac55e 100644 --- a/src/hotspot/share/runtime/stubRoutines.cpp +++ b/src/hotspot/share/runtime/stubRoutines.cpp @@ -188,6 +188,8 @@ JFR_ONLY(address StubRoutines::_jfr_write_checkpoint = nullptr;) JFR_ONLY(RuntimeStub* StubRoutines::_jfr_return_lease_stub = nullptr;) JFR_ONLY(address StubRoutines::_jfr_return_lease = nullptr;) +address StubRoutines::_upcall_stub_exception_handler = nullptr; + // Initialization // // Note: to break cycle with universe initialization, stubs are generated in two phases. diff --git a/src/hotspot/share/runtime/stubRoutines.hpp b/src/hotspot/share/runtime/stubRoutines.hpp index d62c3913f25..77d968263f7 100644 --- a/src/hotspot/share/runtime/stubRoutines.hpp +++ b/src/hotspot/share/runtime/stubRoutines.hpp @@ -269,6 +269,8 @@ class StubRoutines: AllStatic { static address _vector_f_math[VectorSupport::NUM_VEC_SIZES][VectorSupport::NUM_SVML_OP]; static address _vector_d_math[VectorSupport::NUM_VEC_SIZES][VectorSupport::NUM_SVML_OP]; + static address _upcall_stub_exception_handler; + public: // Initialization/Testing static void initialize_initial_stubs(); // must happen before universe::genesis @@ -465,6 +467,11 @@ class StubRoutines: AllStatic { JFR_ONLY(static address jfr_write_checkpoint() { return _jfr_write_checkpoint; }) JFR_ONLY(static address jfr_return_lease() { return _jfr_return_lease; }) + static address upcall_stub_exception_handler() { + assert(_upcall_stub_exception_handler != nullptr, "not implemented"); + return _upcall_stub_exception_handler; + } + static address select_fill_function(BasicType t, bool aligned, const char* &name); // From 4a16d111b16e556f904fb80075631b8439a9482e Mon Sep 17 00:00:00 2001 From: Evgeny Nikitin Date: Tue, 24 Oct 2023 09:16:10 +0000 Subject: [PATCH 085/124] 8318455: Fix the compiler/sharedstubs/SharedTrampolineTest.java and SharedStubToInterpTest.java Reviewed-by: thartmann, shade, eastigeevich --- test/hotspot/jtreg/ProblemList.txt | 2 -- .../jtreg/compiler/sharedstubs/SharedStubToInterpTest.java | 5 +++-- .../jtreg/compiler/sharedstubs/SharedTrampolineTest.java | 6 ++++-- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index 8973b094b4a..fd4119d10c2 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -73,8 +73,6 @@ compiler/vectorapi/VectorLogicalOpIdentityTest.java 8302459 linux-x64,windows-x6 compiler/jvmci/TestUncaughtErrorInCompileMethod.java 8309073 generic-all -compiler/sharedstubs/SharedTrampolineTest.java 8318455 generic-all - compiler/codecache/CheckLargePages.java 8317831 linux-x64 ############################################################################# diff --git a/test/hotspot/jtreg/compiler/sharedstubs/SharedStubToInterpTest.java b/test/hotspot/jtreg/compiler/sharedstubs/SharedStubToInterpTest.java index cd8471317ff..3e578225e53 100644 --- a/test/hotspot/jtreg/compiler/sharedstubs/SharedStubToInterpTest.java +++ b/test/hotspot/jtreg/compiler/sharedstubs/SharedStubToInterpTest.java @@ -51,9 +51,10 @@ public class SharedStubToInterpTest { private final static int ITERATIONS_TO_HEAT_LOOP = 20_000; - private static void runTest(String test) throws Exception { + private static void runTest(String compiler, String test) throws Exception { String testClassName = SharedStubToInterpTest.class.getName() + "$" + test; ArrayList command = new ArrayList(); + command.add(compiler); command.add("-XX:+UnlockDiagnosticVMOptions"); command.add("-Xbatch"); command.add("-XX:+PrintRelocations"); @@ -80,7 +81,7 @@ private static void runTest(String test) throws Exception { public static void main(String[] args) throws Exception { String[] methods = new String[] { "StaticMethodTest", "FinalClassTest", "FinalMethodTest"}; for (String methodName : methods) { - runTest(methodName); + runTest(args[0], methodName); } } diff --git a/test/hotspot/jtreg/compiler/sharedstubs/SharedTrampolineTest.java b/test/hotspot/jtreg/compiler/sharedstubs/SharedTrampolineTest.java index 49158fecd04..1cfa210e3d8 100644 --- a/test/hotspot/jtreg/compiler/sharedstubs/SharedTrampolineTest.java +++ b/test/hotspot/jtreg/compiler/sharedstubs/SharedTrampolineTest.java @@ -28,6 +28,7 @@ * @bug 8280152 * @library /test/lib * + * @requires vm.compiler2.enabled * @requires vm.opt.TieredCompilation == null * @requires os.arch=="aarch64" | os.arch=="riscv64" * @requires vm.debug @@ -46,9 +47,10 @@ public class SharedTrampolineTest { private final static int ITERATIONS_TO_HEAT_LOOP = 20_000; - private static void runTest(String test) throws Exception { + private static void runTest(String compiler, String test) throws Exception { String testClassName = SharedTrampolineTest.class.getName() + "$" + test; ArrayList command = new ArrayList(); + command.add(compiler); command.add("-XX:+UnlockDiagnosticVMOptions"); command.add("-Xbatch"); command.add("-XX:+PrintRelocations"); @@ -72,7 +74,7 @@ private static void runTest(String test) throws Exception { public static void main(String[] args) throws Exception { String[] tests = new String[] {"StaticMethodTest"}; for (String test : tests) { - runTest(test); + runTest(args[0], test); } } From 0baa9ecd76c9be33a1939e47dcae320bc8b65e96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johan=20Sj=C3=B6len?= Date: Tue, 24 Oct 2023 10:08:21 +0000 Subject: [PATCH 086/124] 8318474: Fix memory reporter for thread_count Reviewed-by: mbaesken, azafari --- src/hotspot/share/services/memReporter.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/hotspot/share/services/memReporter.cpp b/src/hotspot/share/services/memReporter.cpp index a277fec5c80..235ce96dba7 100644 --- a/src/hotspot/share/services/memReporter.cpp +++ b/src/hotspot/share/services/memReporter.cpp @@ -236,7 +236,6 @@ void MemSummaryReporter::report_summary_of_type(MEMFLAGS flag, MallocMemory* thread_stack_memory = _malloc_snapshot->by_type(mtThreadStack); const char* scale = current_scale(); // report thread count - assert(ThreadStackTracker::thread_count() == 0, "Not used"); out->print_cr("%27s (threads #" SIZE_FORMAT ")", " ", thread_stack_memory->malloc_count()); out->print("%27s (Stack: " SIZE_FORMAT "%s", " ", amount_in_current_scale(thread_stack_memory->malloc_size()), scale); From 3f446c51564e0358d74d4929dc2fa1b9263ac3b2 Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Tue, 24 Oct 2023 10:12:44 +0000 Subject: [PATCH 087/124] 8318528: Rename TestUnstructuredLocking test Reviewed-by: phh, dholmes --- ...cturedLocking.jasm => TestOutOfOrderUnlocking.jasm} | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) rename test/hotspot/jtreg/runtime/locking/{TestUnstructuredLocking.jasm => TestOutOfOrderUnlocking.jasm} (88%) diff --git a/test/hotspot/jtreg/runtime/locking/TestUnstructuredLocking.jasm b/test/hotspot/jtreg/runtime/locking/TestOutOfOrderUnlocking.jasm similarity index 88% rename from test/hotspot/jtreg/runtime/locking/TestUnstructuredLocking.jasm rename to test/hotspot/jtreg/runtime/locking/TestOutOfOrderUnlocking.jasm index 7e663f78ddc..99abbf6193a 100644 --- a/test/hotspot/jtreg/runtime/locking/TestUnstructuredLocking.jasm +++ b/test/hotspot/jtreg/runtime/locking/TestOutOfOrderUnlocking.jasm @@ -25,17 +25,17 @@ /* * @test id=int * @summary Check that monitorenter A; monitorenter B; monitorexit A; monitorexit B; works - * @compile TestUnstructuredLocking.jasm - * @run main/othervm -Xint TestUnstructuredLocking + * @compile TestOutOfOrderUnlocking.jasm + * @run main/othervm -Xint TestOutOfOrderUnlocking */ /* * @test id=comp * @summary Check that monitorenter A; monitorenter B; monitorexit A; monitorexit B; works, with -Xcomp - * @compile TestUnstructuredLocking.jasm - * @run main/othervm -Xcomp TestUnstructuredLocking + * @compile TestOutOfOrderUnlocking.jasm + * @run main/othervm -Xcomp TestOutOfOrderUnlocking */ -super public class TestUnstructuredLocking version 64:0 { +super public class TestOutOfOrderUnlocking version 64:0 { public static Method main:"([Ljava/lang/String;)V" stack 2 locals 4 { new class java/lang/Object; From 9bfa0829700412291ed26e7bb006b8cb63208870 Mon Sep 17 00:00:00 2001 From: Raffaello Giulietti Date: Tue, 24 Oct 2023 10:20:26 +0000 Subject: [PATCH 088/124] 8318646: Integer#parseInt("") throws empty NumberFormatException message Reviewed-by: redestad, alanb, bpb, darcy, uschindler --- src/java.base/share/classes/java/lang/Integer.java | 6 +++--- src/java.base/share/classes/java/lang/Long.java | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/java.base/share/classes/java/lang/Integer.java b/src/java.base/share/classes/java/lang/Integer.java index 9c19970434c..1c5b3c414ba 100644 --- a/src/java.base/share/classes/java/lang/Integer.java +++ b/src/java.base/share/classes/java/lang/Integer.java @@ -562,7 +562,7 @@ public static int parseInt(String s, int radix) int len = s.length(); if (len == 0) { - throw new NumberFormatException(""); + throw NumberFormatException.forInputString("", radix); } int digit = ~0xFF; int i = 0; @@ -637,7 +637,7 @@ public static int parseInt(CharSequence s, int beginIndex, int endIndex, int rad * and by not updating i anywhere else. */ if (beginIndex == endIndex) { - throw new NumberFormatException(""); + throw NumberFormatException.forInputString("", radix); } int digit = ~0xFF; int i = beginIndex; @@ -827,7 +827,7 @@ public static int parseUnsignedInt(CharSequence s, int beginIndex, int endIndex, * and by not updating i anywhere else. */ if (beginIndex == endIndex) { - throw new NumberFormatException(""); + throw NumberFormatException.forInputString("", radix); } int i = beginIndex; char firstChar = s.charAt(i++); diff --git a/src/java.base/share/classes/java/lang/Long.java b/src/java.base/share/classes/java/lang/Long.java index 481bdbf5569..70bd2d62add 100644 --- a/src/java.base/share/classes/java/lang/Long.java +++ b/src/java.base/share/classes/java/lang/Long.java @@ -592,7 +592,7 @@ public static long parseLong(String s, int radix) int len = s.length(); if (len == 0) { - throw new NumberFormatException(""); + throw NumberFormatException.forInputString("", radix); } int digit = ~0xFF; int i = 0; @@ -667,7 +667,7 @@ public static long parseLong(CharSequence s, int beginIndex, int endIndex, int r * and by not updating i anywhere else. */ if (beginIndex == endIndex) { - throw new NumberFormatException(""); + throw NumberFormatException.forInputString("", radix); } int digit = ~0xFF; // ~0xFF means firstChar char is sign int i = beginIndex; @@ -864,7 +864,7 @@ public static long parseUnsignedLong(CharSequence s, int beginIndex, int endInde * and by not updating i anywhere else. */ if (beginIndex == endIndex) { - throw new NumberFormatException(""); + throw NumberFormatException.forInputString("", radix); } int i = beginIndex; char firstChar = s.charAt(i++); From 5224e979a1cbce1b015e81aa7761743f60357d73 Mon Sep 17 00:00:00 2001 From: Viktor Klang Date: Tue, 24 Oct 2023 10:38:58 +0000 Subject: [PATCH 089/124] 8293713: java/net/httpclient/BufferingSubscriberTest.java fails in timeout, blocked in submission publisher Co-authored-by: Jaikiran Pai Reviewed-by: alanb --- .../share/classes/java/util/concurrent/SubmissionPublisher.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/java.base/share/classes/java/util/concurrent/SubmissionPublisher.java b/src/java.base/share/classes/java/util/concurrent/SubmissionPublisher.java index 4aed7639eb1..b27c57114d6 100644 --- a/src/java.base/share/classes/java/util/concurrent/SubmissionPublisher.java +++ b/src/java.base/share/classes/java/util/concurrent/SubmissionPublisher.java @@ -1059,7 +1059,7 @@ static final class BufferedSubscription final Subscriber subscriber; final BiConsumer, ? super Throwable> onNextHandler; Executor executor; // null on error - Thread waiter; // blocked producer thread + volatile Thread waiter; // blocked producer thread Throwable pendingError; // holds until onError issued BufferedSubscription next; // used only by publisher BufferedSubscription nextRetry; // used only by publisher From bf1a14e3672b7d92b10d16210faf4fd99a860731 Mon Sep 17 00:00:00 2001 From: Jan Lahoda Date: Tue, 24 Oct 2023 12:18:33 +0000 Subject: [PATCH 090/124] 8316470: Incorrect error location for "invalid permits clause" depending on file order Reviewed-by: vromero --- .../com/sun/tools/javac/comp/Attr.java | 202 +++++++++--------- .../javac/sealed/SealedErrorPositions.java | 147 +++++++++++++ 2 files changed, 248 insertions(+), 101 deletions(-) create mode 100644 test/langtools/tools/javac/sealed/SealedErrorPositions.java diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java index 4b44be198d1..189ce74b115 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java @@ -5404,125 +5404,125 @@ void attribClass(ClassSymbol c) throws CompletionFailure { // Get environment current at the point of class definition. Env env = typeEnvs.get(c); - if (c.isSealed() && - !c.isEnum() && - !c.isPermittedExplicit && - c.permitted.isEmpty()) { - log.error(TreeInfo.diagnosticPositionFor(c, env.tree), Errors.SealedClassMustHaveSubclasses); - } - - if (c.isSealed()) { - Set permittedTypes = new HashSet<>(); - boolean sealedInUnnamed = c.packge().modle == syms.unnamedModule || c.packge().modle == syms.noModule; - for (Symbol subTypeSym : c.permitted) { - boolean isTypeVar = false; - if (subTypeSym.type.getTag() == TYPEVAR) { - isTypeVar = true; //error recovery - log.error(TreeInfo.diagnosticPositionFor(subTypeSym, env.tree), - Errors.InvalidPermitsClause(Fragments.IsATypeVariable(subTypeSym.type))); - } - if (subTypeSym.isAnonymous() && !c.isEnum()) { - log.error(TreeInfo.diagnosticPositionFor(subTypeSym, env.tree), Errors.LocalClassesCantExtendSealed(Fragments.Anonymous)); - } - if (permittedTypes.contains(subTypeSym)) { - DiagnosticPosition pos = - env.enclClass.permitting.stream() - .filter(permittedExpr -> TreeInfo.diagnosticPositionFor(subTypeSym, permittedExpr, true) != null) - .limit(2).collect(List.collector()).get(1); - log.error(pos, Errors.InvalidPermitsClause(Fragments.IsDuplicated(subTypeSym.type))); - } else { - permittedTypes.add(subTypeSym); - } - if (sealedInUnnamed) { - if (subTypeSym.packge() != c.packge()) { + // The info.lint field in the envs stored in typeEnvs is deliberately uninitialized, + // because the annotations were not available at the time the env was created. Therefore, + // we look up the environment chain for the first enclosing environment for which the + // lint value is set. Typically, this is the parent env, but might be further if there + // are any envs created as a result of TypeParameter nodes. + Env lintEnv = env; + while (lintEnv.info.lint == null) + lintEnv = lintEnv.next; + + // Having found the enclosing lint value, we can initialize the lint value for this class + env.info.lint = lintEnv.info.lint.augment(c); + + Lint prevLint = chk.setLint(env.info.lint); + JavaFileObject prev = log.useSource(c.sourcefile); + ResultInfo prevReturnRes = env.info.returnResult; + + try { + if (c.isSealed() && + !c.isEnum() && + !c.isPermittedExplicit && + c.permitted.isEmpty()) { + log.error(TreeInfo.diagnosticPositionFor(c, env.tree), Errors.SealedClassMustHaveSubclasses); + } + + if (c.isSealed()) { + Set permittedTypes = new HashSet<>(); + boolean sealedInUnnamed = c.packge().modle == syms.unnamedModule || c.packge().modle == syms.noModule; + for (Symbol subTypeSym : c.permitted) { + boolean isTypeVar = false; + if (subTypeSym.type.getTag() == TYPEVAR) { + isTypeVar = true; //error recovery log.error(TreeInfo.diagnosticPositionFor(subTypeSym, env.tree), - Errors.ClassInUnnamedModuleCantExtendSealedInDiffPackage(c) - ); + Errors.InvalidPermitsClause(Fragments.IsATypeVariable(subTypeSym.type))); } - } else if (subTypeSym.packge().modle != c.packge().modle) { - log.error(TreeInfo.diagnosticPositionFor(subTypeSym, env.tree), - Errors.ClassInModuleCantExtendSealedInDiffModule(c, c.packge().modle) - ); - } - if (subTypeSym == c.type.tsym || types.isSuperType(subTypeSym.type, c.type)) { - log.error(TreeInfo.diagnosticPositionFor(subTypeSym, ((JCClassDecl)env.tree).permitting), - Errors.InvalidPermitsClause( - subTypeSym == c.type.tsym ? - Fragments.MustNotBeSameClass : - Fragments.MustNotBeSupertype(subTypeSym.type) - ) - ); - } else if (!isTypeVar) { - boolean thisIsASuper = types.directSupertypes(subTypeSym.type) - .stream() - .anyMatch(d -> d.tsym == c); - if (!thisIsASuper) { + if (subTypeSym.isAnonymous() && !c.isEnum()) { + log.error(TreeInfo.diagnosticPositionFor(subTypeSym, env.tree), Errors.LocalClassesCantExtendSealed(Fragments.Anonymous)); + } + if (permittedTypes.contains(subTypeSym)) { + DiagnosticPosition pos = + env.enclClass.permitting.stream() + .filter(permittedExpr -> TreeInfo.diagnosticPositionFor(subTypeSym, permittedExpr, true) != null) + .limit(2).collect(List.collector()).get(1); + log.error(pos, Errors.InvalidPermitsClause(Fragments.IsDuplicated(subTypeSym.type))); + } else { + permittedTypes.add(subTypeSym); + } + if (sealedInUnnamed) { + if (subTypeSym.packge() != c.packge()) { + log.error(TreeInfo.diagnosticPositionFor(subTypeSym, env.tree), + Errors.ClassInUnnamedModuleCantExtendSealedInDiffPackage(c) + ); + } + } else if (subTypeSym.packge().modle != c.packge().modle) { log.error(TreeInfo.diagnosticPositionFor(subTypeSym, env.tree), - Errors.InvalidPermitsClause(Fragments.DoesntExtendSealed(subTypeSym.type))); + Errors.ClassInModuleCantExtendSealedInDiffModule(c, c.packge().modle) + ); + } + if (subTypeSym == c.type.tsym || types.isSuperType(subTypeSym.type, c.type)) { + log.error(TreeInfo.diagnosticPositionFor(subTypeSym, ((JCClassDecl)env.tree).permitting), + Errors.InvalidPermitsClause( + subTypeSym == c.type.tsym ? + Fragments.MustNotBeSameClass : + Fragments.MustNotBeSupertype(subTypeSym.type) + ) + ); + } else if (!isTypeVar) { + boolean thisIsASuper = types.directSupertypes(subTypeSym.type) + .stream() + .anyMatch(d -> d.tsym == c); + if (!thisIsASuper) { + log.error(TreeInfo.diagnosticPositionFor(subTypeSym, env.tree), + Errors.InvalidPermitsClause(Fragments.DoesntExtendSealed(subTypeSym.type))); + } } } } - } - List sealedSupers = types.directSupertypes(c.type) - .stream() - .filter(s -> s.tsym.isSealed()) - .map(s -> (ClassSymbol) s.tsym) - .collect(List.collector()); + List sealedSupers = types.directSupertypes(c.type) + .stream() + .filter(s -> s.tsym.isSealed()) + .map(s -> (ClassSymbol) s.tsym) + .collect(List.collector()); - if (sealedSupers.isEmpty()) { - if ((c.flags_field & Flags.NON_SEALED) != 0) { - boolean hasErrorSuper = false; + if (sealedSupers.isEmpty()) { + if ((c.flags_field & Flags.NON_SEALED) != 0) { + boolean hasErrorSuper = false; - hasErrorSuper |= types.directSupertypes(c.type) - .stream() - .anyMatch(s -> s.tsym.kind == Kind.ERR); + hasErrorSuper |= types.directSupertypes(c.type) + .stream() + .anyMatch(s -> s.tsym.kind == Kind.ERR); - ClassType ct = (ClassType) c.type; + ClassType ct = (ClassType) c.type; - hasErrorSuper |= !ct.isCompound() && ct.interfaces_field != ct.all_interfaces_field; + hasErrorSuper |= !ct.isCompound() && ct.interfaces_field != ct.all_interfaces_field; - if (!hasErrorSuper) { - log.error(TreeInfo.diagnosticPositionFor(c, env.tree), Errors.NonSealedWithNoSealedSupertype(c)); + if (!hasErrorSuper) { + log.error(TreeInfo.diagnosticPositionFor(c, env.tree), Errors.NonSealedWithNoSealedSupertype(c)); + } + } + } else { + if (c.isDirectlyOrIndirectlyLocal() && !c.isEnum()) { + log.error(TreeInfo.diagnosticPositionFor(c, env.tree), Errors.LocalClassesCantExtendSealed(c.isAnonymous() ? Fragments.Anonymous : Fragments.Local)); } - } - } else { - if (c.isDirectlyOrIndirectlyLocal() && !c.isEnum()) { - log.error(TreeInfo.diagnosticPositionFor(c, env.tree), Errors.LocalClassesCantExtendSealed(c.isAnonymous() ? Fragments.Anonymous : Fragments.Local)); - } - if (!c.type.isCompound()) { - for (ClassSymbol supertypeSym : sealedSupers) { - if (!supertypeSym.permitted.contains(c.type.tsym)) { - log.error(TreeInfo.diagnosticPositionFor(c.type.tsym, env.tree), Errors.CantInheritFromSealed(supertypeSym)); + if (!c.type.isCompound()) { + for (ClassSymbol supertypeSym : sealedSupers) { + if (!supertypeSym.permitted.contains(c.type.tsym)) { + log.error(TreeInfo.diagnosticPositionFor(c.type.tsym, env.tree), Errors.CantInheritFromSealed(supertypeSym)); + } + } + if (!c.isNonSealed() && !c.isFinal() && !c.isSealed()) { + log.error(TreeInfo.diagnosticPositionFor(c, env.tree), + c.isInterface() ? + Errors.NonSealedOrSealedExpected : + Errors.NonSealedSealedOrFinalExpected); } - } - if (!c.isNonSealed() && !c.isFinal() && !c.isSealed()) { - log.error(TreeInfo.diagnosticPositionFor(c, env.tree), - c.isInterface() ? - Errors.NonSealedOrSealedExpected : - Errors.NonSealedSealedOrFinalExpected); } } - } - // The info.lint field in the envs stored in typeEnvs is deliberately uninitialized, - // because the annotations were not available at the time the env was created. Therefore, - // we look up the environment chain for the first enclosing environment for which the - // lint value is set. Typically, this is the parent env, but might be further if there - // are any envs created as a result of TypeParameter nodes. - Env lintEnv = env; - while (lintEnv.info.lint == null) - lintEnv = lintEnv.next; - - // Having found the enclosing lint value, we can initialize the lint value for this class - env.info.lint = lintEnv.info.lint.augment(c); - - Lint prevLint = chk.setLint(env.info.lint); - JavaFileObject prev = log.useSource(c.sourcefile); - ResultInfo prevReturnRes = env.info.returnResult; - - try { deferredLintHandler.flush(env.tree); env.info.returnResult = null; // java.lang.Enum may not be subclassed by a non-enum diff --git a/test/langtools/tools/javac/sealed/SealedErrorPositions.java b/test/langtools/tools/javac/sealed/SealedErrorPositions.java new file mode 100644 index 00000000000..8140dbdceb0 --- /dev/null +++ b/test/langtools/tools/javac/sealed/SealedErrorPositions.java @@ -0,0 +1,147 @@ +/* + * 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 8316470 + * @summary Verify correct source file is set while reporting errors for sealing from Attr + * @library /tools/lib + * @modules jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.main + * jdk.compiler/com.sun.tools.javac.util + * @build toolbox.ToolBox toolbox.JavacTask + * @run main SealedErrorPositions +*/ + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; + +import toolbox.TestRunner; +import toolbox.JavacTask; +import toolbox.Task; +import toolbox.ToolBox; + +public class SealedErrorPositions extends TestRunner { + + ToolBox tb; + + public static void main(String... args) throws Exception { + new SealedErrorPositions().runTests(); + } + + SealedErrorPositions() { + super(System.err); + tb = new ToolBox(); + } + + public void runTests() throws Exception { + runTests(m -> new Object[] { Paths.get(m.getName()) }); + } + + @Test + public void testDoesNotExtendErrorPosition(Path base) throws IOException { + Path current = base.resolve("."); + Path src = current.resolve("src"); + tb.writeJavaFiles(src, + """ + package test; + sealed class C permits A, B { } + """, + """ + package test; + final class A extends C { } + """, + """ + package test; + final class B { } + """); + Path test = src.resolve("test"); + Path classes = current.resolve("classes"); + + Files.createDirectories(classes); + + var log = + new JavacTask(tb) + .options("-XDrawDiagnostics", + "-implicit:none", + "-sourcepath", src.toString()) + .outdir(classes) + .files(test.resolve("A.java")) + .run(Task.Expect.FAIL) + .writeAll() + .getOutputLines(Task.OutputKind.DIRECT); + + List expectedErrors = List.of( + "C.java:2:27: compiler.err.invalid.permits.clause: (compiler.misc.doesnt.extend.sealed: test.B)", + "1 error"); + + if (!expectedErrors.equals(log)) { + throw new AssertionError("Incorrect errors, expected: " + expectedErrors + + ", actual: " + log); + } + } + + @Test + public void testEmptyImplicitPermitsErrorPosition(Path base) throws IOException { + Path current = base.resolve("."); + Path src = current.resolve("src"); + tb.writeJavaFiles(src, + """ + package test; + sealed class C { } + """, + """ + package test; + final class A extends C { } + """); + Path test = src.resolve("test"); + Path classes = current.resolve("classes"); + + Files.createDirectories(classes); + + var log = + new JavacTask(tb) + .options("-XDrawDiagnostics", + "-implicit:none", + "-sourcepath", src.toString()) + .outdir(classes) + .files(test.resolve("A.java")) + .run(Task.Expect.FAIL) + .writeAll() + .getOutputLines(Task.OutputKind.DIRECT); + + List expectedErrors = List.of( + "C.java:2:8: compiler.err.sealed.class.must.have.subclasses", + "A.java:2:7: compiler.err.cant.inherit.from.sealed: test.C", + "2 errors"); + + if (!expectedErrors.equals(log)) { + throw new AssertionError("Incorrect errors, expected: " + expectedErrors + + ", actual: " + log); + } + } + +} From d4b761242d91aa1bcadc438cce0a9465c0f8b23d Mon Sep 17 00:00:00 2001 From: Varada M Date: Tue, 24 Oct 2023 12:24:04 +0000 Subject: [PATCH 091/124] 8318240: [AIX] Cleaners.java test failure Reviewed-by: mbaesken, asteiner --- .../classes/sun/security/jgss/wrapper/SunNativeProvider.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/java.security.jgss/share/classes/sun/security/jgss/wrapper/SunNativeProvider.java b/src/java.security.jgss/share/classes/sun/security/jgss/wrapper/SunNativeProvider.java index 78e93e9836c..6eb61cd8b9e 100644 --- a/src/java.security.jgss/share/classes/sun/security/jgss/wrapper/SunNativeProvider.java +++ b/src/java.security.jgss/share/classes/sun/security/jgss/wrapper/SunNativeProvider.java @@ -104,6 +104,9 @@ public HashMap run() { // Full path needed, DLL is in jre/bin StaticProperty.javaHome() + "\\bin\\sspi_bridge.dll", }; + case AIX -> new String[]{ + "/opt/freeware/lib64/libgssapi_krb5.so", + }; default -> new String[0]; }; } else { From 21d8a4725fa89803216a96d4716a2cb0b4b1820c Mon Sep 17 00:00:00 2001 From: Leo Korinth Date: Tue, 24 Oct 2023 12:31:59 +0000 Subject: [PATCH 092/124] 8318701: Fix copyright year Reviewed-by: egahlin --- src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordedEvent.java | 2 +- test/jdk/jdk/jfr/jvm/TestEventWriterLog.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordedEvent.java b/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordedEvent.java index 9ec117ffc88..7ffcaabd57c 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordedEvent.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/consumer/RecordedEvent.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2024, 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 diff --git a/test/jdk/jdk/jfr/jvm/TestEventWriterLog.java b/test/jdk/jdk/jfr/jvm/TestEventWriterLog.java index 9f11ee04863..e152b00acae 100644 --- a/test/jdk/jdk/jfr/jvm/TestEventWriterLog.java +++ b/test/jdk/jdk/jfr/jvm/TestEventWriterLog.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 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 From d1077d6f141d6e51f697271286833e01013080d6 Mon Sep 17 00:00:00 2001 From: Jorn Vernee Date: Tue, 24 Oct 2023 12:33:59 +0000 Subject: [PATCH 093/124] 8316046: x64 platforms unecessarily save xmm16-31 when UseAVX >= 3 Reviewed-by: mcimadamore, djelinski --- .../jdk/internal/foreign/abi/x64/sysv/CallArranger.java | 4 +++- .../jdk/internal/foreign/abi/x64/windows/CallArranger.java | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/java.base/share/classes/jdk/internal/foreign/abi/x64/sysv/CallArranger.java b/src/java.base/share/classes/jdk/internal/foreign/abi/x64/sysv/CallArranger.java index 75e8d0926a1..9dadc54b53b 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/abi/x64/sysv/CallArranger.java +++ b/src/java.base/share/classes/jdk/internal/foreign/abi/x64/sysv/CallArranger.java @@ -76,7 +76,9 @@ public class CallArranger { new VMStorage[] { xmm0, xmm1 }, 2, new VMStorage[] { r10, r11 }, - new VMStorage[] { xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15 }, + new VMStorage[] { xmm8, xmm9, xmm10, xmm11, xmm12, xmm13, xmm14, xmm15, + xmm16, xmm17, xmm18, xmm19, xmm20, xmm21, xmm22, xmm23, + xmm24, xmm25, xmm26, xmm27, xmm28, xmm29, xmm30, xmm31 }, 16, 0, //no shadow space r10, r11 // scratch 1 & 2 diff --git a/src/java.base/share/classes/jdk/internal/foreign/abi/x64/windows/CallArranger.java b/src/java.base/share/classes/jdk/internal/foreign/abi/x64/windows/CallArranger.java index 4d4ad65b1c6..dc66ba9832c 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/abi/x64/windows/CallArranger.java +++ b/src/java.base/share/classes/jdk/internal/foreign/abi/x64/windows/CallArranger.java @@ -66,7 +66,9 @@ public class CallArranger { new VMStorage[] { xmm0 }, 0, new VMStorage[] { rax, r10, r11 }, - new VMStorage[] { xmm4, xmm5 }, + new VMStorage[] { xmm4, xmm5, + xmm16, xmm17, xmm18, xmm19, xmm20, xmm21, xmm22, xmm23, + xmm24, xmm25, xmm26, xmm27, xmm28, xmm29, xmm30, xmm31 }, 16, 32, r10, r11 // scratch 1 & 2 From f9795d0d09a82cafb3e79ad8667e505c194d745b Mon Sep 17 00:00:00 2001 From: Hamlin Li Date: Tue, 24 Oct 2023 13:17:28 +0000 Subject: [PATCH 094/124] 8318222: RISC-V: C2 CmpU3 8318223: RISC-V: C2 CmpUL3 Reviewed-by: rehn, fyang --- .../cpu/riscv/macroAssembler_riscv.cpp | 29 ++++++++++++--- .../cpu/riscv/macroAssembler_riscv.hpp | 6 ++++ src/hotspot/cpu/riscv/riscv.ad | 36 +++++++++++++++++++ 3 files changed, 67 insertions(+), 4 deletions(-) diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp index 060284c0cd4..7548408c9a3 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp @@ -4404,8 +4404,8 @@ void MacroAssembler::sign_extend(Register dst, Register src, int bits) { } } -void MacroAssembler::cmp_l2i(Register dst, Register src1, Register src2, Register tmp) -{ +void MacroAssembler::cmp_x2i(Register dst, Register src1, Register src2, + Register tmp, bool is_signed) { if (src1 == src2) { mv(dst, zr); return; @@ -4424,14 +4424,35 @@ void MacroAssembler::cmp_l2i(Register dst, Register src1, Register src2, Registe } // installs 1 if gt else 0 - slt(dst, right, left); + if (is_signed) { + slt(dst, right, left); + } else { + sltu(dst, right, left); + } bnez(dst, done); - slt(dst, left, right); + if (is_signed) { + slt(dst, left, right); + } else { + sltu(dst, left, right); + } // dst = -1 if lt; else if eq , dst = 0 neg(dst, dst); bind(done); } +void MacroAssembler::cmp_l2i(Register dst, Register src1, Register src2, Register tmp) +{ + cmp_x2i(dst, src1, src2, tmp); +} + +void MacroAssembler::cmp_ul2i(Register dst, Register src1, Register src2, Register tmp) { + cmp_x2i(dst, src1, src2, tmp, false); +} + +void MacroAssembler::cmp_uw2i(Register dst, Register src1, Register src2, Register tmp) { + cmp_x2i(dst, src1, src2, tmp, false); +} + // The java_calling_convention describes stack locations as ideal slots on // a frame with no abi restrictions. Since we must observe abi restrictions // (like the placement of the register window) the slots must be biased by diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp index 9c664d9d278..c5df08f47fa 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp @@ -1394,11 +1394,17 @@ class MacroAssembler: public Assembler { void zero_extend(Register dst, Register src, int bits); void sign_extend(Register dst, Register src, int bits); +private: + void cmp_x2i(Register dst, Register src1, Register src2, Register tmp, bool is_signed = true); + +public: // compare src1 and src2 and get -1/0/1 in dst. // if [src1 > src2], dst = 1; // if [src1 == src2], dst = 0; // if [src1 < src2], dst = -1; void cmp_l2i(Register dst, Register src1, Register src2, Register tmp = t0); + void cmp_ul2i(Register dst, Register src1, Register src2, Register tmp = t0); + void cmp_uw2i(Register dst, Register src1, Register src2, Register tmp = t0); // support for argument shuffling void move32_64(VMRegPair src, VMRegPair dst, Register tmp = t0); diff --git a/src/hotspot/cpu/riscv/riscv.ad b/src/hotspot/cpu/riscv/riscv.ad index 553c189891a..4d9621b328e 100644 --- a/src/hotspot/cpu/riscv/riscv.ad +++ b/src/hotspot/cpu/riscv/riscv.ad @@ -8641,6 +8641,42 @@ instruct cmpL3_reg_reg(iRegINoSp dst, iRegL op1, iRegL op2) ins_pipe(pipe_class_default); %} +instruct cmpUL3_reg_reg(iRegINoSp dst, iRegL op1, iRegL op2) +%{ + match(Set dst (CmpUL3 op1 op2)); + + ins_cost(ALU_COST * 3 + BRANCH_COST); + format %{ "sltu $dst, $op2, $op1\t#@cmpUL3_reg_reg\n\t" + "bnez $dst, done\n\t" + "sltu $dst, $op1, $op2\n\t" + "neg $dst, $dst\t#@cmpUL3_reg_reg" + %} + ins_encode %{ + __ cmp_ul2i(t0, as_Register($op1$$reg), as_Register($op2$$reg)); + __ mv(as_Register($dst$$reg), t0); + %} + + ins_pipe(pipe_class_default); +%} + +instruct cmpU3_reg_reg(iRegINoSp dst, iRegI op1, iRegI op2) +%{ + match(Set dst (CmpU3 op1 op2)); + + ins_cost(ALU_COST * 3 + BRANCH_COST); + format %{ "sltu $dst, $op2, $op1\t#@cmpU3_reg_reg\n\t" + "bnez $dst, done\n\t" + "sltu $dst, $op1, $op2\n\t" + "neg $dst, $dst\t#@cmpU3_reg_reg" + %} + ins_encode %{ + __ cmp_uw2i(t0, as_Register($op1$$reg), as_Register($op2$$reg)); + __ mv(as_Register($dst$$reg), t0); + %} + + ins_pipe(pipe_class_default); +%} + instruct cmpLTMask_reg_reg(iRegINoSp dst, iRegI p, iRegI q) %{ match(Set dst (CmpLTMask p q)); From 8879c78d62e3c1f325def56d131f62c479bfdaa9 Mon Sep 17 00:00:00 2001 From: Doug Simon Date: Tue, 24 Oct 2023 13:32:26 +0000 Subject: [PATCH 095/124] 8317689: [JVMCI] include error message when CreateJavaVM in libgraal fails Reviewed-by: phofer, thartmann, never --- src/hotspot/share/compiler/compileBroker.cpp | 4 +++- src/hotspot/share/jvmci/jvmciEnv.cpp | 21 +++++++++++++------- src/hotspot/share/jvmci/jvmciEnv.hpp | 7 +++++++ src/hotspot/share/jvmci/jvmciRuntime.cpp | 6 ++++-- src/hotspot/share/jvmci/jvmciRuntime.hpp | 6 ++++-- src/hotspot/share/prims/whitebox.cpp | 2 +- 6 files changed, 33 insertions(+), 13 deletions(-) diff --git a/src/hotspot/share/compiler/compileBroker.cpp b/src/hotspot/share/compiler/compileBroker.cpp index f265271857d..22a9eb4dcaa 100644 --- a/src/hotspot/share/compiler/compileBroker.cpp +++ b/src/hotspot/share/compiler/compileBroker.cpp @@ -2211,7 +2211,9 @@ void CompileBroker::invoke_compiler_on_method(CompileTask* task) { } else { JVMCIEnv env(thread, &compile_state, __FILE__, __LINE__); if (env.init_error() != JNI_OK) { - failure_reason = os::strdup(err_msg("Error attaching to libjvmci (err: %d)", env.init_error()), mtJVMCI); + const char* msg = env.init_error_msg(); + failure_reason = os::strdup(err_msg("Error attaching to libjvmci (err: %d, %s)", + env.init_error(), msg == nullptr ? "unknown" : msg), mtJVMCI); bool reason_on_C_heap = true; // In case of JNI_ENOMEM, there's a good chance a subsequent attempt to create libjvmci or attach to it // might succeed. Other errors most likely indicate a non-recoverable error in the JVMCI runtime. diff --git a/src/hotspot/share/jvmci/jvmciEnv.cpp b/src/hotspot/share/jvmci/jvmciEnv.cpp index bab3de8c335..24af7715a5b 100644 --- a/src/hotspot/share/jvmci/jvmciEnv.cpp +++ b/src/hotspot/share/jvmci/jvmciEnv.cpp @@ -147,13 +147,14 @@ void JVMCIEnv::init_env_mode_runtime(JavaThread* thread, JNIEnv* parent_env) { _is_hotspot = false; _runtime = JVMCI::compiler_runtime(thread); - _env = _runtime->init_shared_library_javavm(&_init_error); + _env = _runtime->init_shared_library_javavm(&_init_error, &_init_error_msg); if (_env != nullptr) { // Creating the JVMCI shared library VM also attaches the current thread _detach_on_close = true; } else if (_init_error != JNI_OK) { // Caller creating this JVMCIEnv must handle the error. - JVMCI_event_1("[%s:%d] Error creating libjvmci (err: %d)", _file, _line, _init_error); + JVMCI_event_1("[%s:%d] Error creating libjvmci (err: %d, %s)", _file, _line, + _init_error, _init_error_msg == nullptr ? "unknown" : _init_error_msg); return; } else { _runtime->GetEnv(thread, (void**)&parent_env, JNI_VERSION_1_2); @@ -195,17 +196,17 @@ void JVMCIEnv::init_env_mode_runtime(JavaThread* thread, JNIEnv* parent_env) { } JVMCIEnv::JVMCIEnv(JavaThread* thread, JVMCICompileState* compile_state, const char* file, int line): - _throw_to_caller(false), _file(file), _line(line), _init_error(JNI_OK), _compile_state(compile_state) { + _throw_to_caller(false), _file(file), _line(line), _init_error(JNI_OK), _init_error_msg(nullptr), _compile_state(compile_state) { init_env_mode_runtime(thread, nullptr); } JVMCIEnv::JVMCIEnv(JavaThread* thread, const char* file, int line): - _throw_to_caller(false), _file(file), _line(line), _init_error(JNI_OK), _compile_state(nullptr) { + _throw_to_caller(false), _file(file), _line(line), _init_error(JNI_OK), _init_error_msg(nullptr), _compile_state(nullptr) { init_env_mode_runtime(thread, nullptr); } JVMCIEnv::JVMCIEnv(JavaThread* thread, JNIEnv* parent_env, const char* file, int line): - _throw_to_caller(true), _file(file), _line(line), _init_error(JNI_OK), _compile_state(nullptr) { + _throw_to_caller(true), _file(file), _line(line), _init_error(JNI_OK), _init_error_msg(nullptr), _compile_state(nullptr) { assert(parent_env != nullptr, "npe"); init_env_mode_runtime(thread, parent_env); assert(_env == nullptr || parent_env == _env, "mismatched JNIEnvironment"); @@ -218,6 +219,7 @@ void JVMCIEnv::init(JavaThread* thread, bool is_hotspot, const char* file, int l _file = file; _line = line; _init_error = JNI_OK; + _init_error_msg = nullptr; if (is_hotspot) { _env = nullptr; _pop_frame_on_close = false; @@ -237,7 +239,8 @@ void JVMCIEnv::check_init(JVMCI_TRAPS) { if (_init_error == JNI_ENOMEM) { JVMCI_THROW_MSG(OutOfMemoryError, "JNI_ENOMEM creating or attaching to libjvmci"); } - JVMCI_THROW_MSG(InternalError, err_msg("Error creating or attaching to libjvmci (err: %d)", _init_error)); + JVMCI_THROW_MSG(InternalError, err_msg("Error creating or attaching to libjvmci (err: %d, description: %s)", + _init_error, _init_error_msg == nullptr ? "unknown" : _init_error_msg)); } void JVMCIEnv::check_init(TRAPS) { @@ -247,7 +250,8 @@ void JVMCIEnv::check_init(TRAPS) { if (_init_error == JNI_ENOMEM) { THROW_MSG(vmSymbols::java_lang_OutOfMemoryError(), "JNI_ENOMEM creating or attaching to libjvmci"); } - THROW_MSG(vmSymbols::java_lang_OutOfMemoryError(), err_msg("Error creating or attaching to libjvmci (err: %d)", _init_error)); + THROW_MSG(vmSymbols::java_lang_OutOfMemoryError(), err_msg("Error creating or attaching to libjvmci (err: %d, description: %s)", + _init_error, _init_error_msg == nullptr ? "unknown" : _init_error_msg)); } // Prints a pending exception (if any) and its stack trace to st. @@ -572,6 +576,9 @@ jboolean JVMCIEnv::transfer_pending_exception(JavaThread* THREAD, JVMCIEnv* peer } JVMCIEnv::~JVMCIEnv() { + if (_init_error_msg != nullptr) { + os::free((void*) _init_error_msg); + } if (_init_error != JNI_OK) { return; } diff --git a/src/hotspot/share/jvmci/jvmciEnv.hpp b/src/hotspot/share/jvmci/jvmciEnv.hpp index 59600b97fe1..ace0cc53352 100644 --- a/src/hotspot/share/jvmci/jvmciEnv.hpp +++ b/src/hotspot/share/jvmci/jvmciEnv.hpp @@ -172,6 +172,7 @@ class JVMCIEnv : public ResourceObj { int _init_error; // JNI code returned when creating or attaching to a libjvmci isolate. // If not JNI_OK, the JVMCIEnv is invalid and should not be used apart from // calling init_error(). + const char* _init_error_msg; // Message for _init_error if available. C heap allocated. // Translates an exception on the HotSpot heap (i.e., hotspot_env) to an exception on // the shared library heap (i.e., jni_env). The translation includes the stack and cause(s) of `throwable`. @@ -217,6 +218,12 @@ class JVMCIEnv : public ResourceObj { return _init_error; } + // Gets a message describing a non-zero init_error(). + // Valid as long as this JVMCIEnv is valid. + const char* init_error_msg() { + return _init_error_msg; + } + // Checks the value of init_error() and throws an exception in `JVMCI_TRAPS` // (which must not be this) if it is not JNI_OK. void check_init(JVMCI_TRAPS); diff --git a/src/hotspot/share/jvmci/jvmciRuntime.cpp b/src/hotspot/share/jvmci/jvmciRuntime.cpp index 68177fa8acd..226c4f5dea1 100644 --- a/src/hotspot/share/jvmci/jvmciRuntime.cpp +++ b/src/hotspot/share/jvmci/jvmciRuntime.cpp @@ -1253,7 +1253,7 @@ bool JVMCIRuntime::detach_thread(JavaThread* thread, const char* reason, bool ca return destroyed_javavm; } -JNIEnv* JVMCIRuntime::init_shared_library_javavm(int* create_JavaVM_err) { +JNIEnv* JVMCIRuntime::init_shared_library_javavm(int* create_JavaVM_err, const char** err_msg) { MutexLocker locker(_lock); JavaVM* javaVM = _shared_library_javavm; if (javaVM == nullptr) { @@ -1280,7 +1280,7 @@ JNIEnv* JVMCIRuntime::init_shared_library_javavm(int* create_JavaVM_err) { JavaVMInitArgs vm_args; vm_args.version = JNI_VERSION_1_2; vm_args.ignoreUnrecognized = JNI_TRUE; - JavaVMOption options[5]; + JavaVMOption options[6]; jlong javaVM_id = 0; // Protocol: JVMCI shared library JavaVM should support a non-standard "_javavm_id" @@ -1297,6 +1297,8 @@ JNIEnv* JVMCIRuntime::init_shared_library_javavm(int* create_JavaVM_err) { options[3].extraInfo = (void*) _fatal; options[4].optionString = (char*) "_fatal_log"; options[4].extraInfo = (void*) _fatal_log; + options[5].optionString = (char*) "_createvm_errorstr"; + options[5].extraInfo = (void*) err_msg; vm_args.version = JNI_VERSION_1_2; vm_args.options = options; diff --git a/src/hotspot/share/jvmci/jvmciRuntime.hpp b/src/hotspot/share/jvmci/jvmciRuntime.hpp index a3f464cd724..d3898be4ce0 100644 --- a/src/hotspot/share/jvmci/jvmciRuntime.hpp +++ b/src/hotspot/share/jvmci/jvmciRuntime.hpp @@ -280,8 +280,10 @@ class JVMCIRuntime: public CHeapObj { // If the JavaVM was created by this call, then the thread-local JNI // interface pointer for the JavaVM is returned otherwise null is returned. // If this method tried to create the JavaVM but failed, the error code returned - // by JNI_CreateJavaVM is returned in create_JavaVM_err. - JNIEnv* init_shared_library_javavm(int* create_JavaVM_err); + // by JNI_CreateJavaVM is returned in create_JavaVM_err and, if available, an + // error message is malloc'ed and assigned to err_msg. The caller is responsible + // for freeing err_msg. + JNIEnv* init_shared_library_javavm(int* create_JavaVM_err, const char** err_msg); // Determines if the JVMCI shared library JavaVM exists for this runtime. bool has_shared_library_javavm() { return _shared_library_javavm != nullptr; } diff --git a/src/hotspot/share/prims/whitebox.cpp b/src/hotspot/share/prims/whitebox.cpp index e86217f8de6..e0f1b071c30 100644 --- a/src/hotspot/share/prims/whitebox.cpp +++ b/src/hotspot/share/prims/whitebox.cpp @@ -381,7 +381,7 @@ WB_ENTRY(jboolean, WB_IsGCSupportedByJVMCICompiler(JNIEnv* env, jobject o, jint if (EnableJVMCI) { // Enter the JVMCI env that will be used by the CompileBroker. JVMCIEnv jvmciEnv(thread, __FILE__, __LINE__); - return jvmciEnv.runtime()->is_gc_supported(&jvmciEnv, (CollectedHeap::Name)name); + return jvmciEnv.init_error() == JNI_OK && jvmciEnv.runtime()->is_gc_supported(&jvmciEnv, (CollectedHeap::Name)name); } #endif return false; From e67550cfec4dbd1c8c2c9869dda34fa09a5c274b Mon Sep 17 00:00:00 2001 From: Claes Redestad Date: Tue, 24 Oct 2023 13:32:41 +0000 Subject: [PATCH 096/124] 8318509: x86 count_positives intrinsic broken for -XX:AVX3Threshold=0 Reviewed-by: thartmann, jbhateja, epeter --- src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp | 26 ++-- .../intrinsics/string/TestCountPositives.java | 123 +++++++++++------- .../intrinsics/string/TestHasNegatives.java | 97 ++++++++------ 3 files changed, 153 insertions(+), 93 deletions(-) diff --git a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp index 2154601f2f2..29413e5457c 100644 --- a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp @@ -3853,13 +3853,11 @@ void C2_MacroAssembler::count_positives(Register ary1, Register len, VM_Version::supports_bmi2()) { Label test_64_loop, test_tail, BREAK_LOOP; - Register tmp3_aliased = len; - movl(tmp1, len); vpxor(vec2, vec2, vec2, Assembler::AVX_512bit); - andl(tmp1, 64 - 1); // tail count (in chars) 0x3F - andl(len, ~(64 - 1)); // vector count (in chars) + andl(tmp1, 0x0000003f); // tail count (in chars) 0x3F + andl(len, 0xffffffc0); // vector count (in chars) jccb(Assembler::zero, test_tail); lea(ary1, Address(ary1, len, Address::times_1)); @@ -3879,12 +3877,17 @@ void C2_MacroAssembler::count_positives(Register ary1, Register len, testl(tmp1, -1); jcc(Assembler::zero, DONE); + + // check the tail for absense of negatives // ~(~0 << len) applied up to two times (for 32-bit scenario) #ifdef _LP64 - mov64(tmp3_aliased, 0xFFFFFFFFFFFFFFFF); - shlxq(tmp3_aliased, tmp3_aliased, tmp1); - notq(tmp3_aliased); - kmovql(mask2, tmp3_aliased); + { + Register tmp3_aliased = len; + mov64(tmp3_aliased, 0xFFFFFFFFFFFFFFFF); + shlxq(tmp3_aliased, tmp3_aliased, tmp1); + notq(tmp3_aliased); + kmovql(mask2, tmp3_aliased); + } #else Label k_init; jmp(k_init); @@ -3916,8 +3919,13 @@ void C2_MacroAssembler::count_positives(Register ary1, Register len, ktestq(mask1, mask2); jcc(Assembler::zero, DONE); + // do a full check for negative registers in the tail + movl(len, tmp1); // tmp1 holds low 6-bit from original len; + // ary1 already pointing to the right place + jmpb(TAIL_START); + bind(BREAK_LOOP); - // At least one byte in the last 64 bytes is negative. + // At least one byte in the last 64 byte block was negative. // Set up to look at the last 64 bytes as if they were a tail lea(ary1, Address(ary1, len, Address::times_1)); addptr(result, len); diff --git a/test/hotspot/jtreg/compiler/intrinsics/string/TestCountPositives.java b/test/hotspot/jtreg/compiler/intrinsics/string/TestCountPositives.java index afc308c37dd..76ef4766159 100644 --- a/test/hotspot/jtreg/compiler/intrinsics/string/TestCountPositives.java +++ b/test/hotspot/jtreg/compiler/intrinsics/string/TestCountPositives.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 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,88 +21,121 @@ * questions. */ -package compiler.intrinsics.string; - /* * @test - * @bug 8999999 + * @bug 8281146 * @summary Validates StringCoding.countPositives intrinsic with a small range of tests. + * @key randomness * @library /compiler/patches + * @library /test/lib * * @build java.base/java.lang.Helper * @run main compiler.intrinsics.string.TestCountPositives */ +/* + * @test + * @bug 8281146 8318509 + * @summary Validates StringCoding.countPositives intrinsic for AVX3 works with and without + * AVX3Threshold=0 + * @key randomness + * @library /compiler/patches + * @library /test/lib + * + * @build java.base/java.lang.Helper + * @requires vm.cpu.features ~= ".*avx512.*" + * @run main/othervm/timeout=1200 -XX:UseAVX=3 compiler.intrinsics.string.TestCountPositives + * @run main/othervm/timeout=1200 -XX:UseAVX=3 -XX:+UnlockDiagnosticVMOptions -XX:AVX3Threshold=0 compiler.intrinsics.string.TestCountPositives + */ +/** + * This test was derived from compiler.intrinsics.string.TestHasNegatives + */ +package compiler.intrinsics.string; + +import java.lang.Helper; +import java.util.Random; +import java.util.stream.IntStream; + +import jdk.test.lib.Utils; public class TestCountPositives { - private static byte[] tBa = new byte[4096 + 16]; + private static byte[] bytes = new byte[4096 + 32]; + + private static final Random RANDOM = Utils.getRandomInstance(); /** * Completely initialize the test array, preparing it for tests of the * StringCoding.hasNegatives method with a given array segment offset, - * length, and number of negative bytes. + * length, and number of negative bytes. The lowest index that will be + * negative is marked by negOffset */ - public static void initialize(int off, int len, int neg) { - assert (len + off <= tBa.length); + public static void initialize(int off, int len, int neg, int negOffset) { + assert (len + off <= bytes.length); // insert "canary" (negative) values before offset for (int i = 0; i < off; ++i) { - tBa[i] = (byte) (((i + 15) & 0x7F) | 0x80); + bytes[i] = (byte) (((i + 15) & 0x7F) | 0x80); } // fill the array segment for (int i = off; i < len + off; ++i) { - tBa[i] = (byte) (((i - off + 15) & 0x7F)); + bytes[i] = (byte) (((i - off + 15) & 0x7F)); } if (neg != 0) { // modify a number (neg) disparate array bytes inside // segment to be negative. - int div = (neg > 1) ? (len - 1) / (neg - 1) : 0; - int idx; - for (int i = 0; i < neg; ++i) { - idx = off + (len - 1) - div * i; - tBa[idx] = (byte) (0x80 | tBa[idx]); + for (int i = 0; i < neg; i++) { + int idx = off + RANDOM.nextInt(len - negOffset) + negOffset; + bytes[idx] = (byte) (0x80 | bytes[idx]); } } // insert "canary" negative values after array segment - for (int i = len + off; i < tBa.length; ++i) { - tBa[i] = (byte) (((i + 15) & 0x7F) | 0x80); + for (int i = len + off; i < bytes.length; ++i) { + bytes[i] = (byte) (((i + 15) & 0x7F) | 0x80); } } - /** Sizes of array segments to test. */ - private static int sizes[] = { 1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 13, 17, 19, 23, 37, 61, 131, - 4099 }; - /** * Test different array segment sizes, offsets, and number of negative * bytes. */ public static void test_countPositives() throws Exception { - int len, off; - int ng; + for (int off = 0; off < 16; off++) { // starting offset of array segment + // Test all array segment sizes 1-63 + for (int len = 1; len < 64; len++) { + test_countPositives(off, len, 0, 0); + test_countPositives(off, len, 1, 0); + test_countPositives(off, len, RANDOM.nextInt(30) + 2, 0); + } + // Test a random selection of sizes between 64 and 4099, inclusive + for (int i = 0; i < 20; i++) { + int len = 64 + RANDOM.nextInt(4100 - 64); + test_countPositives(off, len, 0, 0); + test_countPositives(off, len, 1, 0); + test_countPositives(off, len, RANDOM.nextInt(len) + 2, 0); + } + for (int len : new int[] { 128, 2048 }) { + // test with negatives only in a 1-63 byte tail + int tail = RANDOM.nextInt(63) + 1; + int ng = RANDOM.nextInt(tail) + 1; + test_countPositives(off, len + tail, ng, len); + } + } + } - for (ng = 0; ng < 57; ++ng) { // number of negatives in array segment - for (off = 0; off < 8; ++off) { // starting offset of array segment - for (int i = 0; i < sizes.length; ++i) { // array segment size - // choice - len = sizes[i]; - if (len + off > tBa.length) - continue; - initialize(off, len, ng); - int calculated = Helper.StringCodingCountPositives(tBa, off, len); - int expected = countPositives(tBa, off, len); - if (calculated != expected) { - if (expected != len && calculated >= 0 && calculated < expected) { - // allow intrinsics to return early with a lower value, - // but only if we're not expecting the full length (no - // negative bytes) - continue; - } - throw new Exception("Failed test countPositives " + "offset: " + off + " " - + "length: " + len + " " + "return: " + calculated + " expected: " + expected + " negatives: " - + ng); - } - } + private static void test_countPositives(int off, int len, int ng, int ngOffset) throws Exception { + assert (len + off < bytes.length); + initialize(off, len, ng, ngOffset); + int calculated = Helper.StringCodingCountPositives(bytes, off, len); + int expected = countPositives(bytes, off, len); + if (calculated != expected) { + if (expected != len && ng >= 0 && calculated >= 0 && calculated < expected) { + // allow intrinsics to return early with a lower value, + // but only if we're not expecting the full length (no + // negative bytes) + return; } + throw new Exception("Failed test countPositives " + "offset: " + off + " " + + "length: " + len + " " + "return: " + calculated + " expected: " + expected + " negatives: " + + ng + " offset: " + ngOffset); } } diff --git a/test/hotspot/jtreg/compiler/intrinsics/string/TestHasNegatives.java b/test/hotspot/jtreg/compiler/intrinsics/string/TestHasNegatives.java index d73ea3f0139..6edf2dc2e56 100644 --- a/test/hotspot/jtreg/compiler/intrinsics/string/TestHasNegatives.java +++ b/test/hotspot/jtreg/compiler/intrinsics/string/TestHasNegatives.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2018, 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 @@ -26,20 +26,39 @@ * @bug 8054307 * @summary Validates StringCoding.hasNegatives intrinsic with a small range of tests. * @library /compiler/patches + * @library /test/lib * * @build java.base/java.lang.Helper * @run main compiler.intrinsics.string.TestHasNegatives */ +/* + * @test + * @bug 8054307 8318509 + * @summary Validates StringCoding.hasNegatives intrinsic for AVX3 works with and without + * AVX3Threshold=0 + * @key randomness + * @library /compiler/patches + * @library /test/lib + * + * @build java.base/java.lang.Helper + * @requires vm.cpu.features ~= ".*avx512.*" + * @run main/othervm/timeout=1200 -XX:UseAVX=3 compiler.intrinsics.string.TestHasNegatives + * @run main/othervm/timeout=1200 -XX:UseAVX=3 -XX:+UnlockDiagnosticVMOptions -XX:AVX3Threshold=0 compiler.intrinsics.string.TestHasNegatives + */ package compiler.intrinsics.string; -/* - * @summary Validates StringCoding.hasNegatives intrinsic with a small - * range of tests. - */ +import java.lang.Helper; +import java.util.Random; +import java.util.stream.IntStream; + +import jdk.test.lib.Utils; + public class TestHasNegatives { - private static byte[] tBa = new byte[4096 + 16]; + private static byte[] bytes = new byte[4096 + 32]; + + private static final Random RANDOM = Utils.getRandomInstance(); /** * Completely initialize the test array, preparing it for tests of the @@ -47,60 +66,60 @@ public class TestHasNegatives { * length, and number of negative bytes. */ public static void initialize(int off, int len, int neg) { - assert (len + off <= tBa.length); + assert (len + off <= bytes.length); // insert "canary" (negative) values before offset for (int i = 0; i < off; ++i) { - tBa[i] = (byte) (((i + 15) & 0x7F) | 0x80); + bytes[i] = (byte) (((i + 15) & 0x7F) | 0x80); } // fill the array segment for (int i = off; i < len + off; ++i) { - tBa[i] = (byte) (((i - off + 15) & 0x7F)); + bytes[i] = (byte) (((i - off + 15) & 0x7F)); } if (neg != 0) { // modify a number (neg) disparate array bytes inside // segment to be negative. - int div = (neg > 1) ? (len - 1) / (neg - 1) : 0; - int idx; - for (int i = 0; i < neg; ++i) { - idx = off + (len - 1) - div * i; - tBa[idx] = (byte) (0x80 | tBa[idx]); + for (int i = 0; i < neg; i++) { + int idx = off + RANDOM.nextInt(len); + bytes[idx] = (byte) (0x80 | bytes[idx]); } } // insert "canary" negative values after array segment - for (int i = len + off; i < tBa.length; ++i) { - tBa[i] = (byte) (((i + 15) & 0x7F) | 0x80); + for (int i = len + off; i < bytes.length; ++i) { + bytes[i] = (byte) (((i + 15) & 0x7F) | 0x80); } } - /** Sizes of array segments to test. */ - private static int sizes[] = { 1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 13, 17, 19, 23, 37, 61, 131, - 4099 }; - /** * Test different array segment sizes, offsets, and number of negative * bytes. */ public static void test_hasNegatives() throws Exception { - int len, off; - int ng; - boolean r; - - for (ng = 0; ng < 57; ++ng) { // number of negatives in array segment - for (off = 0; off < 8; ++off) { // starting offset of array segment - for (int i = 0; i < sizes.length; ++i) { // array segment size - // choice - len = sizes[i]; - if (len + off > tBa.length) - continue; - initialize(off, len, ng); - r = Helper.StringCodingHasNegatives(tBa, off, len); - if (r ^ ((ng == 0) ? false : true)) { - throw new Exception("Failed test hasNegatives " + "offset: " + off + " " - + "length: " + len + " " + "return: " + r + " " + "negatives: " - + ng); - } - } + for (int off = 0; off < 16; off++) { // starting offset of array segment + // Test all array segment sizes 1-63 + for (int len = 1; len < 64; len++) { + test_hasNegatives(off, len, 0); + test_hasNegatives(off, len, 1); + test_hasNegatives(off, len, RANDOM.nextInt(30) + 2); } + // Test a random selection of sizes between 64 and 4099, inclusive + for (int i = 0; i < 20; i++) { + int len = 64 + RANDOM.nextInt(4100 - 64); + test_hasNegatives(off, len, 0); + test_hasNegatives(off, len, 1); + test_hasNegatives(off, len, RANDOM.nextInt(len) + 2); + } + } + } + + private static void test_hasNegatives(int off, int len, int maxNegatives) throws Exception { + assert (len + off < bytes.length); + initialize(off, len, maxNegatives); + boolean expected = (maxNegatives > 0); + boolean actual = Helper.StringCodingHasNegatives(bytes, off, len); + if (actual != expected) { + throw new Exception("Failed test hasNegatives " + "offset: " + off + " " + + "length: " + len + " " + "return: " + actual + " " + "negatives: " + + maxNegatives); } } From 54c613acd7a7f051e65d73a1318346cb4f5a234a Mon Sep 17 00:00:00 2001 From: Zixian Cai Date: Tue, 24 Oct 2023 14:36:52 +0000 Subject: [PATCH 097/124] 8318693: Fix rendering for code blocks nested under list items in building.md Reviewed-by: erikj, ccleary --- doc/building.html | 101 ++++++++++++++++++++++++++++------------------ doc/building.md | 21 +++++++--- 2 files changed, 78 insertions(+), 44 deletions(-) diff --git a/doc/building.html b/doc/building.html index feb699fd24d..2348c398a53 100644 --- a/doc/building.html +++ b/doc/building.html @@ -819,11 +819,11 @@

Running Configure

Some command line examples:

  • Create a 32-bit build for Windows with FreeType2 in -C:\freetype-i586: -bash configure --with-freetype=/cygdrive/c/freetype-i586 --with-target-bits=32

  • +C:\freetype-i586:

    +
    bash configure --with-freetype=/cygdrive/c/freetype-i586 --with-target-bits=32
  • Create a debug build with the server JVM and DTrace -enabled: -bash configure --enable-debug --with-jvm-variants=server --enable-dtrace

  • +enabled:

    +
    bash configure --enable-debug --with-jvm-variants=server --enable-dtrace

Common Configure Arguments

Here follows some of the most common and important @@ -1331,14 +1331,12 @@

ALSA

libasound2-dev packages for your target system. Download them to /tmp.

  • Install the libraries into the cross-compilation toolchain. For -instance:

  • - +instance:

    cd /tools/gcc-linaro-arm-linux-gnueabihf-raspbian-2012.09-20120921_linux/arm-linux-gnueabihf/libc
     dpkg-deb -x /tmp/libasound2_1.0.25-4_armhf.deb .
    -dpkg-deb -x /tmp/libasound2-dev_1.0.25-4_armhf.deb .
    -
      -
    • If alsa is not properly detected by configure, you can -point it out by --with-alsa.
    • +dpkg-deb -x /tmp/libasound2-dev_1.0.25-4_armhf.deb . +
    • If alsa is not properly detected by configure, you +can point it out by --with-alsa.

    X11

    You will need X11 libraries suitable for your target system. @@ -1372,21 +1370,18 @@

    X11

  • Install the libraries into the cross-compilation toolchain. For instance:

    -
        cd /tools/gcc-linaro-arm-linux-gnueabihf-raspbian-2012.09-20120921_linux/arm-linux-gnueabihf/libc/usr
    -    mkdir X11R6
    -    cd X11R6
    -    for deb in /tmp/target-x11/*.deb ; do dpkg-deb -x $deb . ; done
    -    mv usr/* .
    -    cd lib
    -    cp arm-linux-gnueabihf/* .
    -    ```
    -
    -You can ignore the following messages. These libraries are not needed to
    -successfully complete a full JDK build.
    -

    cp: cannot stat -arm-linux-gnueabihf/libICE.so': No such file or directory cp: cannot statarm-linux-gnueabihf/libSM.so': -No such file or directory cp: cannot stat -`arm-linux-gnueabihf/libXt.so': No such file or directory ```

  • +
    cd /tools/gcc-linaro-arm-linux-gnueabihf-raspbian-2012.09-20120921_linux/arm-linux-gnueabihf/libc/usr
    +mkdir X11R6
    +cd X11R6
    +for deb in /tmp/target-x11/*.deb ; do dpkg-deb -x $deb . ; done
    +mv usr/* .
    +cd lib
    +cp arm-linux-gnueabihf/* .
    +

    You can ignore the following messages. These libraries are not needed +to successfully complete a full JDK build.

    +
    cp: cannot stat `arm-linux-gnueabihf/libICE.so': No such file or directory
    +cp: cannot stat `arm-linux-gnueabihf/libSM.so': No such file or directory
    +cp: cannot stat `arm-linux-gnueabihf/libXt.so': No such file or directory
  • If the X11 libraries are not properly detected by configure, you can point them out by --with-x.

  • @@ -1404,17 +1399,30 @@

    Cross compiling with

    For example, cross-compiling to AArch64 from x86_64 could be done like this:

      -
    • Install cross-compiler on the build system: -apt install g++-aarch64-linux-gnu gcc-aarch64-linux-gnu

    • +
    • Install cross-compiler on the build system:

      +
      apt install g++-aarch64-linux-gnu gcc-aarch64-linux-gnu
    • Create chroot on the build system, configuring it for -target system: -sudo debootstrap \ --arch=arm64 \ --verbose \ --include=fakeroot,symlinks,build-essential,libx11-dev,libxext-dev,libxrender-dev,libxrandr-dev,libxtst-dev,libxt-dev,libcups2-dev,libfontconfig1-dev,libasound2-dev,libfreetype6-dev,libpng-dev,libffi-dev \ --resolve-deps \ buster \ ~/sysroot-arm64 \ http://httpredir.debian.org/debian/ # If the target architecture is `riscv64`, # the path should be `debian-ports` instead of `debian`.

    • +target system:

      +
      sudo debootstrap \
      +  --arch=arm64 \
      +  --verbose \
      +  --include=fakeroot,symlinks,build-essential,libx11-dev,libxext-dev,libxrender-dev,libxrandr-dev,libxtst-dev,libxt-dev,libcups2-dev,libfontconfig1-dev,libasound2-dev,libfreetype6-dev,libpng-dev,libffi-dev \
      +  --resolve-deps \
      +  buster \
      +  ~/sysroot-arm64 \
      +  http://httpredir.debian.org/debian/
      +# If the target architecture is `riscv64`,
      +# the path should be `debian-ports` instead of `debian`.
    • Make sure the symlinks inside the newly created chroot point to -proper locations: -sudo chroot ~/sysroot-arm64 symlinks -cr .

    • +proper locations:

      +
      sudo chroot ~/sysroot-arm64 symlinks -cr .
    • Configure and build with newly created chroot as -sysroot/toolchain-path: -sh ./configure \ --openjdk-target=aarch64-linux-gnu \ --with-sysroot=~/sysroot-arm64 make images ls build/linux-aarch64-server-release/

    • +sysroot/toolchain-path:

      +
      sh ./configure \
      +  --openjdk-target=aarch64-linux-gnu \
      +  --with-sysroot=~/sysroot-arm64
      +make images
      +ls build/linux-aarch64-server-release/

    The build does not create new files in that chroot, so it can be reused for multiple builds without additional cleanup.

    @@ -1566,12 +1574,27 @@

    Building for RISC-V

    placeholder <toolchain-installed-path> shown below is the path where you want to install the toolchain.

      -
    • Install the RISC-V GNU compiler toolchain: -git clone --recursive https://github.com/riscv-collab/riscv-gnu-toolchain cd riscv-gnu-toolchain ./configure --prefix=<toolchain-installed-path> make linux export PATH=<toolchain-installed-path>/bin:$PATH

    • -
    • Cross-compile all the required libraries: -# An example for libffi git clone https://github.com/libffi/libffi cd libffi ./configure --host=riscv64-unknown-linux-gnu --prefix=<toolchain-installed-path>/sysroot/usr make make install

    • -
    • Configure and build OpenJDK: -bash configure \ --with-boot-jdk=$BOOT_JDK \ --openjdk-target=riscv64-linux-gnu \ --with-sysroot=<toolchain-installed-path>/sysroot \ --with-toolchain-path=<toolchain-installed-path>/bin \ --with-extra-path=<toolchain-installed-path>/bin make images

    • +
    • Install the RISC-V GNU compiler toolchain:

      +
      git clone --recursive https://github.com/riscv-collab/riscv-gnu-toolchain
      +cd riscv-gnu-toolchain
      +./configure --prefix=<toolchain-installed-path>
      +make linux
      +export PATH=<toolchain-installed-path>/bin:$PATH
    • +
    • Cross-compile all the required libraries:

      +
      # An example for libffi
      +git clone https://github.com/libffi/libffi
      +cd libffi
      +./configure --host=riscv64-unknown-linux-gnu --prefix=<toolchain-installed-path>/sysroot/usr
      +make
      +make install
    • +
    • Configure and build OpenJDK:

      +
      bash configure \
      +  --with-boot-jdk=$BOOT_JDK \
      +  --openjdk-target=riscv64-linux-gnu \
      +  --with-sysroot=<toolchain-installed-path>/sysroot \
      +  --with-toolchain-path=<toolchain-installed-path>/bin \
      +  --with-extra-path=<toolchain-installed-path>/bin
      +make images

    Building for musl

    Just like it's possible to cross-compile for a different CPU, it's diff --git a/doc/building.md b/doc/building.md index 415454cf6c3..ac79cb314b6 100644 --- a/doc/building.md +++ b/doc/building.md @@ -626,11 +626,13 @@ automatically, it will exit and inform you about the problem. Some command line examples: * Create a 32-bit build for Windows with FreeType2 in `C:\freetype-i586`: + ``` bash configure --with-freetype=/cygdrive/c/freetype-i586 --with-target-bits=32 ``` * Create a debug build with the `server` JVM and DTrace enabled: + ``` bash configure --enable-debug --with-jvm-variants=server --enable-dtrace ``` @@ -1100,11 +1102,12 @@ Note that alsa is needed even if you only want to build a headless JDK. system. Download them to /tmp. * Install the libraries into the cross-compilation toolchain. For instance: -``` -cd /tools/gcc-linaro-arm-linux-gnueabihf-raspbian-2012.09-20120921_linux/arm-linux-gnueabihf/libc -dpkg-deb -x /tmp/libasound2_1.0.25-4_armhf.deb . -dpkg-deb -x /tmp/libasound2-dev_1.0.25-4_armhf.deb . -``` + + ``` + cd /tools/gcc-linaro-arm-linux-gnueabihf-raspbian-2012.09-20120921_linux/arm-linux-gnueabihf/libc + dpkg-deb -x /tmp/libasound2_1.0.25-4_armhf.deb . + dpkg-deb -x /tmp/libasound2-dev_1.0.25-4_armhf.deb . + ``` * If alsa is not properly detected by `configure`, you can point it out by `--with-alsa`. @@ -1140,6 +1143,7 @@ Note that X11 is needed even if you only want to build a headless JDK. * libxext-dev * Install the libraries into the cross-compilation toolchain. For instance: + ``` cd /tools/gcc-linaro-arm-linux-gnueabihf-raspbian-2012.09-20120921_linux/arm-linux-gnueabihf/libc/usr mkdir X11R6 @@ -1173,11 +1177,13 @@ for foreign architectures with native compilation speed. For example, cross-compiling to AArch64 from x86_64 could be done like this: * Install cross-compiler on the *build* system: + ``` apt install g++-aarch64-linux-gnu gcc-aarch64-linux-gnu ``` * Create chroot on the *build* system, configuring it for *target* system: + ``` sudo debootstrap \ --arch=arm64 \ @@ -1192,11 +1198,13 @@ For example, cross-compiling to AArch64 from x86_64 could be done like this: ``` * Make sure the symlinks inside the newly created chroot point to proper locations: + ``` sudo chroot ~/sysroot-arm64 symlinks -cr . ``` * Configure and build with newly created chroot as sysroot/toolchain-path: + ``` sh ./configure \ --openjdk-target=aarch64-linux-gnu \ @@ -1255,6 +1263,7 @@ complicate the building process. The placeholder `` shown below is the path where you want to install the toolchain. * Install the RISC-V GNU compiler toolchain: + ``` git clone --recursive https://github.com/riscv-collab/riscv-gnu-toolchain cd riscv-gnu-toolchain @@ -1264,6 +1273,7 @@ shown below is the path where you want to install the toolchain. ``` * Cross-compile all the required libraries: + ``` # An example for libffi git clone https://github.com/libffi/libffi @@ -1274,6 +1284,7 @@ shown below is the path where you want to install the toolchain. ``` * Configure and build OpenJDK: + ``` bash configure \ --with-boot-jdk=$BOOT_JDK \ From e2720987b921b95fd8010cea60d2d6e436e5ebaa Mon Sep 17 00:00:00 2001 From: Vicente Romero Date: Tue, 24 Oct 2023 14:45:10 +0000 Subject: [PATCH 098/124] 8318160: javac does not reject private method reference with type-variable receiver Reviewed-by: mcimadamore --- .../com/sun/tools/javac/comp/Resolve.java | 12 +++++++ ...PrivateMethodReferenceWithTypeVarTest.java | 34 +++++++++++++++++++ .../PrivateMethodReferenceWithTypeVarTest.out | 4 +++ 3 files changed, 50 insertions(+) create mode 100644 test/langtools/tools/javac/lambda/methodReference/PrivateMethodReferenceWithTypeVarTest.java create mode 100644 test/langtools/tools/javac/lambda/methodReference/PrivateMethodReferenceWithTypeVarTest.out diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java index 295bb192a42..ab84d372bd7 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Resolve.java @@ -3605,6 +3605,18 @@ ReferenceKind referenceKind(Symbol sym) { ReferenceKind.BOUND; } } + + @Override + Symbol access(Env env, DiagnosticPosition pos, Symbol location, Symbol sym) { + if (originalSite.hasTag(TYPEVAR) && sym.kind == MTH) { + sym = (sym.flags() & Flags.PRIVATE) != 0 ? + new AccessError(env, site, sym) : + sym; + return accessBase(sym, pos, location, originalSite, name, true); + } else { + return super.access(env, pos, location, sym); + } + } } /** diff --git a/test/langtools/tools/javac/lambda/methodReference/PrivateMethodReferenceWithTypeVarTest.java b/test/langtools/tools/javac/lambda/methodReference/PrivateMethodReferenceWithTypeVarTest.java new file mode 100644 index 00000000000..b87783416a3 --- /dev/null +++ b/test/langtools/tools/javac/lambda/methodReference/PrivateMethodReferenceWithTypeVarTest.java @@ -0,0 +1,34 @@ +/* + * @test /nodynamiccopyright/ + * @bug 8318160 + * @summary javac does not reject private method reference with type-variable receiver + * @compile/fail/ref=PrivateMethodReferenceWithTypeVarTest.out -XDrawDiagnostics PrivateMethodReferenceWithTypeVarTest.java + */ + +import java.util.function.*; + +class PrivateMethodReferenceWithTypeVarTest { + class Foo { + X get() { return null; } + } + + private String asString() { + return "bar"; + } + + private String asString2(Object o) { + return "bar"; + } + + static Function m1() { + return T::asString; + } + + static Function m2(T t) { + return t::asString2; + } + + static Function m2(Foo foo) { + return foo.get()::asString2; + } +} diff --git a/test/langtools/tools/javac/lambda/methodReference/PrivateMethodReferenceWithTypeVarTest.out b/test/langtools/tools/javac/lambda/methodReference/PrivateMethodReferenceWithTypeVarTest.out new file mode 100644 index 00000000000..b4dac12a9ae --- /dev/null +++ b/test/langtools/tools/javac/lambda/methodReference/PrivateMethodReferenceWithTypeVarTest.out @@ -0,0 +1,4 @@ +PrivateMethodReferenceWithTypeVarTest.java:24:16: compiler.err.report.access: asString(), private, PrivateMethodReferenceWithTypeVarTest +PrivateMethodReferenceWithTypeVarTest.java:28:16: compiler.err.report.access: asString2(java.lang.Object), private, PrivateMethodReferenceWithTypeVarTest +PrivateMethodReferenceWithTypeVarTest.java:32:16: compiler.err.report.access: asString2(java.lang.Object), private, PrivateMethodReferenceWithTypeVarTest +3 errors From 6f352740cb5e7c47d226fd4039cfb977c0622488 Mon Sep 17 00:00:00 2001 From: Thomas Schatzl Date: Tue, 24 Oct 2023 14:49:06 +0000 Subject: [PATCH 099/124] 8318702: G1: Fix nonstandard indentation in g1HeapTransition.cpp Reviewed-by: iwalulya --- src/hotspot/share/gc/g1/g1HeapTransition.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1HeapTransition.cpp b/src/hotspot/share/gc/g1/g1HeapTransition.cpp index 49ba19dfdba..a2097041b20 100644 --- a/src/hotspot/share/gc/g1/g1HeapTransition.cpp +++ b/src/hotspot/share/gc/g1/g1HeapTransition.cpp @@ -143,11 +143,11 @@ void G1HeapTransition::print() { usage = blk._usage; assert(usage._eden_region_count == 0, "Expected no eden regions, but got " SIZE_FORMAT, usage._eden_region_count); assert(usage._survivor_region_count == after._survivor_length, "Expected survivors to be " SIZE_FORMAT " but was " SIZE_FORMAT, - after._survivor_length, usage._survivor_region_count); + after._survivor_length, usage._survivor_region_count); assert(usage._old_region_count == after._old_length, "Expected old to be " SIZE_FORMAT " but was " SIZE_FORMAT, - after._old_length, usage._old_region_count); + after._old_length, usage._old_region_count); assert(usage._humongous_region_count == after._humongous_length, "Expected humongous to be " SIZE_FORMAT " but was " SIZE_FORMAT, - after._humongous_length, usage._humongous_region_count); + after._humongous_length, usage._humongous_region_count); } log_regions("Eden", _before._eden_length, after._eden_length, eden_capacity_length_after_gc, @@ -157,17 +157,17 @@ void G1HeapTransition::print() { log_regions("Survivor", _before._survivor_length, after._survivor_length, survivor_capacity_length_before_gc, _before._survivor_length_per_node, after._survivor_length_per_node); log_trace(gc, heap)(" Used: " SIZE_FORMAT "K, Waste: " SIZE_FORMAT "K", - usage._survivor_used / K, ((after._survivor_length * HeapRegion::GrainBytes) - usage._survivor_used) / K); + usage._survivor_used / K, ((after._survivor_length * HeapRegion::GrainBytes) - usage._survivor_used) / K); log_info(gc, heap)("Old regions: " SIZE_FORMAT "->" SIZE_FORMAT, _before._old_length, after._old_length); log_trace(gc, heap)(" Used: " SIZE_FORMAT "K, Waste: " SIZE_FORMAT "K", - usage._old_used / K, ((after._old_length * HeapRegion::GrainBytes) - usage._old_used) / K); + usage._old_used / K, ((after._old_length * HeapRegion::GrainBytes) - usage._old_used) / K); log_info(gc, heap)("Humongous regions: " SIZE_FORMAT "->" SIZE_FORMAT, _before._humongous_length, after._humongous_length); log_trace(gc, heap)(" Used: " SIZE_FORMAT "K, Waste: " SIZE_FORMAT "K", - usage._humongous_used / K, ((after._humongous_length * HeapRegion::GrainBytes) - usage._humongous_used) / K); + usage._humongous_used / K, ((after._humongous_length * HeapRegion::GrainBytes) - usage._humongous_used) / K); MetaspaceUtils::print_metaspace_change(_before._meta_sizes); } From 116503754c4c4bdb91685955ef4456bc76f751c4 Mon Sep 17 00:00:00 2001 From: Naoto Sato Date: Tue, 24 Oct 2023 16:54:57 +0000 Subject: [PATCH 100/124] 8318569: Add getter methods for Locale and Patterns in ListFormat Reviewed-by: joehw, rriggs, iris, mli --- .../share/classes/java/text/ListFormat.java | 20 +++++++++ .../Format/ListFormat/TestListFormat.java | 41 ++++++++++++++++++- 2 files changed, 60 insertions(+), 1 deletion(-) diff --git a/src/java.base/share/classes/java/text/ListFormat.java b/src/java.base/share/classes/java/text/ListFormat.java index d0b1b2aaf2a..920cd9a0762 100644 --- a/src/java.base/share/classes/java/text/ListFormat.java +++ b/src/java.base/share/classes/java/text/ListFormat.java @@ -322,6 +322,26 @@ public static ListFormat getInstance(String[] patterns) { return new ListFormat(Locale.ROOT, Arrays.copyOf(patterns, PATTERN_ARRAY_LENGTH)); } + /** + * {@return the {@code Locale} of this ListFormat} + * + * The {@code locale} is defined by {@link #getInstance(Locale, Type, Style)} or + * {@link #getInstance(String[])}. + */ + public Locale getLocale() { + return locale; + } + + /** + * {@return the patterns used in this ListFormat} + * + * The {@code patterns} are defined by {@link #getInstance(Locale, Type, Style)} or + * {@link #getInstance(String[])}. + */ + public String[] getPatterns() { + return Arrays.copyOf(patterns, patterns.length); + } + /** * {@return the string that consists of the input strings, concatenated with the * patterns of this {@code ListFormat}} diff --git a/test/jdk/java/text/Format/ListFormat/TestListFormat.java b/test/jdk/java/text/Format/ListFormat/TestListFormat.java index 2d260c9a94c..eee6f6dac83 100644 --- a/test/jdk/java/text/Format/ListFormat/TestListFormat.java +++ b/test/jdk/java/text/Format/ListFormat/TestListFormat.java @@ -23,7 +23,7 @@ /* * @test - * @bug 8041488 8316974 + * @bug 8041488 8316974 8318569 * @summary Tests for ListFormat class * @run junit TestListFormat */ @@ -200,6 +200,7 @@ static Arguments[] parseObject_parsePos() { arguments(CUSTOM_PATTERNS_MINIMAL, SAMPLE4), }; } + static Arguments[] getInstance_3Arg_InheritPatterns() { return new Arguments[] { arguments(ListFormat.Type.STANDARD, ListFormat.Style.FULL), @@ -213,6 +214,17 @@ static Arguments[] getInstance_3Arg_InheritPatterns() { arguments(ListFormat.Type.UNIT, ListFormat.Style.NARROW), }; } + + static Arguments[] getLocale_localeDependent() { + return new Arguments[] { + arguments(Locale.ROOT), + arguments(Locale.US), + arguments(Locale.GERMANY), + arguments(Locale.JAPAN), + arguments(Locale.SIMPLIFIED_CHINESE), + }; + } + @ParameterizedTest @MethodSource void getInstance_1Arg(String[] patterns, List input, String expected) throws ParseException { @@ -235,6 +247,33 @@ void getInstance_3Arg(Locale l, ListFormat.Type type, ListFormat.Style style, St compareResult(f, SAMPLE3, expected, roundTrip); } + @Test + void getLocale_invariant() { + var f = ListFormat.getInstance(CUSTOM_PATTERNS_FULL); + assertEquals(Locale.ROOT, f.getLocale()); + } + + @Test + void getLocale_default() { + var f = ListFormat.getInstance(); + assertEquals(Locale.getDefault(Locale.Category.FORMAT), f.getLocale()); + } + + @ParameterizedTest + @MethodSource + void getLocale_localeDependent(Locale l) { + var f = ListFormat.getInstance(l, ListFormat.Type.STANDARD, ListFormat.Style.FULL); + assertEquals(l, f.getLocale()); + } + + @Test + void getPatterns_immutability() { + var f = ListFormat.getInstance(CUSTOM_PATTERNS_FULL); + var p = f.getPatterns(); + p[0] = null; + assertArrayEquals(CUSTOM_PATTERNS_FULL, f.getPatterns()); + } + @Test void format_3Arg() { var f = ListFormat.getInstance(); From 1f2a80b78a6378b5b03f08a1e61614b8db40654c Mon Sep 17 00:00:00 2001 From: vamsi-parasa Date: Tue, 24 Oct 2023 18:31:33 +0000 Subject: [PATCH 101/124] 8318306: java/util/Arrays/Sorting.java fails with "Array is not sorted at 8228-th position: 8251.0 and 8153.0" Reviewed-by: thartmann, jbhateja --- src/hotspot/share/opto/library_call.cpp | 74 ++++++++++--------- .../intrinsics/SortingDeoptimizationTest.java | 72 ++++++++++++++++++ 2 files changed, 112 insertions(+), 34 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/intrinsics/SortingDeoptimizationTest.java diff --git a/src/hotspot/share/opto/library_call.cpp b/src/hotspot/share/opto/library_call.cpp index 4a9d7fb1616..62d78580953 100644 --- a/src/hotspot/share/opto/library_call.cpp +++ b/src/hotspot/share/opto/library_call.cpp @@ -5367,8 +5367,6 @@ void LibraryCallKit::create_new_uncommon_trap(CallStaticJavaNode* uncommon_trap_ //------------------------------inline_array_partition----------------------- bool LibraryCallKit::inline_array_partition() { - const char *stubName = "array_partition_stub"; - Node* elementType = null_check(argument(0)); Node* obj = argument(1); Node* offset = argument(2); @@ -5377,38 +5375,48 @@ bool LibraryCallKit::inline_array_partition() { Node* indexPivot1 = argument(6); Node* indexPivot2 = argument(7); - const TypeInstPtr* elem_klass = gvn().type(elementType)->isa_instptr(); - ciType* elem_type = elem_klass->const_oop()->as_instance()->java_mirror_type(); - BasicType bt = elem_type->basic_type(); - address stubAddr = nullptr; - stubAddr = StubRoutines::select_array_partition_function(); - // stub not loaded - if (stubAddr == nullptr) { - return false; - } - // get the address of the array - const TypeAryPtr* obj_t = _gvn.type(obj)->isa_aryptr(); - if (obj_t == nullptr || obj_t->elem() == Type::BOTTOM ) { - return false; // failed input validation - } - Node* obj_adr = make_unsafe_address(obj, offset); + Node* pivotIndices = nullptr; - // create the pivotIndices array of type int and size = 2 - Node* size = intcon(2); - Node* klass_node = makecon(TypeKlassPtr::make(ciTypeArrayKlass::make(T_INT))); - Node* pivotIndices = new_array(klass_node, size, 0); // no arguments to push - AllocateArrayNode* alloc = tightly_coupled_allocation(pivotIndices); - guarantee(alloc != nullptr, "created above"); - Node* pivotIndices_adr = basic_plus_adr(pivotIndices, arrayOopDesc::base_offset_in_bytes(T_INT)); + // Set the original stack and the reexecute bit for the interpreter to reexecute + // the bytecode that invokes DualPivotQuicksort.partition() if deoptimization happens. + { PreserveReexecuteState preexecs(this); + jvms()->set_should_reexecute(true); - // pass the basic type enum to the stub - Node* elemType = intcon(bt); + const TypeInstPtr* elem_klass = gvn().type(elementType)->isa_instptr(); + ciType* elem_type = elem_klass->const_oop()->as_instance()->java_mirror_type(); + BasicType bt = elem_type->basic_type(); + address stubAddr = nullptr; + stubAddr = StubRoutines::select_array_partition_function(); + // stub not loaded + if (stubAddr == nullptr) { + return false; + } + // get the address of the array + const TypeAryPtr* obj_t = _gvn.type(obj)->isa_aryptr(); + if (obj_t == nullptr || obj_t->elem() == Type::BOTTOM ) { + return false; // failed input validation + } + Node* obj_adr = make_unsafe_address(obj, offset); - // Call the stub - make_runtime_call(RC_LEAF|RC_NO_FP, OptoRuntime::array_partition_Type(), - stubAddr, stubName, TypePtr::BOTTOM, - obj_adr, elemType, fromIndex, toIndex, pivotIndices_adr, - indexPivot1, indexPivot2); + // create the pivotIndices array of type int and size = 2 + Node* size = intcon(2); + Node* klass_node = makecon(TypeKlassPtr::make(ciTypeArrayKlass::make(T_INT))); + pivotIndices = new_array(klass_node, size, 0); // no arguments to push + AllocateArrayNode* alloc = tightly_coupled_allocation(pivotIndices); + guarantee(alloc != nullptr, "created above"); + Node* pivotIndices_adr = basic_plus_adr(pivotIndices, arrayOopDesc::base_offset_in_bytes(T_INT)); + + // pass the basic type enum to the stub + Node* elemType = intcon(bt); + + // Call the stub + const char *stubName = "array_partition_stub"; + make_runtime_call(RC_LEAF|RC_NO_FP, OptoRuntime::array_partition_Type(), + stubAddr, stubName, TypePtr::BOTTOM, + obj_adr, elemType, fromIndex, toIndex, pivotIndices_adr, + indexPivot1, indexPivot2); + + } // original reexecute is set back here if (!stopped()) { set_result(pivotIndices); @@ -5421,9 +5429,6 @@ bool LibraryCallKit::inline_array_partition() { //------------------------------inline_array_sort----------------------- bool LibraryCallKit::inline_array_sort() { - const char *stubName; - stubName = "arraysort_stub"; - Node* elementType = null_check(argument(0)); Node* obj = argument(1); Node* offset = argument(2); @@ -5451,6 +5456,7 @@ bool LibraryCallKit::inline_array_sort() { Node* elemType = intcon(bt); // Call the stub. + const char *stubName = "arraysort_stub"; make_runtime_call(RC_LEAF|RC_NO_FP, OptoRuntime::array_sort_Type(), stubAddr, stubName, TypePtr::BOTTOM, obj_adr, elemType, fromIndex, toIndex); diff --git a/test/hotspot/jtreg/compiler/intrinsics/SortingDeoptimizationTest.java b/test/hotspot/jtreg/compiler/intrinsics/SortingDeoptimizationTest.java new file mode 100644 index 00000000000..f9fbcfefb99 --- /dev/null +++ b/test/hotspot/jtreg/compiler/intrinsics/SortingDeoptimizationTest.java @@ -0,0 +1,72 @@ +/* + * 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 8318306 + * @run main/othervm/timeout=200 -XX:+IgnoreUnrecognizedVMOptions -Xcomp -ea -esa -XX:CompileThreshold=100 -XX:+UnlockExperimentalVMOptions -server -XX:-TieredCompilation -XX:+DeoptimizeALot SortingDeoptimizationTest 1e-2 100 50 + * @summary Exercise Arrays.parallelSort when -XX:+DeoptimizeALot is enabled + * + */ + +import java.io.PrintStream; +import java.util.Arrays; +import java.util.Random; + +public class SortingDeoptimizationTest { + + private static final PrintStream err = System.err; + private static final PrintStream out = System.out; + + public static void main(String[] args) { + int MAX = 2147483647; // 2^32 - 1 + float fraction = Float.parseFloat(args[0]); + int size = (int) (fraction * MAX); // size is a fraction of the MAX size + int iters = Integer.parseInt(args[1]); // number of iterations + int max = args.length > 2 ? Integer.parseInt(args[2]) : -1 ; // max value for the array elements + long seed = 0xC0FFEE; + Random rand = new Random(seed); + + for (int i = 0; i < iters; i++) { + boolean isSorted = runSort(size, max, rand); + out.println("Iteration " + i + ": is sorted? -> "+ isSorted); + if (!isSorted) fail("Array is not correctly sorted."); + } + } + + private static void fail(String message) { + err.format("\n*** TEST FAILED ***\n\n%s\n\n", message); + throw new RuntimeException("Test failed"); + } + + private static boolean runSort(int size, int max, Random rand) { + int[] a = new int[size]; + for (int i = 0; i < a.length; i++) a[i] = max > 0 ? rand.nextInt(max) : rand.nextInt(); + // call parallel sort + Arrays.parallelSort(a); + // check if sorted + boolean isSorted = true; + for (int i = 0; i < (a.length -1); i++) isSorted = isSorted && (a[i] <= a[i+1]); + return isSorted; + } +} From 1ddf826aea7fd18209336dce550821638d5ef89c Mon Sep 17 00:00:00 2001 From: Weijun Wang Date: Tue, 24 Oct 2023 18:32:01 +0000 Subject: [PATCH 102/124] 8316964: Security tools should not call System.exit Reviewed-by: valeriep --- .../sun/security/tools/keytool/Main.java | 27 ++- .../security/krb5/internal/tools/Kinit.java | 78 +++---- .../krb5/internal/tools/KinitOptions.java | 7 +- .../security/krb5/internal/tools/Klist.java | 190 +++++++++--------- .../security/krb5/internal/tools/Ktab.java | 89 +++++--- .../sun/security/tools/jarsigner/Main.java | 62 +++--- .../sun/security/krb5/tools/ExitOrNot.java | 61 ++++++ .../security/tools/jarsigner/ExitOrNot.java | 52 +++++ 8 files changed, 358 insertions(+), 208 deletions(-) create mode 100644 test/jdk/sun/security/krb5/tools/ExitOrNot.java create mode 100644 test/jdk/sun/security/tools/jarsigner/ExitOrNot.java diff --git a/src/java.base/share/classes/sun/security/tools/keytool/Main.java b/src/java.base/share/classes/sun/security/tools/keytool/Main.java index 2effa3425d7..b094acc51fe 100644 --- a/src/java.base/share/classes/sun/security/tools/keytool/Main.java +++ b/src/java.base/share/classes/sun/security/tools/keytool/Main.java @@ -405,26 +405,38 @@ public String toString() { collator.setStrength(Collator.PRIMARY); } - private Main() { } - public static void main(String[] args) throws Exception { Main kt = new Main(); - kt.run(args, System.out); + int exitCode = kt.run(args, System.out); + if (exitCode != 0) { + System.exit(exitCode); + } + } + + private static class ExitException extends RuntimeException { + @java.io.Serial + static final long serialVersionUID = 0L; + private final int errorCode; + public ExitException(int errorCode) { + this.errorCode = errorCode; + } } - private void run(String[] args, PrintStream out) throws Exception { + public int run(String[] args, PrintStream out) throws Exception { try { - args = parseArgs(args); + parseArgs(args); if (command != null) { doCommands(out); } + } catch (ExitException ee) { + return ee.errorCode; } catch (Exception e) { System.out.println(rb.getString("keytool.error.") + e); if (verbose) { e.printStackTrace(System.out); } if (!debug) { - System.exit(1); + return 1; } else { throw e; } @@ -441,6 +453,7 @@ private void run(String[] args, PrintStream out) throws Exception { ksStream.close(); } } + return 0; } /** @@ -5247,7 +5260,7 @@ private void tinyHelp() { if (debug) { throw new RuntimeException("NO BIG ERROR, SORRY"); } else { - System.exit(1); + throw new ExitException(1); } } diff --git a/src/java.security.jgss/windows/classes/sun/security/krb5/internal/tools/Kinit.java b/src/java.security.jgss/windows/classes/sun/security/krb5/internal/tools/Kinit.java index 813939643c3..a14ece6ee0e 100644 --- a/src/java.security.jgss/windows/classes/sun/security/krb5/internal/tools/Kinit.java +++ b/src/java.security.jgss/windows/classes/sun/security/krb5/internal/tools/Kinit.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -92,14 +92,44 @@ public class Kinit { */ public static void main(String[] args) { - try { - Kinit self = new Kinit(args); + Kinit kinit = new Kinit(); + int exitCode = kinit.run(args); + if (exitCode != 0) { + System.exit(exitCode); } - catch (Exception e) { - String msg = null; - if (e instanceof KrbException) { - msg = ((KrbException)e).krbErrorMessage() + " " + - ((KrbException)e).returnCodeMessage(); + } + + /** + * Run the Kinit command. + * @param args array of ticket request options. + * Available options are: -f, -p, -c, principal, password. + * @return the exit code + */ + public int run(String[] args) { + try { + if (args == null || args.length == 0) { + options = new KinitOptions(); + } else { + options = new KinitOptions(args); + } + switch (options.action) { + case 0: + // Help, already displayed in new KinitOptions(). + break; + case 1: + acquire(); + break; + case 2: + renew(); + break; + default: + throw new KrbException("kinit does not support action " + + options.action); + } + } catch (Exception e) { + String msg; + if (e instanceof KrbException ke) { + msg = ke.krbErrorMessage() + " " + ke.returnCodeMessage(); } else { msg = e.getMessage(); } @@ -109,37 +139,9 @@ public static void main(String[] args) { System.out.println("Exception: " + e); } e.printStackTrace(); - System.exit(-1); - } - return; - } - - /** - * Constructs a new Kinit object. - * @param args array of ticket request options. - * Available options are: -f, -p, -c, principal, password. - * @exception IOException if an I/O error occurs. - * @exception RealmException if the Realm could not be instantiated. - * @exception KrbException if error occurs during Kerberos operation. - */ - private Kinit(String[] args) - throws IOException, RealmException, KrbException { - if (args == null || args.length == 0) { - options = new KinitOptions(); - } else { - options = new KinitOptions(args); - } - switch (options.action) { - case 1: - acquire(); - break; - case 2: - renew(); - break; - default: - throw new KrbException("kinit does not support action " - + options.action); + return -1; } + return 0; } private void renew() diff --git a/src/java.security.jgss/windows/classes/sun/security/krb5/internal/tools/KinitOptions.java b/src/java.security.jgss/windows/classes/sun/security/krb5/internal/tools/KinitOptions.java index 5cfc574d95a..445b806bb50 100644 --- a/src/java.security.jgss/windows/classes/sun/security/krb5/internal/tools/KinitOptions.java +++ b/src/java.security.jgss/windows/classes/sun/security/krb5/internal/tools/KinitOptions.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -46,7 +46,7 @@ */ class KinitOptions { - // 1. acquire, 2. renew, 3. validate + // 0. Help, 1. acquire, 2. renew, 3. validate public int action = 1; // forwardable and proxiable flags have two states: @@ -143,7 +143,8 @@ public KinitOptions(String[] args) // -help: legacy. args[i].equalsIgnoreCase("-help")) { printHelp(); - System.exit(0); + action = 0; + return; } else if (p == null) { // Haven't yet processed a "principal" p = args[i]; try { diff --git a/src/java.security.jgss/windows/classes/sun/security/krb5/internal/tools/Klist.java b/src/java.security.jgss/windows/classes/sun/security/krb5/internal/tools/Klist.java index 5a0c3bee077..16c9fd99ec4 100644 --- a/src/java.security.jgss/windows/classes/sun/security/krb5/internal/tools/Klist.java +++ b/src/java.security.jgss/windows/classes/sun/security/krb5/internal/tools/Klist.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -78,115 +78,111 @@ public class Klist { */ public static void main(String[] args) { Klist klist = new Klist(); + int exitCode = klist.run(args); + if (exitCode != 0) { + System.exit(exitCode); + } + } + + public int run(String[] args) { if ((args == null) || (args.length == 0)) { - klist.action = 'c'; // default will list default credentials cache. + action = 'c'; // default will list default credentials cache. } else { - klist.processArgs(args); + Character arg; + for (int i = 0; i < args.length; i++) { + if (args[i].equals("-?") || + args[i].equals("-h") || + args[i].equals("--help")) { + printHelp(); + return 0; + } + if ((args[i].length() >= 2) && (args[i].startsWith("-"))) { + arg = Character.valueOf(args[i].charAt(1)); + switch (arg.charValue()) { + case 'c': + action = 'c'; + break; + case 'k': + action = 'k'; + break; + case 'a': + options[2] = 'a'; + break; + case 'n': + options[3] = 'n'; + break; + case 'f': + options[1] = 'f'; + break; + case 'e': + options[0] = 'e'; + break; + case 'K': + options[1] = 'K'; + break; + case 't': + options[2] = 't'; + break; + default: + System.out.println("Invalid argument: " + args[i]); + printHelp(); + return -1; + } + } else { + if (!args[i].startsWith("-") && (i == args.length - 1)) { + // the argument is the last one. + name = args[i]; + } else { + System.out.println("Invalid argument: " + args[i]); + printHelp(); // incorrect input format. + return -1; + } + } + } } - switch (klist.action) { + switch (action) { case 'c': - if (klist.name == null) { - klist.target = CredentialsCache.getInstance(); - klist.name = CredentialsCache.cacheName(); + if (name == null) { + target = CredentialsCache.getInstance(); + name = CredentialsCache.cacheName(); } else - klist.target = CredentialsCache.getInstance(klist.name); + target = CredentialsCache.getInstance(name); - if (klist.target != null) { - klist.displayCache(); + if (target != null) { + return displayCache(); } else { - klist.displayMessage("Credentials cache"); - System.exit(-1); + return displayError("Credentials cache"); } - break; case 'k': - KeyTab ktab = KeyTab.getInstance(klist.name); + KeyTab ktab = KeyTab.getInstance(name); if (ktab.isMissing()) { - System.out.println("KeyTab " + klist.name + " not found."); - System.exit(-1); + System.out.println("KeyTab " + name + " not found."); + return -1; } else if (!ktab.isValid()) { - System.out.println("KeyTab " + klist.name + System.out.println("KeyTab " + name + " format not supported."); - System.exit(-1); + return -1; } - klist.target = ktab; - klist.name = ktab.tabName(); - klist.displayTab(); - break; + target = ktab; + name = ktab.tabName(); + return displayTab(); default: - if (klist.name != null) { - klist.printHelp(); - System.exit(-1); - } else { - klist.target = CredentialsCache.getInstance(); - klist.name = CredentialsCache.cacheName(); - if (klist.target != null) { - klist.displayCache(); - } else { - klist.displayMessage("Credentials cache"); - System.exit(-1); - } - } - } - } - - /** - * Parses the command line arguments. - */ - void processArgs(String[] args) { - Character arg; - for (int i = 0; i < args.length; i++) { - if (args[i].equals("-?") || - args[i].equals("-h") || - args[i].equals("--help")) { + if (name != null) { printHelp(); - System.exit(0); - } - if ((args[i].length() >= 2) && (args[i].startsWith("-"))) { - arg = Character.valueOf(args[i].charAt(1)); - switch (arg.charValue()) { - case 'c': - action = 'c'; - break; - case 'k': - action = 'k'; - break; - case 'a': - options[2] = 'a'; - break; - case 'n': - options[3] = 'n'; - break; - case 'f': - options[1] = 'f'; - break; - case 'e': - options[0] = 'e'; - break; - case 'K': - options[1] = 'K'; - break; - case 't': - options[2] = 't'; - break; - default: - printHelp(); - System.exit(-1); - } - + return -1; } else { - if (!args[i].startsWith("-") && (i == args.length - 1)) { - // the argument is the last one. - name = args[i]; - arg = null; + target = CredentialsCache.getInstance(); + name = CredentialsCache.cacheName(); + if (target != null) { + return displayCache(); } else { - printHelp(); // incorrect input format. - System.exit(-1); + return displayError("Credentials cache"); } } } } - void displayTab() { + int displayTab() { KeyTab table = (KeyTab)target; KeyTabEntry[] entries = table.getEntries(); if (entries.length == 0) { @@ -201,7 +197,7 @@ void displayTab() { entries.length + " entries found.\n"); for (int i = 0; i < entries.length; i++) { System.out.println("[" + (i + 1) + "] " + - "Service principal: " + + "Service principal: " + entries[i].getService().toString()); System.out.println("\t KVNO: " + entries[i].getKey().getKeyVersionNumber()); @@ -221,18 +217,19 @@ void displayTab() { } } } + return 0; } - void displayCache() { + int displayCache() { CredentialsCache cache = (CredentialsCache)target; sun.security.krb5.internal.ccache.Credentials[] creds = cache.getCredsList(); if (creds == null) { System.out.println ("No credentials available in the cache " + name); - System.exit(-1); + return -1; } - System.out.println("\nCredentials cache: " + name); + System.out.println("\nCredentials cache: " + name); String defaultPrincipal = cache.getPrimaryPrincipal().toString(); int num = creds.length; @@ -327,7 +324,7 @@ void displayCache() { if (DEBUG) { e.printStackTrace(); } - System.exit(-1); + return -1; } } } else { @@ -342,14 +339,17 @@ void displayCache() { System.out.println(" " + e); } } + + return 0; } - void displayMessage(String target) { + int displayError(String target) { if (name == null) { System.out.println("Default " + target + " not found."); } else { System.out.println(target + " " + name + " not found."); } + return -1; } /** * Reformats the date from the form - @@ -359,7 +359,7 @@ void displayMessage(String target) { * the day, mm is the minute within the hour, * ss is the second within the minute, zzz is the time zone, * and yyyy is the year. - * @param date the string form of Date object. + * @param kt the string form of Date object. */ private String format(KerberosTime kt) { String date = kt.toDate().toString(); diff --git a/src/java.security.jgss/windows/classes/sun/security/krb5/internal/tools/Ktab.java b/src/java.security.jgss/windows/classes/sun/security/krb5/internal/tools/Ktab.java index df12b2d6c11..21002f3369a 100644 --- a/src/java.security.jgss/windows/classes/sun/security/krb5/internal/tools/Ktab.java +++ b/src/java.security.jgss/windows/classes/sun/security/krb5/internal/tools/Ktab.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -73,52 +73,76 @@ public class Ktab { */ public static void main(String[] args) { Ktab ktab = new Ktab(); + int exitCode = ktab.run(args); + if (exitCode != 0) { + System.exit(exitCode); + } + } + + private static class ExitException extends RuntimeException { + @java.io.Serial + static final long serialVersionUID = 0L; + private final int errorCode; + public ExitException(int errorCode) { + this.errorCode = errorCode; + } + } + + public int run(String[] args) { + try { + run0(args); + return 0; + } catch (ExitException ee) { + return ee.errorCode; + } + } + + private void run0(String[] args) throws ExitException { if ((args.length == 1) && ((args[0].equalsIgnoreCase("-?")) || (args[0].equalsIgnoreCase("-h")) || (args[0].equalsIgnoreCase("--help")) || // -help: legacy. (args[0].equalsIgnoreCase("-help")))) { - ktab.printHelp(); - System.exit(0); + printHelp(); return; } else if ((args == null) || (args.length == 0)) { - ktab.action = 'l'; + action = 'l'; } else { - ktab.processArgs(args); + processArgs(args); } - ktab.table = KeyTab.getInstance(ktab.name); - if (ktab.table.isMissing() && ktab.action != 'a') { - if (ktab.name == null) { + table = KeyTab.getInstance(name); + if (table.isMissing() && action != 'a') { + if (name == null) { System.out.println("No default key table exists."); } else { System.out.println("Key table " + - ktab.name + " does not exist."); + name + " does not exist."); } - System.exit(-1); + throw new ExitException(-1); } - if (!ktab.table.isValid()) { - if (ktab.name == null) { + if (!table.isValid()) { + if (name == null) { System.out.println("The format of the default key table " + " is incorrect."); } else { System.out.println("The format of key table " + - ktab.name + " is incorrect."); + name + " is incorrect."); } - System.exit(-1); + throw new ExitException(-1); } - switch (ktab.action) { + switch (action) { case 'l': - ktab.listKt(); + listKt(); break; case 'a': - ktab.addEntry(); + addEntry(); break; case 'd': - ktab.deleteEntry(); + deleteEntry(); break; default: - ktab.error("A command must be provided"); + error("A command must be provided"); } } @@ -267,7 +291,7 @@ void processArgs(String[] args) { void addEntry() { if (salt != null && fopt) { System.err.println("-s and -f cannot coexist when adding a keytab entry."); - System.exit(-1); + throw new ExitException(-1); } PrincipalName pname = null; try { @@ -276,7 +300,7 @@ void addEntry() { System.err.println("Failed to add " + principal + " to keytab."); e.printStackTrace(); - System.exit(-1); + throw new ExitException(-1); } if (password == null) { try { @@ -288,7 +312,7 @@ void addEntry() { } catch (IOException e) { System.err.println("Failed to read the password."); e.printStackTrace(); - System.exit(-1); + throw new ExitException(-1); } } @@ -313,11 +337,11 @@ void addEntry() { } catch (KrbException e) { System.err.println("Failed to add " + principal + " to keytab."); e.printStackTrace(); - System.exit(-1); + throw new ExitException(-1); } catch (IOException e) { System.err.println("Failed to save new entry."); e.printStackTrace(); - System.exit(-1); + throw new ExitException(-1); } } @@ -399,22 +423,23 @@ void deleteEntry() { System.out.flush(); answer = cis.readLine(); if (answer.equalsIgnoreCase("Y") || - answer.equalsIgnoreCase("Yes")); - else { + answer.equalsIgnoreCase("Yes")) { + ; + } else { // no error, the user did not want to delete the entry - System.exit(0); + return; } } } catch (KrbException e) { System.err.println("Error occurred while deleting the entry. "+ "Deletion failed."); e.printStackTrace(); - System.exit(-1); + throw new ExitException(-1); } catch (IOException e) { System.err.println("Error occurred while deleting the entry. "+ " Deletion failed."); e.printStackTrace(); - System.exit(-1); + throw new ExitException(-1); } int count = table.deleteEntries(pname, etype, vDel); @@ -422,7 +447,7 @@ void deleteEntry() { if (count == 0) { System.err.println("No matched entry in the keytab. " + "Deletion fails."); - System.exit(-1); + throw new ExitException(-1); } else { try { table.save(); @@ -430,7 +455,7 @@ void deleteEntry() { System.err.println("Error occurs while saving the keytab. " + "Deletion fails."); e.printStackTrace(); - System.exit(-1); + throw new ExitException(-1); } System.out.println("Done! " + count + " entries removed."); } @@ -441,7 +466,7 @@ void error(String... errors) { System.out.println("Error: " + error + "."); } printHelp(); - System.exit(-1); + throw new ExitException(-1); } /** diff --git a/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Main.java b/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Main.java index 117fea688c7..ed2c9be8543 100644 --- a/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Main.java +++ b/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Main.java @@ -135,7 +135,19 @@ public class Main { // This is the entry that get launched by the security tool jarsigner. public static void main(String args[]) throws Exception { Main js = new Main(); - js.run(args); + int exitCode = js.run(args); + if (exitCode != 0) { + System.exit(exitCode); + } + } + + private static class ExitException extends RuntimeException { + @java.io.Serial + static final long serialVersionUID = 0L; + private final int errorCode; + public ExitException(int errorCode) { + this.errorCode = errorCode; + } } X509Certificate[] certChain; // signer's cert chain (when composing) @@ -230,13 +242,13 @@ public static void main(String args[]) throws Exception { PKIXBuilderParameters pkixParameters; Set trustedCerts = new HashSet<>(); - public void run(String args[]) { + public int run(String args[]) { try { - args = parseArgs(args); + parseArgs(args); // Try to load and install the specified providers if (providers != null) { - for (String provName: providers) { + for (String provName : providers) { try { KeyStoreUtil.loadProviderByName(provName, providerArgs.get(provName)); @@ -263,7 +275,7 @@ public void run(String args[]) { } else { cl = ClassLoader.getSystemClassLoader(); } - for (String provClass: providerClasses) { + for (String provClass : providerClasses) { try { KeyStoreUtil.loadProviderByClass(provClass, providerArgs.get(provClass), cl); @@ -285,19 +297,9 @@ public void run(String args[]) { loadKeyStore(keystore, false); } catch (Exception e) { if ((keystore != null) || (storepass != null)) { - System.out.println(rb.getString("jarsigner.error.") + - e.getMessage()); - if (debug) { - e.printStackTrace(); - } - System.exit(1); + throw e; } } - /* if (debug) { - SignatureFileVerifier.setDebug(true); - ManifestEntryVerifier.setDebug(true); - } - */ verifyJar(jarfile); } else { loadKeyStore(keystore, true); @@ -305,12 +307,14 @@ public void run(String args[]) { signJar(jarfile, alias); } + } catch (ExitException ee) { + return ee.errorCode; } catch (Exception e) { System.out.println(rb.getString("jarsigner.error.") + e); if (debug) { e.printStackTrace(); } - System.exit(1); + return 1; } finally { // zero-out private key password if (keypass != null) { @@ -343,10 +347,10 @@ public void run(String args[]) { if (tsaChainNotValidated) { exitCode |= 64; } - if (exitCode != 0) { - System.exit(exitCode); - } + return exitCode; } + + return 0; } /* @@ -612,12 +616,12 @@ static void usageNoArg() { static void usage() { System.out.println(); System.out.println(rb.getString("Please.type.jarsigner.help.for.usage")); - System.exit(1); + throw new ExitException(1); } static void doPrintVersion() { System.out.println("jarsigner " + System.getProperty("java.version")); - System.exit(0); + throw new ExitException(0); } static void fullusage() { @@ -719,7 +723,7 @@ static void fullusage() { (".print.this.help.message")); System.out.println(); - System.exit(0); + throw new ExitException(0); } void verifyJar(String jarName) @@ -1105,19 +1109,11 @@ void verifyJar(String jarName) } else { displayMessagesAndResult(false); } - return; - } catch (Exception e) { - System.out.println(rb.getString("jarsigner.") + e); - if (debug) { - e.printStackTrace(); - } } finally { // close the resource if (jf != null) { jf.close(); } } - - System.exit(1); } private void displayMessagesAndResult(boolean isSigning) { @@ -2469,7 +2465,7 @@ void getAliasInfo(String alias) throws Exception { void error(String message) { System.out.println(rb.getString("jarsigner.")+message); - System.exit(1); + throw new ExitException(1); } @@ -2478,7 +2474,7 @@ void error(String message, Throwable e) { if (debug) { e.printStackTrace(); } - System.exit(1); + throw new ExitException(1); } /** diff --git a/test/jdk/sun/security/krb5/tools/ExitOrNot.java b/test/jdk/sun/security/krb5/tools/ExitOrNot.java new file mode 100644 index 00000000000..9f3000dcb75 --- /dev/null +++ b/test/jdk/sun/security/krb5/tools/ExitOrNot.java @@ -0,0 +1,61 @@ +/* + * 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 8316964 + * @summary check exit code in kinit, klist, and ktab + * @requires os.family == "windows" + * @library /test/lib + * @modules java.security.jgss/sun.security.krb5.internal.tools + */ + +import jdk.test.lib.Asserts; +import jdk.test.lib.Platform; +import jdk.test.lib.SecurityTools; + +public class ExitOrNot { + + private static final int BAD = Platform.isWindows() ? -1 : 255; + + public static void main(String[] args) throws Exception { + + // launching the tool still exits + SecurityTools.kinit("u@R p1 p2") + .shouldHaveExitValue(BAD); + + SecurityTools.klist("-x") + .shouldHaveExitValue(BAD); + + SecurityTools.ktab("-x") + .shouldHaveExitValue(BAD); + + // calling the run() methods returns the exit code + Asserts.assertEQ(new sun.security.krb5.internal.tools.Kinit() + .run("u@R p1 p2".split(" ")), -1); + Asserts.assertEQ(new sun.security.krb5.internal.tools.Klist() + .run("-x".split(" ")), -1); + Asserts.assertEQ(new sun.security.krb5.internal.tools.Ktab() + .run("-x".split(" ")), -1); + } +} diff --git a/test/jdk/sun/security/tools/jarsigner/ExitOrNot.java b/test/jdk/sun/security/tools/jarsigner/ExitOrNot.java new file mode 100644 index 00000000000..ae55074f3a5 --- /dev/null +++ b/test/jdk/sun/security/tools/jarsigner/ExitOrNot.java @@ -0,0 +1,52 @@ +/* + * 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 8316964 + * @summary check exit code in jarsigner and keytool + * @library /test/lib + * @modules java.base/sun.security.tools.keytool + * jdk.jartool/sun.security.tools.jarsigner + */ + +import jdk.test.lib.Asserts; +import jdk.test.lib.SecurityTools; + +public class ExitOrNot { + public static void main(String[] args) throws Exception { + + // launching the tool still exits + SecurityTools.jarsigner("1 2 3") + .shouldHaveExitValue(1); + SecurityTools.keytool("-x") + .shouldHaveExitValue(1); + + // calling the run() methods no longer + Asserts.assertEQ(new sun.security.tools.jarsigner.Main() + .run("1 2 3".split(" ")), 1); + + Asserts.assertEQ(new sun.security.tools.keytool.Main() + .run("-x".split(" "), System.out), 1); + } +} From 9c819fd3b7e564b53514185573f4ffe28368b46b Mon Sep 17 00:00:00 2001 From: Eamonn McManus Date: Tue, 24 Oct 2023 18:32:33 +0000 Subject: [PATCH 103/124] 8318051: Duration.between uses exceptions for control flow Reviewed-by: rriggs --- .../share/classes/java/time/Duration.java | 33 ++++++++++--------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/src/java.base/share/classes/java/time/Duration.java b/src/java.base/share/classes/java/time/Duration.java index c1894e2db5a..ab46159efd6 100644 --- a/src/java.base/share/classes/java/time/Duration.java +++ b/src/java.base/share/classes/java/time/Duration.java @@ -486,23 +486,26 @@ private static Duration create(boolean negate, long daysAsSecs, long hoursAsSecs * @throws ArithmeticException if the calculation exceeds the capacity of {@code Duration} */ public static Duration between(Temporal startInclusive, Temporal endExclusive) { - try { + long secs = startInclusive.until(endExclusive, SECONDS); + if (secs == 0) { + // We don't know which Temporal is earlier, so the adjustment below would not work. + // But we do know that there's no danger of until(NANOS) overflowing in that case. return ofNanos(startInclusive.until(endExclusive, NANOS)); - } catch (DateTimeException | ArithmeticException ex) { - long secs = startInclusive.until(endExclusive, SECONDS); - long nanos; - try { - nanos = endExclusive.getLong(NANO_OF_SECOND) - startInclusive.getLong(NANO_OF_SECOND); - if (secs > 0 && nanos < 0) { - secs++; - } else if (secs < 0 && nanos > 0) { - secs--; - } - } catch (DateTimeException ex2) { - nanos = 0; - } - return ofSeconds(secs, nanos); } + long nanos; + try { + nanos = endExclusive.getLong(NANO_OF_SECOND) - startInclusive.getLong(NANO_OF_SECOND); + } catch (DateTimeException ex2) { + nanos = 0; + } + if (nanos < 0 && secs > 0) { + // ofSeconds will subtract one even though until(SECONDS) already gave the correct + // number of seconds. So compensate. Similarly for the secs < 0 case below. + secs++; + } else if (nanos > 0 && secs < 0) { + secs--; + } + return ofSeconds(secs, nanos); } //----------------------------------------------------------------------- From f1dfdc1a79f3a16eae58d15d1945541a08f7e145 Mon Sep 17 00:00:00 2001 From: Alexander Matveev Date: Tue, 24 Oct 2023 21:41:20 +0000 Subject: [PATCH 104/124] 8311877: [macos] Add CLI options to provide signing identity directly to codesign and productbuild Reviewed-by: asemenyuk --- .../jdk/jpackage/internal/MacAppBundler.java | 26 +++- .../jpackage/internal/MacAppImageBuilder.java | 50 ++++++-- .../internal/MacBaseInstallerBundler.java | 7 ++ .../jdk/jpackage/internal/MacPkgBundler.java | 54 ++++++-- .../resources/MacResources.properties | 3 +- .../resources/MacResources_de.properties | 3 +- .../resources/MacResources_ja.properties | 3 +- .../resources/MacResources_zh_CN.properties | 3 +- .../jdk/jpackage/internal/Arguments.java | 24 ++++ .../jpackage/internal/BundlerParamInfo.java | 28 +++-- .../jdk/jpackage/internal/ValidOptions.java | 6 +- .../resources/HelpResources.properties | 16 ++- .../resources/MainResources.properties | 5 +- .../resources/MainResources_de.properties | 3 +- .../resources/MainResources_ja.properties | 3 +- .../resources/MainResources_zh_CN.properties | 3 +- .../jpackage/macosx/SigningAppImageTest.java | 26 ++-- .../macosx/SigningAppImageTwoStepsTest.java | 34 ++++-- .../jpackage/macosx/SigningOptionsTest.java | 115 ++++++++++++++++++ ...SigningPackageFromTwoStepAppImageTest.java | 53 ++++++-- .../jpackage/macosx/SigningPackageTest.java | 86 +++++++++++-- .../macosx/SigningPackageTwoStepTest.java | 51 ++++++-- .../jpackage/macosx/base/SigningBase.java | 32 +++-- .../tests/PredefinedAppImageErrorTest.java | 2 +- 24 files changed, 531 insertions(+), 105 deletions(-) create mode 100644 test/jdk/tools/jpackage/macosx/SigningOptionsTest.java diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppBundler.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppBundler.java index cf031cb47a5..06796db9884 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppBundler.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppBundler.java @@ -85,6 +85,13 @@ public MacAppBundler() { }, (s, p) -> s); + public static final BundlerParamInfo APP_IMAGE_SIGN_IDENTITY = + new StandardBundlerParam<>( + Arguments.CLIOptions.MAC_APP_IMAGE_SIGN_IDENTITY.getId(), + String.class, + params -> "", + null); + public static final BundlerParamInfo BUNDLE_ID_SIGNING_PREFIX = new StandardBundlerParam<>( Arguments.CLIOptions.MAC_BUNDLE_SIGNING_PREFIX.getId(), @@ -127,14 +134,21 @@ private static void doValidate(Map params) // reject explicitly set sign to true and no valid signature key if (Optional.ofNullable( SIGN_BUNDLE.fetchFrom(params)).orElse(Boolean.FALSE)) { - String signingIdentity = - DEVELOPER_ID_APP_SIGNING_KEY.fetchFrom(params); - if (signingIdentity == null) { - throw new ConfigException( - I18N.getString("error.explicit-sign-no-cert"), - I18N.getString("error.explicit-sign-no-cert.advice")); + // Validate DEVELOPER_ID_APP_SIGNING_KEY only if user provided + // SIGNING_KEY_USER. + if (!SIGNING_KEY_USER.getIsDefaultValue(params)) { // --mac-signing-key-user-name + String signingIdentity = + DEVELOPER_ID_APP_SIGNING_KEY.fetchFrom(params); + if (signingIdentity == null) { + throw new ConfigException( + I18N.getString("error.explicit-sign-no-cert"), + I18N.getString("error.explicit-sign-no-cert.advice")); + } } + // No need to validate --mac-app-image-sign-identity, since it is + // pass through option. + // Signing will not work without Xcode with command line developer tools try { ProcessBuilder pb = new ProcessBuilder("/usr/bin/xcrun", "--help"); diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppImageBuilder.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppImageBuilder.java index d9250ae1474..ea86c41d981 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppImageBuilder.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppImageBuilder.java @@ -25,8 +25,10 @@ package jdk.jpackage.internal; +import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; +import java.io.PrintStream; import java.io.Writer; import java.nio.file.Files; import java.nio.file.Path; @@ -53,7 +55,10 @@ import jdk.internal.util.OSVersion; import static jdk.jpackage.internal.MacAppBundler.BUNDLE_ID_SIGNING_PREFIX; import static jdk.jpackage.internal.MacAppBundler.DEVELOPER_ID_APP_SIGNING_KEY; +import static jdk.jpackage.internal.MacAppBundler.APP_IMAGE_SIGN_IDENTITY; import static jdk.jpackage.internal.MacBaseInstallerBundler.SIGNING_KEYCHAIN; +import static jdk.jpackage.internal.MacBaseInstallerBundler.SIGNING_KEY_USER; +import static jdk.jpackage.internal.MacBaseInstallerBundler.INSTALLER_SIGN_IDENTITY; import static jdk.jpackage.internal.OverridableResource.createResource; import static jdk.jpackage.internal.StandardBundlerParam.APP_NAME; import static jdk.jpackage.internal.StandardBundlerParam.CONFIG_ROOT; @@ -395,12 +400,25 @@ private void doSigning(Map params) } catch (InterruptedException e) { Log.error(e.getMessage()); } - String signingIdentity = - DEVELOPER_ID_APP_SIGNING_KEY.fetchFrom(params); + String signingIdentity = null; + // Try --mac-app-image-sign-identity first if set + if (!APP_IMAGE_SIGN_IDENTITY.getIsDefaultValue(params)) { + signingIdentity = APP_IMAGE_SIGN_IDENTITY.fetchFrom(params); + } else { + // Check if INSTALLER_SIGN_IDENTITY is set and if it is set + // then do not sign app image, otherwise use --mac-signing-key-user-name + if (INSTALLER_SIGN_IDENTITY.getIsDefaultValue(params)) { + // --mac-sign and/or --mac-signing-key-user-name case + signingIdentity = DEVELOPER_ID_APP_SIGNING_KEY.fetchFrom(params); + } + } if (signingIdentity != null) { signAppBundle(params, root, signingIdentity, BUNDLE_ID_SIGNING_PREFIX.fetchFrom(params), ENTITLEMENTS.fetchFrom(params)); + } else { + // Case when user requested to sign installer only + signAppBundle(params, root, "-", null, null); } restoreKeychainList(params); } else if (OperatingSystem.isMacOS()) { @@ -715,6 +733,25 @@ private static List getCodesignArgs( return args; } + private static void runCodesign(ProcessBuilder pb, boolean quiet) + throws IOException { + try (ByteArrayOutputStream baos = new ByteArrayOutputStream(); + PrintStream ps = new PrintStream(baos)) { + try { + IOUtils.exec(pb, false, ps, false, + Executor.INFINITE_TIMEOUT, quiet); + } catch (IOException ioe) { + // Log output of "codesign" in case of + // error. It should help user to diagnose + // issue when using --mac-app-image-sign-identity + Log.info(MessageFormat.format(I18N.getString( + "error.tool.failed.with.output"), "codesign")); + Log.info(baos.toString().strip()); + throw ioe; + } + } + } + static void signAppBundle( Map params, Path appLocation, String signingIdentity, String identifierPrefix, Path entitlements) @@ -781,8 +818,7 @@ static void signAppBundle( p.toFile().setWritable(true, true); ProcessBuilder pb = new ProcessBuilder(args); // run quietly - IOUtils.exec(pb, false, null, false, - Executor.INFINITE_TIMEOUT, true); + runCodesign(pb, true); Files.setPosixFilePermissions(p, oldPermissions); } catch (IOException ioe) { toThrow.set(ioe); @@ -810,8 +846,7 @@ static void signAppBundle( List args = getCodesignArgs(true, path, signingIdentity, identifierPrefix, entitlements, keyChain); ProcessBuilder pb = new ProcessBuilder(args); - - IOUtils.exec(pb); + runCodesign(pb, false); } catch (IOException e) { toThrow.set(e); } @@ -842,8 +877,7 @@ static void signAppBundle( List args = getCodesignArgs(true, appLocation, signingIdentity, identifierPrefix, entitlements, keyChain); ProcessBuilder pb = new ProcessBuilder(args); - - IOUtils.exec(pb); + runCodesign(pb, false); } private static String extractBundleIdentifier(Map params) { diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBaseInstallerBundler.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBaseInstallerBundler.java index b4f63d66f57..8d9db0a0077 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBaseInstallerBundler.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacBaseInstallerBundler.java @@ -79,6 +79,13 @@ public abstract class MacBaseInstallerBundler extends AbstractBundler { params -> "", null); + public static final BundlerParamInfo INSTALLER_SIGN_IDENTITY = + new StandardBundlerParam<>( + Arguments.CLIOptions.MAC_INSTALLER_SIGN_IDENTITY.getId(), + String.class, + params -> "", + null); + public static final BundlerParamInfo MAC_INSTALLER_NAME = new StandardBundlerParam<> ( "mac.installerName", diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgBundler.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgBundler.java index 60cd11b6f06..6ac84975451 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgBundler.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacPkgBundler.java @@ -28,7 +28,9 @@ import jdk.internal.util.Architecture; import jdk.internal.util.OSVersion; +import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.io.PrintStream; import java.io.PrintWriter; import java.net.URI; import java.net.URISyntaxException; @@ -54,6 +56,8 @@ import static jdk.jpackage.internal.StandardBundlerParam.SIGN_BUNDLE; import static jdk.jpackage.internal.MacBaseInstallerBundler.SIGNING_KEYCHAIN; import static jdk.jpackage.internal.MacBaseInstallerBundler.SIGNING_KEY_USER; +import static jdk.jpackage.internal.MacBaseInstallerBundler.INSTALLER_SIGN_IDENTITY; +import static jdk.jpackage.internal.MacAppBundler.APP_IMAGE_SIGN_IDENTITY; import static jdk.jpackage.internal.StandardBundlerParam.APP_STORE; import static jdk.jpackage.internal.MacAppImageBuilder.MAC_CF_BUNDLE_IDENTIFIER; import static jdk.jpackage.internal.OverridableResource.createResource; @@ -605,8 +609,19 @@ private Path createPKG(Map params, Log.verbose(I18N.getString("message.signing.pkg")); } - String signingIdentity = - DEVELOPER_ID_INSTALLER_SIGNING_KEY.fetchFrom(params); + String signingIdentity = null; + // --mac-installer-sign-identity + if (!INSTALLER_SIGN_IDENTITY.getIsDefaultValue(params)) { + signingIdentity = INSTALLER_SIGN_IDENTITY.fetchFrom(params); + } else { + // Use --mac-signing-key-user-name if user did not request + // to sign just app image using --mac-app-image-sign-identity + if (APP_IMAGE_SIGN_IDENTITY.getIsDefaultValue(params)) { + // --mac-signing-key-user-name + signingIdentity = DEVELOPER_ID_INSTALLER_SIGNING_KEY.fetchFrom(params); + } + } + if (signingIdentity != null) { commandLine.add("--sign"); commandLine.add(signingIdentity); @@ -638,7 +653,21 @@ private Path createPKG(Map params, commandLine.add(finalPKG.toAbsolutePath().toString()); pb = new ProcessBuilder(commandLine); - IOUtils.exec(pb, false, null, true, Executor.INFINITE_TIMEOUT); + + try (ByteArrayOutputStream baos = new ByteArrayOutputStream(); + PrintStream ps = new PrintStream(baos)) { + try { + IOUtils.exec(pb, false, ps, true, Executor.INFINITE_TIMEOUT); + } catch (IOException ioe) { + // Log output of "productbuild" in case of + // error. It should help user to diagnose + // issue when using --mac-installer-sign-identity + Log.info(MessageFormat.format(I18N.getString( + "error.tool.failed.with.output"), "productbuild")); + Log.info(baos.toString().strip()); + throw ioe; + } + } return finalPKG; } catch (Exception ignored) { @@ -702,14 +731,19 @@ public boolean validate(Map params) // reject explicitly set sign to true and no valid signature key if (Optional.ofNullable( SIGN_BUNDLE.fetchFrom(params)).orElse(Boolean.FALSE)) { - String signingIdentity = - DEVELOPER_ID_INSTALLER_SIGNING_KEY.fetchFrom(params); - if (signingIdentity == null) { - throw new ConfigException( - I18N.getString("error.explicit-sign-no-cert"), - I18N.getString( - "error.explicit-sign-no-cert.advice")); + if (!SIGNING_KEY_USER.getIsDefaultValue(params)) { + String signingIdentity = + DEVELOPER_ID_INSTALLER_SIGNING_KEY.fetchFrom(params); + if (signingIdentity == null) { + throw new ConfigException( + I18N.getString("error.explicit-sign-no-cert"), + I18N.getString( + "error.explicit-sign-no-cert.advice")); + } } + + // No need to validate --mac-installer-sign-identity, since it is + // pass through option. } // hdiutil is always available so there's no need diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources.properties b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources.properties index c575df2494e..de4e7157b2a 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources.properties +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. +# 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 @@ -44,6 +44,7 @@ error.no.xcode.signing.advice=Install Xcode with command line developer tools. error.cert.not.found=No certificate found matching [{0}] using keychain [{1}] error.multiple.certs.found=WARNING: Multiple certificates found matching [{0}] using keychain [{1}], using first one error.app-image.mac-sign.required=Error: --mac-sign option is required with predefined application image and with type [app-image] +error.tool.failed.with.output=Error: "{0}" failed with following output: resource.bundle-config-file=Bundle config file resource.app-info-plist=Application Info.plist resource.runtime-info-plist=Java Runtime Info.plist diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources_de.properties b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources_de.properties index 6dd037c9bce..8586041d417 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources_de.properties +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources_de.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. +# 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 @@ -44,6 +44,7 @@ error.no.xcode.signing.advice=Installieren Sie Xcode mit Befehlszeilen-Entwickle error.cert.not.found=Kein Zertifikat gefunden, das [{0}] mit Schlüsselbund [{1}] entspricht error.multiple.certs.found=WARNUNG: Mehrere Zertifikate gefunden, die [{0}] mit Schlüsselbund [{1}] entsprechen. Es wird das erste Zertifikat verwendet error.app-image.mac-sign.required=Fehler: Die Option "--mac-sign" ist mit einem vordefinierten Anwendungsimage und Typ [app-image] erforderlich +error.tool.failed.with.output=Error: "{0}" failed with following output: resource.bundle-config-file=Bundle-Konfigurationsdatei resource.app-info-plist=Info.plist der Anwendung resource.runtime-info-plist=Info.plist von Java Runtime diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources_ja.properties b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources_ja.properties index b75d1dc465f..518e3e45f97 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources_ja.properties +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources_ja.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. +# 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 @@ -44,6 +44,7 @@ error.no.xcode.signing.advice=Xcodeとコマンドライン・デベロッパ・ error.cert.not.found=キーチェーン[{1}]を使用する[{0}]と一致する証明書が見つかりません error.multiple.certs.found=警告: キーチェーン[{1}]を使用する[{0}]と一致する複数の証明書が見つかりました。最初のものを使用します error.app-image.mac-sign.required=エラー: --mac-signオプションは、事前定義済アプリケーション・イメージおよびタイプ[app-image]で必要です +error.tool.failed.with.output=Error: "{0}" failed with following output: resource.bundle-config-file=バンドル構成ファイル resource.app-info-plist=アプリケーションのInfo.plist resource.runtime-info-plist=JavaランタイムのInfo.plist diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources_zh_CN.properties b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources_zh_CN.properties index dc1f592852d..c4e4bd22939 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources_zh_CN.properties +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/resources/MacResources_zh_CN.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. +# 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 @@ -44,6 +44,7 @@ error.no.xcode.signing.advice=安装带命令行开发人员工具的 Xcode。 error.cert.not.found=使用密钥链 [{1}] 找不到与 [{0}] 匹配的证书 error.multiple.certs.found=警告:使用密钥链 [{1}] 找到多个与 [{0}] 匹配的证书,将使用第一个证书 error.app-image.mac-sign.required=错误:预定义的应用程序映像和类型 [app image] 需要 --mac-sign 选项 +error.tool.failed.with.output=Error: "{0}" failed with following output: resource.bundle-config-file=包配置文件 resource.app-info-plist=应用程序 Info.plist resource.runtime-info-plist=Java 运行时 Info.plist diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Arguments.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Arguments.java index b4a28e7fb3c..16cd89d9d52 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Arguments.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Arguments.java @@ -338,6 +338,12 @@ public enum CLIOptions { MAC_SIGNING_KEY_NAME ("mac-signing-key-user-name", OptionCategories.PLATFORM_MAC), + MAC_APP_IMAGE_SIGN_IDENTITY ("mac-app-image-sign-identity", + OptionCategories.PLATFORM_MAC), + + MAC_INSTALLER_SIGN_IDENTITY ("mac-installer-sign-identity", + OptionCategories.PLATFORM_MAC), + MAC_SIGNING_KEYCHAIN ("mac-signing-keychain", OptionCategories.PLATFORM_MAC), @@ -631,6 +637,24 @@ private void validateArguments() throws PackagerException { CLIOptions.JLINK_OPTIONS.getIdWithPrefix()); } } + if (allOptions.contains(CLIOptions.MAC_SIGNING_KEY_NAME) && + allOptions.contains(CLIOptions.MAC_APP_IMAGE_SIGN_IDENTITY)) { + throw new PackagerException("ERR_MutuallyExclusiveOptions", + CLIOptions.MAC_SIGNING_KEY_NAME.getIdWithPrefix(), + CLIOptions.MAC_APP_IMAGE_SIGN_IDENTITY.getIdWithPrefix()); + } + if (allOptions.contains(CLIOptions.MAC_SIGNING_KEY_NAME) && + allOptions.contains(CLIOptions.MAC_INSTALLER_SIGN_IDENTITY)) { + throw new PackagerException("ERR_MutuallyExclusiveOptions", + CLIOptions.MAC_SIGNING_KEY_NAME.getIdWithPrefix(), + CLIOptions.MAC_INSTALLER_SIGN_IDENTITY.getIdWithPrefix()); + } + if (isMac && (imageOnly || "dmg".equals(type)) && + allOptions.contains(CLIOptions.MAC_INSTALLER_SIGN_IDENTITY)) { + throw new PackagerException("ERR_InvalidTypeOption", + CLIOptions.MAC_INSTALLER_SIGN_IDENTITY.getIdWithPrefix(), + type); + } if (allOptions.contains(CLIOptions.DMG_CONTENT) && !("dmg".equals(type))) { throw new PackagerException("ERR_InvalidTypeOption", diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BundlerParamInfo.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BundlerParamInfo.java index 4173980002b..fa99073ff7f 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BundlerParamInfo.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/BundlerParamInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 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 @@ -46,11 +46,6 @@ class BundlerParamInfo { */ Class valueType; - /** - * Indicates if value was set using default value function - */ - boolean isDefaultValue; - /** * If the value is not set, and no fallback value is found, * the parameter uses the value returned by the producer. @@ -70,8 +65,24 @@ Class getValueType() { return valueType; } - boolean getIsDefaultValue() { - return isDefaultValue; + /** + * Returns true if value was not provided on command line for this + * parameter. + * + * @param params - params from which value will be fetch + * @return true if value was not provided on command line, false otherwise + */ + boolean getIsDefaultValue(Map params) { + Object o = params.get(getID()); + if (o != null) { + return false; // We have user provided value + } + + if (params.containsKey(getID())) { + return false; // explicit nulls are allowed for provided value + } + + return true; } Function, T> getDefaultValueFunction() { @@ -114,7 +125,6 @@ final T fetchFrom(Map params, T result = getDefaultValueFunction().apply(params); if (result != null) { params.put(getID(), result); - isDefaultValue = true; } return result; } diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ValidOptions.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ValidOptions.java index 4d3e163cdc1..89a2e4b56fe 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ValidOptions.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ValidOptions.java @@ -27,6 +27,7 @@ import java.util.EnumSet; import java.util.HashMap; + import jdk.internal.util.OperatingSystem; import jdk.jpackage.internal.Arguments.CLIOptions; @@ -62,7 +63,6 @@ enum USE { private static final HashMap> options = new HashMap<>(); - // initializing list of mandatory arguments static { put(CLIOptions.NAME.getId(), USE.ALL); @@ -130,6 +130,10 @@ enum USE { EnumSet.of(USE.ALL, USE.SIGN)); put(CLIOptions.MAC_SIGNING_KEY_NAME.getId(), EnumSet.of(USE.ALL, USE.SIGN)); + put(CLIOptions.MAC_APP_IMAGE_SIGN_IDENTITY.getId(), + EnumSet.of(USE.ALL, USE.SIGN)); + put(CLIOptions.MAC_INSTALLER_SIGN_IDENTITY.getId(), + EnumSet.of(USE.INSTALL, USE.SIGN)); put(CLIOptions.MAC_SIGNING_KEYCHAIN.getId(), EnumSet.of(USE.ALL, USE.SIGN)); put(CLIOptions.MAC_APP_STORE.getId(), USE.ALL); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/HelpResources.properties b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/HelpResources.properties index 6c92cf3e55c..c21daab30d0 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/HelpResources.properties +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/HelpResources.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. +# 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 @@ -265,7 +265,19 @@ MSG_Help_mac_launcher=\ \ Name of the keychain to search for the signing identity\n\ \ If not specified, the standard keychains are used.\n\ \ --mac-signing-key-user-name \n\ -\ Team or user name portion of Apple signing identities.\n\ +\ Team or user name portion of Apple signing identities. For direct\n\ +\ control of the signing identity used to sign application images or\n\ +\ installers use --mac-app-image-sign-identity and/or\n\ +\ --mac-installer-sign-identity. This option cannot be combined with\n\ +\ --mac-app-image-sign-identity or --mac-installer-sign-identity.\n\ +\ --mac-app-image-sign-identity \n\ +\ Identity used to sign application image. This value will be passed\n\ +\ directly to --sign option of "codesign" tool. This option cannot\n\ +\ be combined with --mac-signing-key-user-name.\n\ +\ --mac-installer-sign-identity \n\ +\ Identity used to sign "pkg" installer. This value will be passed\n\ +\ directly to --sign option of "productbuild" tool. This option\n\ +\ cannot be combined with --mac-signing-key-user-name.\n\ \ --mac-app-store\n\ \ Indicates that the jpackage output is intended for the\n\ \ Mac App Store.\n\ diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources.properties b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources.properties index 5297ef92d34..4c5d51d5bcc 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources.properties +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. +# 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 @@ -92,10 +92,11 @@ ERR_NoMainClass=Error: Main application class is missing ERR_UnsupportedOption=Error: Option [{0}] is not valid on this platform ERR_InvalidTypeOption=Error: Option [{0}] is not valid with type [{1}] ERR_NoInstallerEntryPoint=Error: Option [{0}] is not valid without --module or --main-jar entry point option -ERR_MutuallyExclusiveOptions="Error: Mutually exclusive options [{0}] and [{1}] +ERR_MutuallyExclusiveOptions=Error: Mutually exclusive options [{0}] and [{1}] ERR_InvalidOptionWithAppImageSigning=Error: Option [{0}] is not valid when signing application image ERR_MissingArgument=Error: Missing argument: {0} +ERR_MissingRequiredArgument=Error: {0} argument requires at least one of [{1}] argument(s) ERR_MissingAppResources=Error: No application jars found ERR_AppImageNotExist=Error: App image directory "{0}" does not exist ERR_NoAddLauncherName=Error: --add-launcher option requires a name and a file path (--add-launcher =) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources_de.properties b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources_de.properties index 732c8a339f9..e505262ea28 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources_de.properties +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources_de.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. +# 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 @@ -95,6 +95,7 @@ ERR_MutuallyExclusiveOptions="Fehler: Optionen [{0}] und [{1}] schließen sich g ERR_InvalidOptionWithAppImageSigning=Fehler: Option [{0}] ist nicht gültig beim Signieren eines Anwendungsimages ERR_MissingArgument=Fehler: Fehlendes Argument: {0} +ERR_MissingRequiredArgument=Error: {0} argument requires at least one of [{1}] argument(s) ERR_MissingAppResources=Fehler: Keine Anwendungs-JAR-Dateien gefunden ERR_AppImageNotExist=Fehler: Anwendungsimageverzeichnis "{0}" ist nicht vorhanden ERR_NoAddLauncherName=Fehler: Für Option --add-launcher müssen ein Name und ein Dateipfad angegeben werden (--add-launcher =) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources_ja.properties b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources_ja.properties index 8b4c457e61c..6cc9c23793c 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources_ja.properties +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources_ja.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. +# 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 @@ -95,6 +95,7 @@ ERR_MutuallyExclusiveOptions="エラー: 相互排他的なオプション[{0}] ERR_InvalidOptionWithAppImageSigning=エラー: アプリケーション・イメージへの署名時にオプション[{0}]が有効ではありません ERR_MissingArgument=エラー: 引数がありません: {0} +ERR_MissingRequiredArgument=Error: {0} argument requires at least one of [{1}] argument(s) ERR_MissingAppResources=エラー: アプリケーションjarが見つかりませんでした ERR_AppImageNotExist=エラー: アプリケーション・イメージ・ディレクトリ"{0}"は存在しません ERR_NoAddLauncherName=エラー: --add-launcherオプションには名前およびファイル・パスが必要です(--add-launcher =) diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources_zh_CN.properties b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources_zh_CN.properties index 4a37c781ba4..7eab865568c 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources_zh_CN.properties +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/MainResources_zh_CN.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. +# 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 @@ -95,6 +95,7 @@ ERR_MutuallyExclusiveOptions="错误:选项 [{0}] 和 [{1}] 相互排斥 ERR_InvalidOptionWithAppImageSigning=错误:对应用程序映像签名时,选项 [{0}] 无效 ERR_MissingArgument=错误: 缺少参数: {0} +ERR_MissingRequiredArgument=Error: {0} argument requires at least one of [{1}] argument(s) ERR_MissingAppResources=错误: 找不到应用程序 jar ERR_AppImageNotExist=错误:应用程序映像目录 "{0}" 不存在 ERR_NoAddLauncherName=错误:--add-launcher 选项需要一个名称和一个文件路径 (--add-launcher =) diff --git a/test/jdk/tools/jpackage/macosx/SigningAppImageTest.java b/test/jdk/tools/jpackage/macosx/SigningAppImageTest.java index 6cea5ebd332..65793baa096 100644 --- a/test/jdk/tools/jpackage/macosx/SigningAppImageTest.java +++ b/test/jdk/tools/jpackage/macosx/SigningAppImageTest.java @@ -55,28 +55,40 @@ * @build SigningAppImageTest * @modules jdk.jpackage/jdk.jpackage.internal * @requires (os.family == "mac") - * @run main/othervm -Xmx512m jdk.jpackage.test.Main + * @run main/othervm/timeout=720 -Xmx512m jdk.jpackage.test.Main * --jpt-run=SigningAppImageTest */ public class SigningAppImageTest { @Test - @Parameter({"true", "0"}) // ({"sign or not", "certificate index"}) - @Parameter({"true", "1"}) - @Parameter({"false", "-1"}) + // ({"sign or not", "signing-key or sign-identity", "certificate index"}) + // Sign, signing-key and ASCII certificate + @Parameter({"true", "true", SigningBase.ASCII_INDEX}) + // Sign, signing-key and UNICODE certificate + @Parameter({"true", "true", SigningBase.UNICODE_INDEX}) + // Sign, signing-indentity and UNICODE certificate + @Parameter({"true", "false", SigningBase.UNICODE_INDEX}) + // Unsigned + @Parameter({"false", "true", "-1"}) public void test(String... testArgs) throws Exception { boolean doSign = Boolean.parseBoolean(testArgs[0]); - int certIndex = Integer.parseInt(testArgs[1]); + boolean signingKey = Boolean.parseBoolean(testArgs[1]); + int certIndex = Integer.parseInt(testArgs[2]); SigningCheck.checkCertificates(certIndex); JPackageCommand cmd = JPackageCommand.helloAppImage(); if (doSign) { cmd.addArguments("--mac-sign", - "--mac-signing-key-user-name", - SigningBase.getDevName(certIndex), "--mac-signing-keychain", SigningBase.getKeyChain()); + if (signingKey) { + cmd.addArguments("--mac-signing-key-user-name", + SigningBase.getDevName(certIndex)); + } else { + cmd.addArguments("--mac-app-image-sign-identity", + SigningBase.getAppCert(certIndex)); + } } AdditionalLauncher testAL = new AdditionalLauncher("testAL"); testAL.applyTo(cmd); diff --git a/test/jdk/tools/jpackage/macosx/SigningAppImageTwoStepsTest.java b/test/jdk/tools/jpackage/macosx/SigningAppImageTwoStepsTest.java index b5d1030ab95..cf479d9ba94 100644 --- a/test/jdk/tools/jpackage/macosx/SigningAppImageTwoStepsTest.java +++ b/test/jdk/tools/jpackage/macosx/SigningAppImageTwoStepsTest.java @@ -56,15 +56,23 @@ * @build SigningAppImageTwoStepsTest * @modules jdk.jpackage/jdk.jpackage.internal * @requires (os.family == "mac") - * @run main/othervm/timeout=360 -Xmx512m jdk.jpackage.test.Main + * @run main/othervm/timeout=720 -Xmx512m jdk.jpackage.test.Main * --jpt-run=SigningAppImageTwoStepsTest */ public class SigningAppImageTwoStepsTest { @Test - @Parameter("true") - @Parameter("false") - public void test(boolean signAppImage) throws Exception { + // ({"sign or not", "signing-key or sign-identity"}) + // Sign and signing-key + @Parameter({"true", "true"}) + // Sign and sign-identity + @Parameter({"true", "false"}) + // Unsigned + @Parameter({"false", "true"}) + public void test(String... testArgs) throws Exception { + boolean signAppImage = Boolean.parseBoolean(testArgs[0]); + boolean signingKey = Boolean.parseBoolean(testArgs[1]); + SigningCheck.checkCertificates(SigningBase.DEFAULT_INDEX); Path appimageOutput = TKit.createTempDirectory("appimage"); @@ -76,10 +84,15 @@ public void test(boolean signAppImage) throws Exception { .setArgumentValue("--dest", appimageOutput); if (signAppImage) { appImageCmd.addArguments("--mac-sign", - "--mac-signing-key-user-name", - SigningBase.getDevName(SigningBase.DEFAULT_INDEX), "--mac-signing-keychain", SigningBase.getKeyChain()); + if (signingKey) { + appImageCmd.addArguments("--mac-signing-key-user-name", + SigningBase.getDevName(SigningBase.DEFAULT_INDEX)); + } else { + appImageCmd.addArguments("--mac-app-image-sign-identity", + SigningBase.getAppCert(SigningBase.DEFAULT_INDEX)); + } } // Add addtional launcher @@ -97,9 +110,14 @@ public void test(boolean signAppImage) throws Exception { cmd.setPackageType(PackageType.IMAGE) .addArguments("--app-image", appImageCmd.outputBundle().toAbsolutePath()) .addArguments("--mac-sign") - .addArguments("--mac-signing-key-user-name", - SigningBase.getDevName(SigningBase.DEFAULT_INDEX)) .addArguments("--mac-signing-keychain", SigningBase.getKeyChain()); + if (signingKey) { + cmd.addArguments("--mac-signing-key-user-name", + SigningBase.getDevName(SigningBase.DEFAULT_INDEX)); + } else { + cmd.addArguments("--mac-app-image-sign-identity", + SigningBase.getAppCert(SigningBase.DEFAULT_INDEX)); + } cmd.executeAndAssertImageCreated(); // Should be signed app image diff --git a/test/jdk/tools/jpackage/macosx/SigningOptionsTest.java b/test/jdk/tools/jpackage/macosx/SigningOptionsTest.java new file mode 100644 index 00000000000..10b2dd6c8d2 --- /dev/null +++ b/test/jdk/tools/jpackage/macosx/SigningOptionsTest.java @@ -0,0 +1,115 @@ +/* + * 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. + */ + +import java.util.Collection; +import java.util.List; +import jdk.jpackage.test.Annotations.Parameters; +import jdk.jpackage.test.Annotations.Test; +import jdk.jpackage.test.JPackageCommand; +import jdk.jpackage.test.TKit; + +/* + * @test + * @summary Test jpackage signing options errors + * @library ../helpers + * @build SigningOptionsTest + * @modules jdk.jpackage/jdk.jpackage.internal + * @requires (os.family == "mac") + * @run main/othervm/timeout=360 -Xmx512m jdk.jpackage.test.Main + * --jpt-run=SigningOptionsTest + * --jpt-before-run=jdk.jpackage.test.JPackageCommand.useExecutableByDefault + */ + +/* + * @test + * @summary Test jpackage signing options errors + * @library ../helpers + * @build SigningOptionsTest + * @modules jdk.jpackage/jdk.jpackage.internal + * @requires (os.family == "mac") + * @run main/othervm/timeout=360 -Xmx512m jdk.jpackage.test.Main + * --jpt-run=SigningOptionsTest + * --jpt-before-run=jdk.jpackage.test.JPackageCommand.useToolProviderByDefault + */ + +public final class SigningOptionsTest { + + private final String expectedError; + private final JPackageCommand cmd; + + @Parameters + public static Collection input() { + return List.of(new Object[][]{ + // --mac-signing-key-user-name and --mac-app-image-sign-identity + {"Hello", + new String[]{"--mac-sign", + "--mac-signing-key-user-name", "test-key", + "--mac-app-image-sign-identity", "test-identity"}, + null, + "Mutually exclusive options"}, + // --mac-signing-key-user-name and --mac-installer-sign-identity + {"Hello", + new String[]{"--mac-sign", + "--mac-signing-key-user-name", "test-key", + "--mac-installer-sign-identity", "test-identity"}, + null, + "Mutually exclusive options"}, + // --mac-installer-sign-identity and --type app-image + {"Hello", + new String[]{"--mac-sign", + "--mac-installer-sign-identity", "test-identity"}, + null, + "Option [--mac-installer-sign-identity] is not valid with type"}, + // --mac-installer-sign-identity and --type dmg + {"Hello", + new String[]{"--type", "dmg", + "--mac-sign", + "--mac-installer-sign-identity", "test-identity"}, + new String[]{"--type"}, + "Option [--mac-installer-sign-identity] is not valid with type"}, + }); + } + + public SigningOptionsTest(String javaAppDesc, String[] jpackageArgs, + String[] removeArgs, String expectedError) { + this.expectedError = expectedError; + + cmd = JPackageCommand.helloAppImage(javaAppDesc) + .saveConsoleOutput(true).dumpOutput(true); + if (jpackageArgs != null) { + cmd.addArguments(jpackageArgs); + } if (removeArgs != null) { + for (String arg : removeArgs) { + cmd.removeArgumentWithValue(arg); + } + } + } + + @Test + public void test() { + List output = cmd.execute(1).getOutput(); + TKit.assertNotNull(output, "output is null"); + TKit.assertTextStream(expectedError).apply(output.stream()); + } + +} diff --git a/test/jdk/tools/jpackage/macosx/SigningPackageFromTwoStepAppImageTest.java b/test/jdk/tools/jpackage/macosx/SigningPackageFromTwoStepAppImageTest.java index 861bcecfe09..48f5dca8986 100644 --- a/test/jdk/tools/jpackage/macosx/SigningPackageFromTwoStepAppImageTest.java +++ b/test/jdk/tools/jpackage/macosx/SigningPackageFromTwoStepAppImageTest.java @@ -72,7 +72,7 @@ private static void verifyPKG(JPackageCommand cmd) { } Path outputBundle = cmd.outputBundle(); - SigningBase.verifyPkgutil(outputBundle, SigningBase.DEFAULT_INDEX); + SigningBase.verifyPkgutil(outputBundle, true, SigningBase.DEFAULT_INDEX); SigningBase.verifySpctl(outputBundle, "install", SigningBase.DEFAULT_INDEX); } @@ -97,9 +97,17 @@ private static void verifyAppImageInDMG(JPackageCommand cmd) { } @Test - @Parameter("true") - @Parameter("false") - public static void test(boolean signAppImage) throws Exception { + // ({"sign or not", "signing-key or sign-identity"}) + // Sign and signing-key + @Parameter({"true", "true"}) + // Sign and sign-identity + @Parameter({"true", "false"}) + // Unsigned + @Parameter({"false", "true"}) + public void test(String... testArgs) throws Exception { + boolean signAppImage = Boolean.parseBoolean(testArgs[0]); + boolean signingKey = Boolean.parseBoolean(testArgs[1]); + SigningCheck.checkCertificates(SigningBase.DEFAULT_INDEX); Path appimageOutput = TKit.createTempDirectory("appimage"); @@ -110,9 +118,15 @@ public static void test(boolean signAppImage) throws Exception { JPackageCommand appImageCmd = JPackageCommand.helloAppImage() .setArgumentValue("--dest", appimageOutput); if (signAppImage) { - appImageCmd.addArguments("--mac-sign", "--mac-signing-key-user-name", - SigningBase.getDevName(SigningBase.DEFAULT_INDEX), + appImageCmd.addArguments("--mac-sign", "--mac-signing-keychain", SigningBase.getKeyChain()); + if (signingKey) { + appImageCmd.addArguments("--mac-signing-key-user-name", + SigningBase.getDevName(SigningBase.DEFAULT_INDEX)); + } else { + appImageCmd.addArguments("--mac-app-image-sign-identity", + SigningBase.getAppCert(SigningBase.DEFAULT_INDEX)); + } } // Generate app image @@ -126,9 +140,14 @@ public static void test(boolean signAppImage) throws Exception { appImageSignedCmd.setPackageType(PackageType.IMAGE) .addArguments("--app-image", appImageCmd.outputBundle().toAbsolutePath()) .addArguments("--mac-sign") - .addArguments("--mac-signing-key-user-name", - SigningBase.getDevName(SigningBase.DEFAULT_INDEX)) .addArguments("--mac-signing-keychain", SigningBase.getKeyChain()); + if (signingKey) { + appImageSignedCmd.addArguments("--mac-signing-key-user-name", + SigningBase.getDevName(SigningBase.DEFAULT_INDEX)); + } else { + appImageSignedCmd.addArguments("--mac-app-image-sign-identity", + SigningBase.getAppCert(SigningBase.DEFAULT_INDEX)); + } appImageSignedCmd.executeAndAssertImageCreated(); // Should be signed app image @@ -141,16 +160,30 @@ public static void test(boolean signAppImage) throws Exception { cmd.removeArgumentWithValue("--input"); if (signAppImage) { cmd.addArguments("--mac-sign", - "--mac-signing-key-user-name", - SigningBase.getDevName(SigningBase.DEFAULT_INDEX), "--mac-signing-keychain", SigningBase.getKeyChain()); + if (signingKey) { + cmd.addArguments("--mac-signing-key-user-name", + SigningBase.getDevName(SigningBase.DEFAULT_INDEX)); + } else { + cmd.addArguments("--mac-installer-sign-identity", + SigningBase.getInstallerCert(SigningBase.DEFAULT_INDEX)); + } } }) .forTypes(PackageType.MAC_PKG) .addBundleVerifier( SigningPackageFromTwoStepAppImageTest::verifyPKG) .forTypes(PackageType.MAC_DMG) + .addInitializer(cmd -> { + if (signAppImage && !signingKey) { + // jpackage throws expected error with + // --mac-installer-sign-identity and DMG type + cmd.removeArgument("--mac-sign"); + cmd.removeArgumentWithValue("--mac-signing-keychain"); + cmd.removeArgumentWithValue("--mac-installer-sign-identity"); + } + }) .addBundleVerifier( SigningPackageFromTwoStepAppImageTest::verifyDMG) .addBundleVerifier( diff --git a/test/jdk/tools/jpackage/macosx/SigningPackageTest.java b/test/jdk/tools/jpackage/macosx/SigningPackageTest.java index d7a2395db2a..c555b0386cd 100644 --- a/test/jdk/tools/jpackage/macosx/SigningPackageTest.java +++ b/test/jdk/tools/jpackage/macosx/SigningPackageTest.java @@ -59,15 +59,27 @@ * @build SigningPackageTest * @modules jdk.jpackage/jdk.jpackage.internal * @requires (os.family == "mac") - * @run main/othervm/timeout=360 -Xmx512m jdk.jpackage.test.Main + * @run main/othervm/timeout=720 -Xmx512m jdk.jpackage.test.Main * --jpt-run=SigningPackageTest */ public class SigningPackageTest { + private static boolean isAppImageSigned(JPackageCommand cmd) { + return cmd.hasArgument("--mac-signing-key-user-name") || + cmd.hasArgument("--mac-app-image-sign-identity"); + } + + private static boolean isPKGSigned(JPackageCommand cmd) { + return cmd.hasArgument("--mac-signing-key-user-name") || + cmd.hasArgument("--mac-installer-sign-identity"); + } + private static void verifyPKG(JPackageCommand cmd) { Path outputBundle = cmd.outputBundle(); - SigningBase.verifyPkgutil(outputBundle, getCertIndex(cmd)); - SigningBase.verifySpctl(outputBundle, "install", getCertIndex(cmd)); + SigningBase.verifyPkgutil(outputBundle, isPKGSigned(cmd), getCertIndex(cmd)); + if (isPKGSigned(cmd)) { + SigningBase.verifySpctl(outputBundle, "install", getCertIndex(cmd)); + } } private static void verifyDMG(JPackageCommand cmd) { @@ -82,22 +94,45 @@ private static void verifyAppImageInDMG(JPackageCommand cmd) { // We will be called with all folders in DMG since JDK-8263155, but // we only need to verify app. if (dmgImage.endsWith(cmd.name() + ".app")) { - SigningBase.verifyCodesign(launcherPath, true, getCertIndex(cmd)); - SigningBase.verifyCodesign(dmgImage, true, getCertIndex(cmd)); - SigningBase.verifySpctl(dmgImage, "exec", getCertIndex(cmd)); + SigningBase.verifyCodesign(launcherPath, isAppImageSigned(cmd), + getCertIndex(cmd)); + SigningBase.verifyCodesign(dmgImage, isAppImageSigned(cmd), + getCertIndex(cmd)); + if (isAppImageSigned(cmd)) { + SigningBase.verifySpctl(dmgImage, "exec", getCertIndex(cmd)); + } } }); } private static int getCertIndex(JPackageCommand cmd) { - String devName = cmd.getArgumentValue("--mac-signing-key-user-name"); - return SigningBase.getDevNameIndex(devName); + if (cmd.hasArgument("--mac-signing-key-user-name")) { + String devName = cmd.getArgumentValue("--mac-signing-key-user-name"); + return SigningBase.getDevNameIndex(devName); + } else { + // Signing-indentity + return Integer.valueOf(SigningBase.UNICODE_INDEX); + } } @Test - @Parameter("0") - @Parameter("1") - public static void test(int certIndex) throws Exception { + // ("signing-key or sign-identity", "sign app-image", "sign pkg", "certificate index"}) + // Signing-key and ASCII certificate + @Parameter({"true", "true", "true", SigningBase.ASCII_INDEX}) + // Signing-key and UNICODE certificate + @Parameter({"true", "true", "true", SigningBase.UNICODE_INDEX}) + // Signing-indentity and UNICODE certificate + @Parameter({"false", "true", "true", SigningBase.UNICODE_INDEX}) + // Signing-indentity, but sign app-image only and UNICODE certificate + @Parameter({"false", "true", "false", SigningBase.UNICODE_INDEX}) + // Signing-indentity, but sign pkg only and UNICODE certificate + @Parameter({"false", "false", "true", SigningBase.UNICODE_INDEX}) + public static void test(String... testArgs) throws Exception { + boolean signingKey = Boolean.parseBoolean(testArgs[0]); + boolean signAppImage = Boolean.parseBoolean(testArgs[1]); + boolean signPKG = Boolean.parseBoolean(testArgs[2]); + int certIndex = Integer.parseInt(testArgs[3]); + SigningCheck.checkCertificates(certIndex); new PackageTest() @@ -105,12 +140,39 @@ public static void test(int certIndex) throws Exception { .forTypes(PackageType.MAC) .addInitializer(cmd -> { cmd.addArguments("--mac-sign", - "--mac-signing-key-user-name", SigningBase.getDevName(certIndex), "--mac-signing-keychain", SigningBase.getKeyChain()); + if (signingKey) { + cmd.addArguments("--mac-signing-key-user-name", + SigningBase.getDevName(certIndex)); + } else { + if (signAppImage) { + cmd.addArguments("--mac-app-image-sign-identity", + SigningBase.getAppCert(certIndex)); + } + if (signPKG) { + cmd.addArguments("--mac-installer-sign-identity", + SigningBase.getInstallerCert(certIndex)); + } + } }) .forTypes(PackageType.MAC_PKG) .addBundleVerifier(SigningPackageTest::verifyPKG) .forTypes(PackageType.MAC_DMG) + .addInitializer(cmd -> { + if (!signingKey) { + // jpackage throws expected error with + // --mac-installer-sign-identity and DMG type + cmd.removeArgumentWithValue("--mac-installer-sign-identity"); + // In case of not signing app image and DMG we need to + // remove signing completely, otherwise we will default + // to --mac-signing-key-user-name once + // --mac-installer-sign-identity is removed. + if (!signAppImage) { + cmd.removeArgumentWithValue("--mac-signing-keychain"); + cmd.removeArgument("--mac-sign"); + } + } + }) .addBundleVerifier(SigningPackageTest::verifyDMG) .addBundleVerifier(SigningPackageTest::verifyAppImageInDMG) .run(); diff --git a/test/jdk/tools/jpackage/macosx/SigningPackageTwoStepTest.java b/test/jdk/tools/jpackage/macosx/SigningPackageTwoStepTest.java index 66145a9793b..a34f7921b91 100644 --- a/test/jdk/tools/jpackage/macosx/SigningPackageTwoStepTest.java +++ b/test/jdk/tools/jpackage/macosx/SigningPackageTwoStepTest.java @@ -73,7 +73,7 @@ private static void verifyPKG(JPackageCommand cmd) { } Path outputBundle = cmd.outputBundle(); - SigningBase.verifyPkgutil(outputBundle, SigningBase.DEFAULT_INDEX); + SigningBase.verifyPkgutil(outputBundle, true, SigningBase.DEFAULT_INDEX); SigningBase.verifySpctl(outputBundle, "install", SigningBase.DEFAULT_INDEX); } @@ -101,10 +101,18 @@ private static void verifyAppImageInDMG(JPackageCommand cmd) { } @Test - @Parameter("true") - @Parameter("false") - public static void test(boolean signAppImage) throws Exception { - SigningCheck.checkCertificates(0); + // (Signed, "signing-key or sign-identity"}) + // Signed and signing-key + @Parameter({"true", "true"}) + // Signed and signing-identity + @Parameter({"true", "false"}) + // Unsigned + @Parameter({"false", "true"}) + public static void test(String... testArgs) throws Exception { + boolean signAppImage = Boolean.parseBoolean(testArgs[0]); + boolean signingKey = Boolean.parseBoolean(testArgs[1]); + + SigningCheck.checkCertificates(SigningBase.DEFAULT_INDEX); Path appimageOutput = TKit.createTempDirectory("appimage"); @@ -112,10 +120,15 @@ public static void test(boolean signAppImage) throws Exception { .setArgumentValue("--dest", appimageOutput); if (signAppImage) { appImageCmd.addArguments("--mac-sign") - .addArguments("--mac-signing-key-user-name", - SigningBase.getDevName(0)) - .addArguments("--mac-signing-keychain", - SigningBase.getKeyChain()); + .addArguments("--mac-signing-keychain", + SigningBase.getKeyChain()); + if (signingKey) { + appImageCmd.addArguments("--mac-signing-key-user-name", + SigningBase.getDevName(SigningBase.DEFAULT_INDEX)); + } else { + appImageCmd.addArguments("--mac-app-image-sign-identity", + SigningBase.getAppCert(SigningBase.DEFAULT_INDEX)); + } } new PackageTest() @@ -126,15 +139,31 @@ public static void test(boolean signAppImage) throws Exception { cmd.removeArgumentWithValue("--input"); if (signAppImage) { cmd.addArguments("--mac-sign", - "--mac-signing-key-user-name", - SigningBase.getDevName(0), "--mac-signing-keychain", SigningBase.getKeyChain()); + if (signingKey) { + cmd.addArguments("--mac-signing-key-user-name", + SigningBase.getDevName(SigningBase.DEFAULT_INDEX)); + } else { + cmd.addArguments("--mac-installer-sign-identity", + SigningBase.getInstallerCert(SigningBase.DEFAULT_INDEX)); + } } }) .forTypes(PackageType.MAC_PKG) .addBundleVerifier(SigningPackageTwoStepTest::verifyPKG) .forTypes(PackageType.MAC_DMG) + .addInitializer(cmd -> { + if (signAppImage && !signingKey) { + // jpackage throws expected error with + // --mac-installer-sign-identity and DMG type + cmd.removeArgumentWithValue("--mac-installer-sign-identity"); + // It will do nothing, but it signals test that app + // image itself is signed for verification. + cmd.addArguments("--mac-app-image-sign-identity", + SigningBase.getAppCert(SigningBase.DEFAULT_INDEX)); + } + }) .addBundleVerifier(SigningPackageTwoStepTest::verifyDMG) .addBundleVerifier(SigningPackageTwoStepTest::verifyAppImageInDMG) .run(); diff --git a/test/jdk/tools/jpackage/macosx/base/SigningBase.java b/test/jdk/tools/jpackage/macosx/base/SigningBase.java index 702e7b1f7ae..15031bc42be 100644 --- a/test/jdk/tools/jpackage/macosx/base/SigningBase.java +++ b/test/jdk/tools/jpackage/macosx/base/SigningBase.java @@ -33,6 +33,8 @@ public class SigningBase { public static int DEFAULT_INDEX = 0; + public static final String ASCII_INDEX = "0"; + public static final String UNICODE_INDEX = "0"; private static String [] DEV_NAMES = { "jpackage.openjdk.java.net", "jpackage.openjdk.java.net (ö)", @@ -182,22 +184,30 @@ private static void verifySpctlResult(List output, Path target, checkString(output, lookupString); } - private static List pkgutilResult(Path target) { + private static List pkgutilResult(Path target, boolean signed) { List result = new Executor() .setExecutable("/usr/sbin/pkgutil") .addArguments("--check-signature", target.toString()) - .executeAndGetOutput(); + .saveOutput() + .execute(signed ? 0 : 1) + .getOutput(); return result; } - private static void verifyPkgutilResult(List result, int certIndex) { + private static void verifyPkgutilResult(List result, boolean signed, + int certIndex) { result.stream().forEachOrdered(TKit::trace); - String lookupString = "Status: signed by"; - checkString(result, lookupString); - lookupString = "1. " + getInstallerCert(certIndex); - checkString(result, lookupString); + if (signed) { + String lookupString = "Status: signed by"; + checkString(result, lookupString); + lookupString = "1. " + getInstallerCert(certIndex); + checkString(result, lookupString); + } else { + String lookupString = "Status: no signature"; + checkString(result, lookupString); + } } public static void verifyCodesign(Path target, boolean signed, int certIndex) { @@ -228,9 +238,9 @@ public static void verifySpctl(Path target, String type, int certIndex) { verifySpctlResult(output, target, type, result.getExitCode(), certIndex); } - public static void verifyPkgutil(Path target, int certIndex) { - List result = pkgutilResult(target); - verifyPkgutilResult(result, certIndex); + public static void verifyPkgutil(Path target, boolean signed, int certIndex) { + List result = pkgutilResult(target, signed); + verifyPkgutilResult(result, signed, certIndex); } public static void verifyAppImageSignature(JPackageCommand appImageCmd, @@ -247,7 +257,7 @@ public static void verifyAppImageSignature(JPackageCommand appImageCmd, Path appImage = appImageCmd.outputBundle(); SigningBase.verifyCodesign(appImage, isSigned, SigningBase.DEFAULT_INDEX); if (isSigned) { - SigningBase.verifySpctl(appImage, "exec", 0); + SigningBase.verifySpctl(appImage, "exec", SigningBase.DEFAULT_INDEX); } } diff --git a/test/jdk/tools/jpackage/share/jdk/jpackage/tests/PredefinedAppImageErrorTest.java b/test/jdk/tools/jpackage/share/jdk/jpackage/tests/PredefinedAppImageErrorTest.java index 8fb3e602449..d03c7cf28df 100644 --- a/test/jdk/tools/jpackage/share/jdk/jpackage/tests/PredefinedAppImageErrorTest.java +++ b/test/jdk/tools/jpackage/share/jdk/jpackage/tests/PredefinedAppImageErrorTest.java @@ -69,7 +69,7 @@ public static Collection input() throws IOException { }, // --mac-app-store is required {"Hello", - new String[]{"--mac-sign", "--mac-app-store"}, + new String[]{"--mac-sign", "--mac-app-store", "--mac-app-image-sign-identity", "test"}, new String[]{"--input", "--dest", "--name", "--main-jar", "--main-class"}, TKit.isOSX() ? "Option [--mac-app-store] is not valid" : From 5ce718eb175dd0855983577d41b0af57422f4a0e Mon Sep 17 00:00:00 2001 From: Jayathirth D V Date: Wed, 25 Oct 2023 04:01:59 +0000 Subject: [PATCH 105/124] 8318100: Remove redundant check for Metal support Reviewed-by: prr, dnguyen --- .../macosx/classes/sun/java2d/MacOSFlags.java | 11 +---------- .../sun/java2d/metal/MTLGraphicsConfig.java | 14 -------------- .../java2d/metal/MTLGraphicsConfig.m | 16 ---------------- 3 files changed, 1 insertion(+), 40 deletions(-) diff --git a/src/java.desktop/macosx/classes/sun/java2d/MacOSFlags.java b/src/java.desktop/macosx/classes/sun/java2d/MacOSFlags.java index 5e09d39692b..37b573a339b 100644 --- a/src/java.desktop/macosx/classes/sun/java2d/MacOSFlags.java +++ b/src/java.desktop/macosx/classes/sun/java2d/MacOSFlags.java @@ -125,16 +125,7 @@ private static void initJavaFlags() { System.out.println("Could not enable OpenGL pipeline (CGL not available)"); } oglEnabled = false; - metalEnabled = MTLGraphicsConfig.isMetalAvailable(); - } - } else if (metalEnabled && !oglEnabled) { - // Check whether Metal framework is available - if (!MTLGraphicsConfig.isMetalAvailable()) { - if (metalVerbose) { - System.out.println("Could not enable Metal pipeline (Metal framework not available)"); - } - metalEnabled = false; - oglEnabled = CGLGraphicsConfig.isCGLAvailable(); + metalEnabled = true; } } diff --git a/src/java.desktop/macosx/classes/sun/java2d/metal/MTLGraphicsConfig.java b/src/java.desktop/macosx/classes/sun/java2d/metal/MTLGraphicsConfig.java index 64117b8999e..8a992361b96 100644 --- a/src/java.desktop/macosx/classes/sun/java2d/metal/MTLGraphicsConfig.java +++ b/src/java.desktop/macosx/classes/sun/java2d/metal/MTLGraphicsConfig.java @@ -72,7 +72,6 @@ public final class MTLGraphicsConfig extends CGraphicsConfig implements AccelGraphicsConfig, SurfaceManager.ProxiedGraphicsConfig { - private static boolean mtlAvailable; private static ImageCapabilities imageCaps = new MTLImageCaps(); @SuppressWarnings("removal") @@ -89,7 +88,6 @@ public final class MTLGraphicsConfig extends CGraphicsConfig private final Object disposerReferent = new Object(); private final int maxTextureSize; - private static native boolean isMetalFrameworkAvailable(); private static native boolean tryLoadMetalLibrary(int displayID, String shaderLib); private static native long getMTLConfigInfo(int displayID, String mtlShadersLib); @@ -99,10 +97,6 @@ public final class MTLGraphicsConfig extends CGraphicsConfig */ private static native int nativeGetMaxTextureSize(); - static { - mtlAvailable = isMetalFrameworkAvailable(); - } - private MTLGraphicsConfig(CGraphicsDevice device, long configInfo, int maxTextureSize, ContextCapabilities mtlCaps) { @@ -133,10 +127,6 @@ public SurfaceData createManagedSurface(int w, int h, int transparency) { public static MTLGraphicsConfig getConfig(CGraphicsDevice device, int displayID) { - if (!mtlAvailable) { - return null; - } - if (!tryLoadMetalLibrary(displayID, mtlShadersLib)) { return null; } @@ -171,10 +161,6 @@ public static MTLGraphicsConfig getConfig(CGraphicsDevice device, return new MTLGraphicsConfig(device, cfginfo, textureSize, caps); } - public static boolean isMetalAvailable() { - return mtlAvailable; - } - /** * Returns true if the provided capability bit is present for this config. * See MTLContext.java for a list of supported capabilities. diff --git a/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLGraphicsConfig.m b/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLGraphicsConfig.m index af6662cecf2..7b165a668b3 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLGraphicsConfig.m +++ b/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLGraphicsConfig.m @@ -54,22 +54,6 @@ free(mtlinfo); } -JNIEXPORT jboolean JNICALL -Java_sun_java2d_metal_MTLGraphicsConfig_isMetalFrameworkAvailable - (JNIEnv *env, jclass mtlgc) -{ - jboolean metalSupported = JNI_FALSE; - - // It is guaranteed that metal supported GPU is available since macOS 10.14 - if (@available(macOS 10.14, *)) { - metalSupported = JNI_TRUE; - } - - J2dRlsTraceLn1(J2D_TRACE_INFO, "MTLGraphicsConfig_isMetalFrameworkAvailable : %d", metalSupported); - - return metalSupported; -} - JNIEXPORT jboolean JNICALL Java_sun_java2d_metal_MTLGraphicsConfig_tryLoadMetalLibrary (JNIEnv *env, jclass mtlgc, jint displayID, jstring shadersLibName) From d7205e690fe92464caee9122e11a88b4cc5c2c2d Mon Sep 17 00:00:00 2001 From: Prasanta Sadhukhan Date: Wed, 25 Oct 2023 07:22:04 +0000 Subject: [PATCH 106/124] 8318102: macos10.14 check in CSystemColors can be removed. Reviewed-by: prr, aivanov --- .../macosx/native/libawt_lwawt/awt/CSystemColors.m | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/src/java.desktop/macosx/native/libawt_lwawt/awt/CSystemColors.m b/src/java.desktop/macosx/native/libawt_lwawt/awt/CSystemColors.m index 40ef6e67d01..1bd767c320b 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/awt/CSystemColors.m +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/CSystemColors.m @@ -96,11 +96,7 @@ + (void)reloadColors { sColors[java_awt_SystemColor_TEXT_INACTIVE_TEXT] = [NSColor disabledControlTextColor]; sColors[java_awt_SystemColor_CONTROL] = [NSColor controlColor]; sColors[java_awt_SystemColor_CONTROL_TEXT] = [NSColor controlTextColor]; - if (@available(macOS 10.14, *)) { - sColors[java_awt_SystemColor_CONTROL_HIGHLIGHT] = [NSColor selectedContentBackgroundColor]; - } else { - sColors[java_awt_SystemColor_CONTROL_HIGHLIGHT] = [NSColor alternateSelectedControlColor]; - } + sColors[java_awt_SystemColor_CONTROL_HIGHLIGHT] = [NSColor selectedContentBackgroundColor]; sColors[java_awt_SystemColor_CONTROL_LT_HIGHLIGHT] = [NSColor alternateSelectedControlTextColor]; sColors[java_awt_SystemColor_CONTROL_SHADOW] = [NSColor controlShadowColor]; sColors[java_awt_SystemColor_CONTROL_DK_SHADOW] = [NSColor controlDarkShadowColor]; @@ -121,11 +117,7 @@ + (void)reloadColors { } // added for JTable Focus Ring - if (@available(macOS 10.14, *)) { - appleColors[sun_lwawt_macosx_LWCToolkit_CELL_HIGHLIGHT_COLOR] = [NSColor controlAccentColor]; - } else { - appleColors[sun_lwawt_macosx_LWCToolkit_CELL_HIGHLIGHT_COLOR] = [NSColor keyboardFocusIndicatorColor]; - } + appleColors[sun_lwawt_macosx_LWCToolkit_CELL_HIGHLIGHT_COLOR] = [NSColor controlAccentColor]; appleColors[sun_lwawt_macosx_LWCToolkit_KEYBOARD_FOCUS_COLOR] = [NSColor keyboardFocusIndicatorColor]; appleColors[sun_lwawt_macosx_LWCToolkit_INACTIVE_SELECTION_BACKGROUND_COLOR] = [NSColor secondarySelectedControlColor]; appleColors[sun_lwawt_macosx_LWCToolkit_INACTIVE_SELECTION_FOREGROUND_COLOR] = [NSColor controlDarkShadowColor]; From ba7d08b8199172058bd369d880d2d6a9f9649319 Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Wed, 25 Oct 2023 08:29:58 +0000 Subject: [PATCH 107/124] 8316961: Fallback implementations for 64-bit Atomic::{add,xchg} on 32-bit platforms Reviewed-by: eosterlund, dholmes, kbarrett, simonis --- src/hotspot/os_cpu/bsd_x86/atomic_bsd_x86.hpp | 8 +++ .../os_cpu/linux_arm/atomic_linux_arm.hpp | 7 ++ .../os_cpu/linux_x86/atomic_linux_x86.hpp | 8 +++ src/hotspot/share/runtime/atomic.hpp | 65 ++++++++++++++++++- test/hotspot/gtest/runtime/test_atomic.cpp | 23 ++++--- 5 files changed, 100 insertions(+), 11 deletions(-) diff --git a/src/hotspot/os_cpu/bsd_x86/atomic_bsd_x86.hpp b/src/hotspot/os_cpu/bsd_x86/atomic_bsd_x86.hpp index 77104194b0b..9ba246f553d 100644 --- a/src/hotspot/os_cpu/bsd_x86/atomic_bsd_x86.hpp +++ b/src/hotspot/os_cpu/bsd_x86/atomic_bsd_x86.hpp @@ -153,6 +153,14 @@ inline T Atomic::PlatformCmpxchg<8>::operator()(T volatile* dest, return cmpxchg_using_helper(_Atomic_cmpxchg_long, dest, compare_value, exchange_value); } +// No direct support for 8-byte xchg; emulate using cmpxchg. +template<> +struct Atomic::PlatformXchg<8> : Atomic::XchgUsingCmpxchg<8> {}; + +// No direct support for 8-byte add; emulate using cmpxchg. +template<> +struct Atomic::PlatformAdd<8> : Atomic::AddUsingCmpxchg<8> {}; + template<> template inline T Atomic::PlatformLoad<8>::operator()(T const volatile* src) const { diff --git a/src/hotspot/os_cpu/linux_arm/atomic_linux_arm.hpp b/src/hotspot/os_cpu/linux_arm/atomic_linux_arm.hpp index 814dbd9aab5..513217649e6 100644 --- a/src/hotspot/os_cpu/linux_arm/atomic_linux_arm.hpp +++ b/src/hotspot/os_cpu/linux_arm/atomic_linux_arm.hpp @@ -128,6 +128,13 @@ inline T Atomic::PlatformXchg<4>::operator()(T volatile* dest, return xchg_using_helper(ARMAtomicFuncs::_xchg_func, dest, exchange_value); } +// No direct support for 8-byte xchg; emulate using cmpxchg. +template<> +struct Atomic::PlatformXchg<8> : Atomic::XchgUsingCmpxchg<8> {}; + +// No direct support for 8-byte add; emulate using cmpxchg. +template<> +struct Atomic::PlatformAdd<8> : Atomic::AddUsingCmpxchg<8> {}; // The memory_order parameter is ignored - we always provide the strongest/most-conservative ordering diff --git a/src/hotspot/os_cpu/linux_x86/atomic_linux_x86.hpp b/src/hotspot/os_cpu/linux_x86/atomic_linux_x86.hpp index 2e472a02068..0156546ba9b 100644 --- a/src/hotspot/os_cpu/linux_x86/atomic_linux_x86.hpp +++ b/src/hotspot/os_cpu/linux_x86/atomic_linux_x86.hpp @@ -153,6 +153,14 @@ inline T Atomic::PlatformCmpxchg<8>::operator()(T volatile* dest, return cmpxchg_using_helper(_Atomic_cmpxchg_long, dest, compare_value, exchange_value); } +// No direct support for 8-byte xchg; emulate using cmpxchg. +template<> +struct Atomic::PlatformXchg<8> : Atomic::XchgUsingCmpxchg<8> {}; + +// No direct support for 8-byte add; emulate using cmpxchg. +template<> +struct Atomic::PlatformAdd<8> : Atomic::AddUsingCmpxchg<8> {}; + template<> template inline T Atomic::PlatformLoad<8>::operator()(T const volatile* src) const { diff --git a/src/hotspot/share/runtime/atomic.hpp b/src/hotspot/share/runtime/atomic.hpp index c85bf9055ab..ac0ce49d26e 100644 --- a/src/hotspot/share/runtime/atomic.hpp +++ b/src/hotspot/share/runtime/atomic.hpp @@ -398,11 +398,15 @@ class Atomic : AllStatic { T compare_value, T exchange_value); - // Support platforms that do not provide Read-Modify-Write - // byte-level atomic access. To use, derive PlatformCmpxchg<1> from - // this class. + // Support platforms that do not provide Read-Modify-Write atomic + // accesses for 1-byte and 8-byte widths. To use, derive PlatformCmpxchg<1>, + // PlatformAdd, PlatformXchg from these classes. public: // Temporary, can't be private: C++03 11.4/2. Fixed by C++11. struct CmpxchgByteUsingInt; + template + struct XchgUsingCmpxchg; + template + class AddUsingCmpxchg; private: // Dispatch handler for xchg. Provides type-based validity @@ -677,6 +681,47 @@ struct Atomic::CmpxchgByteUsingInt { atomic_memory_order order) const; }; +// Define the class before including platform file, which may use this +// as a base class, requiring it be complete. The definition is later +// in this file, near the other definitions related to xchg. +template +struct Atomic::XchgUsingCmpxchg { + template + T operator()(T volatile* dest, + T exchange_value, + atomic_memory_order order) const; +}; + +// Define the class before including platform file, which may use this +// as a base class, requiring it be complete. +template +class Atomic::AddUsingCmpxchg { +public: + template + static inline D add_then_fetch(D volatile* dest, + I add_value, + atomic_memory_order order) { + D addend = add_value; + return fetch_then_add(dest, add_value, order) + add_value; + } + + template + static inline D fetch_then_add(D volatile* dest, + I add_value, + atomic_memory_order order) { + STATIC_ASSERT(byte_size == sizeof(I)); + STATIC_ASSERT(byte_size == sizeof(D)); + + D old_value; + D new_value; + do { + old_value = Atomic::load(dest); + new_value = old_value + add_value; + } while (old_value != Atomic::cmpxchg(dest, old_value, new_value, order)); + return old_value; + } +}; + // Define the class before including platform file, which may specialize // the operator definition. No generic definition of specializations // of the operator template are provided, nor are there any generic @@ -1170,4 +1215,18 @@ inline D Atomic::xchg(volatile D* dest, T exchange_value, atomic_memory_order or return XchgImpl()(dest, exchange_value, order); } +template +template +inline T Atomic::XchgUsingCmpxchg::operator()(T volatile* dest, + T exchange_value, + atomic_memory_order order) const { + STATIC_ASSERT(byte_size == sizeof(T)); + + T old_value; + do { + old_value = Atomic::load(dest); + } while (old_value != Atomic::cmpxchg(dest, old_value, exchange_value, order)); + return old_value; +} + #endif // SHARE_RUNTIME_ATOMIC_HPP diff --git a/test/hotspot/gtest/runtime/test_atomic.cpp b/test/hotspot/gtest/runtime/test_atomic.cpp index e7c6f9e3f2b..744714c6f7f 100644 --- a/test/hotspot/gtest/runtime/test_atomic.cpp +++ b/test/hotspot/gtest/runtime/test_atomic.cpp @@ -59,14 +59,14 @@ TEST_VM(AtomicAddTest, int32) { Support().test_fetch_add(); } -// 64bit Atomic::add is only supported on 64bit platforms. -#ifdef _LP64 TEST_VM(AtomicAddTest, int64) { + // Check if 64-bit atomics are available on the machine. + if (!VM_Version::supports_cx8()) return; + using Support = AtomicAddTestSupport; Support().test_add(); Support().test_fetch_add(); } -#endif // _LP64 TEST_VM(AtomicAddTest, ptr) { uint _test_values[10] = {}; @@ -108,13 +108,13 @@ TEST_VM(AtomicXchgTest, int32) { Support().test(); } -// 64bit Atomic::xchg is only supported on 64bit platforms. -#ifdef _LP64 TEST_VM(AtomicXchgTest, int64) { + // Check if 64-bit atomics are available on the machine. + if (!VM_Version::supports_cx8()) return; + using Support = AtomicXchgTestSupport; Support().test(); } -#endif // _LP64 template struct AtomicCmpxchgTestSupport { @@ -142,6 +142,9 @@ TEST_VM(AtomicCmpxchgTest, int32) { } TEST_VM(AtomicCmpxchgTest, int64) { + // Check if 64-bit atomics are available on the machine. + if (!VM_Version::supports_cx8()) return; + using Support = AtomicCmpxchgTestSupport; Support().test(); } @@ -345,12 +348,16 @@ TEST_VM(AtomicBitopsTest, uint32) { AtomicBitopsTestSupport()(); } -#ifdef _LP64 TEST_VM(AtomicBitopsTest, int64) { + // Check if 64-bit atomics are available on the machine. + if (!VM_Version::supports_cx8()) return; + AtomicBitopsTestSupport()(); } TEST_VM(AtomicBitopsTest, uint64) { + // Check if 64-bit atomics are available on the machine. + if (!VM_Version::supports_cx8()) return; + AtomicBitopsTestSupport()(); } -#endif // _LP64 From c3cdfe2a328c59213b614a2b723184582550f8c7 Mon Sep 17 00:00:00 2001 From: Zixian Cai Date: Wed, 25 Oct 2023 08:33:10 +0000 Subject: [PATCH 108/124] 8318692: Add instructions for creating Ubuntu-based sysroot for cross compilation Reviewed-by: erikj, shade --- doc/building.html | 11 +++++++++++ doc/building.md | 15 +++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/doc/building.html b/doc/building.html index 2348c398a53..3601fa8af16 100644 --- a/doc/building.html +++ b/doc/building.html @@ -1413,6 +1413,17 @@

    Cross compiling with http://httpredir.debian.org/debian/ # If the target architecture is `riscv64`, # the path should be `debian-ports` instead of `debian`. +
  • To create a Ubuntu-based chroot:

    +
    sudo debootstrap \
    +  --arch=arm64 \
    +  --verbose \
    +  --components=main,universe \
    +  --include=fakeroot,symlinks,build-essential,libx11-dev,libxext-dev,libxrender-dev,libxrandr-dev,libxtst-dev,libxt-dev,libcups2-dev,libfontconfig1-dev,libasound2-dev,libfreetype6-dev,libpng-dev,libffi-dev \
    +  --resolve-deps \
    +  jammy \
    +  ~/sysroot-arm64 \
    +  http://ports.ubuntu.com/ubuntu-ports/
    +# symlinks is in the universe repository
  • Make sure the symlinks inside the newly created chroot point to proper locations:

    sudo chroot ~/sysroot-arm64 symlinks -cr .
  • diff --git a/doc/building.md b/doc/building.md index ac79cb314b6..68c65bf0517 100644 --- a/doc/building.md +++ b/doc/building.md @@ -1197,6 +1197,21 @@ For example, cross-compiling to AArch64 from x86_64 could be done like this: # the path should be `debian-ports` instead of `debian`. ``` + * To create a Ubuntu-based chroot: + + ``` + sudo debootstrap \ + --arch=arm64 \ + --verbose \ + --components=main,universe \ + --include=fakeroot,symlinks,build-essential,libx11-dev,libxext-dev,libxrender-dev,libxrandr-dev,libxtst-dev,libxt-dev,libcups2-dev,libfontconfig1-dev,libasound2-dev,libfreetype6-dev,libpng-dev,libffi-dev \ + --resolve-deps \ + jammy \ + ~/sysroot-arm64 \ + http://ports.ubuntu.com/ubuntu-ports/ + # symlinks is in the universe repository + ``` + * Make sure the symlinks inside the newly created chroot point to proper locations: ``` From d2d1592dd94e897fae6fc4098e43b4fffb6d6750 Mon Sep 17 00:00:00 2001 From: Albert Mingkun Yang Date: Wed, 25 Oct 2023 08:43:54 +0000 Subject: [PATCH 109/124] 8318713: G1: Use more accurate age in predict_eden_copy_time_ms Reviewed-by: tschatzl, iwalulya --- src/hotspot/share/gc/g1/g1Policy.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/share/gc/g1/g1Policy.cpp b/src/hotspot/share/gc/g1/g1Policy.cpp index 13736b891e2..1bc1d44691b 100644 --- a/src/hotspot/share/gc/g1/g1Policy.cpp +++ b/src/hotspot/share/gc/g1/g1Policy.cpp @@ -1099,7 +1099,7 @@ double G1Policy::predict_eden_copy_time_ms(uint count, size_t* bytes_to_copy) co if (count == 0) { return 0.0; } - size_t const expected_bytes = _eden_surv_rate_group->accum_surv_rate_pred(count) * HeapRegion::GrainBytes; + size_t const expected_bytes = _eden_surv_rate_group->accum_surv_rate_pred(count - 1) * HeapRegion::GrainBytes; if (bytes_to_copy != nullptr) { *bytes_to_copy = expected_bytes; } From 14090ef6039ff2f3064f397a75219b2bc715cc27 Mon Sep 17 00:00:00 2001 From: Alexey Ivanov Date: Wed, 25 Oct 2023 11:17:00 +0000 Subject: [PATCH 110/124] 8294158: HTML formatting for PassFailJFrame instructions Reviewed-by: azvegint, prr --- .../awt/regtesthelpers/PassFailJFrame.java | 45 ++++++++++++++++--- 1 file changed, 40 insertions(+), 5 deletions(-) diff --git a/test/jdk/java/awt/regtesthelpers/PassFailJFrame.java b/test/jdk/java/awt/regtesthelpers/PassFailJFrame.java index 92ff9371933..4d8f3c6659c 100644 --- a/test/jdk/java/awt/regtesthelpers/PassFailJFrame.java +++ b/test/jdk/java/awt/regtesthelpers/PassFailJFrame.java @@ -51,6 +51,7 @@ import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JDialog; +import javax.swing.JEditorPane; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JOptionPane; @@ -58,6 +59,9 @@ import javax.swing.JScrollPane; import javax.swing.JTextArea; import javax.swing.Timer; +import javax.swing.text.JTextComponent; +import javax.swing.text.html.HTMLEditorKit; +import javax.swing.text.html.StyleSheet; import static javax.swing.SwingUtilities.invokeAndWait; import static javax.swing.SwingUtilities.isEventDispatchThread; @@ -81,8 +85,11 @@ public class PassFailJFrame { private static volatile boolean failed; private static volatile boolean timeout; private static volatile String testFailedReason; + private static final AtomicInteger imgCounter = new AtomicInteger(0); + private static JFrame frame; + private static Robot robot; public enum Position {HORIZONTAL, VERTICAL, TOP_LEFT_CORNER} @@ -169,7 +176,7 @@ public PassFailJFrame(String title, String instructions, long testTimeOut, InvocationTargetException { if (isEventDispatchThread()) { createUI(title, instructions, testTimeOut, rows, columns, - enableScreenCapture); + enableScreenCapture); } else { invokeAndWait(() -> createUI(title, instructions, testTimeOut, rows, columns, enableScreenCapture)); @@ -187,9 +194,11 @@ private static void createUI(String title, String instructions, boolean enableScreenCapture) { frame = new JFrame(title); frame.setLayout(new BorderLayout()); - JTextArea instructionsText = new JTextArea(instructions, rows, columns); - instructionsText.setEditable(false); - instructionsText.setLineWrap(true); + + JTextComponent text = instructions.startsWith("") + ? configureHTML(instructions, rows, columns) + : configurePlainText(instructions, rows, columns); + text.setEditable(false); long tTimeout = TimeUnit.MINUTES.toMillis(testTimeOut); @@ -210,7 +219,7 @@ private static void createUI(String title, String instructions, }); timer.start(); frame.add(testTimeoutLabel, BorderLayout.NORTH); - frame.add(new JScrollPane(instructionsText), BorderLayout.CENTER); + frame.add(new JScrollPane(text), BorderLayout.CENTER); JButton btnPass = new JButton("Pass"); btnPass.addActionListener((e) -> { @@ -249,6 +258,32 @@ public void windowClosing(WindowEvent e) { windowList.add(frame); } + private static JTextComponent configurePlainText(String instructions, + int rows, int columns) { + JTextArea text = new JTextArea(instructions, rows, columns); + text.setLineWrap(true); + text.setWrapStyleWord(true); + return text; + } + + private static JTextComponent configureHTML(String instructions, + int rows, int columns) { + JEditorPane text = new JEditorPane("text/html", instructions); + text.putClientProperty(JEditorPane.HONOR_DISPLAY_PROPERTIES, + Boolean.TRUE); + // Set preferred size as if it were JTextArea + text.setPreferredSize(new JTextArea(rows, columns).getPreferredSize()); + + HTMLEditorKit kit = (HTMLEditorKit) text.getEditorKit(); + StyleSheet styles = kit.getStyleSheet(); + // Reduce the default margins + styles.addRule("ol, ul { margin-left-ltr: 20; margin-left-rtl: 20 }"); + // Make the size of code blocks the same as other text + styles.addRule("code { font-size: inherit }"); + + return text; + } + private static JComponent createCapturePanel() { JComboBox screenShortType = new JComboBox<>(CaptureType.values()); From 42b9ac8a07b540f4d7955a778923d24a876451cc Mon Sep 17 00:00:00 2001 From: Alexey Ivanov Date: Wed, 25 Oct 2023 11:31:44 +0000 Subject: [PATCH 111/124] 8294156: Allow PassFailJFrame.Builder to create test UI Reviewed-by: azvegint, prr --- .../awt/regtesthelpers/PassFailJFrame.java | 481 +++++++++++++++--- 1 file changed, 404 insertions(+), 77 deletions(-) diff --git a/test/jdk/java/awt/regtesthelpers/PassFailJFrame.java b/test/jdk/java/awt/regtesthelpers/PassFailJFrame.java index 4d8f3c6659c..d2e650b2134 100644 --- a/test/jdk/java/awt/regtesthelpers/PassFailJFrame.java +++ b/test/jdk/java/awt/regtesthelpers/PassFailJFrame.java @@ -29,19 +29,23 @@ import java.awt.GraphicsEnvironment; import java.awt.Image; import java.awt.Insets; +import java.awt.Point; import java.awt.Rectangle; import java.awt.Robot; import java.awt.Toolkit; import java.awt.Window; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; +import java.awt.event.WindowListener; import java.awt.image.RenderedImage; import java.io.File; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.List; +import java.util.Objects; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; @@ -63,9 +67,83 @@ import javax.swing.text.html.HTMLEditorKit; import javax.swing.text.html.StyleSheet; +import static java.util.Collections.unmodifiableList; import static javax.swing.SwingUtilities.invokeAndWait; import static javax.swing.SwingUtilities.isEventDispatchThread; +/** + * Provides a framework for manual tests to display test instructions and + * Pass/Fail buttons. + *

    + * Instructions for the user can be either plain text or HTML as supported + * by Swing. If the instructions start with {@code }, the + * instructions are displayed as HTML. + *

    + * A simple test would look like this: + *

    {@code
    + * public class SampleManualTest {
    + *     private static final String INSTRUCTIONS =
    + *             "Click Pass, or click Fail if the test failed.";
    + *
    + *     public static void main(String[] args) throws Exception {
    + *         PassFailJFrame.builder()
    + *                       .instructions(INSTRUCTIONS)
    + *                       .testUI(() -> createTestUI())
    + *                       .build()
    + *                       .awaitAndCheck();
    + *     }
    + *
    + *     private static List createTestUI() {
    + *         JFrame testUI = new JFrame("Test UI");
    + *         testUI.setSize(250, 150);
    + *         return List.of(testUI);
    + *     }
    + * }
    + * }
    + *

    + * The above example uses the {@link Builder Builder} to set the parameters of + * the instruction frame. It is the recommended way. + *

    + * The framework will create instruction UI, it will call + * the provided {@code createTestUI} on the Event Dispatch Thread (EDT), + * and it will automatically position the test UI and make it visible. + *

    + * Alternatively, use one of the {@code PassFailJFrame} constructors to + * create an object, then create secondary test UI, register it + * with {@code PassFailJFrame}, position it and make it visible. + * The following sample demonstrates it: + *

    {@code
    + * public class SampleOldManualTest {
    + *     private static final String INSTRUCTIONS =
    + *             "Click Pass, or click Fail if the test failed.";
    + *
    + *     public static void main(String[] args) throws Exception {
    + *         PassFailJFrame passFail = new PassFailJFrame(INSTRUCTIONS);
    + *
    + *         SwingUtilities.invokeAndWait(() -> createTestUI());
    + *
    + *         passFail.awaitAndCheck();
    + *     }
    + *
    + *     private static void createTestUI() {
    + *         JFrame testUI = new JFrame("Test UI");
    + *         testUI.setSize(250, 150);
    + *         PassFailJFrame.addTestWindow(testUI);
    + *         PassFailJFrame.positionTestWindow(testUI, PassFailJFrame.Position.HORIZONTAL);
    + *         testUI.setVisible(true);
    + *     }
    + * }
    + * }
    + *

    + * Use methods of the {@code Builder} class or constructors of the + * {@code PassFailJFrame} class to control other parameters: + *

      + *
    • the title of the instruction UI,
    • + *
    • the timeout of the test,
    • + *
    • the size of the instruction UI via rows and columns, and
    • + *
    • to enable screenshots.
    • + *
    + */ public class PassFailJFrame { private static final String TITLE = "Test Instruction Frame"; @@ -172,21 +250,67 @@ public PassFailJFrame(String title, String instructions, long testTimeOut, */ public PassFailJFrame(String title, String instructions, long testTimeOut, int rows, int columns, - boolean enableScreenCapture) throws InterruptedException, - InvocationTargetException { - if (isEventDispatchThread()) { - createUI(title, instructions, testTimeOut, rows, columns, - enableScreenCapture); - } else { - invokeAndWait(() -> createUI(title, instructions, testTimeOut, - rows, columns, enableScreenCapture)); - } + boolean enableScreenCapture) + throws InterruptedException, InvocationTargetException { + invokeOnEDT(() -> createUI(title, instructions, + testTimeOut, + rows, columns, + enableScreenCapture)); } private PassFailJFrame(Builder builder) throws InterruptedException, InvocationTargetException { this(builder.title, builder.instructions, builder.testTimeOut, - builder.rows, builder.columns, builder.screenCapture); + builder.rows, builder.columns, builder.screenCapture); + + if (builder.windowCreator != null) { + invokeOnEDT(() -> + builder.testWindows = builder.windowCreator.createTestUI()); + } + + if (builder.testWindows != null) { + addTestWindow(builder.testWindows); + builder.testWindows + .forEach(w -> w.addWindowListener(windowClosingHandler)); + + if (builder.positionWindows != null) { + positionInstructionFrame(builder.position); + invokeOnEDT(() -> { + builder.positionWindows + .positionTestWindows(unmodifiableList(builder.testWindows), + builder.instructionUIHandler); + + windowList.forEach(w -> w.setVisible(true)); + }); + } else if (builder.testWindows.size() == 1) { + Window window = builder.testWindows.get(0); + positionTestWindow(window, builder.position); + window.setVisible(true); + } else { + positionTestWindow(null, builder.position); + } + } + } + + /** + * Performs an operation on EDT. If called on EDT, invokes {@code run} + * directly, otherwise wraps into {@code invokeAndWait}. + * + * @param doRun an operation to run on EDT + * @throws InterruptedException if we're interrupted while waiting for + * the event dispatching thread to finish executing + * {@code doRun.run()} + * @throws InvocationTargetException if an exception is thrown while + * running {@code doRun} + * @see javax.swing.SwingUtilities#invokeAndWait(Runnable) + */ + private static void invokeOnEDT(Runnable doRun) + throws InterruptedException, InvocationTargetException { + if (isEventDispatchThread()) { + doRun.run(); + } else { + invokeAndWait(doRun); + } } private static void createUI(String title, String instructions, @@ -241,16 +365,7 @@ private static void createUI(String title, String instructions, buttonsPanel.add(createCapturePanel()); } - frame.addWindowListener(new WindowAdapter() { - @Override - public void windowClosing(WindowEvent e) { - super.windowClosing(e); - testFailedReason = FAILURE_REASON - + "User closed the instruction Frame"; - failed = true; - latch.countDown(); - } - }); + frame.addWindowListener(windowClosingHandler); frame.add(buttonsPanel, BorderLayout.SOUTH); frame.pack(); @@ -284,6 +399,101 @@ private static JTextComponent configureHTML(String instructions, return text; } + + /** + * Creates one or more windows for test UI. + */ + @FunctionalInterface + public interface WindowCreator { + /** + * Creates one or more windows for test UI. + * This method is called by the framework on the EDT. + * @return a list of windows. + */ + List createTestUI(); + } + + /** + * Positions test UI windows. + */ + @FunctionalInterface + public interface PositionWindows { + /** + * Positions test UI windows. + * This method is called by the framework on the EDT after + * the instruction UI frame was positioned on the screen. + *

    + * The list of the test windows contains the windows + * that were passed to the framework via + * {@link Builder#testUI(WindowCreator) testUI} method. + * + * @param testWindows the list of test windows + * @param instructionUI information about the instruction frame + */ + void positionTestWindows(List testWindows, + InstructionUI instructionUI); + } + + /** + * Provides information about the instruction frame. + */ + public interface InstructionUI { + /** + * {@return the location of the instruction frame} + */ + Point getLocation(); + + /** + * {@return the size of the instruction frame} + */ + Dimension getSize(); + + /** + * {@return the bounds of the instruction frame} + */ + Rectangle getBounds(); + + /** + * Allows to change the location of the instruction frame. + * + * @param location the new location of the instruction frame + */ + void setLocation(Point location); + + /** + * Allows to change the location of the instruction frame. + * + * @param x the x coordinate of the new location + * @param y the y coordinate of the new location + */ + void setLocation(int x, int y); + + /** + * Returns the specified position that was used to set + * the initial location of the instruction frame. + * + * @return the specified position + * + * @see Position + */ + Position getPosition(); + } + + + private static final class WindowClosingHandler extends WindowAdapter { + @Override + public void windowClosing(WindowEvent e) { + testFailedReason = FAILURE_REASON + + "User closed a window"; + failed = true; + latch.countDown(); + } + } + + private static final WindowListener windowClosingHandler = + new WindowClosingHandler(); + + private static JComponent createCapturePanel() { JComboBox screenShortType = new JComboBox<>(CaptureType.values()); @@ -409,13 +619,11 @@ public void awaitAndCheck() throws InterruptedException, InvocationTargetExcepti } /** - * Dispose all the window(s) i,e both the test instruction frame and - * the window(s) that is added via addTestWindow(Window testWindow) + * Disposes of all the windows. It disposes of the test instruction frame + * and all other windows added via {@link #addTestWindow(Window)}. */ private static synchronized void disposeWindows() { - for (Window win : windowList) { - win.dispose(); - } + windowList.forEach(Window::dispose); } /** @@ -450,6 +658,36 @@ private static void getFailureReason() { latch.countDown(); } + private static void positionInstructionFrame(final Position position) { + Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); + + // Get the screen insets to position the frame by taking into + // account the location of taskbar or menu bar on screen. + GraphicsConfiguration gc = GraphicsEnvironment.getLocalGraphicsEnvironment() + .getDefaultScreenDevice() + .getDefaultConfiguration(); + Insets screenInsets = Toolkit.getDefaultToolkit().getScreenInsets(gc); + + switch (position) { + case HORIZONTAL: + int newX = ((screenSize.width / 2) - frame.getWidth()); + frame.setLocation((newX + screenInsets.left), + (frame.getY() + screenInsets.top)); + break; + + case VERTICAL: + int newY = ((screenSize.height / 2) - frame.getHeight()); + frame.setLocation((frame.getX() + screenInsets.left), + (newY + screenInsets.top)); + break; + + case TOP_LEFT_CORNER: + frame.setLocation(screenInsets.left, screenInsets.top); + break; + } + syncLocationToWindowManager(); + } + /** * Approximately positions the instruction frame relative to the test * window as specified by the {@code position} parameter. If {@code testWindow} @@ -480,40 +718,23 @@ private static void getFailureReason() { * */ public static void positionTestWindow(Window testWindow, Position position) { - Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); - - // Get the screen insets to position the frame by taking into - // account the location of taskbar/menubars on screen. - GraphicsConfiguration gc = GraphicsEnvironment.getLocalGraphicsEnvironment() - .getDefaultScreenDevice().getDefaultConfiguration(); - Insets screenInsets = Toolkit.getDefaultToolkit().getScreenInsets(gc); - - if (position.equals(Position.HORIZONTAL)) { - int newX = ((screenSize.width / 2) - frame.getWidth()); - frame.setLocation((newX + screenInsets.left), - (frame.getY() + screenInsets.top)); - syncLocationToWindowManager(); - if (testWindow != null) { - testWindow.setLocation((frame.getX() + frame.getWidth() + 5), - frame.getY()); - } - } else if (position.equals(Position.VERTICAL)) { - int newY = ((screenSize.height / 2) - frame.getHeight()); - frame.setLocation((frame.getX() + screenInsets.left), - (newY + screenInsets.top)); - syncLocationToWindowManager(); - if (testWindow != null) { - testWindow.setLocation(frame.getX(), - (frame.getY() + frame.getHeight() + 5)); - } - } else if (position.equals(Position.TOP_LEFT_CORNER)) { - frame.setLocation(screenInsets.left, screenInsets.top); - syncLocationToWindowManager(); - if (testWindow != null) { - testWindow.setLocation((frame.getX() + frame.getWidth() + 5), - frame.getY()); + positionInstructionFrame(position); + + if (testWindow != null) { + switch (position) { + case HORIZONTAL: + case TOP_LEFT_CORNER: + testWindow.setLocation((frame.getX() + frame.getWidth() + 5), + frame.getY()); + break; + + case VERTICAL: + testWindow.setLocation(frame.getX(), + (frame.getY() + frame.getHeight() + 5)); + break; } } + // make instruction frame visible after updating // frame & window positions frame.setVisible(true); @@ -553,13 +774,7 @@ public static Rectangle getInstructionFrameBounds() throws InterruptedException, InvocationTargetException { final Rectangle[] bounds = {null}; - if (isEventDispatchThread()) { - bounds[0] = frame != null ? frame.getBounds() : null; - } else { - invokeAndWait(() -> { - bounds[0] = frame != null ? frame.getBounds() : null; - }); - } + invokeOnEDT(() -> bounds[0] = frame != null ? frame.getBounds() : null); return bounds[0]; } @@ -574,6 +789,16 @@ public static synchronized void addTestWindow(Window testWindow) { windowList.add(testWindow); } + /** + * Adds a collection of test windows to the windowList to be disposed of + * when the test completes. + * + * @param testWindows the collection of test windows to be disposed of + */ + public static synchronized void addTestWindow(Collection testWindows) { + windowList.addAll(testWindows); + } + /** * Forcibly pass the test. *

    The sample usage: @@ -607,13 +832,20 @@ public static void forceFail(String reason) { latch.countDown(); } - public static class Builder { + public static final class Builder { private String title; private String instructions; private long testTimeOut; private int rows; private int columns; - private boolean screenCapture = false; + private boolean screenCapture; + + private List testWindows; + private WindowCreator windowCreator; + private PositionWindows positionWindows; + private InstructionUI instructionUIHandler; + + private Position position; public Builder title(String title) { this.title = title; @@ -645,6 +877,51 @@ public Builder screenCapture() { return this; } + public Builder testUI(Window window) { + return testUI(List.of(window)); + } + + public Builder testUI(Window... windows) { + return testUI(List.of(windows)); + } + + public Builder testUI(List windows) { + if (windows == null) { + throw new IllegalArgumentException("The list of windows can't be null"); + } + if (windows.stream() + .anyMatch(Objects::isNull)) { + throw new IllegalArgumentException("The windows list can't contain null"); + } + + if (windowCreator != null) { + throw new IllegalStateException("windowCreator is already set"); + } + this.testWindows = windows; + return this; + } + + public Builder testUI(WindowCreator windowCreator) { + if (windowCreator == null) { + throw new IllegalArgumentException("The window creator can't be null"); + } + if (testWindows != null) { + throw new IllegalStateException("testWindows are already set"); + } + this.windowCreator = windowCreator; + return this; + } + + public Builder positionTestUI(PositionWindows positionWindows) { + this.positionWindows = positionWindows; + return this; + } + + public Builder position(Position position) { + this.position = position; + return this; + } + public PassFailJFrame build() throws InterruptedException, InvocationTargetException { validate(); @@ -652,26 +929,76 @@ public PassFailJFrame build() throws InterruptedException, } private void validate() { - if (this.title == null) { - this.title = TITLE; + if (title == null) { + title = TITLE; } - if (this.instructions == null || this.instructions.length() == 0) { - throw new RuntimeException("Please provide the test " + - "instruction for this manual test"); + if (instructions == null || instructions.isEmpty()) { + throw new IllegalStateException("Please provide the test " + + "instructions for this manual test"); } - if (this.testTimeOut == 0L) { - this.testTimeOut = TEST_TIMEOUT; + if (testTimeOut == 0L) { + testTimeOut = TEST_TIMEOUT; } - if (this.rows == 0) { - this.rows = ROWS; + if (rows == 0) { + rows = ROWS; } - if (this.columns == 0) { - this.columns = COLUMNS; + if (columns == 0) { + columns = COLUMNS; + } + + if (position == null + && (testWindows != null || windowCreator != null)) { + + position = Position.HORIZONTAL; + } + + if (positionWindows != null) { + if (testWindows == null && windowCreator == null) { + throw new IllegalStateException("To position windows, " + + "provide an a list of windows to the builder"); + } + instructionUIHandler = new InstructionUIHandler(); } } + + private final class InstructionUIHandler implements InstructionUI { + @Override + public Point getLocation() { + return frame.getLocation(); + } + + @Override + public Dimension getSize() { + return frame.getSize(); + } + + @Override + public Rectangle getBounds() { + return frame.getBounds(); + } + + @Override + public void setLocation(Point location) { + setLocation(location.x, location.y); + } + + @Override + public void setLocation(int x, int y) { + frame.setLocation(x, y); + } + + @Override + public Position getPosition() { + return position; + } + } + } + + public static Builder builder() { + return new Builder(); } } From c587211bf8c60a7a1f6cc63770c38ede6cb4e173 Mon Sep 17 00:00:00 2001 From: Alexey Ivanov Date: Wed, 25 Oct 2023 11:33:47 +0000 Subject: [PATCH 112/124] 8316003: Update FileChooserSymLinkTest.java to HTML instructions Reviewed-by: prr --- .../JFileChooser/FileChooserSymLinkTest.java | 73 +++++++++++-------- 1 file changed, 43 insertions(+), 30 deletions(-) diff --git a/test/jdk/javax/swing/JFileChooser/FileChooserSymLinkTest.java b/test/jdk/javax/swing/JFileChooser/FileChooserSymLinkTest.java index a161a94d90c..ef29b708536 100644 --- a/test/jdk/javax/swing/JFileChooser/FileChooserSymLinkTest.java +++ b/test/jdk/javax/swing/JFileChooser/FileChooserSymLinkTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 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 @@ -74,48 +74,61 @@ public void run() { static void initialize() throws InterruptedException, InvocationTargetException { //Initialize the components final String INSTRUCTIONS = """ + Instructions to Test: - 1. Open an elevated Command Prompt. - 2. Paste the following commands: - cd /d C:\\ +

      +
    1. Open an elevated Command Prompt. +
    2. Paste the following commands: +
      cd /d C:\\
                       mkdir FileChooserTest
                       cd FileChooserTest
                       mkdir target
      -                mklink /d link target
      +                mklink /d link target
      - 3. Navigate to C:\\FileChooserTest in the JFileChooser. - 4. Use "Enable Multi-Selection" checkbox to enable/disable - MultiSelection Mode - 5. Single-selection: - Click "link" directory, the absolute path of the symbolic - link should be displayed. If it's null, click FAIL. - Click "target" directory, its absolute path should be - displayed. - - Enable multiple selection by clicking the checkbox. - Multi-selection: - Click "link", press Ctrl and then click "target". - Both should be selected and their absolute paths should be - displayed. - - If "link" can't be selected or if its absolute path is null, - click FAIL. - - If "link" can be selected in both single- and multi-selection modes, - click PASS. - 6. When done with testing, paste the following commands to - remove the 'FileChooserTest' directory: - cd \\ - rmdir /s /q C:\\FileChooserTest +
    3. Navigate to C:\\FileChooserTest in + the JFileChooser. +
    4. Perform testing in single- and multi-selection modes: +
        +
      • Single-selection: +
          +
        1. Ensure Enable multi-selection is cleared + (the default state). +
        2. Click link directory, + the absolute path of the symbolic + link should be displayed.
          + If it's null, click Fail. +
        3. Click target directory, + its absolute path should be displayed. +
        +
      • Multi-selection: +
          +
        1. Select Enable multi-selection. +
        2. Click link, +
        3. Press Ctrl and + then click target. +
        4. Both should be selected and + their absolute paths should be displayed. +
        5. If link can't be selected or + if its absolute path is null, + click Fail. +
        +
      +

      If link can be selected in both + single- and multi-selection modes, click Pass.

      +
    5. When done with testing, paste the following commands to + remove the FileChooserTest directory: +
      cd \\
      +                rmdir /s /q C:\\FileChooserTest
      or use File Explorer to clean it up. +
    """; frame = new JFrame("JFileChooser Symbolic Link test"); panel = new JPanel(new BorderLayout()); multiSelection = new JCheckBox("Enable Multi-Selection"); pathList = new JTextArea(10, 50); jfc = new JFileChooser(new File("C:\\")); - passFailJFrame = new PassFailJFrame("Test Instructions", INSTRUCTIONS, 5L, 35, 40); + passFailJFrame = new PassFailJFrame("Test Instructions", INSTRUCTIONS, 5L, 35, 50); PassFailJFrame.addTestWindow(frame); PassFailJFrame.positionTestWindow(frame, PassFailJFrame.Position.HORIZONTAL); From 202c0137b86cd7bcbe0c1eddf2657f45698ab667 Mon Sep 17 00:00:00 2001 From: Frederic Thevenet Date: Wed, 25 Oct 2023 12:58:01 +0000 Subject: [PATCH 113/124] 8318669: Target OS detection in 'test-prebuilt' makefile target is incorrect when running on MSYS2 Reviewed-by: ihse, erikj --- make/RunTestsPrebuilt.gmk | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/make/RunTestsPrebuilt.gmk b/make/RunTestsPrebuilt.gmk index ae14b1e5336..93febe5ed31 100644 --- a/make/RunTestsPrebuilt.gmk +++ b/make/RunTestsPrebuilt.gmk @@ -158,6 +158,10 @@ ifeq ($(UNAME_OS), CYGWIN) OPENJDK_TARGET_OS := windows OPENJDK_TARGET_OS_TYPE := windows OPENJDK_TARGET_OS_ENV := windows.cygwin +else ifeq ($(UNAME_OS), MINGW64) + OPENJDK_TARGET_OS := windows + OPENJDK_TARGET_OS_TYPE := windows + OPENJDK_TARGET_OS_ENV := windows.msys2 else OPENJDK_TARGET_OS_TYPE:=unix ifeq ($(UNAME_OS), Linux) @@ -170,6 +174,9 @@ else OPENJDK_TARGET_OS_ENV := $(OPENJDK_TARGET_OS) endif +# Sanity check env detection +$(info Detected target OS, type and env: [$(OPENJDK_TARGET_OS)] [$(OPENJDK_TARGET_OS_TYPE)] [$(OPENJDK_TARGET_OS_ENV)]) + # Assume little endian unless otherwise specified OPENJDK_TARGET_CPU_ENDIAN := little From 3abd772672a4dfd984459283235f3b1d8fb28a49 Mon Sep 17 00:00:00 2001 From: Alexey Ivanov Date: Wed, 25 Oct 2023 13:25:34 +0000 Subject: [PATCH 114/124] 8316017: Refactor timeout handler in PassFailJFrame Reviewed-by: prr --- .../awt/regtesthelpers/PassFailJFrame.java | 173 ++++++++++++------ 1 file changed, 116 insertions(+), 57 deletions(-) diff --git a/test/jdk/java/awt/regtesthelpers/PassFailJFrame.java b/test/jdk/java/awt/regtesthelpers/PassFailJFrame.java index d2e650b2134..e4fe393fd6e 100644 --- a/test/jdk/java/awt/regtesthelpers/PassFailJFrame.java +++ b/test/jdk/java/awt/regtesthelpers/PassFailJFrame.java @@ -34,6 +34,8 @@ import java.awt.Robot; import java.awt.Toolkit; import java.awt.Window; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.awt.event.WindowListener; @@ -155,14 +157,26 @@ public class PassFailJFrame { * Prefix for the user-provided failure reason. */ private static final String FAILURE_REASON = "Failure Reason:\n"; + /** + * The failure reason message when the user didn't provide one. + */ + private static final String EMPTY_REASON = "(no reason provided)"; private static final List windowList = new ArrayList<>(); - private static final Timer timer = new Timer(0, null); + private static final CountDownLatch latch = new CountDownLatch(1); - private static volatile boolean failed; - private static volatile boolean timeout; - private static volatile String testFailedReason; + private static TimeoutHandler timeoutHandler; + + /** + * The description of why the test fails. + *

    + * Note: do not use this field directly, + * use the {@link #setFailureReason(String) setFailureReason} and + * {@link #getFailureReason() getFailureReason} methods to modify and + * to read its value. + */ + private static String failureReason; private static final AtomicInteger imgCounter = new AtomicInteger(0); @@ -319,42 +333,27 @@ private static void createUI(String title, String instructions, frame = new JFrame(title); frame.setLayout(new BorderLayout()); + JLabel testTimeoutLabel = new JLabel("", JLabel.CENTER); + timeoutHandler = new TimeoutHandler(testTimeoutLabel, testTimeOut); + frame.add(testTimeoutLabel, BorderLayout.NORTH); + JTextComponent text = instructions.startsWith("") ? configureHTML(instructions, rows, columns) : configurePlainText(instructions, rows, columns); text.setEditable(false); - long tTimeout = TimeUnit.MINUTES.toMillis(testTimeOut); - - final JLabel testTimeoutLabel = new JLabel(String.format("Test " + - "timeout: %s", convertMillisToTimeStr(tTimeout)), JLabel.CENTER); - final long startTime = System.currentTimeMillis(); - timer.setDelay(1000); - timer.addActionListener((e) -> { - long leftTime = tTimeout - (System.currentTimeMillis() - startTime); - if ((leftTime < 0) || failed) { - timer.stop(); - testFailedReason = FAILURE_REASON - + "Timeout User did not perform testing."; - timeout = true; - latch.countDown(); - } - testTimeoutLabel.setText(String.format("Test timeout: %s", convertMillisToTimeStr(leftTime))); - }); - timer.start(); - frame.add(testTimeoutLabel, BorderLayout.NORTH); frame.add(new JScrollPane(text), BorderLayout.CENTER); JButton btnPass = new JButton("Pass"); btnPass.addActionListener((e) -> { latch.countDown(); - timer.stop(); + timeoutHandler.stop(); }); JButton btnFail = new JButton("Fail"); btnFail.addActionListener((e) -> { - getFailureReason(); - timer.stop(); + requestFailureReason(); + timeoutHandler.stop(); }); JPanel buttonsPanel = new JPanel(); @@ -480,12 +479,58 @@ public interface InstructionUI { } + private static final class TimeoutHandler implements ActionListener { + private final long endTime; + + private final Timer timer; + + private final JLabel label; + + public TimeoutHandler(final JLabel label, final long testTimeOut) { + endTime = System.currentTimeMillis() + TimeUnit.MINUTES.toMillis(testTimeOut); + + this.label = label; + + timer = new Timer(1000, this); + timer.start(); + updateTime(testTimeOut); + } + + @Override + public void actionPerformed(ActionEvent e) { + long leftTime = endTime - System.currentTimeMillis(); + if (leftTime < 0) { + timer.stop(); + setFailureReason(FAILURE_REASON + + "Timeout - User did not perform testing."); + latch.countDown(); + } + updateTime(leftTime); + } + + private void updateTime(final long leftTime) { + if (leftTime < 0) { + label.setText("Test timeout: 00:00:00"); + return; + } + long hours = leftTime / 3_600_000; + long minutes = (leftTime - hours * 3_600_000) / 60_000; + long seconds = (leftTime - hours * 3_600_000 - minutes * 60_000) / 1_000; + label.setText(String.format("Test timeout: %02d:%02d:%02d", + hours, minutes, seconds)); + } + + public void stop() { + timer.stop(); + } + } + + private static final class WindowClosingHandler extends WindowAdapter { @Override public void windowClosing(WindowEvent e) { - testFailedReason = FAILURE_REASON - + "User closed a window"; - failed = true; + setFailureReason(FAILURE_REASON + + "User closed a window"); latch.countDown(); } } @@ -579,14 +624,28 @@ private static void captureScreen(CaptureType type) { JOptionPane.INFORMATION_MESSAGE); } - private static String convertMillisToTimeStr(long millis) { - if (millis < 0) { - return "00:00:00"; + /** + * Sets the failure reason which describes why the test fails. + * This method ensures the {@code failureReason} field does not change + * after it's set to a non-{@code null} value. + * @param reason the description of why the test fails + * @throws IllegalArgumentException if the {@code reason} parameter + * is {@code null} + */ + private static synchronized void setFailureReason(final String reason) { + if (reason == null) { + throw new IllegalArgumentException("The failure reason must not be null"); } - long hours = millis / 3_600_000; - long minutes = (millis - hours * 3_600_000) / 60_000; - long seconds = (millis - hours * 3_600_000 - minutes * 60_000) / 1_000; - return String.format("%02d:%02d:%02d", hours, minutes, seconds); + if (failureReason == null) { + failureReason = reason; + } + } + + /** + * {@return the description of why the test fails} + */ + private static synchronized String getFailureReason() { + return failureReason; } /** @@ -607,30 +666,18 @@ public void awaitAndCheck() throws InterruptedException, InvocationTargetExcepti latch.await(); invokeAndWait(PassFailJFrame::disposeWindows); - if (timeout) { - throw new RuntimeException(testFailedReason); - } - - if (failed) { - throw new RuntimeException("Test failed! : " + testFailedReason); + String failure = getFailureReason(); + if (failure != null) { + throw new RuntimeException(failure); } System.out.println("Test passed!"); } /** - * Disposes of all the windows. It disposes of the test instruction frame - * and all other windows added via {@link #addTestWindow(Window)}. - */ - private static synchronized void disposeWindows() { - windowList.forEach(Window::dispose); - } - - /** - * Read the test failure reason and add the reason to the test result - * example in the jtreg .jtr file. + * Requests the description of the test failure reason from the tester. */ - private static void getFailureReason() { + private static void requestFailureReason() { final JDialog dialog = new JDialog(frame, "Test Failure ", true); dialog.setTitle("Failure reason"); JPanel jPanel = new JPanel(new BorderLayout()); @@ -638,7 +685,9 @@ private static void getFailureReason() { JButton okButton = new JButton("OK"); okButton.addActionListener((ae) -> { - testFailedReason = FAILURE_REASON + jTextArea.getText(); + String text = jTextArea.getText(); + setFailureReason(FAILURE_REASON + + (!text.isEmpty() ? text : EMPTY_REASON)); dialog.setVisible(false); }); @@ -653,11 +702,22 @@ private static void getFailureReason() { dialog.pack(); dialog.setVisible(true); - failed = true; + // Ensure the test fails even if the dialog is closed + // without clicking the OK button + setFailureReason(FAILURE_REASON + EMPTY_REASON); + dialog.dispose(); latch.countDown(); } + /** + * Disposes of all the windows. It disposes of the test instruction frame + * and all other windows added via {@link #addTestWindow(Window)}. + */ + private static synchronized void disposeWindows() { + windowList.forEach(Window::dispose); + } + private static void positionInstructionFrame(final Position position) { Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); @@ -827,8 +887,7 @@ public static void forceFail() { * @param reason the reason why the test is failed */ public static void forceFail(String reason) { - failed = true; - testFailedReason = FAILURE_REASON + reason; + setFailureReason(FAILURE_REASON + reason); latch.countDown(); } From b026d0b480dcd4c0a3346078dd10047653ed3751 Mon Sep 17 00:00:00 2001 From: Roland Westrelin Date: Wed, 25 Oct 2023 13:32:56 +0000 Subject: [PATCH 115/124] 8312980: C2: "malformed control flow" created during incremental inlining Co-authored-by: Emanuel Peter Reviewed-by: thartmann, epeter --- src/hotspot/share/opto/replacednodes.cpp | 206 +++++++++++++----- src/hotspot/share/opto/replacednodes.hpp | 4 + .../TestReplacedNodesAfterLateInline.java | 80 +++++++ ...ReplacedNodesAfterLateInlineManyPaths.java | 72 ++++++ 4 files changed, 306 insertions(+), 56 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/inlining/TestReplacedNodesAfterLateInline.java create mode 100644 test/hotspot/jtreg/compiler/inlining/TestReplacedNodesAfterLateInlineManyPaths.java diff --git a/src/hotspot/share/opto/replacednodes.cpp b/src/hotspot/share/opto/replacednodes.cpp index 78c1703799e..56c5ee1c0bf 100644 --- a/src/hotspot/share/opto/replacednodes.cpp +++ b/src/hotspot/share/opto/replacednodes.cpp @@ -106,88 +106,175 @@ void ReplacedNodes::apply(Node* n, uint idx) { } } -static void enqueue_use(Node* n, Node* use, Unique_Node_List& work) { - if (use->is_Phi()) { - Node* r = use->in(0); - assert(r->is_Region(), "Phi should have Region"); - for (uint i = 1; i < use->req(); i++) { - if (use->in(i) == n) { - work.push(r->in(i)); - } - } - } else { - work.push(use); - } -} - // Perform node replacement following late inlining. void ReplacedNodes::apply(Compile* C, Node* ctl) { // ctl is the control on exit of the method that was late inlined if (is_empty()) { return; } + ResourceMark rm; + Node_Stack stack(0); + Unique_Node_List to_fix; // nodes to clone + uses at the end of the chain that need to updated + VectorSet seen; + VectorSet valid_control; + for (int i = 0; i < _replaced_nodes->length(); i++) { ReplacedNode replaced = _replaced_nodes->at(i); Node* initial = replaced.initial(); Node* improved = replaced.improved(); assert (ctl != nullptr && !ctl->is_top(), "replaced node should have actual control"); - ResourceMark rm; - Unique_Node_List work; - // Go over all the uses of the node that is considered for replacement... - for (DUIterator j = initial->outs(); initial->has_out(j); j++) { - Node* use = initial->out(j); + if (initial->outcnt() == 0) { + continue; + } - if (use == improved || use->outcnt() == 0) { - continue; - } - work.clear(); - enqueue_use(initial, use, work); - bool replace = true; - // Check that this use is dominated by ctl. Go ahead with the replacement if it is. - while (work.size() != 0 && replace) { - Node* n = work.pop(); - if (use->outcnt() == 0) { - continue; + // Find uses of initial that are dominated by ctl so, initial can be replaced by improved. + // Proving domination here is not straightforward. To do so, we follow uses of initial, and uses of uses until we + // encounter a node which is a control node or is pinned at some control. Then, we try to prove this control is + // dominated by ctl. If that's the case, it's legal to replace initial by improved but for this chain of uses only. + // It may not be the case for some other chain of uses, so we clone that chain and perform the replacement only for + // these uses. + assert(stack.is_empty(), ""); + stack.push(initial, 1); + Node* use = initial->raw_out(0); + stack.push(use, 0); + + while (!stack.is_empty()) { + assert(stack.size() > 1, "at least initial + one use"); + Node* n = stack.node(); + + uint current_size = stack.size(); + + if (seen.test_set(n->_idx)) { + if (to_fix.member(n)) { + collect_nodes_to_clone(stack, to_fix); } - if (n->is_CFG() || (n->in(0) != nullptr && !n->in(0)->is_top())) { - // Skip projections, since some of the multi nodes aren't CFG (e.g., LoadStore and SCMemProj). - if (n->is_Proj()) { - n = n->in(0); + } else if (n->outcnt() != 0 && n != improved) { + if (n->is_Phi()) { + Node* region = n->in(0); + Node* prev = stack.node_at(stack.size() - 2); + for (uint j = 1; j < region->req(); ++j) { + if (n->in(j) == prev) { + Node* in = region->in(j); + if (in != nullptr && !in->is_top()) { + if (is_dominator(ctl, in)) { + valid_control.set(in->_idx); + collect_nodes_to_clone(stack, to_fix); + } + } + } } - if (!n->is_CFG()) { - n = n->in(0); + } else if (n->is_CFG()) { + if (is_dominator(ctl, n)) { + collect_nodes_to_clone(stack, to_fix); } - assert(n->is_CFG(), "should be CFG now"); - int depth = 0; - while(n != ctl) { - n = IfNode::up_one_dom(n); - depth++; - // limit search depth - if (depth >= 100 || n == nullptr) { - replace = false; - break; - } + } else if (n->in(0) != nullptr && n->in(0)->is_CFG()) { + Node* c = n->in(0); + if (is_dominator(ctl, c)) { + collect_nodes_to_clone(stack, to_fix); } } else { - for (DUIterator k = n->outs(); n->has_out(k); k++) { - enqueue_use(n, n->out(k), work); + uint idx = stack.index(); + if (idx < n->outcnt()) { + stack.set_index(idx + 1); + stack.push(n->raw_out(idx), 0); } } } - if (replace) { - bool is_in_table = C->initial_gvn()->hash_delete(use); - int replaced = use->replace_edge(initial, improved); - if (is_in_table) { - C->initial_gvn()->hash_find_insert(use); + if (stack.size() == current_size) { + for (;;) { + stack.pop(); + if (stack.is_empty()) { + break; + } + n = stack.node(); + uint idx = stack.index(); + if (idx < n->outcnt()) { + stack.set_index(idx + 1); + stack.push(n->raw_out(idx), 0); + break; + } } - C->record_for_igvn(use); + } + } + } + if (to_fix.size() > 0) { + uint hash_table_size = _replaced_nodes->length(); + for (uint i = 0; i < to_fix.size(); ++i) { + Node* n = to_fix.at(i); + if (n->is_CFG() || n->in(0) != nullptr) { // End of a chain is not cloned + continue; + } + hash_table_size++; + } + // Map from current node to cloned/replaced node + ResizeableResourceHashtable clones(hash_table_size, hash_table_size); + // Record mapping from initial to improved nodes + for (int i = 0; i < _replaced_nodes->length(); i++) { + ReplacedNode replaced = _replaced_nodes->at(i); + Node* initial = replaced.initial(); + Node* improved = replaced.improved(); + clones.put(initial, improved); + // If initial needs to be cloned but is also improved then there's no need to clone it. + if (to_fix.member(initial)) { + to_fix.remove(initial); + } + } - assert(replaced > 0, "inconsistent"); - --j; + // Clone nodes and record mapping from current to cloned nodes + for (uint i = 0; i < to_fix.size(); ++i) { + Node* n = to_fix.at(i); + if (n->is_CFG() || n->in(0) != nullptr) { // End of a chain + continue; } + Node* clone = n->clone(); + bool added = clones.put(n, clone); + assert(added, "clone node must be added to mapping"); + C->initial_gvn()->set_type_bottom(clone); + to_fix.map(i, clone); // Update list of nodes with cloned node + } + + // Fix edges in cloned nodes and use at the end of the chain + for (uint i = 0; i < to_fix.size(); ++i) { + Node* n = to_fix.at(i); + bool is_in_table = C->initial_gvn()->hash_delete(n); + uint updates = 0; + for (uint j = 0; j < n->req(); ++j) { + Node* in = n->in(j); + if (in == nullptr || (n->is_Phi() && n->in(0)->in(j) == nullptr)) { + continue; + } + if (n->is_Phi() && !valid_control.test(n->in(0)->in(j)->_idx)) { + continue; + } + Node** clone_ptr = clones.get(in); + if (clone_ptr != nullptr) { + Node* clone = *clone_ptr; + n->set_req(j, clone); + updates++; + } + } + assert(updates > 0, ""); + C->record_for_igvn(n); + if (is_in_table) { + C->initial_gvn()->hash_find_insert(n); + } + } + } +} + +bool ReplacedNodes::is_dominator(const Node* ctl, Node* n) const { + assert(n->is_CFG(), "should be CFG now"); + int depth = 0; + while (n != ctl) { + n = IfNode::up_one_dom(n); + depth++; + // limit search depth + if (depth >= 100 || n == nullptr) { + return false; } } + return true; } void ReplacedNodes::dump(outputStream *st) const { @@ -224,3 +311,10 @@ void ReplacedNodes::merge_with(const ReplacedNodes& other) { _replaced_nodes->trunc_to(len - shift); } } + +void ReplacedNodes::collect_nodes_to_clone(const Node_Stack& stack, Unique_Node_List& to_fix) { + for (uint i = stack.size() - 1; i >= 1; i--) { + Node* n = stack.node_at(i); + to_fix.push(n); + } +} diff --git a/src/hotspot/share/opto/replacednodes.hpp b/src/hotspot/share/opto/replacednodes.hpp index c569e55ce5f..9b66a2c5f49 100644 --- a/src/hotspot/share/opto/replacednodes.hpp +++ b/src/hotspot/share/opto/replacednodes.hpp @@ -76,6 +76,10 @@ class ReplacedNodes { bool is_empty() const; void dump(outputStream *st) const; void apply(Compile* C, Node* ctl); + + bool is_dominator(const Node* ctl, Node* n) const; + + void collect_nodes_to_clone(const Node_Stack& stack, Unique_Node_List& to_fix); }; #endif // SHARE_OPTO_REPLACEDNODES_HPP diff --git a/test/hotspot/jtreg/compiler/inlining/TestReplacedNodesAfterLateInline.java b/test/hotspot/jtreg/compiler/inlining/TestReplacedNodesAfterLateInline.java new file mode 100644 index 00000000000..26e1c7740da --- /dev/null +++ b/test/hotspot/jtreg/compiler/inlining/TestReplacedNodesAfterLateInline.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2023, Red Hat, Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * bug 8312980 + * @summary C2: "malformed control flow" created during incremental inlining + * @requires vm.compiler2.enabled + * @run main/othervm -XX:-TieredCompilation -XX:-BackgroundCompilation -XX:+IgnoreUnrecognizedVMOptions -XX:+AlwaysIncrementalInline TestReplacedNodesAfterLateInline + */ + +public class TestReplacedNodesAfterLateInline { + private static B fieldB = new B(); + private static A fieldA = new A(); + private static volatile int volatileField; + + public static void main(String[] args) { + for (int i = 0; i < 20_000; i++) { + test(false, fieldA, true); + test(false, fieldA, false); + testHelper(fieldB); + testHelper2(fieldB, true, false, true); + testHelper2(fieldA, false, true, true); + continue; + } + } + + private static int test(boolean flag, Object o, boolean flag2) { + if (o == null) { + } + if (flag2) { + return testHelper2(o, true, true, flag); + } + return ((A) o).field; + } + + private static int testHelper2(Object o, boolean flag, boolean flag2, boolean flag3) { + if (flag3) { + if (flag) { + testHelper(o); + } + if (flag2) { + return ((A) o).field; + } + } + volatileField = 42; + return volatileField; + } + + private static void testHelper(Object o) { + B b = (B)o; + } + + private static class A { + public int field; + } + + private static class B { + } +} diff --git a/test/hotspot/jtreg/compiler/inlining/TestReplacedNodesAfterLateInlineManyPaths.java b/test/hotspot/jtreg/compiler/inlining/TestReplacedNodesAfterLateInlineManyPaths.java new file mode 100644 index 00000000000..b30e5652420 --- /dev/null +++ b/test/hotspot/jtreg/compiler/inlining/TestReplacedNodesAfterLateInlineManyPaths.java @@ -0,0 +1,72 @@ +/* + * 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 8312980 + * @summary C2: "malformed control flow" created during incremental inlining + * @requires vm.compiler2.enabled + * @run main/othervm -XX:CompileCommand=compileonly,TestReplacedNodesAfterLateInlineManyPaths::* -XX:-BackgroundCompilation + * -XX:+IgnoreUnrecognizedVMOptions -XX:+AlwaysIncrementalInline TestReplacedNodesAfterLateInlineManyPaths + */ + +public class TestReplacedNodesAfterLateInlineManyPaths { + public static void main(String[] args) { + for (int i = 0; i < 20_000; i++) { + test("" + i); + } + } + + public static int test(String s) { + int result = 0; + int len = s.length(); + int i = 0; + while (i < len) { + // charAt is inlined late, and i is constrained by CastII(i >= 0) + // The constraint comes from intrinsic checkIndex + s.charAt(i); + // Graph below intentionally branches out 4x, and merges again (4-fold diamonds). + // This creates an exponential explosion in number of paths. + int e = i; + e = (e & 7) + (e & 31) + (e & 1111) + (e & 1000_000); + e = (e & 7) + (e & 31) + (e & 1111) + (e & 1000_000); + e = (e & 7) + (e & 31) + (e & 1111) + (e & 1000_000); + e = (e & 7) + (e & 31) + (e & 1111) + (e & 1000_000); + e = (e & 7) + (e & 31) + (e & 1111) + (e & 1000_000); + // Comment out lines below to make it not assert + // assert(C->live_nodes() <= C->max_node_limit()) failed: Live Node limit exceeded limit + e = (e & 7) + (e & 31) + (e & 1111) + (e & 1000_000); + e = (e & 7) + (e & 31) + (e & 1111) + (e & 1000_000); + e = (e & 7) + (e & 31) + (e & 1111) + (e & 1000_000); + e = (e & 7) + (e & 31) + (e & 1111) + (e & 1000_000); + e = (e & 7) + (e & 31) + (e & 1111) + (e & 1000_000); + e = (e & 7) + (e & 31) + (e & 1111) + (e & 1000_000); + e = (e & 7) + (e & 31) + (e & 1111) + (e & 1000_000); + e = (e & 7) + (e & 31) + (e & 1111) + (e & 1000_000); + e = (e & 7) + (e & 31) + (e & 1111) + (e & 1000_000); + result += e; + i++; + } + return result; + } +} From cee44a625594fd805a05c4a69033eb677a5a6f17 Mon Sep 17 00:00:00 2001 From: Elif Aslan Date: Wed, 25 Oct 2023 15:00:44 +0000 Subject: [PATCH 116/124] 8318608: Enable parallelism in vmTestbase/nsk/stress/threads tests Reviewed-by: lmesnik, shade --- .../nsk/stress/thread/TEST.properties | 24 ------------------- 1 file changed, 24 deletions(-) delete mode 100644 test/hotspot/jtreg/vmTestbase/nsk/stress/thread/TEST.properties diff --git a/test/hotspot/jtreg/vmTestbase/nsk/stress/thread/TEST.properties b/test/hotspot/jtreg/vmTestbase/nsk/stress/thread/TEST.properties deleted file mode 100644 index 8b51b2a9115..00000000000 --- a/test/hotspot/jtreg/vmTestbase/nsk/stress/thread/TEST.properties +++ /dev/null @@ -1,24 +0,0 @@ -# -# Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. -# -# This code is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# version 2 for more details (a copy is included in the LICENSE file that -# accompanied this code). -# -# You should have received a copy of the GNU General Public License version -# 2 along with this work; if not, write to the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -# or visit www.oracle.com if you need additional information or have any -# questions. -# - -exclusiveAccess.dirs=. From 43f31d73852d63ccdcc2dcd8d6c7355435a50fb3 Mon Sep 17 00:00:00 2001 From: Elif Aslan Date: Wed, 25 Oct 2023 15:01:11 +0000 Subject: [PATCH 117/124] 8318607: Enable parallelism in vmTestbase/nsk/stress/jni tests Reviewed-by: lmesnik, shade --- .../vmTestbase/nsk/stress/jni/TEST.properties | 24 ------------------- 1 file changed, 24 deletions(-) delete mode 100644 test/hotspot/jtreg/vmTestbase/nsk/stress/jni/TEST.properties diff --git a/test/hotspot/jtreg/vmTestbase/nsk/stress/jni/TEST.properties b/test/hotspot/jtreg/vmTestbase/nsk/stress/jni/TEST.properties deleted file mode 100644 index 8b51b2a9115..00000000000 --- a/test/hotspot/jtreg/vmTestbase/nsk/stress/jni/TEST.properties +++ /dev/null @@ -1,24 +0,0 @@ -# -# Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License version 2 only, as -# published by the Free Software Foundation. -# -# This code is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# version 2 for more details (a copy is included in the LICENSE file that -# accompanied this code). -# -# You should have received a copy of the GNU General Public License version -# 2 along with this work; if not, write to the Free Software Foundation, -# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. -# -# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA -# or visit www.oracle.com if you need additional information or have any -# questions. -# - -exclusiveAccess.dirs=. From 29d462a07239a57b83850b9a8662573291fdbdf7 Mon Sep 17 00:00:00 2001 From: Elif Aslan Date: Wed, 25 Oct 2023 15:23:13 +0000 Subject: [PATCH 118/124] 8318727: Enable parallelism in vmTestbase/vm/gc/concurrent tests Reviewed-by: shade, lmesnik --- .../lp30yp0rp0mr30st300/TEST.properties | 23 ------------------- .../lp30yp0rp0mr70st300t1/TEST.properties | 23 ------------------- .../lp30yp0rp30mr0st300/TEST.properties | 23 ------------------- .../lp30yp0rp30mr30st0t1/TEST.properties | 23 ------------------- .../lp30yp0rp30mr70st0/TEST.properties | 23 ------------------- .../lp30yp0rp30mr70st300t1/TEST.properties | 23 ------------------- .../lp30yp0rp70mr30st0/TEST.properties | 23 ------------------- .../lp30yp0rp70mr30st300t1/TEST.properties | 23 ------------------- .../lp30yp10rp0mr30st300/TEST.properties | 23 ------------------- .../lp30yp10rp0mr70st300t1/TEST.properties | 23 ------------------- .../lp30yp10rp30mr0st300/TEST.properties | 23 ------------------- .../lp30yp10rp30mr30st0t1/TEST.properties | 23 ------------------- .../lp30yp10rp30mr70st0/TEST.properties | 23 ------------------- .../lp30yp10rp30mr70st300t1/TEST.properties | 23 ------------------- .../lp30yp10rp70mr30st0/TEST.properties | 23 ------------------- .../lp30yp10rp70mr30st300t1/TEST.properties | 23 ------------------- .../lp30yp25rp0mr30st300/TEST.properties | 23 ------------------- .../lp30yp25rp0mr70st300t1/TEST.properties | 23 ------------------- .../lp30yp25rp30mr0st300/TEST.properties | 23 ------------------- .../lp30yp25rp30mr30st0t1/TEST.properties | 23 ------------------- .../lp30yp25rp30mr70st0/TEST.properties | 23 ------------------- .../lp30yp25rp30mr70st300t1/TEST.properties | 23 ------------------- .../lp30yp25rp70mr30st0/TEST.properties | 23 ------------------- .../lp30yp25rp70mr30st300t1/TEST.properties | 23 ------------------- .../lp50yp0rp0mr30st300/TEST.properties | 23 ------------------- .../lp50yp0rp0mr70st300t1/TEST.properties | 23 ------------------- .../lp50yp0rp30mr0st300/TEST.properties | 23 ------------------- .../lp50yp0rp30mr30st0t1/TEST.properties | 23 ------------------- .../lp50yp0rp30mr70st0/TEST.properties | 23 ------------------- .../lp50yp0rp30mr70st300t1/TEST.properties | 23 ------------------- .../lp50yp0rp70mr30st0/TEST.properties | 23 ------------------- .../lp50yp0rp70mr30st300t1/TEST.properties | 23 ------------------- .../lp50yp10rp0mr30st300/TEST.properties | 23 ------------------- .../lp50yp10rp0mr70st300t1/TEST.properties | 23 ------------------- .../lp50yp10rp30mr0st300/TEST.properties | 23 ------------------- .../lp50yp10rp30mr30st0t1/TEST.properties | 23 ------------------- .../lp50yp10rp30mr70st0/TEST.properties | 23 ------------------- .../lp50yp10rp30mr70st300t1/TEST.properties | 23 ------------------- .../lp50yp10rp70mr30st0/TEST.properties | 23 ------------------- .../lp50yp10rp70mr30st300t1/TEST.properties | 23 ------------------- .../lp60yp0rp30mr0st300/TEST.properties | 23 ------------------- 41 files changed, 943 deletions(-) delete mode 100644 test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp30yp0rp0mr30st300/TEST.properties delete mode 100644 test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp30yp0rp0mr70st300t1/TEST.properties delete mode 100644 test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp30yp0rp30mr0st300/TEST.properties delete mode 100644 test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp30yp0rp30mr30st0t1/TEST.properties delete mode 100644 test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp30yp0rp30mr70st0/TEST.properties delete mode 100644 test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp30yp0rp30mr70st300t1/TEST.properties delete mode 100644 test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp30yp0rp70mr30st0/TEST.properties delete mode 100644 test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp30yp0rp70mr30st300t1/TEST.properties delete mode 100644 test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp30yp10rp0mr30st300/TEST.properties delete mode 100644 test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp30yp10rp0mr70st300t1/TEST.properties delete mode 100644 test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp30yp10rp30mr0st300/TEST.properties delete mode 100644 test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp30yp10rp30mr30st0t1/TEST.properties delete mode 100644 test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp30yp10rp30mr70st0/TEST.properties delete mode 100644 test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp30yp10rp30mr70st300t1/TEST.properties delete mode 100644 test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp30yp10rp70mr30st0/TEST.properties delete mode 100644 test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp30yp10rp70mr30st300t1/TEST.properties delete mode 100644 test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp30yp25rp0mr30st300/TEST.properties delete mode 100644 test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp30yp25rp0mr70st300t1/TEST.properties delete mode 100644 test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp30yp25rp30mr0st300/TEST.properties delete mode 100644 test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp30yp25rp30mr30st0t1/TEST.properties delete mode 100644 test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp30yp25rp30mr70st0/TEST.properties delete mode 100644 test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp30yp25rp30mr70st300t1/TEST.properties delete mode 100644 test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp30yp25rp70mr30st0/TEST.properties delete mode 100644 test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp30yp25rp70mr30st300t1/TEST.properties delete mode 100644 test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp50yp0rp0mr30st300/TEST.properties delete mode 100644 test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp50yp0rp0mr70st300t1/TEST.properties delete mode 100644 test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp50yp0rp30mr0st300/TEST.properties delete mode 100644 test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp50yp0rp30mr30st0t1/TEST.properties delete mode 100644 test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp50yp0rp30mr70st0/TEST.properties delete mode 100644 test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp50yp0rp30mr70st300t1/TEST.properties delete mode 100644 test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp50yp0rp70mr30st0/TEST.properties delete mode 100644 test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp50yp0rp70mr30st300t1/TEST.properties delete mode 100644 test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp50yp10rp0mr30st300/TEST.properties delete mode 100644 test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp50yp10rp0mr70st300t1/TEST.properties delete mode 100644 test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp50yp10rp30mr0st300/TEST.properties delete mode 100644 test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp50yp10rp30mr30st0t1/TEST.properties delete mode 100644 test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp50yp10rp30mr70st0/TEST.properties delete mode 100644 test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp50yp10rp30mr70st300t1/TEST.properties delete mode 100644 test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp50yp10rp70mr30st0/TEST.properties delete mode 100644 test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp50yp10rp70mr30st300t1/TEST.properties delete mode 100644 test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp60yp0rp30mr0st300/TEST.properties diff --git a/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp30yp0rp0mr30st300/TEST.properties b/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp30yp0rp0mr30st300/TEST.properties deleted file mode 100644 index 04b22a107ac..00000000000 --- a/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp30yp0rp0mr30st300/TEST.properties +++ /dev/null @@ -1,23 +0,0 @@ -# -# Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# 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. -# -exclusiveAccess.dirs=. diff --git a/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp30yp0rp0mr70st300t1/TEST.properties b/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp30yp0rp0mr70st300t1/TEST.properties deleted file mode 100644 index 04b22a107ac..00000000000 --- a/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp30yp0rp0mr70st300t1/TEST.properties +++ /dev/null @@ -1,23 +0,0 @@ -# -# Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# 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. -# -exclusiveAccess.dirs=. diff --git a/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp30yp0rp30mr0st300/TEST.properties b/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp30yp0rp30mr0st300/TEST.properties deleted file mode 100644 index 04b22a107ac..00000000000 --- a/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp30yp0rp30mr0st300/TEST.properties +++ /dev/null @@ -1,23 +0,0 @@ -# -# Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# 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. -# -exclusiveAccess.dirs=. diff --git a/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp30yp0rp30mr30st0t1/TEST.properties b/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp30yp0rp30mr30st0t1/TEST.properties deleted file mode 100644 index 04b22a107ac..00000000000 --- a/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp30yp0rp30mr30st0t1/TEST.properties +++ /dev/null @@ -1,23 +0,0 @@ -# -# Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# 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. -# -exclusiveAccess.dirs=. diff --git a/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp30yp0rp30mr70st0/TEST.properties b/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp30yp0rp30mr70st0/TEST.properties deleted file mode 100644 index 04b22a107ac..00000000000 --- a/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp30yp0rp30mr70st0/TEST.properties +++ /dev/null @@ -1,23 +0,0 @@ -# -# Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# 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. -# -exclusiveAccess.dirs=. diff --git a/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp30yp0rp30mr70st300t1/TEST.properties b/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp30yp0rp30mr70st300t1/TEST.properties deleted file mode 100644 index 04b22a107ac..00000000000 --- a/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp30yp0rp30mr70st300t1/TEST.properties +++ /dev/null @@ -1,23 +0,0 @@ -# -# Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# 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. -# -exclusiveAccess.dirs=. diff --git a/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp30yp0rp70mr30st0/TEST.properties b/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp30yp0rp70mr30st0/TEST.properties deleted file mode 100644 index 04b22a107ac..00000000000 --- a/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp30yp0rp70mr30st0/TEST.properties +++ /dev/null @@ -1,23 +0,0 @@ -# -# Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# 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. -# -exclusiveAccess.dirs=. diff --git a/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp30yp0rp70mr30st300t1/TEST.properties b/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp30yp0rp70mr30st300t1/TEST.properties deleted file mode 100644 index 04b22a107ac..00000000000 --- a/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp30yp0rp70mr30st300t1/TEST.properties +++ /dev/null @@ -1,23 +0,0 @@ -# -# Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# 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. -# -exclusiveAccess.dirs=. diff --git a/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp30yp10rp0mr30st300/TEST.properties b/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp30yp10rp0mr30st300/TEST.properties deleted file mode 100644 index 04b22a107ac..00000000000 --- a/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp30yp10rp0mr30st300/TEST.properties +++ /dev/null @@ -1,23 +0,0 @@ -# -# Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# 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. -# -exclusiveAccess.dirs=. diff --git a/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp30yp10rp0mr70st300t1/TEST.properties b/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp30yp10rp0mr70st300t1/TEST.properties deleted file mode 100644 index 04b22a107ac..00000000000 --- a/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp30yp10rp0mr70st300t1/TEST.properties +++ /dev/null @@ -1,23 +0,0 @@ -# -# Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# 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. -# -exclusiveAccess.dirs=. diff --git a/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp30yp10rp30mr0st300/TEST.properties b/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp30yp10rp30mr0st300/TEST.properties deleted file mode 100644 index 04b22a107ac..00000000000 --- a/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp30yp10rp30mr0st300/TEST.properties +++ /dev/null @@ -1,23 +0,0 @@ -# -# Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# 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. -# -exclusiveAccess.dirs=. diff --git a/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp30yp10rp30mr30st0t1/TEST.properties b/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp30yp10rp30mr30st0t1/TEST.properties deleted file mode 100644 index 04b22a107ac..00000000000 --- a/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp30yp10rp30mr30st0t1/TEST.properties +++ /dev/null @@ -1,23 +0,0 @@ -# -# Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# 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. -# -exclusiveAccess.dirs=. diff --git a/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp30yp10rp30mr70st0/TEST.properties b/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp30yp10rp30mr70st0/TEST.properties deleted file mode 100644 index 04b22a107ac..00000000000 --- a/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp30yp10rp30mr70st0/TEST.properties +++ /dev/null @@ -1,23 +0,0 @@ -# -# Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# 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. -# -exclusiveAccess.dirs=. diff --git a/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp30yp10rp30mr70st300t1/TEST.properties b/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp30yp10rp30mr70st300t1/TEST.properties deleted file mode 100644 index 04b22a107ac..00000000000 --- a/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp30yp10rp30mr70st300t1/TEST.properties +++ /dev/null @@ -1,23 +0,0 @@ -# -# Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# 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. -# -exclusiveAccess.dirs=. diff --git a/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp30yp10rp70mr30st0/TEST.properties b/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp30yp10rp70mr30st0/TEST.properties deleted file mode 100644 index 04b22a107ac..00000000000 --- a/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp30yp10rp70mr30st0/TEST.properties +++ /dev/null @@ -1,23 +0,0 @@ -# -# Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# 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. -# -exclusiveAccess.dirs=. diff --git a/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp30yp10rp70mr30st300t1/TEST.properties b/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp30yp10rp70mr30st300t1/TEST.properties deleted file mode 100644 index 04b22a107ac..00000000000 --- a/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp30yp10rp70mr30st300t1/TEST.properties +++ /dev/null @@ -1,23 +0,0 @@ -# -# Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# 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. -# -exclusiveAccess.dirs=. diff --git a/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp30yp25rp0mr30st300/TEST.properties b/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp30yp25rp0mr30st300/TEST.properties deleted file mode 100644 index 04b22a107ac..00000000000 --- a/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp30yp25rp0mr30st300/TEST.properties +++ /dev/null @@ -1,23 +0,0 @@ -# -# Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# 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. -# -exclusiveAccess.dirs=. diff --git a/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp30yp25rp0mr70st300t1/TEST.properties b/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp30yp25rp0mr70st300t1/TEST.properties deleted file mode 100644 index 04b22a107ac..00000000000 --- a/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp30yp25rp0mr70st300t1/TEST.properties +++ /dev/null @@ -1,23 +0,0 @@ -# -# Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# 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. -# -exclusiveAccess.dirs=. diff --git a/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp30yp25rp30mr0st300/TEST.properties b/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp30yp25rp30mr0st300/TEST.properties deleted file mode 100644 index 04b22a107ac..00000000000 --- a/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp30yp25rp30mr0st300/TEST.properties +++ /dev/null @@ -1,23 +0,0 @@ -# -# Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# 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. -# -exclusiveAccess.dirs=. diff --git a/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp30yp25rp30mr30st0t1/TEST.properties b/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp30yp25rp30mr30st0t1/TEST.properties deleted file mode 100644 index 04b22a107ac..00000000000 --- a/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp30yp25rp30mr30st0t1/TEST.properties +++ /dev/null @@ -1,23 +0,0 @@ -# -# Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# 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. -# -exclusiveAccess.dirs=. diff --git a/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp30yp25rp30mr70st0/TEST.properties b/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp30yp25rp30mr70st0/TEST.properties deleted file mode 100644 index 04b22a107ac..00000000000 --- a/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp30yp25rp30mr70st0/TEST.properties +++ /dev/null @@ -1,23 +0,0 @@ -# -# Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# 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. -# -exclusiveAccess.dirs=. diff --git a/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp30yp25rp30mr70st300t1/TEST.properties b/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp30yp25rp30mr70st300t1/TEST.properties deleted file mode 100644 index 04b22a107ac..00000000000 --- a/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp30yp25rp30mr70st300t1/TEST.properties +++ /dev/null @@ -1,23 +0,0 @@ -# -# Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# 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. -# -exclusiveAccess.dirs=. diff --git a/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp30yp25rp70mr30st0/TEST.properties b/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp30yp25rp70mr30st0/TEST.properties deleted file mode 100644 index 04b22a107ac..00000000000 --- a/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp30yp25rp70mr30st0/TEST.properties +++ /dev/null @@ -1,23 +0,0 @@ -# -# Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# 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. -# -exclusiveAccess.dirs=. diff --git a/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp30yp25rp70mr30st300t1/TEST.properties b/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp30yp25rp70mr30st300t1/TEST.properties deleted file mode 100644 index 04b22a107ac..00000000000 --- a/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp30yp25rp70mr30st300t1/TEST.properties +++ /dev/null @@ -1,23 +0,0 @@ -# -# Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# 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. -# -exclusiveAccess.dirs=. diff --git a/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp50yp0rp0mr30st300/TEST.properties b/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp50yp0rp0mr30st300/TEST.properties deleted file mode 100644 index 04b22a107ac..00000000000 --- a/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp50yp0rp0mr30st300/TEST.properties +++ /dev/null @@ -1,23 +0,0 @@ -# -# Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# 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. -# -exclusiveAccess.dirs=. diff --git a/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp50yp0rp0mr70st300t1/TEST.properties b/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp50yp0rp0mr70st300t1/TEST.properties deleted file mode 100644 index 04b22a107ac..00000000000 --- a/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp50yp0rp0mr70st300t1/TEST.properties +++ /dev/null @@ -1,23 +0,0 @@ -# -# Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# 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. -# -exclusiveAccess.dirs=. diff --git a/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp50yp0rp30mr0st300/TEST.properties b/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp50yp0rp30mr0st300/TEST.properties deleted file mode 100644 index 04b22a107ac..00000000000 --- a/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp50yp0rp30mr0st300/TEST.properties +++ /dev/null @@ -1,23 +0,0 @@ -# -# Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# 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. -# -exclusiveAccess.dirs=. diff --git a/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp50yp0rp30mr30st0t1/TEST.properties b/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp50yp0rp30mr30st0t1/TEST.properties deleted file mode 100644 index 04b22a107ac..00000000000 --- a/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp50yp0rp30mr30st0t1/TEST.properties +++ /dev/null @@ -1,23 +0,0 @@ -# -# Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# 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. -# -exclusiveAccess.dirs=. diff --git a/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp50yp0rp30mr70st0/TEST.properties b/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp50yp0rp30mr70st0/TEST.properties deleted file mode 100644 index 04b22a107ac..00000000000 --- a/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp50yp0rp30mr70st0/TEST.properties +++ /dev/null @@ -1,23 +0,0 @@ -# -# Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# 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. -# -exclusiveAccess.dirs=. diff --git a/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp50yp0rp30mr70st300t1/TEST.properties b/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp50yp0rp30mr70st300t1/TEST.properties deleted file mode 100644 index 04b22a107ac..00000000000 --- a/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp50yp0rp30mr70st300t1/TEST.properties +++ /dev/null @@ -1,23 +0,0 @@ -# -# Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# 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. -# -exclusiveAccess.dirs=. diff --git a/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp50yp0rp70mr30st0/TEST.properties b/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp50yp0rp70mr30st0/TEST.properties deleted file mode 100644 index 04b22a107ac..00000000000 --- a/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp50yp0rp70mr30st0/TEST.properties +++ /dev/null @@ -1,23 +0,0 @@ -# -# Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# 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. -# -exclusiveAccess.dirs=. diff --git a/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp50yp0rp70mr30st300t1/TEST.properties b/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp50yp0rp70mr30st300t1/TEST.properties deleted file mode 100644 index 04b22a107ac..00000000000 --- a/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp50yp0rp70mr30st300t1/TEST.properties +++ /dev/null @@ -1,23 +0,0 @@ -# -# Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# 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. -# -exclusiveAccess.dirs=. diff --git a/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp50yp10rp0mr30st300/TEST.properties b/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp50yp10rp0mr30st300/TEST.properties deleted file mode 100644 index 04b22a107ac..00000000000 --- a/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp50yp10rp0mr30st300/TEST.properties +++ /dev/null @@ -1,23 +0,0 @@ -# -# Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# 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. -# -exclusiveAccess.dirs=. diff --git a/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp50yp10rp0mr70st300t1/TEST.properties b/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp50yp10rp0mr70st300t1/TEST.properties deleted file mode 100644 index 04b22a107ac..00000000000 --- a/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp50yp10rp0mr70st300t1/TEST.properties +++ /dev/null @@ -1,23 +0,0 @@ -# -# Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# 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. -# -exclusiveAccess.dirs=. diff --git a/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp50yp10rp30mr0st300/TEST.properties b/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp50yp10rp30mr0st300/TEST.properties deleted file mode 100644 index 04b22a107ac..00000000000 --- a/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp50yp10rp30mr0st300/TEST.properties +++ /dev/null @@ -1,23 +0,0 @@ -# -# Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# 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. -# -exclusiveAccess.dirs=. diff --git a/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp50yp10rp30mr30st0t1/TEST.properties b/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp50yp10rp30mr30st0t1/TEST.properties deleted file mode 100644 index 04b22a107ac..00000000000 --- a/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp50yp10rp30mr30st0t1/TEST.properties +++ /dev/null @@ -1,23 +0,0 @@ -# -# Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# 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. -# -exclusiveAccess.dirs=. diff --git a/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp50yp10rp30mr70st0/TEST.properties b/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp50yp10rp30mr70st0/TEST.properties deleted file mode 100644 index 04b22a107ac..00000000000 --- a/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp50yp10rp30mr70st0/TEST.properties +++ /dev/null @@ -1,23 +0,0 @@ -# -# Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# 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. -# -exclusiveAccess.dirs=. diff --git a/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp50yp10rp30mr70st300t1/TEST.properties b/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp50yp10rp30mr70st300t1/TEST.properties deleted file mode 100644 index 04b22a107ac..00000000000 --- a/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp50yp10rp30mr70st300t1/TEST.properties +++ /dev/null @@ -1,23 +0,0 @@ -# -# Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# 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. -# -exclusiveAccess.dirs=. diff --git a/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp50yp10rp70mr30st0/TEST.properties b/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp50yp10rp70mr30st0/TEST.properties deleted file mode 100644 index 04b22a107ac..00000000000 --- a/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp50yp10rp70mr30st0/TEST.properties +++ /dev/null @@ -1,23 +0,0 @@ -# -# Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# 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. -# -exclusiveAccess.dirs=. diff --git a/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp50yp10rp70mr30st300t1/TEST.properties b/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp50yp10rp70mr30st300t1/TEST.properties deleted file mode 100644 index 04b22a107ac..00000000000 --- a/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp50yp10rp70mr30st300t1/TEST.properties +++ /dev/null @@ -1,23 +0,0 @@ -# -# Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# 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. -# -exclusiveAccess.dirs=. diff --git a/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp60yp0rp30mr0st300/TEST.properties b/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp60yp0rp30mr0st300/TEST.properties deleted file mode 100644 index 04b22a107ac..00000000000 --- a/test/hotspot/jtreg/vmTestbase/vm/gc/concurrent/lp60yp0rp30mr0st300/TEST.properties +++ /dev/null @@ -1,23 +0,0 @@ -# -# Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. -# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. -# -# This code is free software; you can redistribute it and/or modify it -# 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. -# -exclusiveAccess.dirs=. From 9e98ee6726a7762cce9dae85e2e1b4ca9527fc3c Mon Sep 17 00:00:00 2001 From: Hamlin Li Date: Wed, 25 Oct 2023 15:37:42 +0000 Subject: [PATCH 119/124] 8318735: RISC-V: Enable related hotspot tests run on riscv Reviewed-by: fyang, luhenry --- test/hotspot/jtreg/compiler/c2/irTests/CmpUWithZero.java | 4 ++-- .../jtreg/compiler/intrinsics/TestCompareUnsigned.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/test/hotspot/jtreg/compiler/c2/irTests/CmpUWithZero.java b/test/hotspot/jtreg/compiler/c2/irTests/CmpUWithZero.java index f5b37f229d0..2e8fdd1aea4 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/CmpUWithZero.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/CmpUWithZero.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Red Hat, Inc. All rights reserved. + * Copyright (c) 2022, 2023, 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,7 +29,7 @@ * @test * bug 8290529 * @summary verify that x Date: Wed, 25 Oct 2023 16:38:13 +0000 Subject: [PATCH 120/124] 8317360: Missing null checks in JfrCheckpointManager and JfrStringPool initialization routines Reviewed-by: shade, egahlin --- .../share/jfr/recorder/checkpoint/jfrCheckpointManager.cpp | 3 +++ src/hotspot/share/jfr/recorder/stringpool/jfrStringPool.cpp | 3 +++ 2 files changed, 6 insertions(+) diff --git a/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointManager.cpp b/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointManager.cpp index 118813ef88e..eb1258e35a2 100644 --- a/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointManager.cpp +++ b/src/hotspot/share/jfr/recorder/checkpoint/jfrCheckpointManager.cpp @@ -109,6 +109,9 @@ bool JfrCheckpointManager::initialize() { // preallocate buffer count to each of the epoch live lists for (size_t i = 0; i < global_buffer_prealloc_count * 2; ++i) { Buffer* const buffer = mspace_allocate(global_buffer_size, _global_mspace); + if (buffer == nullptr) { + return false; + } _global_mspace->add_to_live_list(buffer, i % 2 == 0); } assert(_global_mspace->free_list_is_empty(), "invariant"); diff --git a/src/hotspot/share/jfr/recorder/stringpool/jfrStringPool.cpp b/src/hotspot/share/jfr/recorder/stringpool/jfrStringPool.cpp index 47cfca6b892..217b6dbddc3 100644 --- a/src/hotspot/share/jfr/recorder/stringpool/jfrStringPool.cpp +++ b/src/hotspot/share/jfr/recorder/stringpool/jfrStringPool.cpp @@ -131,6 +131,9 @@ bool JfrStringPool::initialize() { // preallocate buffer count to each of the epoch live lists for (size_t i = 0; i < string_pool_cache_count * 2; ++i) { Buffer* const buffer = mspace_allocate(string_pool_buffer_size, _mspace); + if (buffer == nullptr) { + return false; + } _mspace->add_to_live_list(buffer, i % 2 == 0); } assert(_mspace->free_list_is_empty(), "invariant"); From a5208870e16e11514e5b6acae9e933423e54aea0 Mon Sep 17 00:00:00 2001 From: Naoto Sato Date: Wed, 25 Oct 2023 16:50:31 +0000 Subject: [PATCH 121/124] 8318487: Specification of the ListFormat.equals() method can be improved Reviewed-by: joehw, rriggs, lancea, iris --- src/java.base/share/classes/java/text/ListFormat.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/java.base/share/classes/java/text/ListFormat.java b/src/java.base/share/classes/java/text/ListFormat.java index 920cd9a0762..cd26f68bf46 100644 --- a/src/java.base/share/classes/java/text/ListFormat.java +++ b/src/java.base/share/classes/java/text/ListFormat.java @@ -500,11 +500,12 @@ public AttributedCharacterIterator formatToCharacterIterator(Object arguments) { } /** - * Checks if this {@code ListFormat} is equal to another {@code ListFormat}. - * The comparison is based on the {@code Locale} and formatting patterns, given or - * generated with {@code Locale}, {@code Type}, and {@code Style}. - * @param obj the object to check, {@code null} returns {@code false} - * @return {@code true} if this is equals to the other {@code ListFormat} + * Compares the specified object with this {@code ListFormat} for equality. + * Returns {@code true} if the specified object is also a {@code ListFormat}, and + * {@code locale} and {@code patterns}, returned from {@link #getLocale()} + * and {@link #getPatterns()} respectively, are equal. + * @param obj the object to be compared for equality. + * @return {@code true} if the specified object is equal to this {@code ListFormat} */ @Override public boolean equals(Object obj) { From ca3bdfc0c7a74e23329cd9487279992e345b2efd Mon Sep 17 00:00:00 2001 From: Justin Lu Date: Wed, 25 Oct 2023 17:12:37 +0000 Subject: [PATCH 122/124] 8318186: ChoiceFormat inconsistency between applyPattern() and setChoices() Reviewed-by: naoto --- src/java.base/share/classes/java/text/ChoiceFormat.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/java.base/share/classes/java/text/ChoiceFormat.java b/src/java.base/share/classes/java/text/ChoiceFormat.java index 538454d669a..6f27137ea0d 100644 --- a/src/java.base/share/classes/java/text/ChoiceFormat.java +++ b/src/java.base/share/classes/java/text/ChoiceFormat.java @@ -235,8 +235,9 @@ public class ChoiceFormat extends NumberFormat { /** * Apply the given pattern to this ChoiceFormat object. The syntax * for the ChoiceFormat pattern can be seen in the {@linkplain ##patterns - * Patterns} section. - * + * Patterns} section. Unlike {@link #setChoices(double[], String[])} this + * method will throw an {@code IllegalArgumentException} if the {@code + * limits} are not in ascending order. * @param newPattern a pattern string * @throws NullPointerException if {@code newPattern} * is {@code null} From 10427c023a142a24db3c2492977a7233a1afc25d Mon Sep 17 00:00:00 2001 From: Justin Lu Date: Wed, 25 Oct 2023 17:12:55 +0000 Subject: [PATCH 123/124] 8318613: ChoiceFormat patterns are not well tested Reviewed-by: naoto --- .../Format/ChoiceFormat/PatternsTest.java | 153 ++++++++++++++++++ 1 file changed, 153 insertions(+) create mode 100644 test/jdk/java/text/Format/ChoiceFormat/PatternsTest.java diff --git a/test/jdk/java/text/Format/ChoiceFormat/PatternsTest.java b/test/jdk/java/text/Format/ChoiceFormat/PatternsTest.java new file mode 100644 index 00000000000..dc514f5459f --- /dev/null +++ b/test/jdk/java/text/Format/ChoiceFormat/PatternsTest.java @@ -0,0 +1,153 @@ +/* + * 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 6801704 + * @summary Test the expected behavior for a wide range of patterns (both + * correct and incorrect). This test documents the behavior of incorrect + * ChoiceFormat patterns either throwing an exception, or discarding + * the incorrect portion of a pattern. + * @run junit PatternsTest + */ + +import java.text.ChoiceFormat; + +import org.junit.jupiter.api.Test; +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.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.params.provider.Arguments.arguments; + +public class PatternsTest { + + private static final String ERR1 = + "Each interval must contain a number before a format"; + private static final String ERR2 = + "Incorrect order of intervals, must be in ascending order"; + + // Check that some valid patterns do not throw an exception. Check + // them against the expected values they should be formatted as. + @ParameterizedTest + @MethodSource + public void validPatternsTest(String pattern, String[] expectedValues) { + var fmt = new ChoiceFormat(pattern); + for (int i=1; i<=expectedValues.length; i++) { + assertEquals(expectedValues[i-1], fmt.format(i), + String.format("ChoiceFormat formatted %s incorrectly:", i)); + } + } + + // Valid patterns ranging from normal appearing to odd. These should not + // throw an exception or discard any portions of the pattern. + private static Arguments[] validPatternsTest() { + return new Arguments[] { + // Multi pattern with trailing empty string Format + arguments("1#foo|2#bar|3#", new String[]{"foo", "bar", ""}), + // Multi patten with trailing '|' + arguments("1#foo|2#bar|", new String[]{"foo", "bar"}), + // Using a '>' (not a Relation) within a Format + arguments("1#foo|2#bar>", new String[]{"foo", "bar>"}), + // Standard Multi Pattern + arguments("1#foo|2#bar", new String[]{"foo", "bar"}), + // Same numerical value Limits, different Relations + arguments("1#foo|1 new ChoiceFormat(pattern)); + assertEquals(errMsg, ex.getMessage()); + } + + // Variety of patterns that break the ChoiceFormat pattern syntax and throw + // an exception. + private static Arguments[] invalidPatternsThrowsTest() { + return new Arguments[] { + arguments("#foo", ERR1), // No Limit + arguments("0#foo|#|1#bar", ERR1), // Missing Relation in SubPattern + arguments("#|", ERR1), // Missing Limit + arguments("##|", ERR1), // Double Relations + arguments("0#foo1#", ERR1), // SubPattern not separated by '|' + arguments("0#foo#", ERR1), // Using a Relation in a format + arguments("0#test|#", ERR1), // SubPattern missing Limit + arguments("0#foo|3#bar|1#baz", ERR2), // Non-ascending Limits + }; + } + + // Check that the incorrect pattern discards the trailing incorrect portion. + // These incorrect patterns should ideally throw an exception, but for + // behavioral compatibility reasons do not. + @ParameterizedTest + @MethodSource + public void invalidPatternsDiscardedTest(String brokenPattern, String actualPattern) { + var cf1 = new ChoiceFormat(brokenPattern); + var cf2 = new ChoiceFormat(actualPattern); + assertEquals(cf2, cf1, + String.format("Expected %s, but got %s", cf2.toPattern(), cf1.toPattern())); + } + + // Variety of incorrect patterns with the actual expected pattern + // after discarding occurs. + private static Arguments[] invalidPatternsDiscardedTest() { + return new Arguments[] { + // Incomplete SubPattern at the end of the Pattern + arguments("0#foo|1#bar|baz", "0#foo|1#bar"), + + // --- These throw an ArrayIndexOutOfBoundsException + // when attempting to format with them --- + // SubPattern with only a Limit (which is interpreted as a Format) + arguments("0", ""), + // SubPattern with only a Format + arguments("foo", ""), + // empty string + arguments("", "") + }; + } + + // Calling format() with empty limits and formats + // throws an ArrayIndexOutOfBoundsException + @Test + public void emptyLimitsAndFormatsTest() { + var cf1 = new ChoiceFormat(""); + assertThrows(ArrayIndexOutOfBoundsException.class, + () -> cf1.format(1)); + + var cf2 = new ChoiceFormat(new double[]{}, new String[]{}); + assertThrows(ArrayIndexOutOfBoundsException.class, + () -> cf2.format(2)); + } +} From d96f38b80c1606b54b9f3dbfe9717ab9653a0605 Mon Sep 17 00:00:00 2001 From: Frederic Thevenet Date: Wed, 25 Oct 2023 17:30:21 +0000 Subject: [PATCH 124/124] 8317510: Change Windows debug symbol files naming to avoid losing info when an executable and a library share the same name Reviewed-by: ihse, erikj --- make/CreateJmods.gmk | 20 +---- make/Images.gmk | 7 +- make/ZipSecurity.gmk | 6 +- make/common/NativeCompilation.gmk | 16 ++-- make/hotspot/test/GtestImage.gmk | 2 +- .../projectcreator/WinGammaPlatformVC10.java | 4 +- make/scripts/compare_exceptions.sh.incl | 4 +- .../ErrorHandling/TestSymbolsInHsErrFile.java | 76 +++++++++++++++++++ 8 files changed, 99 insertions(+), 36 deletions(-) create mode 100644 test/hotspot/jtreg/runtime/ErrorHandling/TestSymbolsInHsErrFile.java diff --git a/make/CreateJmods.gmk b/make/CreateJmods.gmk index 2901930cf88..6fbaef6bdf1 100644 --- a/make/CreateJmods.gmk +++ b/make/CreateJmods.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2014, 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,13 +81,11 @@ endif ifneq ($(CMDS_DIR), ) DEPS += $(call FindFiles, $(CMDS_DIR)) ifeq ($(call isTargetOs, windows)+$(SHIP_DEBUG_SYMBOLS), true+public) - # For public debug symbols on Windows, we have to use stripped pdbs, rename them - # and filter out a few launcher pdbs where there's a lib that goes by the same name + # For public debug symbols on Windows, we have to use stripped pdbs and rename them rename_stripped = $(patsubst %.stripped.pdb,%.pdb,$1) CMDS_DIR_FILTERED := $(subst modules_cmds,modules_cmds_filtered, $(CMDS_DIR)) FILES_CMDS := $(filter-out %.pdb, $(call FindFiles, $(CMDS_DIR))) \ - $(filter-out %jimage.stripped.pdb %jpackage.stripped.pdb %java.stripped.pdb, \ - $(filter %.stripped.pdb, $(call FindFiles, $(CMDS_DIR)))) + $(filter %.stripped.pdb, $(call FindFiles, $(CMDS_DIR))) $(eval $(call SetupCopyFiles, COPY_FILTERED_CMDS, \ SRC := $(CMDS_DIR), \ DEST := $(CMDS_DIR_FILTERED), \ @@ -96,18 +94,6 @@ ifneq ($(CMDS_DIR), ) )) DEPS += $(COPY_FILTERED_CMDS) JMOD_FLAGS += --cmds $(CMDS_DIR_FILTERED) - else ifeq ($(call isTargetOs, windows)+$(SHIP_DEBUG_SYMBOLS), true+full) - # For full debug symbols on Windows, we have to filter out a few launcher pdbs - # where there's a lib that goes by the same name - CMDS_DIR_FILTERED := $(subst modules_cmds,modules_cmds_filtered, $(CMDS_DIR)) - $(eval $(call SetupCopyFiles, COPY_FILTERED_CMDS, \ - SRC := $(CMDS_DIR), \ - DEST := $(CMDS_DIR_FILTERED), \ - FILES := $(filter-out %jimage.pdb %jpackage.pdb %java.pdb, \ - $(call FindFiles, $(CMDS_DIR))), \ - )) - DEPS += $(COPY_FILTERED_CMDS) - JMOD_FLAGS += --cmds $(CMDS_DIR_FILTERED) else JMOD_FLAGS += --cmds $(CMDS_DIR) endif diff --git a/make/Images.gmk b/make/Images.gmk index aeda1e2f0d6..adf53a83c4f 100644 --- a/make/Images.gmk +++ b/make/Images.gmk @@ -274,9 +274,6 @@ else endif endif -FILTERED_PDBS := %jimage.stripped.pdb %jpackage.stripped.pdb %java.stripped.pdb \ - %jimage.pdb %jpackage.pdb %java.pdb %jimage.map %jpackage.map %java.map - # Param 1 - either JDK or JRE SetupCopyDebuginfo = \ $(foreach m, $(ALL_$1_MODULES), \ @@ -290,8 +287,8 @@ SetupCopyDebuginfo = \ $(eval $(call SetupCopyFiles, COPY_$1_CMDS_DEBUGINFO_$m, \ SRC := $(SUPPORT_OUTPUTDIR)/modules_cmds/$m, \ DEST := $($1_IMAGE_DIR)/$(CMDS_TARGET_SUBDIR), \ - FILES := $(filter-out $(FILTERED_PDBS), $(call FindDebuginfoFiles, \ - $(SUPPORT_OUTPUTDIR)/modules_cmds/$m)), \ + FILES := $(call FindDebuginfoFiles, \ + $(SUPPORT_OUTPUTDIR)/modules_cmds/$m), \ )) \ $(eval $1_TARGETS += $$(COPY_$1_CMDS_DEBUGINFO_$m)) \ ) diff --git a/make/ZipSecurity.gmk b/make/ZipSecurity.gmk index 4f960cd2fcd..00b552fae0a 100644 --- a/make/ZipSecurity.gmk +++ b/make/ZipSecurity.gmk @@ -87,9 +87,9 @@ ifeq ($(call isTargetOs, windows), true) $(eval $(call SetupZipArchive,BUILD_JGSS_BIN_ZIP, \ SRC := $(SUPPORT_OUTPUTDIR), \ INCLUDE_FILES := modules_libs/java.security.jgss/w2k_lsa_auth.dll \ - modules_libs/java.security.jgss/w2k_lsa_auth.diz \ - modules_libs/java.security.jgss/w2k_lsa_auth.map \ - modules_libs/java.security.jgss/w2k_lsa_auth.pdb, \ + modules_libs/java.security.jgss/w2k_lsa_auth.dll.diz \ + modules_libs/java.security.jgss/w2k_lsa_auth.dll.map \ + modules_libs/java.security.jgss/w2k_lsa_auth.dll.pdb, \ ZIP := $(IMAGES_OUTPUTDIR)/$(JGSS_ZIP_NAME))) TARGETS += $(IMAGES_OUTPUTDIR)/$(JGSS_ZIP_NAME) diff --git a/make/common/NativeCompilation.gmk b/make/common/NativeCompilation.gmk index 6056f4632a5..68d1dba27ff 100644 --- a/make/common/NativeCompilation.gmk +++ b/make/common/NativeCompilation.gmk @@ -1073,13 +1073,13 @@ define SetupNativeCompilationBody ifneq ($$($1_TYPE), STATIC_LIBRARY) # Generate debuginfo files. ifeq ($(call isTargetOs, windows), true) - $1_EXTRA_LDFLAGS += -debug "-pdb:$$($1_SYMBOLS_DIR)/$$($1_NOSUFFIX).pdb" \ - "-map:$$($1_SYMBOLS_DIR)/$$($1_NOSUFFIX).map" + $1_EXTRA_LDFLAGS += -debug "-pdb:$$($1_SYMBOLS_DIR)/$$($1_BASENAME).pdb" \ + "-map:$$($1_SYMBOLS_DIR)/$$($1_BASENAME).map" ifeq ($(SHIP_DEBUG_SYMBOLS), public) - $1_EXTRA_LDFLAGS += "-pdbstripped:$$($1_SYMBOLS_DIR)/$$($1_NOSUFFIX).stripped.pdb" + $1_EXTRA_LDFLAGS += "-pdbstripped:$$($1_SYMBOLS_DIR)/$$($1_BASENAME).stripped.pdb" endif - $1_DEBUGINFO_FILES := $$($1_SYMBOLS_DIR)/$$($1_NOSUFFIX).pdb \ - $$($1_SYMBOLS_DIR)/$$($1_NOSUFFIX).map + $1_DEBUGINFO_FILES := $$($1_SYMBOLS_DIR)/$$($1_BASENAME).pdb \ + $$($1_SYMBOLS_DIR)/$$($1_BASENAME).map else ifeq ($(call isTargetOs, linux), true) $1_DEBUGINFO_FILES := $$($1_SYMBOLS_DIR)/$$($1_NOSUFFIX).debuginfo @@ -1127,7 +1127,11 @@ define SetupNativeCompilationBody $1 += $$($1_DEBUGINFO_FILES) ifeq ($$($1_ZIP_EXTERNAL_DEBUG_SYMBOLS), true) - $1_DEBUGINFO_ZIP := $$($1_SYMBOLS_DIR)/$$($1_NOSUFFIX).diz + ifeq ($(call isTargetOs, windows), true) + $1_DEBUGINFO_ZIP := $$($1_SYMBOLS_DIR)/$$($1_BASENAME).diz + else + $1_DEBUGINFO_ZIP := $$($1_SYMBOLS_DIR)/$$($1_NOSUFFIX).diz + endif $1 += $$($1_DEBUGINFO_ZIP) # The dependency on TARGET is needed for debuginfo files diff --git a/make/hotspot/test/GtestImage.gmk b/make/hotspot/test/GtestImage.gmk index d216328e567..9b2a37962cd 100644 --- a/make/hotspot/test/GtestImage.gmk +++ b/make/hotspot/test/GtestImage.gmk @@ -61,7 +61,7 @@ ifeq ($(call isTargetOs, windows), true) $(eval $(call SetupCopyFiles, COPY_GTEST_PDB_$v, \ SRC := $(HOTSPOT_OUTPUTDIR)/variant-$v/libjvm/gtest, \ DEST := $(TEST_IMAGE_DIR)/hotspot/gtest/$v, \ - FILES := jvm.pdb gtestLauncher.pdb, \ + FILES := jvm.dll.pdb gtestLauncher.exe.pdb, \ )) \ $(eval TARGETS += $$(COPY_GTEST_PDB_$v)) \ ) \ diff --git a/make/ide/visualstudio/hotspot/src/classes/build/tools/projectcreator/WinGammaPlatformVC10.java b/make/ide/visualstudio/hotspot/src/classes/build/tools/projectcreator/WinGammaPlatformVC10.java index 092e5afd3e8..ed085dae095 100644 --- a/make/ide/visualstudio/hotspot/src/classes/build/tools/projectcreator/WinGammaPlatformVC10.java +++ b/make/ide/visualstudio/hotspot/src/classes/build/tools/projectcreator/WinGammaPlatformVC10.java @@ -329,7 +329,7 @@ Vector getBaseCompilerFlags(Vector defines, Vector includes, String outDir) { addAttr(rv, "PrecompiledHeaderOutputFile", outDir+Util.sep+"vm.pch"); addAttr(rv, "AssemblerListingLocation", outDir); addAttr(rv, "ObjectFileName", outDir+Util.sep); - addAttr(rv, "ProgramDataBaseFileName", outDir+Util.sep+"jvm.pdb"); + addAttr(rv, "ProgramDataBaseFileName", outDir+Util.sep+"jvm.dll.pdb"); // Set /nologo option addAttr(rv, "SuppressStartupBanner", "true"); // Surpass the default /Tc or /Tp. @@ -409,7 +409,7 @@ Vector getBaseLinkerFlags(String outDir, String outDll, String platformName) { addAttr(rv, "OutputFile", outDll); addAttr(rv, "SuppressStartupBanner", "true"); addAttr(rv, "ModuleDefinitionFile", outDir+Util.sep+"vm.def"); - addAttr(rv, "ProgramDatabaseFile", outDir+Util.sep+"jvm.pdb"); + addAttr(rv, "ProgramDatabaseFile", outDir+Util.sep+"jvm.dll.pdb"); addAttr(rv, "SubSystem", "Windows"); addAttr(rv, "BaseAddress", "0x8000000"); addAttr(rv, "ImportLibrary", outDir+Util.sep+"jvm.lib"); diff --git a/make/scripts/compare_exceptions.sh.incl b/make/scripts/compare_exceptions.sh.incl index d9f62aa1132..d5043637145 100644 --- a/make/scripts/compare_exceptions.sh.incl +++ b/make/scripts/compare_exceptions.sh.incl @@ -49,8 +49,8 @@ elif [ "$OPENJDK_TARGET_OS" = "windows" ]; then SKIP_BIN_DIFF="true" SKIP_FULLDUMP_DIFF="true" ACCEPTED_JARZIP_CONTENTS=" - /modules_libs/java.security.jgss/w2k_lsa_auth.pdb - /modules_libs/java.security.jgss/w2k_lsa_auth.map + /modules_libs/java.security.jgss/w2k_lsa_auth.dll.pdb + /modules_libs/java.security.jgss/w2k_lsa_auth.dll.map /modules_libs/java.security.jgss/w2k_lsa_auth.dll " elif [ "$OPENJDK_TARGET_OS" = "macosx" ]; then diff --git a/test/hotspot/jtreg/runtime/ErrorHandling/TestSymbolsInHsErrFile.java b/test/hotspot/jtreg/runtime/ErrorHandling/TestSymbolsInHsErrFile.java new file mode 100644 index 00000000000..b6a7b582611 --- /dev/null +++ b/test/hotspot/jtreg/runtime/ErrorHandling/TestSymbolsInHsErrFile.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, Red Hat, Inc. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + + +/* + * @test symbolsHsErr + * @summary Test that function names are present in native frames of hs-err file as a proof that symbols are available. + * @library /test/lib + * @requires vm.flagless + * @requires vm.debug + * @requires os.family == "windows" + * @modules java.base/jdk.internal.misc + * java.management + * @run driver TestSymbolsInHsErrFile + */ + +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; + +public class TestSymbolsInHsErrFile { + + public static void main(String[] args) throws Exception { + + // Start a jvm and cause a SIGSEGV / ACCESS_VIOLATION + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-XX:+UnlockDiagnosticVMOptions", + "-Xmx100M", + "-XX:-CreateCoredumpOnCrash", + "-XX:ErrorHandlerTest=14", + "-version"); + + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldNotHaveExitValue(0); + + // Verify that the hs_err problematic frame contains a function name that points to origin of the crash; + // on Windows/MSVC, if symbols are present and loaded, we should see a ref to either 'crash_with_segfault' + // 'VMError::controlled_crash' depending on whether the compile optimizations (i.e. crash_with_segfault + // was inlined or not): + // # Problematic frame: + // # V [jvm.dll+0x.....] crash_with_segfault+0x10 + // or + // # V [jvm.dll+0x.....] VMError::controlled_crash+0x99 + // + // If symbols could not be loaded, however, then the frame will contain not function name at all, i.e. + // # Problematic frame: + // # V [jvm.dll+0x.....] + // NB: this is not true for other OS/Compilers, where the functions names are present even with no symbols, + // hence this test being restricted to Windows only. + output.shouldMatch(("# V \\[jvm.dll.*\\].*(crash_with_segfault|controlled_crash).*")); + + } + +} + +